aboutsummaryrefslogtreecommitdiffstats
path: root/frontend/src/components/auth
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/components/auth')
-rw-r--r--frontend/src/components/auth/LoginForm.js99
-rw-r--r--frontend/src/components/auth/RegisterForm.js167
2 files changed, 266 insertions, 0 deletions
diff --git a/frontend/src/components/auth/LoginForm.js b/frontend/src/components/auth/LoginForm.js
new file mode 100644
index 0000000..fd5aeb7
--- /dev/null
+++ b/frontend/src/components/auth/LoginForm.js
@@ -0,0 +1,99 @@
+import { useState } from 'react';
+import { useForm } from 'react-hook-form';
+import { z } from 'zod';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { useAuth } from '@/context/auth-context';
+import { Button } from '@/components/ui/button';
+import { Input } from '@/components/ui/input';
+import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
+
+// Form validation schema
+const formSchema = z.object({
+ email: z.string().email('Invalid email address'),
+ password: z.string().min(6, 'Password must be at least 6 characters'),
+});
+
+const LoginForm = () => {
+ const { login } = useAuth();
+ const [isLoading, setIsLoading] = useState(false);
+ const [error, setError] = useState('');
+
+ const form = useForm({
+ resolver: zodResolver(formSchema),
+ defaultValues: {
+ email: '',
+ password: '',
+ },
+ });
+
+ const onSubmit = async (values) => {
+ try {
+ setIsLoading(true);
+ setError('');
+ await login({
+ email: values.email,
+ password: values.password,
+ });
+ } catch (error) {
+ setError(error.message || 'Login failed. Please try again.');
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return (
+ <div className="w-full max-w-md mx-auto">
+ <div className="bg-white dark:bg-slate-800 p-8 rounded-lg shadow-md">
+ <h2 className="text-2xl font-bold mb-6 text-center">Login</h2>
+
+ {error && (
+ <div className="bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 p-3 rounded-md mb-4">
+ {error}
+ </div>
+ )}
+
+ <Form {...form}>
+ <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
+ <FormField
+ control={form.control}
+ name="email"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>Email</FormLabel>
+ <FormControl>
+ <Input placeholder="[email protected]" type="email" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ <FormField
+ control={form.control}
+ name="password"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>Password</FormLabel>
+ <FormControl>
+ <Input placeholder="••••••••" type="password" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ <Button
+ type="submit"
+ className="w-full"
+ disabled={isLoading}
+ >
+ {isLoading ? 'Logging in...' : 'Login'}
+ </Button>
+ </form>
+ </Form>
+ </div>
+ </div>
+ );
+};
+
+export default LoginForm; \ No newline at end of file
diff --git a/frontend/src/components/auth/RegisterForm.js b/frontend/src/components/auth/RegisterForm.js
new file mode 100644
index 0000000..3c321ea
--- /dev/null
+++ b/frontend/src/components/auth/RegisterForm.js
@@ -0,0 +1,167 @@
+import { useState } from 'react';
+import { useForm } from 'react-hook-form';
+import { z } from 'zod';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { useAuth } from '@/context/auth-context';
+import { Button } from '@/components/ui/button';
+import { Input } from '@/components/ui/input';
+import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
+
+// Form validation schema
+const formSchema = z.object({
+ name: z.string().min(2, 'Name must be at least 2 characters'),
+ email: z.string().email('Invalid email address'),
+ password: z.string().min(6, 'Password must be at least 6 characters'),
+ confirmPassword: z.string().min(6, 'Password must be at least 6 characters'),
+ phone: z.string().optional(),
+ address: z.string().optional(),
+}).refine((data) => data.password === data.confirmPassword, {
+ message: "Passwords don't match",
+ path: ['confirmPassword'],
+});
+
+const RegisterForm = () => {
+ const { register } = useAuth();
+ const [isLoading, setIsLoading] = useState(false);
+ const [error, setError] = useState('');
+
+ const form = useForm({
+ resolver: zodResolver(formSchema),
+ defaultValues: {
+ name: '',
+ email: '',
+ password: '',
+ confirmPassword: '',
+ phone: '',
+ address: '',
+ },
+ });
+
+ const onSubmit = async (values) => {
+ try {
+ setIsLoading(true);
+ setError('');
+
+ // Remove confirmPassword from the data sent to API
+ const { confirmPassword, ...userData } = values;
+
+ await register(userData);
+ } catch (error) {
+ setError(error.message || 'Registration failed. Please try again.');
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return (
+ <div className="w-full max-w-md mx-auto">
+ <div className="bg-white dark:bg-slate-800 p-8 rounded-lg shadow-md">
+ <h2 className="text-2xl font-bold mb-6 text-center">Create Account</h2>
+
+ {error && (
+ <div className="bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 p-3 rounded-md mb-4">
+ {error}
+ </div>
+ )}
+
+ <Form {...form}>
+ <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
+ <FormField
+ control={form.control}
+ name="name"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>Name</FormLabel>
+ <FormControl>
+ <Input placeholder="John Doe" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ <FormField
+ control={form.control}
+ name="email"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>Email</FormLabel>
+ <FormControl>
+ <Input placeholder="[email protected]" type="email" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ <FormField
+ control={form.control}
+ name="password"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>Password</FormLabel>
+ <FormControl>
+ <Input placeholder="••••••••" type="password" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ <FormField
+ control={form.control}
+ name="confirmPassword"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>Confirm Password</FormLabel>
+ <FormControl>
+ <Input placeholder="••••••••" type="password" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ <FormField
+ control={form.control}
+ name="phone"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>Phone (Optional)</FormLabel>
+ <FormControl>
+ <Input placeholder="(123) 456-7890" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ <FormField
+ control={form.control}
+ name="address"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>Address (Optional)</FormLabel>
+ <FormControl>
+ <Input placeholder="123 Main St, City, State" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ <Button
+ type="submit"
+ className="w-full"
+ disabled={isLoading}
+ >
+ {isLoading ? 'Creating Account...' : 'Register'}
+ </Button>
+ </form>
+ </Form>
+ </div>
+ </div>
+ );
+};
+
+export default RegisterForm; \ No newline at end of file