133 lines
3.4 KiB
TypeScript
133 lines
3.4 KiB
TypeScript
import { Text } from "react-native";
|
|
import { Controller, useForm } from "react-hook-form";
|
|
import { z } from "zod";
|
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
|
|
import { FormInput } from "@/components/auth/FormInput";
|
|
import { PasswordInput } from "@/components/auth/PasswordInput";
|
|
import { MessageDisplay } from "@/components/auth/MessageDisplay";
|
|
import { AuthButton } from "@/components/auth/AuthButton";
|
|
|
|
const signInSchema = z.object({
|
|
emailAddress: z
|
|
.string()
|
|
.trim()
|
|
.min(1, "Email is required")
|
|
.pipe(z.email("Enter a valid email address")),
|
|
password: z
|
|
.string()
|
|
.min(1, "Password is required")
|
|
.max(128, "Password is too long"),
|
|
});
|
|
|
|
type SignInValues = z.infer<typeof signInSchema>;
|
|
|
|
interface SignInFormProps {
|
|
errorMessage: string;
|
|
successMessage: string;
|
|
isLoading: boolean;
|
|
onSignInSubmit: (values: {
|
|
emailAddress: string;
|
|
password: string;
|
|
}) => void | Promise<void>;
|
|
}
|
|
|
|
export const SignInForm = ({
|
|
errorMessage,
|
|
successMessage,
|
|
isLoading,
|
|
onSignInSubmit,
|
|
}: SignInFormProps) => {
|
|
const { control, handleSubmit } = useForm<SignInValues>({
|
|
resolver: zodResolver(signInSchema),
|
|
defaultValues: { emailAddress: "", password: "" },
|
|
mode: "onBlur",
|
|
reValidateMode: "onBlur",
|
|
shouldUnregister: false,
|
|
});
|
|
|
|
const submit = (vals: SignInValues) =>
|
|
onSignInSubmit({
|
|
emailAddress: vals.emailAddress.trim().toLowerCase(),
|
|
password: vals.password,
|
|
});
|
|
|
|
return (
|
|
<>
|
|
<Controller
|
|
control={control}
|
|
name="emailAddress"
|
|
render={({
|
|
field: { onChange, onBlur, value },
|
|
fieldState: { error },
|
|
}) => (
|
|
<>
|
|
<FormInput
|
|
label="Email"
|
|
value={value}
|
|
onChangeText={onChange}
|
|
onBlur={onBlur}
|
|
icon="email"
|
|
keyboardType="email-address"
|
|
disabled={isLoading}
|
|
style={{ marginBottom: 8 }}
|
|
returnKeyType="next"
|
|
/>
|
|
{error ? (
|
|
<Text
|
|
style={{ color: "#F83434", marginTop: -4, marginBottom: 8 }}
|
|
>
|
|
{error.message}
|
|
</Text>
|
|
) : null}
|
|
</>
|
|
)}
|
|
/>
|
|
|
|
<Controller
|
|
control={control}
|
|
name="password"
|
|
render={({
|
|
field: { onChange, onBlur, value },
|
|
fieldState: { error },
|
|
}) => (
|
|
<>
|
|
<PasswordInput
|
|
label="Password"
|
|
value={value}
|
|
onChangeText={onChange}
|
|
onBlur={onBlur}
|
|
disabled={isLoading}
|
|
style={{ marginBottom: 8 }}
|
|
returnKeyType="done"
|
|
onSubmitEditing={() => handleSubmit(submit)()}
|
|
/>
|
|
{error ? (
|
|
<Text
|
|
style={{ color: "#F83434", marginTop: -4, marginBottom: 8 }}
|
|
>
|
|
{error.message}
|
|
</Text>
|
|
) : null}
|
|
</>
|
|
)}
|
|
/>
|
|
|
|
{errorMessage ? (
|
|
<MessageDisplay message={errorMessage} type="error" />
|
|
) : null}
|
|
{successMessage ? (
|
|
<MessageDisplay message={successMessage} type="success" />
|
|
) : null}
|
|
|
|
<AuthButton
|
|
onPress={handleSubmit(submit)}
|
|
loading={isLoading}
|
|
disabled={isLoading}
|
|
>
|
|
{isLoading ? "Signing in..." : "Sign In"}
|
|
</AuthButton>
|
|
</>
|
|
);
|
|
};
|