import React, { useState } from "react"; import { View, TextInput, Alert } from "react-native"; import { useForm, Controller } from "react-hook-form"; import { MyButton, MyText, MyTextInput, ProfileImage, tw, BottomDialog } from "common-ui"; import { trpc } from "@/src/trpc-client"; interface RegisterFormInputs { name: string; email: string; mobile: string; password: string; confirmPassword: string; termsAccepted: boolean; profileImageUri?: string; } interface RegistrationFormProps { onSubmit: (data: FormData) => void | Promise; isLoading?: boolean; initialValues?: Partial; isEdit?: boolean; } function RegistrationForm({ onSubmit, isLoading = false, initialValues, isEdit = false }: RegistrationFormProps) { const [profileImageUri, setProfileImageUri] = useState(); const [profileImageFile, setProfileImageFile] = useState(); const [isPasswordDialogOpen, setIsPasswordDialogOpen] = useState(false); const [password, setPassword] = useState(''); const [confirmPassword, setConfirmPassword] = useState(''); const updatePasswordMutation = trpc.user.auth.updatePassword.useMutation(); // Set initial profile image URI for edit mode React.useEffect(() => { if (isEdit && initialValues?.profileImageUri) { setProfileImageUri(initialValues.profileImageUri); } }, [isEdit, initialValues?.profileImageUri]); const { control, handleSubmit, formState: { errors }, setError, clearErrors, watch, } = useForm({ defaultValues: { name: "", email: "", mobile: "", password: "", confirmPassword: "", termsAccepted: false, ...initialValues, }, }); const validateMobile = (mobile: string): boolean => { // Remove all non-digit characters const cleanMobile = mobile.replace(/\D/g, ''); // Check if it's a valid Indian mobile number (10 digits, starts with 6-9) return cleanMobile.length === 10 && /^[6-9]/.test(cleanMobile); }; const validateEmail = (email: string): boolean => { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); }; const handleFormSubmit = async (data: RegisterFormInputs) => { clearErrors(); // Validate name if (!data.name.trim()) { setError("name", { type: "manual", message: "Name is required", }); return; } if (data.name.trim().length < 2) { setError("name", { type: "manual", message: "Name must be at least 2 characters", }); return; } // Validate email if (!data.email.trim()) { setError("email", { type: "manual", message: "Email is required", }); return; } if (!validateEmail(data.email)) { setError("email", { type: "manual", message: "Please enter a valid email address", }); return; } // Validate mobile number if (!data.mobile.trim()) { setError("mobile", { type: "manual", message: "Mobile number is required", }); return; } if (!validateMobile(data.mobile)) { setError("mobile", { type: "manual", message: "Please enter a valid 10-digit mobile number", }); return; } // Validate password (only in registration mode) if (!isEdit) { if (!data.password) { setError("password", { type: "manual", message: "Password is required", }); return; } if (data.password.length < 6) { setError("password", { type: "manual", message: "Password must be at least 6 characters", }); return; } // Validate confirm password if (data.password !== data.confirmPassword) { setError("confirmPassword", { type: "manual", message: "Passwords do not match", }); return; } } // Validate terms (only in registration mode) if (!isEdit && !data.termsAccepted) { setError("termsAccepted", { type: "manual", message: "You must accept the terms and conditions", }); return; } // Create FormData const formData = new FormData(); formData.append('name', data.name.trim()); formData.append('email', data.email.trim().toLowerCase()); formData.append('mobile', data.mobile.replace(/\D/g, '')); // Only include password if provided (for edit mode) if (data.password) { formData.append('password', data.password); } if (profileImageFile) { formData.append('profileImage', { uri: profileImageFile.uri, type: profileImageFile.mimeType || 'image/jpeg', name: profileImageFile.name || 'profile.jpg', } as any); } await onSubmit(formData); }; const handleUpdatePassword = async () => { if (password !== confirmPassword) { Alert.alert('Error', 'Passwords do not match'); return; } if (password.length < 6) { Alert.alert('Error', 'Password must be at least 6 characters'); return; } try { await updatePasswordMutation.mutateAsync({ password }); Alert.alert('Success', 'Password updated successfully'); setIsPasswordDialogOpen(false); setPassword(''); setConfirmPassword(''); } catch (error: any) { Alert.alert('Error', error.message || 'Failed to update password'); } }; return ( <> { setProfileImageUri(uri); setProfileImageFile(file); }} size={100} editable={true} /> ( )} /> {errors.name && ( {errors.name.message} )} ( )} /> {errors.email && ( {errors.email.message} )} ( { // Format mobile number as user types const clean = text.replace(/\D/g, ''); if (clean.length <= 10) { onChange(clean); } }} onBlur={onBlur} keyboardType="phone-pad" maxLength={10} style={tw`bg-gray-50`} error={!!errors.mobile} /> )} /> {errors.mobile && ( {errors.mobile.message} )} {!isEdit && ( <> ( )} /> {errors.password && ( {errors.password.message} )} ( )} /> {errors.confirmPassword && ( {errors.confirmPassword.message} )} ( onChange(!value)} > {value && ( )} I agree to the{" "} Terms and Conditions {" "} and{" "} Privacy Policy )} /> {errors.termsAccepted && ( {errors.termsAccepted.message} )} )} {isLoading ? (isEdit ? "Updating..." : "Creating Account...") : (isEdit ? "Update Profile" : "Create Account")} {isEdit && ( setIsPasswordDialogOpen(true)} fillColor="brand500" textColor="white1" fullWidth /> )} {isEdit && ( setIsPasswordDialogOpen(false)}> Update Password setIsPasswordDialogOpen(false)} fillColor="gray1" textColor="white1" /> )} ); } export default RegistrationForm;