feat: design applications and first api calls
Co-authored-by: Walid <87608619+WalidKorchi@users.noreply.github.com>
This commit is contained in:
@ -4,10 +4,11 @@ import useTranslation from 'next-translate/useTranslation'
|
||||
import { ErrorPage } from 'components/ErrorPage'
|
||||
import { Head } from 'components/Head'
|
||||
import { Header } from 'components/Header'
|
||||
import { Footer } from 'components/Footer'
|
||||
import { Footer, FooterProps } from 'components/Footer'
|
||||
|
||||
const Error404: React.FC = () => {
|
||||
const Error404: React.FC<FooterProps> = (props) => {
|
||||
const { t } = useTranslation()
|
||||
const { version } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -17,13 +18,15 @@ const Error404: React.FC = () => {
|
||||
<main className='flex flex-col md:mx-auto md:max-w-4xl lg:max-w-7xl'>
|
||||
<ErrorPage statusCode={404} message={t('errors:page-not-found')} />
|
||||
</main>
|
||||
<Footer />
|
||||
<Footer version={version} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const getStaticProps: GetStaticProps = async () => {
|
||||
return { props: {} }
|
||||
export const getStaticProps: GetStaticProps<FooterProps> = async () => {
|
||||
const { readPackage } = await import('read-pkg')
|
||||
const { version } = await readPackage()
|
||||
return { props: { version } }
|
||||
}
|
||||
|
||||
export default Error404
|
||||
|
@ -4,10 +4,11 @@ import useTranslation from 'next-translate/useTranslation'
|
||||
import { ErrorPage } from 'components/ErrorPage'
|
||||
import { Head } from 'components/Head'
|
||||
import { Header } from 'components/Header'
|
||||
import { Footer } from 'components/Footer'
|
||||
import { Footer, FooterProps } from 'components/Footer'
|
||||
|
||||
const Error500: React.FC = () => {
|
||||
const Error500: React.FC<FooterProps> = (props) => {
|
||||
const { t } = useTranslation()
|
||||
const { version } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -17,13 +18,15 @@ const Error500: React.FC = () => {
|
||||
<main className='flex flex-col md:mx-auto md:max-w-4xl lg:max-w-7xl'>
|
||||
<ErrorPage statusCode={500} message={t('errors:server-error')} />
|
||||
</main>
|
||||
<Footer />
|
||||
<Footer version={version} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const getStaticProps: GetStaticProps = async () => {
|
||||
return { props: {} }
|
||||
export const getStaticProps: GetStaticProps<FooterProps> = async () => {
|
||||
const { readPackage } = await import('read-pkg')
|
||||
const { version } = await readPackage()
|
||||
return { props: { version } }
|
||||
}
|
||||
|
||||
export default Error500
|
||||
|
53
pages/application/[guildId]/[channelId].tsx
Normal file
53
pages/application/[guildId]/[channelId].tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import { Head } from 'components/Head'
|
||||
import { Application } from 'components/Application'
|
||||
import { Messages } from 'components/Application/Messages'
|
||||
import {
|
||||
authenticationFromServerSide,
|
||||
AuthenticationProvider,
|
||||
PagePropsWithAuthentication
|
||||
} from 'utils/authentication'
|
||||
|
||||
export interface ChannelPageProps extends PagePropsWithAuthentication {
|
||||
channelId: number
|
||||
guildId: number
|
||||
}
|
||||
|
||||
const ChannelPage: React.FC<ChannelPageProps> = (props) => {
|
||||
const { channelId, guildId, authentication } = props
|
||||
|
||||
return (
|
||||
<AuthenticationProvider authentication={authentication}>
|
||||
<Head title='Thream | Application' />
|
||||
<Application
|
||||
path={{
|
||||
channelId,
|
||||
guildId
|
||||
}}
|
||||
>
|
||||
<Messages />
|
||||
</Application>
|
||||
</AuthenticationProvider>
|
||||
)
|
||||
}
|
||||
|
||||
export const getServerSideProps = authenticationFromServerSide({
|
||||
shouldBeAuthenticated: true,
|
||||
fetchData: async (context) => {
|
||||
const channelId = Number(context?.params?.channelId)
|
||||
const guildId = Number(context?.params?.guildId)
|
||||
if (isNaN(channelId) || isNaN(guildId)) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: '/application',
|
||||
permanent: false
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
channelId,
|
||||
guildId
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default ChannelPage
|
84
pages/application/guilds/create.tsx
Normal file
84
pages/application/guilds/create.tsx
Normal file
@ -0,0 +1,84 @@
|
||||
import Image from 'next/image'
|
||||
import { Form } from 'react-component-form'
|
||||
import TextareaAutosize from 'react-textarea-autosize'
|
||||
|
||||
import { Head } from 'components/Head'
|
||||
import { Application } from 'components/Application'
|
||||
import { Input } from 'components/design/Input'
|
||||
import { Main } from 'components/design/Main'
|
||||
import { Button } from 'components/design/Button'
|
||||
import { FormState } from 'components/design/FormState'
|
||||
import {
|
||||
authenticationFromServerSide,
|
||||
AuthenticationProvider,
|
||||
PagePropsWithAuthentication
|
||||
} from 'utils/authentication'
|
||||
|
||||
const CreateGuild: React.FC<PagePropsWithAuthentication> = (props) => {
|
||||
return (
|
||||
<AuthenticationProvider authentication={props.authentication}>
|
||||
<Head title='Thream | Create a Guild' />
|
||||
<Application path='/application/guilds/create'>
|
||||
<Main>
|
||||
<Form className='w-4/6 max-w-xs'>
|
||||
<div className='flex flex-col'>
|
||||
<div className='flex justify-between mt-6 mb-2'>
|
||||
<label className='pl-1' htmlFor='icon'>
|
||||
Icon
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className='mt-2 relative flex flex-col items-center'>
|
||||
<button className='relative w-14 h-14 flex items-center overflow-hidden justify-center text-green-800 dark:text-green-400 transform scale-125 hover:scale-150'>
|
||||
<Image
|
||||
src='/images/data/guild-default.png'
|
||||
alt='logo'
|
||||
width={56}
|
||||
height={56}
|
||||
className='w-14 h-14 rounded-full'
|
||||
/>
|
||||
<input
|
||||
name='icon'
|
||||
id='icon'
|
||||
type='file'
|
||||
className='absolute w-22 h-20 -top-8 -left-8 opacity-0 cursor-pointer'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Input type='text' placeholder='Name' name='name' label='Name' />
|
||||
|
||||
<div className='flex flex-col'>
|
||||
<div className='flex justify-between mt-6 mb-2'>
|
||||
<label className='pl-1' htmlFor='description'>
|
||||
Description
|
||||
</label>
|
||||
</div>
|
||||
<div className='mt-0 relative'>
|
||||
<TextareaAutosize
|
||||
className='p-3 rounded-lg bg-[#f1f1f1] text-[#2a2a2a] caret-green-600 font-paragraph w-full focus:border focus:outline-none resize-none focus:shadow-green'
|
||||
placeholder='Description...'
|
||||
id='description'
|
||||
name='description'
|
||||
wrap='soft'
|
||||
></TextareaAutosize>
|
||||
<FormState state='idle' />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button className='w-full mt-6' type='submit'>
|
||||
Create
|
||||
</Button>
|
||||
</Form>
|
||||
</Main>
|
||||
</Application>
|
||||
</AuthenticationProvider>
|
||||
)
|
||||
}
|
||||
|
||||
export const getServerSideProps = authenticationFromServerSide({
|
||||
shouldBeAuthenticated: true
|
||||
})
|
||||
|
||||
export default CreateGuild
|
61
pages/application/guilds/join.tsx
Normal file
61
pages/application/guilds/join.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
import Image from 'next/image'
|
||||
|
||||
import { Head } from 'components/Head'
|
||||
import { Application } from 'components/Application'
|
||||
import {
|
||||
authenticationFromServerSide,
|
||||
AuthenticationProvider,
|
||||
PagePropsWithAuthentication
|
||||
} from 'utils/authentication'
|
||||
|
||||
const JoinGuildPage: React.FC<PagePropsWithAuthentication> = (props) => {
|
||||
return (
|
||||
<AuthenticationProvider authentication={props.authentication}>
|
||||
<Head title='Thream | Application' />
|
||||
<Application path='/application/guilds/join'>
|
||||
<input
|
||||
className='w-10/12 sm:w-8/12 md:w-6/12 lg:w-5/12 bg-white dark:bg-[#3B3B3B] border-gray-500 dark:border-gray-700 p-3 my-6 mt-16 mx-auto rounded-md border'
|
||||
type='search'
|
||||
name='search_guild'
|
||||
placeholder='🔎 Search...'
|
||||
/>
|
||||
<div className='w-full flex items-center justify-center p-12'>
|
||||
<div className='max-w-[1600px] grid grid-cols-1 xl:grid-cols-3 md:grid-cols-2 sm:grid-cols-1 gap-8'>
|
||||
{new Array(100).fill(null).map((_, index) => {
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className='max-w-sm flex flex-col items-center justify-center border-gray-500 dark:border-gray-700 p-4 cursor-pointer rounded shadow-lg border transition duration-200 ease-in-out hover:-translate-y-2 hover:shadow-none'
|
||||
>
|
||||
<Image
|
||||
src='/images/icons/Thream.png'
|
||||
alt='logo'
|
||||
width={80}
|
||||
height={80}
|
||||
/>
|
||||
<div className='m-2 text-center mt-3'>
|
||||
<h3 className='font-bold text-xl mb-2'>Guild</h3>
|
||||
<p className='text-base w-11/12 mx-auto'>
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
|
||||
Voluptatibus quia, nulla! Maiores et perferendis eaque,
|
||||
exercitationem praesentium nihil.
|
||||
</p>
|
||||
</div>
|
||||
<p className='flex flex-col text-green-800 dark:text-green-400 mt-4'>
|
||||
54 members
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</Application>
|
||||
</AuthenticationProvider>
|
||||
)
|
||||
}
|
||||
|
||||
export const getServerSideProps = authenticationFromServerSide({
|
||||
shouldBeAuthenticated: true
|
||||
})
|
||||
|
||||
export default JoinGuildPage
|
25
pages/application/index.tsx
Normal file
25
pages/application/index.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import { Head } from 'components/Head'
|
||||
import { Application } from 'components/Application'
|
||||
import { PopupGuild } from 'components/Application/PopupGuild/PopupGuild.stories'
|
||||
import {
|
||||
authenticationFromServerSide,
|
||||
AuthenticationProvider,
|
||||
PagePropsWithAuthentication
|
||||
} from 'utils/authentication'
|
||||
|
||||
const ApplicationPage: React.FC<PagePropsWithAuthentication> = (props) => {
|
||||
return (
|
||||
<AuthenticationProvider authentication={props.authentication}>
|
||||
<Head title='Thream | Application' />
|
||||
<Application path='/application'>
|
||||
<PopupGuild />
|
||||
</Application>
|
||||
</AuthenticationProvider>
|
||||
)
|
||||
}
|
||||
|
||||
export const getServerSideProps = authenticationFromServerSide({
|
||||
shouldBeAuthenticated: true
|
||||
})
|
||||
|
||||
export default ApplicationPage
|
26
pages/application/users/[userId].tsx
Normal file
26
pages/application/users/[userId].tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import { Head } from 'components/Head'
|
||||
import { Application } from 'components/Application'
|
||||
import {
|
||||
authenticationFromServerSide,
|
||||
AuthenticationProvider,
|
||||
PagePropsWithAuthentication
|
||||
} from 'utils/authentication'
|
||||
|
||||
import { UserProfile } from 'components/UserProfile'
|
||||
|
||||
const UserProfilePage: React.FC<PagePropsWithAuthentication> = (props) => {
|
||||
return (
|
||||
<AuthenticationProvider authentication={props.authentication}>
|
||||
<Head title='Thream | Settings' />
|
||||
<Application path='/application/users/[userId]'>
|
||||
<UserProfile user={props.authentication.user} />
|
||||
</Application>
|
||||
</AuthenticationProvider>
|
||||
)
|
||||
}
|
||||
|
||||
export const getServerSideProps = authenticationFromServerSide({
|
||||
shouldBeAuthenticated: true
|
||||
})
|
||||
|
||||
export default UserProfilePage
|
105
pages/authentication/forgot-password.tsx
Normal file
105
pages/authentication/forgot-password.tsx
Normal file
@ -0,0 +1,105 @@
|
||||
import { useState, useMemo } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { AuthenticationForm } from 'components/Authentication'
|
||||
import useTranslation from 'next-translate/useTranslation'
|
||||
import { HandleForm } from 'react-component-form'
|
||||
import axios from 'axios'
|
||||
import { Type } from '@sinclair/typebox'
|
||||
|
||||
import { Head } from 'components/Head'
|
||||
import { Header } from 'components/Header'
|
||||
import { Main } from 'components/design/Main'
|
||||
import { Footer, FooterProps } from 'components/Footer'
|
||||
import { Input } from 'components/design/Input'
|
||||
import { Button } from 'components/design/Button'
|
||||
import { FormState } from 'components/design/FormState'
|
||||
import { useFormState } from 'hooks/useFormState'
|
||||
import { authenticationFromServerSide } from 'utils/authentication'
|
||||
import { ScrollableBody } from 'components/ScrollableBody'
|
||||
import { api } from 'utils/api'
|
||||
import { userSchema } from '../../models/User'
|
||||
import { ajv } from '../../utils/ajv'
|
||||
|
||||
const ForgotPassword: React.FC<FooterProps> = (props) => {
|
||||
const { t } = useTranslation()
|
||||
const { version } = props
|
||||
const [formState, setFormState] = useFormState()
|
||||
const [messageTranslationKey, setMessageTranslationKey] = useState<
|
||||
string | undefined
|
||||
>(undefined)
|
||||
|
||||
const validateSchema = useMemo(() => {
|
||||
return Type.Object({
|
||||
email: userSchema.email
|
||||
})
|
||||
}, [])
|
||||
|
||||
const validate = useMemo(() => {
|
||||
return ajv.compile(validateSchema)
|
||||
}, [validateSchema])
|
||||
|
||||
const handleSubmit: HandleForm = async (formData, formElement) => {
|
||||
const isValid = validate(formData)
|
||||
if (!isValid) {
|
||||
setFormState('error')
|
||||
setMessageTranslationKey('errors:email')
|
||||
} else {
|
||||
setFormState('loading')
|
||||
try {
|
||||
await api.post(
|
||||
`/users/reset-password?redirectURI=${window.location.origin}/authentication/reset-password`,
|
||||
formData
|
||||
)
|
||||
formElement.reset()
|
||||
setFormState('success')
|
||||
setMessageTranslationKey('authentication:success-forgot-password')
|
||||
} catch (error) {
|
||||
setFormState('error')
|
||||
if (axios.isAxiosError(error) && error.response?.status === 400) {
|
||||
setMessageTranslationKey('errors:email')
|
||||
} else {
|
||||
setMessageTranslationKey('errors:server-error')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<ScrollableBody>
|
||||
<Head title={`Thream | ${t('authentication:forgot-password')}`} />
|
||||
<Header />
|
||||
<Main>
|
||||
<AuthenticationForm onSubmit={handleSubmit}>
|
||||
<Input type='email' placeholder='Email' name='email' label='Email' />
|
||||
<Button data-cy='submit' className='w-full mt-6' type='submit'>
|
||||
{t('authentication:submit')}
|
||||
</Button>
|
||||
<p className='mt-3 font-headline text-sm text-green-800 dark:text-green-400 hover:underline'>
|
||||
<Link href='/authentication/signin'>
|
||||
<a>{t('authentication:already-know-password')}</a>
|
||||
</Link>
|
||||
</p>
|
||||
</AuthenticationForm>
|
||||
<FormState
|
||||
id='message'
|
||||
state={formState}
|
||||
message={
|
||||
messageTranslationKey != null ? t(messageTranslationKey) : null
|
||||
}
|
||||
/>
|
||||
</Main>
|
||||
<Footer version={version} />
|
||||
</ScrollableBody>
|
||||
)
|
||||
}
|
||||
|
||||
export const getServerSideProps = authenticationFromServerSide({
|
||||
shouldBeAuthenticated: false,
|
||||
fetchData: async () => {
|
||||
const { readPackage } = await import('read-pkg')
|
||||
const { version } = await readPackage()
|
||||
return { version }
|
||||
}
|
||||
})
|
||||
|
||||
export default ForgotPassword
|
104
pages/authentication/reset-password.tsx
Normal file
104
pages/authentication/reset-password.tsx
Normal file
@ -0,0 +1,104 @@
|
||||
import { useState, useMemo } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import useTranslation from 'next-translate/useTranslation'
|
||||
import { HandleForm } from 'react-component-form'
|
||||
import axios from 'axios'
|
||||
import { Type } from '@sinclair/typebox'
|
||||
|
||||
import { Head } from 'components/Head'
|
||||
import { Header } from 'components/Header'
|
||||
import { Main } from 'components/design/Main'
|
||||
import { Footer, FooterProps } from 'components/Footer'
|
||||
import { Input } from 'components/design/Input'
|
||||
import { Button } from 'components/design/Button'
|
||||
import { FormState } from 'components/design/FormState'
|
||||
import { useFormState } from 'hooks/useFormState'
|
||||
import { authenticationFromServerSide } from 'utils/authentication'
|
||||
import { AuthenticationForm } from 'components/Authentication'
|
||||
import { ScrollableBody } from 'components/ScrollableBody/ScrollableBody'
|
||||
import { api } from 'utils/api'
|
||||
import { userSchema } from '../../models/User'
|
||||
import { ajv } from '../../utils/ajv'
|
||||
|
||||
const ResetPassword: React.FC<FooterProps> = (props) => {
|
||||
const { t } = useTranslation()
|
||||
const router = useRouter()
|
||||
const { version } = props
|
||||
const [formState, setFormState] = useFormState()
|
||||
const [messageTranslationKey, setMessageTranslationKey] = useState<
|
||||
string | undefined
|
||||
>(undefined)
|
||||
|
||||
const validateSchema = useMemo(() => {
|
||||
return Type.Object({
|
||||
password: userSchema.password
|
||||
})
|
||||
}, [])
|
||||
|
||||
const validate = useMemo(() => {
|
||||
return ajv.compile(validateSchema)
|
||||
}, [validateSchema])
|
||||
|
||||
const handleSubmit: HandleForm = async (formData, formElement) => {
|
||||
const isValid = validate(formData)
|
||||
if (!isValid) {
|
||||
setFormState('error')
|
||||
setMessageTranslationKey('errors:invalid')
|
||||
} else {
|
||||
setFormState('loading')
|
||||
try {
|
||||
await api.put(`/users/reset-password`, {
|
||||
...formData,
|
||||
temporaryToken: router.query.temporaryToken
|
||||
})
|
||||
await router.push('/authentication/signin')
|
||||
} catch (error) {
|
||||
setFormState('error')
|
||||
if (axios.isAxiosError(error) && error.response?.status === 400) {
|
||||
setMessageTranslationKey('errors:invalid')
|
||||
} else {
|
||||
setMessageTranslationKey('errors:server-error')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<ScrollableBody>
|
||||
<Head title={`Thream | ${t('authentication:reset-password')}`} />
|
||||
<Header />
|
||||
<Main>
|
||||
<AuthenticationForm onSubmit={handleSubmit}>
|
||||
<Input
|
||||
type='password'
|
||||
placeholder='Password'
|
||||
name='password'
|
||||
label='Password'
|
||||
/>
|
||||
<Button data-cy='submit' className='w-full mt-6' type='submit'>
|
||||
{t('authentication:submit')}
|
||||
</Button>
|
||||
</AuthenticationForm>
|
||||
<FormState
|
||||
id='message'
|
||||
state={formState}
|
||||
message={
|
||||
messageTranslationKey != null ? t(messageTranslationKey) : null
|
||||
}
|
||||
/>
|
||||
</Main>
|
||||
<Footer version={version} />
|
||||
</ScrollableBody>
|
||||
)
|
||||
}
|
||||
|
||||
export const getServerSideProps = authenticationFromServerSide({
|
||||
shouldBeAuthenticated: false,
|
||||
fetchData: async () => {
|
||||
const { readPackage } = await import('read-pkg')
|
||||
const { version } = await readPackage()
|
||||
return { version }
|
||||
}
|
||||
})
|
||||
|
||||
export default ResetPassword
|
33
pages/authentication/signin.tsx
Normal file
33
pages/authentication/signin.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import useTranslation from 'next-translate/useTranslation'
|
||||
|
||||
import { Head } from 'components/Head'
|
||||
import { Authentication } from 'components/Authentication'
|
||||
import { Header } from 'components/Header'
|
||||
import { Footer, FooterProps } from 'components/Footer'
|
||||
import { authenticationFromServerSide } from 'utils/authentication'
|
||||
import { ScrollableBody } from 'components/ScrollableBody'
|
||||
|
||||
const Signin: React.FC<FooterProps> = (props) => {
|
||||
const { version } = props
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<ScrollableBody>
|
||||
<Head title={`Thream | ${t('authentication:signup')}`} />
|
||||
<Header />
|
||||
<Authentication mode='signin' />
|
||||
<Footer version={version} />
|
||||
</ScrollableBody>
|
||||
)
|
||||
}
|
||||
|
||||
export const getServerSideProps = authenticationFromServerSide({
|
||||
shouldBeAuthenticated: false,
|
||||
fetchData: async () => {
|
||||
const { readPackage } = await import('read-pkg')
|
||||
const { version } = await readPackage()
|
||||
return { version }
|
||||
}
|
||||
})
|
||||
|
||||
export default Signin
|
33
pages/authentication/signup.tsx
Normal file
33
pages/authentication/signup.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import useTranslation from 'next-translate/useTranslation'
|
||||
|
||||
import { Head } from 'components/Head'
|
||||
import { Authentication } from 'components/Authentication'
|
||||
import { Header } from 'components/Header'
|
||||
import { Footer, FooterProps } from 'components/Footer'
|
||||
import { authenticationFromServerSide } from 'utils/authentication'
|
||||
import { ScrollableBody } from 'components/ScrollableBody'
|
||||
|
||||
const Signup: React.FC<FooterProps> = (props) => {
|
||||
const { version } = props
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<ScrollableBody>
|
||||
<Head title={`Thream | ${t('authentication:signup')}`} />
|
||||
<Header />
|
||||
<Authentication mode='signup' />
|
||||
<Footer version={version} />
|
||||
</ScrollableBody>
|
||||
)
|
||||
}
|
||||
|
||||
export const getServerSideProps = authenticationFromServerSide({
|
||||
shouldBeAuthenticated: false,
|
||||
fetchData: async () => {
|
||||
const { readPackage } = await import('read-pkg')
|
||||
const { version } = await readPackage()
|
||||
return { version }
|
||||
}
|
||||
})
|
||||
|
||||
export default Signup
|
@ -1,19 +1,21 @@
|
||||
import { GetStaticProps } from 'next'
|
||||
import Link from 'next/link'
|
||||
import Image from 'next/image'
|
||||
|
||||
import Translation from 'next-translate/Trans'
|
||||
import useTranslation from 'next-translate/useTranslation'
|
||||
|
||||
import { Head } from 'components/Head'
|
||||
import { Header } from 'components/Header'
|
||||
import { Main } from 'components/design/Main'
|
||||
import { Footer } from 'components/Footer'
|
||||
import { Footer, FooterProps } from 'components/Footer'
|
||||
import { SocialMediaButton } from 'components/design/SocialMediaButton'
|
||||
import { Button } from 'components/design/Button'
|
||||
import { ScrollableBody } from 'components/ScrollableBody'
|
||||
|
||||
const Home: React.FC = () => {
|
||||
const Home: React.FC<FooterProps> = (props) => {
|
||||
const { t } = useTranslation()
|
||||
const { version } = props
|
||||
|
||||
return (
|
||||
<ScrollableBody>
|
||||
@ -52,7 +54,11 @@ const Home: React.FC = () => {
|
||||
/>
|
||||
</div>
|
||||
<div className='flex justify-center items-center text-center mt-8 space-x-4'>
|
||||
<Button>{t('home:get-started')}</Button>
|
||||
<Link href='/authentication/signup'>
|
||||
<a data-cy='get-started'>
|
||||
<Button>{t('home:get-started')}</Button>
|
||||
</a>
|
||||
</Link>
|
||||
<a
|
||||
href='https://github.com/Thream'
|
||||
target='_blank'
|
||||
@ -64,13 +70,15 @@ const Home: React.FC = () => {
|
||||
</section>
|
||||
</section>
|
||||
</Main>
|
||||
<Footer />
|
||||
<Footer version={version} />
|
||||
</ScrollableBody>
|
||||
)
|
||||
}
|
||||
|
||||
export const getStaticProps: GetStaticProps = async () => {
|
||||
return { props: {} }
|
||||
export const getStaticProps: GetStaticProps<FooterProps> = async () => {
|
||||
const { readPackage } = await import('read-pkg')
|
||||
const { version } = await readPackage()
|
||||
return { props: { version } }
|
||||
}
|
||||
|
||||
export default Home
|
||||
|
Reference in New Issue
Block a user