Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions apps/admin/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "src/app/global.css",
"baseColor": "zinc",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@ielts/ui/components",
"ui": "@ielts/ui/components/ui",
"utils": "@ielts/ui/lib/utils",
"hooks": "@ielts/ui/hooks",
"lib": "@ielts/ui/lib"
}
}
5 changes: 5 additions & 0 deletions apps/admin/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "@ielts/admin",
"version": "0.0.0",
"private": true
}
158 changes: 72 additions & 86 deletions apps/admin/src/app/(auth)/forgot-password/page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
'use client';

import {
Box,
Link as ChakraLink,
FormControl,
FormLabel,
Text,
useToast,
VStack,
} from '@chakra-ui/react';
import { axiosInstance } from '@ielts/auth';
import { Button, Card, CardContent, CardHeader, Input } from '@ielts/ui';
import { Button, Card, CardContent, Input, Label, useToast } from '@ielts/ui';
import { useMutation } from '@tanstack/react-query';
import type { AxiosError } from 'axios';
import { Mail, Shield } from 'lucide-react';
import Link from 'next/link';
import { type FormEvent, useState } from 'react';

Expand All @@ -27,7 +19,7 @@ interface ErrorResponse {
export default function ForgotPasswordPage() {
const [email, setEmail] = useState('');
const [submitted, setSubmitted] = useState(false);
const toast = useToast();
const { toast } = useToast();

const forgotPasswordMutation = useMutation<{ success: boolean }, AxiosError>({
mutationFn: async () => {
Expand All @@ -41,17 +33,14 @@ export default function ForgotPasswordPage() {
toast({
title: 'Email sent!',
description: 'Check your inbox for reset instructions.',
status: 'success',
duration: 5000,
});
},
onError: (error: AxiosError) => {
const err = error as unknown as ErrorResponse;
toast({
title: 'Failed to send email',
description: err.response?.data?.message || 'Please try again',
status: 'error',
duration: 5000,
variant: 'destructive',
});
},
});
Expand All @@ -63,82 +52,79 @@ export default function ForgotPasswordPage() {

if (submitted) {
return (
<Box
minH="100vh"
display="flex"
alignItems="center"
justifyContent="center"
bg="gray.900"
py={12}
px={4}
>
<Card maxW="md" w="full" p={8}>
<CardContent>
<VStack spacing={4}>
<Text fontSize="3xl">βœ…</Text>
<Text fontSize="2xl" fontWeight="bold" color="gray.50">
Check Your Email
</Text>
<Text color="gray.400" textAlign="center">
We've sent password reset instructions to {email}
</Text>
<ChakraLink as={Link} href="/login" color="brand.400" fontWeight="bold">
Return to login
</ChakraLink>
</VStack>
</CardContent>
</Card>
</Box>
<main className="min-h-screen bg-background flex items-center justify-center p-4">
<div className="w-full max-w-md space-y-6 text-center">
<div className="flex h-16 w-16 items-center justify-center rounded-2xl bg-green-500/10 mx-auto mb-4">
<Mail className="h-8 w-8 text-green-500" />
</div>
<h1 className="text-3xl font-bold tracking-tight text-foreground">
Check Your Email
</h1>
<p className="text-sm text-muted-foreground">
We've sent password reset instructions to <span className="font-medium text-foreground">{email}</span>
</p>

<Card className="border-border bg-card shadow-2xl glass-card mt-8">
<CardContent className="pt-6">
<Button asChild className="w-full glow-button">
<Link href="/login">Return to login</Link>
</Button>
</CardContent>
</Card>
</div>
</main>
);
}

return (
<Box
minH="100vh"
display="flex"
alignItems="center"
justifyContent="center"
bg="gray.900"
py={12}
px={4}
>
<Card maxW="md" w="full" p={8}>
<CardHeader>
<VStack spacing={2} textAlign="center">
<Text fontSize="3xl" fontWeight="bold" color="gray.50">
Forgot Password?
</Text>
<Text color="gray.400" fontSize="md">
Enter your admin email to reset your password
</Text>
</VStack>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit}>
<VStack spacing={6}>
<FormControl isRequired>
<FormLabel fontWeight="bold" color="gray.300">
Email
</FormLabel>
<Input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="admin@email.com"
/>
</FormControl>
<main className="min-h-screen bg-background flex items-center justify-center p-4">
<div className="w-full max-w-md space-y-6">
<div className="flex flex-col items-center text-center space-y-2 mb-8">
<div className="flex h-16 w-16 items-center justify-center rounded-2xl bg-primary/10 mb-2">
<Shield className="h-8 w-8 text-primary" />
</div>
<h1 className="text-3xl font-bold tracking-tight text-foreground">
Forgot Password?
</h1>
<p className="text-sm text-muted-foreground">
Enter your admin email to reset your password
</p>
</div>

<Button type="submit" width="100%" isLoading={forgotPasswordMutation.isPending}>
Send Reset Link
</Button>
<Card className="border-border bg-card shadow-2xl glass-card">
<CardContent className="pt-6">
<form onSubmit={handleSubmit} className="space-y-6">
<div className="space-y-4">
<div className="grid gap-2">
<Label htmlFor="email" className="font-semibold text-muted-foreground">
Email
</Label>
<Input
id="email"
type="email"
autoComplete="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="admin@email.com"
required
className="bg-background text-foreground border-input"
/>
</div>
</div>

<div className="space-y-4 pt-2 flex flex-col items-center">
<Button type="submit" className="w-full glow-button" disabled={forgotPasswordMutation.isPending}>
{forgotPasswordMutation.isPending ? 'Sending...' : 'Send Reset Link'}
</Button>

<ChakraLink as={Link} href="/login" color="brand.400" fontWeight="bold">
Back to login
</ChakraLink>
</VStack>
</form>
</CardContent>
</Card>
</Box>
<Link href="/login" className="text-sm font-semibold text-primary hover:underline transition-colors mt-2">
Back to login
</Link>
</div>
</form>
</CardContent>
</Card>
</div>
</main>
);
}
Loading