11import {
22 getFormProps ,
33 getInputProps ,
4- getSelectProps ,
54 useForm ,
65} from '@conform-to/react'
76import { getZodConstraint , parseWithZod } from '@conform-to/zod/v4'
@@ -22,32 +21,22 @@ import {
2221 CheckboxField ,
2322 ErrorList ,
2423 Field ,
25- SelectField ,
2624} from '#app/components/forms.tsx'
2725import { Spacer } from '#app/components/spacer.tsx'
2826import { StatusButton } from '#app/components/ui/status-button.tsx'
2927import { login , requireAnonymous } from '#app/utils/auth.server.ts'
3028import { checkHoneypot } from '#app/utils/honeypot.server.ts'
3129import { useIsPending } from '#app/utils/misc.tsx'
32- import { PasswordSchema } from '#app/utils/user-validation.ts'
30+ import { PasswordSchema , UsernameSchema } from '#app/utils/user-validation.ts'
3331import { handleNewSession } from './login.server.ts'
3432
3533const LoginFormSchema = z . object ( {
36- countryCode : z . string ( ) . min ( 1 , 'Country code is required' ) ,
37- phoneNumber : z . string ( ) . min ( 1 , 'Phone number is required' ) ,
34+ username : UsernameSchema ,
3835 password : PasswordSchema ,
3936 redirectTo : z . string ( ) . optional ( ) ,
4037 remember : z . boolean ( ) . optional ( ) ,
4138} )
4239
43- const countryCodes = [
44- { label : 'United States (+1)' , value : '+1' } ,
45- { label : 'United Kingdom (+44)' , value : '+44' } ,
46- { label : 'Czech Republic (+420)' , value : '+420' } ,
47- { label : 'Canada (+1)' , value : '+1' } ,
48- { label : 'Australia (+61)' , value : '+61' } ,
49- ]
50-
5140export async function loader ( { request } : LoaderFunctionArgs ) {
5241 await requireAnonymous ( request )
5342 return json ( { } )
@@ -63,14 +52,13 @@ export async function action({ request }: ActionFunctionArgs) {
6352 if ( intent !== null ) return { ...data , session : null }
6453
6554 const session = await login ( {
66- identifier : data . phoneNumber ,
67- countryCode : data . countryCode ,
55+ identifier : data . username ,
6856 password : data . password ,
6957 } )
7058 if ( ! session ) {
7159 ctx . addIssue ( {
7260 code : z . ZodIssueCode . custom ,
73- message : 'Invalid phone number or password' ,
61+ message : 'Invalid username or password' ,
7462 } )
7563 return z . NEVER
7664 }
@@ -108,7 +96,6 @@ export default function LoginPage() {
10896 constraint : getZodConstraint ( LoginFormSchema ) ,
10997 defaultValue : {
11098 redirectTo,
111- countryCode : countryCodes [ 0 ] ?. value ?? '+1' ,
11299 } ,
113100 lastResult : actionData ?. result ,
114101 onValidate ( { formData } ) {
@@ -132,32 +119,15 @@ export default function LoginPage() {
132119 < div className = "border-border bg-card mt-8 w-full max-w-lg rounded-[32px] border px-6 py-8 shadow-sm" >
133120 < Form method = "POST" { ...getFormProps ( form ) } className = "space-y-6" >
134121 < HoneypotInputs />
135- < div className = "grid gap-4 md:grid-cols-[200px_1fr]" >
136- < SelectField
137- labelProps = { { children : 'Country Code' } }
138- selectProps = { {
139- ...getSelectProps ( fields . countryCode ) ,
140- children : countryCodes . map ( ( code ) => (
141- < option
142- key = { `${ code . value } -${ code . label } ` }
143- value = { code . value }
144- >
145- { code . label }
146- </ option >
147- ) ) ,
148- } }
149- errors = { fields . countryCode . errors }
150- />
151- < Field
152- labelProps = { { children : 'Phone Number' } }
153- inputProps = { {
154- ...getInputProps ( fields . phoneNumber , { type : 'text' } ) ,
155- autoFocus : true ,
156- autoComplete : 'tel' ,
157- } }
158- errors = { fields . phoneNumber . errors }
159- />
160- </ div >
122+ < Field
123+ labelProps = { { children : 'Username' } }
124+ inputProps = { {
125+ ...getInputProps ( fields . username , { type : 'text' } ) ,
126+ autoFocus : true ,
127+ autoComplete : 'username' ,
128+ } }
129+ errors = { fields . username . errors }
130+ />
161131
162132 < Field
163133 labelProps = { { children : 'Password' } }
0 commit comments