-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5561c91
commit a34397c
Showing
11 changed files
with
302 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { AccountSignInForm } from '@/components/auth/AccountSignInForm'; | ||
import { setRequestLocale } from 'next-intl/server'; | ||
|
||
export default async function AccountPage({ | ||
params, | ||
}: { | ||
params: Promise<{ locale: string }>; | ||
}) { | ||
const { locale } = await params; | ||
setRequestLocale(locale); | ||
return <AccountSignInForm />; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { Button } from '@/components/ui/Button'; | ||
import { Separator } from '@/components/ui/Separator'; | ||
import { Link } from '@/lib/locale/navigation'; | ||
import { getTranslations, setRequestLocale } from 'next-intl/server'; | ||
|
||
export default async function CreateAccountPage({ | ||
params, | ||
}: { | ||
params: Promise<{ locale: string }>; | ||
}) { | ||
const { locale } = await params; | ||
setRequestLocale(locale); | ||
const t = await getTranslations('auth'); | ||
return ( | ||
<div className='flex h-full flex-col transition-opacity duration-500'> | ||
<div className='mb-4 space-y-2 text-center'> | ||
<h1 className='text-4xl'>{t('success')}</h1> | ||
<p className='text-sm'> | ||
{ | ||
'you are now a member of Hackerspace. Now you can finally start praying to our one true leader' | ||
} | ||
</p> | ||
</div> | ||
<Separator /> | ||
<div className='absolute bottom-0 space-y-4'> | ||
<Button asChild> | ||
<Link href='/'>{t('home')}</Link> | ||
</Button> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
'use client'; | ||
|
||
import { accountSignInSchema } from '@/validations/auth/accountSignInSchema'; | ||
import { useTranslations } from 'next-intl'; | ||
import { useState } from 'react'; | ||
|
||
import { api } from '@/lib/api/client'; | ||
import { Link } from '@/lib/locale/navigation'; | ||
import { useRouter } from '@/lib/locale/navigation'; | ||
|
||
import { usePending } from '@/components/auth/PendingBar'; | ||
import { PasswordInput } from '@/components/composites/PasswordInput'; | ||
import { Button } from '@/components/ui/Button'; | ||
import { | ||
Form, | ||
FormControl, | ||
FormItem, | ||
FormLabel, | ||
FormMessage, | ||
useForm, | ||
} from '@/components/ui/Form'; | ||
import { Input } from '@/components/ui/Input'; | ||
|
||
function AccountSignInForm() { | ||
const router = useRouter(); | ||
const t = useTranslations('auth'); | ||
const [accountCreated, setAccountCreated] = useState(false); | ||
const formSchema = accountSignInSchema(t as (key: string) => string, false); | ||
const { isPending, setPending } = usePending(); | ||
|
||
const form = useForm(formSchema, { | ||
defaultValues: { | ||
username: '', | ||
password: '', | ||
}, | ||
onSubmit: () => { | ||
if (!accountCreated) { | ||
router.push('/auth/create-account'); | ||
} | ||
router.push('/'); | ||
}, | ||
}); | ||
|
||
return ( | ||
<div | ||
className={`flex h-full flex-col transition-opacity duration-500 ${isPending ? 'pointer-events-none opacity-50' : ''}`} | ||
> | ||
<div className='mb-4 space-y-2 text-center'> | ||
<h1 className='text-4xl'>{t('signIn')}</h1> | ||
<p className='text-sm'>{t('useYourAccount')}</p> | ||
</div> | ||
<Form onSubmit={form.handleSubmit} className='flex-grow'> | ||
<form.Field name='username'> | ||
{(field) => ( | ||
<FormItem errors={field.state.meta.errors}> | ||
<FormLabel>{t('form.username.label')}</FormLabel> | ||
<FormControl> | ||
<Input | ||
placeholder='[email protected]' | ||
autoComplete='username' | ||
value={field.state.value} | ||
onChange={(e) => field.handleChange(e.target.value)} | ||
onBlur={field.handleBlur} | ||
/> | ||
</FormControl> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
</form.Field> | ||
<form.Field name='password'> | ||
{(field) => ( | ||
<FormItem errors={field.state.meta.errors}> | ||
<div className='flex items-center justify-between'> | ||
<FormLabel>{t('form.password.label')}</FormLabel> | ||
<Button | ||
className='h-auto p-0 leading-none' | ||
asChild | ||
variant='link' | ||
> | ||
<Link href='/auth/forgot-password'> | ||
{`${t('forgotPassword')}?`} | ||
</Link> | ||
</Button> | ||
</div> | ||
<FormControl> | ||
<PasswordInput | ||
autoComplete='current-password' | ||
value={field.state.value} | ||
onChange={(e) => field.handleChange(e.target.value)} | ||
onBlur={field.handleBlur} | ||
/> | ||
</FormControl> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
</form.Field> | ||
<div className='absolute bottom-0 flex w-full xs:flex-row flex-col xs:justify-end justify-between gap-2'> | ||
<form.Subscribe selector={(state) => [state.canSubmit]}> | ||
{([canSubmit]) => ( | ||
<Button className='min-w-28' type='submit' disabled={!canSubmit}> | ||
{t('submit')} | ||
</Button> | ||
)} | ||
</form.Subscribe> | ||
</div> | ||
</Form> | ||
</div> | ||
); | ||
} | ||
|
||
export { AccountSignInForm }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
'use client'; | ||
|
||
import { EyeIcon, EyeOffIcon } from 'lucide-react'; | ||
import { useTranslations } from 'next-intl'; | ||
import * as React from 'react'; | ||
|
||
import { cx } from '@/lib/utils'; | ||
|
||
import { Button } from '@/components/ui/Button'; | ||
import { Input, type InputProps } from '@/components/ui/Input'; | ||
|
||
const PasswordInput = React.forwardRef<HTMLInputElement, InputProps>( | ||
({ className, ...props }, ref) => { | ||
const t = useTranslations('ui'); | ||
const [showPassword, setShowPassword] = React.useState(false); | ||
const disabled = | ||
props.value === '' || props.value === undefined || props.disabled; | ||
|
||
return ( | ||
<div className='relative'> | ||
<Input | ||
type={showPassword ? 'text' : 'password'} | ||
className={cx('pr-10', className)} | ||
ref={ref} | ||
{...props} | ||
/> | ||
<Button | ||
type='button' | ||
variant='ghost' | ||
size='sm' | ||
className='absolute top-0 right-0 h-full px-3 py-2 hover:bg-transparent' | ||
onClick={() => setShowPassword((prev) => !prev)} | ||
disabled={disabled} | ||
aria-label={showPassword ? t('showPassword') : t('hidePassword')} | ||
> | ||
{showPassword && !disabled ? ( | ||
<EyeIcon className='h-4 w-4' aria-hidden='true' /> | ||
) : ( | ||
<EyeOffIcon className='h-4 w-4' aria-hidden='true' /> | ||
)} | ||
</Button> | ||
</div> | ||
); | ||
}, | ||
); | ||
PasswordInput.displayName = 'PasswordInput'; | ||
|
||
export { PasswordInput }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { z } from 'zod'; | ||
|
||
function accountSignInSchema(t: (key: string) => string, isStrict = true) { | ||
let passwordSchema = z.string().min(1, t('form.password.required')); | ||
|
||
if (isStrict) { | ||
passwordSchema = passwordSchema | ||
.min(8, t('form.password.minLength')) | ||
.max(50, t('form.password.maxLength')) | ||
.regex(/[A-Z]/, t('form.password.uppercase')) | ||
.regex(/[^a-zA-Z0-9]/, t('form.password.specialChar')); | ||
} | ||
|
||
return z.object({ | ||
username: z | ||
.string() | ||
.min(1, t('form.username.required')) | ||
.min(5, t('form.username.minLength')) | ||
.max(8, t('form.username.maxLength')) | ||
.regex(/^[a-z]+$/, t('form.username.invalid')), | ||
password: passwordSchema, | ||
}); | ||
} | ||
|
||
export { accountSignInSchema }; |