A very performant and light (2mb in memory) link shortener and tracker. Written in Rust and React and uses Postgres/SQLite.
at master 4.9 kB view raw
1import { useState, useEffect } from 'react' 2import { useForm } from 'react-hook-form' 3import { z } from 'zod' 4import { zodResolver } from '@hookform/resolvers/zod' 5import { useAuth } from '../context/AuthContext' 6import { Button } from '@/components/ui/button' 7import { Input } from '@/components/ui/input' 8import { Card } from '@/components/ui/card' 9import { 10 Form, 11 FormControl, 12 FormField, 13 FormItem, 14 FormLabel, 15 FormMessage, 16} from '@/components/ui/form' 17import { useToast } from '@/hooks/use-toast' 18import { checkFirstUser } from '../api/client' 19 20const formSchema = z.object({ 21 email: z.string().email('Invalid email address'), 22 password: z.string().min(6, 'Password must be at least 6 characters long'), 23 adminToken: z.string().optional(), 24}) 25 26type FormValues = z.infer<typeof formSchema> 27 28export function AuthForms() { 29 const [isFirstUser, setIsFirstUser] = useState<boolean | null>(null) 30 const { login, register } = useAuth() 31 const { toast } = useToast() 32 33 const form = useForm<FormValues>({ 34 resolver: zodResolver(formSchema), 35 defaultValues: { 36 email: '', 37 password: '', 38 adminToken: '', 39 }, 40 }) 41 42 useEffect(() => { 43 const init = async () => { 44 try { 45 const isFirst = await checkFirstUser() 46 setIsFirstUser(isFirst) 47 } catch (err) { 48 console.error('Error checking first user:', err) 49 setIsFirstUser(false) 50 } 51 } 52 53 init() 54 }, []) 55 56 const onSubmit = async (values: FormValues) => { 57 try { 58 if (isFirstUser) { 59 await register(values.email, values.password, values.adminToken || '') 60 } else { 61 await login(values.email, values.password) 62 } 63 form.reset() 64 } catch (err: any) { 65 toast({ 66 variant: 'destructive', 67 title: 'Error', 68 description: err.response?.data || 'An error occurred', 69 }) 70 } 71 } 72 73 if (isFirstUser === null) { 74 return <div>Loading...</div> 75 } 76 77 return ( 78 <Card className="w-full max-w-md mx-auto p-6"> 79 <div className="mb-6 text-center"> 80 <h2 className="text-2xl font-bold"> 81 {isFirstUser ? 'Create Admin Account' : 'Login'} 82 </h2> 83 <p className="text-sm text-muted-foreground mt-1"> 84 {isFirstUser 85 ? 'Set up your admin account to get started' 86 : 'Welcome back! Please login to your account'} 87 </p> 88 </div> 89 90 <Form {...form}> 91 <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4"> 92 <FormField 93 control={form.control} 94 name="email" 95 render={({ field }) => ( 96 <FormItem> 97 <FormLabel>Email</FormLabel> 98 <FormControl> 99 <Input type="email" {...field} /> 100 </FormControl> 101 <FormMessage /> 102 </FormItem> 103 )} 104 /> 105 106 <FormField 107 control={form.control} 108 name="password" 109 render={({ field }) => ( 110 <FormItem> 111 <FormLabel>Password</FormLabel> 112 <FormControl> 113 <Input type="password" {...field} /> 114 </FormControl> 115 <FormMessage /> 116 </FormItem> 117 )} 118 /> 119 120 {isFirstUser && ( 121 <FormField 122 control={form.control} 123 name="adminToken" 124 render={({ field }) => ( 125 <FormItem> 126 <FormLabel>Admin Setup Token</FormLabel> 127 <FormControl> 128 <Input type="text" {...field} /> 129 </FormControl> 130 <FormMessage /> 131 </FormItem> 132 )} 133 /> 134 )} 135 136 <Button type="submit" className="w-full"> 137 {isFirstUser ? 'Create Account' : 'Sign in'} 138 </Button> 139 </form> 140 </Form> 141 </Card> 142 ) 143}