Skip to content

Commit

Permalink
feat(frontend): forget password and logout
Browse files Browse the repository at this point in the history
  • Loading branch information
tithanayut committed Feb 15, 2025
1 parent 08cb7a8 commit 14e683d
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 7 deletions.
2 changes: 2 additions & 0 deletions frontend/app/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export default [
layout('routes/auth/layout.tsx', [
route('login', 'routes/auth/login.tsx'),
route('register', 'routes/auth/register.tsx'),
route('logout', 'routes/auth/logout.tsx'),
route('forget-password', 'routes/auth/forget-password.tsx'),
route('pending-verification', 'routes/auth/pending-verification.tsx'),
]),
] satisfies RouteConfig;
72 changes: 72 additions & 0 deletions frontend/app/routes/auth/forget-password.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Link, useNavigate } from 'react-router';
import { Button } from '~/components/ui/button';
import { Input } from '~/components/ui/input';
import { Label } from '~/components/ui/label';
import { ChevronLeft } from 'lucide-react';
import { redirectIfLoggedIn } from '~/common/auth';
import type { Route } from './+types/register';
import * as zod from 'zod';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { client } from '~/clients/client';
import toast from 'react-hot-toast';

export async function loader({ request }: Route.LoaderArgs) {
await redirectIfLoggedIn(request, '/home');
}

const ForgetPasswordSchema = zod.object({
email: zod.string().nonempty({ message: 'Please enter your email' }).email({ message: 'Please enter a valid email' }),
});
type ForgetPasswordSchema = zod.infer<typeof ForgetPasswordSchema>;

export default function ForgetPassword() {
const navigate = useNavigate();
const {
register,
formState: { errors },
handleSubmit,
} = useForm({
resolver: zodResolver(ForgetPasswordSchema),
});
const { mutateAsync, isPending } = client.useMutation('post', '/account/v1/reset-password');

const handleRegister = async ({ email }: ForgetPasswordSchema) => {
try {
await mutateAsync({ body: { email } });
toast.dismiss();
toast.success('Email sent successfully');
navigate('/pending-verification');
} catch {
toast.error('Something went wrong');
}
};

return (
<div className="flex flex-col gap-12 p-8">
<Link to="/login" className="flex items-center gap-1.5 text-secondary">
<ChevronLeft /> Back
</Link>
<div className="flex flex-col gap-14 w-2/3 mx-auto">
<div className="flex flex-col gap-6">
<h1 className="text-4xl font-bold">Forget password</h1>
<h2 className="text-lg text-secondary">Don&apos;t worry! Just a few steps away.</h2>
</div>
<div className="flex flex-col gap-10">
<form className="flex flex-col gap-5" onSubmit={handleSubmit(handleRegister)}>
<div className="flex flex-col gap-2.5">
<Label htmlFor="email" className="text-secondary">
Email
</Label>
<Input id="email" placeholder="Enter your email" className="h-14" {...register('email')} />
{errors.email && <p className="text-destructive">{errors.email.message}</p>}
</div>
<Button className="h-14 text-md" disabled={isPending}>
Continue
</Button>
</form>
</div>
</div>
</div>
);
}
23 changes: 19 additions & 4 deletions frontend/app/routes/auth/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ export default function Login() {
client_id: GOOGLE_CLIENT_ID,
callback: handleLoginWithGoogle,
});
window.google.accounts.id.prompt();
if (googleSignInButtonRef.current) {
window.google.accounts.id.renderButton(googleSignInButtonRef.current, {
type: 'standard',
Expand Down Expand Up @@ -107,9 +106,14 @@ export default function Login() {
<p className="text-destructive">{errors.email?.message}</p>
</div>
<div className="flex flex-col gap-2.5">
<Label htmlFor="password" className="text-secondary">
Password
</Label>
<div className="flex justify-between items-center">
<Label htmlFor="password" className="text-secondary">
Password
</Label>
<Link to="/forget-password" className="text-sm text-blue-500 hover:underline">
Forget Password
</Link>
</div>
<Input
id="password"
type="password"
Expand All @@ -123,6 +127,17 @@ export default function Login() {
Sign in
</Button>
</form>
<div className="text-center text-secondary">
Don&apos;t have an account?{' '}
<Link to="/register" className="text-blue-500 hover:underline">
Create an account
</Link>
</div>
<div className="flex items-center gap-2">
<div className="border-t border-secondary w-1/2"></div>
<div className="text-gray-500">or</div>
<div className="border-t border-secondary w-1/2"></div>
</div>
<div ref={googleSignInButtonRef} />
{/* <Button className="h-14 text-md" variant="outline" disabled={isPending}>
Sign in with Google <img src={google} />
Expand Down
39 changes: 39 additions & 0 deletions frontend/app/routes/auth/logout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useNavigate } from 'react-router';
import { ChevronLeft } from 'lucide-react';

import { client } from '~/clients/client';
import { useEffect } from 'react';
import toast from 'react-hot-toast';

export default function Logout() {
const navigate = useNavigate();
const { mutateAsync } = client.useMutation('post', '/auth/v1/logout');

useEffect(() => {
const logout = async () => {
try {
await mutateAsync({});
toast.success('Logged out successfully');
navigate('/login');
} catch {
toast.error('Something went wrong');
return;
}
};
logout();
}, []);

return (
<div className="flex flex-col gap-12 p-8">
<button className="flex items-center gap-1.5 text-secondary" onClick={() => navigate(-1)}>
<ChevronLeft /> Back
</button>
<div className="flex flex-col gap-14 w-2/3 mx-auto">
<div className="flex flex-col gap-6">
<h1 className="text-4xl font-bold">Logout</h1>
<h2 className="text-lg text-secondary">Please wait a moment...</h2>
</div>
</div>
</div>
);
}
2 changes: 1 addition & 1 deletion frontend/app/routes/auth/pending-verification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default function PendingVerification() {
<h2 className="text-lg text-secondary">Just one last step!</h2>
</div>
<div className="flex flex-col gap-10">
<p>We have sent a verification email to your inbox.</p>
<p>We have sent an email to your inbox.</p>
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/routes/auth/register.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export default function Register() {

return (
<div className="flex flex-col gap-12 p-8">
<Link to="/register" className="flex items-center gap-1.5 text-secondary">
<Link to="/login" className="flex items-center gap-1.5 text-secondary">
<ChevronLeft /> Back
</Link>
<div className="flex flex-col gap-14 w-2/3 mx-auto">
Expand Down
11 changes: 10 additions & 1 deletion frontend/app/routes/home.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import { requireAuth } from '~/common/auth';
import type { Route } from './+types/home';
import { Link } from 'react-router';
import { Button } from '~/components/ui/button';

export async function loader({ request }: Route.LoaderArgs) {
await requireAuth(request);
}

export default function Home() {
return <div>Home</div>;
return (
<div className="flex justify-between p-8">
<h1 className="text-xl">Home</h1>
<Button asChild variant="outline" className="w-fit">
<Link to="/logout">Logout</Link>
</Button>
</div>
);
}

0 comments on commit 14e683d

Please sign in to comment.