update auth guard and sign-in forms, add guidelines for custom auth to handle login and logout,

This commit is contained in:
louiscklaw
2025-05-11 07:54:23 +08:00
parent 25c1d3c917
commit 9a8fd1c073
4 changed files with 139 additions and 25 deletions

View File

@@ -29,6 +29,7 @@ export function AuthGuard({ children }: AuthGuardProps): React.JSX.Element | nul
return;
}
// NOTE: here state that if user = null, eject user to login page
if (!user) {
logger.debug('[AuthGuard]: User is not logged in, redirecting to sign in');

View File

@@ -0,0 +1,10 @@
# GUIDELINES
This folder contains login pages
the `@` sign refer to `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/002_source/cms/src`
## Assumption and Requirements
- assume `pb` is located in `@/lib/pb`
- no need to handle error in this function, i'll handle it in the caller

View File

@@ -1,4 +1,6 @@
'use client';
// RULES:
// refer to ticket REQ0016 for login flow
import * as React from 'react';
import RouterLink from 'next/link';
@@ -25,6 +27,7 @@ import { authClient } from '@/lib/auth/custom/client';
import { useUser } from '@/hooks/use-user';
import { DynamicLogo } from '@/components/core/logo';
import { toast } from '@/components/core/toaster';
import { pb } from '@/lib/pb';
interface OAuthProvider {
id: 'google' | 'discord';
@@ -44,7 +47,7 @@ const schema = zod.object({
type Values = zod.infer<typeof schema>;
const defaultValues = { email: '', password: '' } satisfies Values;
const defaultValues = { email: 'admin@123.com', password: 'admin@123.com' } satisfies Values;
export function SignInForm(): React.JSX.Element {
const router = useRouter();
@@ -103,15 +106,31 @@ export function SignInForm(): React.JSX.Element {
return (
<Stack spacing={4}>
<div>
<Box component={RouterLink} href={paths.home} sx={{ display: 'inline-block', fontSize: 0 }}>
<DynamicLogo colorDark="light" colorLight="dark" height={32} width={122} />
<Box
component={RouterLink}
href={paths.home}
sx={{ display: 'inline-block', fontSize: 0 }}
>
<DynamicLogo
colorDark="light"
colorLight="dark"
height={32}
width={122}
/>
</Box>
</div>
<Stack spacing={1}>
<Typography variant="h5">Sign in</Typography>
<Typography color="text.secondary" variant="body2">
<Typography
color="text.secondary"
variant="body2"
>
Don&apos;t have an account?{' '}
<Link component={RouterLink} href={paths.auth.custom.signUp} variant="subtitle2">
<Link
component={RouterLink}
href={paths.auth.custom.signUp}
variant="subtitle2"
>
Sign up
</Link>
</Typography>
@@ -123,7 +142,15 @@ export function SignInForm(): React.JSX.Element {
<Button
color="secondary"
disabled={isPending}
endIcon={<Box alt="" component="img" height={24} src={provider.logo} width={24} />}
endIcon={
<Box
alt=""
component="img"
height={24}
src={provider.logo}
width={24}
/>
}
key={provider.id}
onClick={(): void => {
onAuth(provider.id).catch(() => {
@@ -147,7 +174,10 @@ export function SignInForm(): React.JSX.Element {
render={({ field }) => (
<FormControl error={Boolean(errors.email)}>
<InputLabel>Email address</InputLabel>
<OutlinedInput {...field} type="email" />
<OutlinedInput
{...field}
type="email"
/>
{errors.email ? <FormHelperText>{errors.email.message}</FormHelperText> : null}
</FormControl>
)}
@@ -187,27 +217,65 @@ export function SignInForm(): React.JSX.Element {
)}
/>
{errors.root ? <Alert color="error">{errors.root.message}</Alert> : null}
<Button disabled={isPending} type="submit" variant="contained">
<Button
disabled={isPending}
type="submit"
variant="contained"
>
Sign in
</Button>
</Stack>
</form>
<div>
<Link component={RouterLink} href={paths.auth.custom.resetPassword} variant="subtitle2">
<Link
component={RouterLink}
href={paths.auth.custom.resetPassword}
variant="subtitle2"
>
Forgot password?
</Link>
</div>
</Stack>
</Stack>
<Alert color="warning">
Use{' '}
<Typography component="span" sx={{ fontWeight: 700 }} variant="inherit">
sofia@devias.io
</Typography>{' '}
with password{' '}
<Typography component="span" sx={{ fontWeight: 700 }} variant="inherit">
Secret1
</Typography>
<Stack>
<Box>
user:{' '}
<Typography
component="span"
sx={{ fontWeight: 700 }}
variant="inherit"
>
admin@123.com
</Typography>{' '}
password{' '}
<Typography
component="span"
sx={{ fontWeight: 700 }}
variant="inherit"
>
admin@123.com
</Typography>
</Box>
<Box>
user{' '}
<Typography
component="span"
sx={{ fontWeight: 700 }}
variant="inherit"
>
sofia@devias.io
</Typography>{' '}
password{' '}
<Typography
component="span"
sx={{ fontWeight: 700 }}
variant="inherit"
>
Secret1
</Typography>
</Box>
</Stack>
</Alert>
</Stack>
);

View File

@@ -115,15 +115,31 @@ export function SignInForm(): React.JSX.Element {
return (
<Stack spacing={4}>
<div>
<Box component={RouterLink} href={paths.home} sx={{ display: 'inline-block', fontSize: 0 }}>
<DynamicLogo colorDark="light" colorLight="dark" height={32} width={122} />
<Box
component={RouterLink}
href={paths.home}
sx={{ display: 'inline-block', fontSize: 0 }}
>
<DynamicLogo
colorDark="light"
colorLight="dark"
height={32}
width={122}
/>
</Box>
</div>
<Stack spacing={1}>
<Typography variant="h5">Sign in</Typography>
<Typography color="text.secondary" variant="body2">
<Typography
color="text.secondary"
variant="body2"
>
Don&apos;t have an account?{' '}
<Link component={RouterLink} href={paths.auth.supabase.signUp} variant="subtitle2">
<Link
component={RouterLink}
href={paths.auth.supabase.signUp}
variant="subtitle2"
>
Sign up
</Link>
</Typography>
@@ -135,7 +151,15 @@ export function SignInForm(): React.JSX.Element {
<Button
color="secondary"
disabled={isPending}
endIcon={<Box alt="" component="img" height={24} src={provider.logo} width={24} />}
endIcon={
<Box
alt=""
component="img"
height={24}
src={provider.logo}
width={24}
/>
}
key={provider.id}
onClick={(): void => {
onAuth(provider.id).catch(() => {
@@ -159,7 +183,10 @@ export function SignInForm(): React.JSX.Element {
render={({ field }) => (
<FormControl error={Boolean(errors.email)}>
<InputLabel>Email address</InputLabel>
<OutlinedInput {...field} type="email" />
<OutlinedInput
{...field}
type="email"
/>
{errors.email ? <FormHelperText>{errors.email.message}</FormHelperText> : null}
</FormControl>
)}
@@ -199,13 +226,21 @@ export function SignInForm(): React.JSX.Element {
)}
/>
{errors.root ? <Alert color="error">{errors.root.message}</Alert> : null}
<Button disabled={isPending} type="submit" variant="contained">
<Button
disabled={isPending}
type="submit"
variant="contained"
>
Sign in
</Button>
</Stack>
</form>
<div>
<Link component={RouterLink} href={paths.auth.supabase.resetPassword} variant="subtitle2">
<Link
component={RouterLink}
href={paths.auth.supabase.resetPassword}
variant="subtitle2"
>
Forgot password?
</Link>
</div>