228 lines
7.4 KiB
TypeScript
228 lines
7.4 KiB
TypeScript
"use client"
|
|
|
|
import { zodResolver } from "@hookform/resolvers/zod"
|
|
import { useRouter } from "next/navigation"
|
|
import { FormProvider, useForm } from "react-hook-form"
|
|
import { useIntl } from "react-intl"
|
|
|
|
import {
|
|
membershipTermsAndConditions,
|
|
privacyPolicy,
|
|
} from "@/constants/currentWebHrefs"
|
|
import { trpc } from "@/lib/trpc/client"
|
|
|
|
import Button from "@/components/TempDesignSystem/Button"
|
|
import Checkbox from "@/components/TempDesignSystem/Form/Checkbox"
|
|
import CountrySelect from "@/components/TempDesignSystem/Form/Country"
|
|
import DateSelect from "@/components/TempDesignSystem/Form/Date"
|
|
import Input from "@/components/TempDesignSystem/Form/Input"
|
|
import NewPassword from "@/components/TempDesignSystem/Form/NewPassword"
|
|
import Phone from "@/components/TempDesignSystem/Form/Phone"
|
|
import Link from "@/components/TempDesignSystem/Link"
|
|
import Body from "@/components/TempDesignSystem/Text/Body"
|
|
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
|
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
|
import Title from "@/components/TempDesignSystem/Text/Title"
|
|
import { toast } from "@/components/TempDesignSystem/Toasts"
|
|
import useLang from "@/hooks/useLang"
|
|
|
|
import { type SignUpSchema, signUpSchema } from "./schema"
|
|
|
|
import styles from "./form.module.css"
|
|
|
|
import type { SignUpFormProps } from "@/types/components/form/signupForm"
|
|
|
|
export default function SignupForm({ link, subtitle, title }: SignUpFormProps) {
|
|
const intl = useIntl()
|
|
const router = useRouter()
|
|
const lang = useLang()
|
|
const country = intl.formatMessage({ id: "Country" })
|
|
const email = intl.formatMessage({ id: "Email address" })
|
|
const phoneNumber = intl.formatMessage({ id: "Phone number" })
|
|
const zipCode = intl.formatMessage({ id: "Zip code" })
|
|
const signupButtonText = intl.formatMessage({
|
|
id: "Join now",
|
|
})
|
|
|
|
const signup = trpc.user.signup.useMutation({
|
|
onSuccess: (data) => {
|
|
if (data.success && data.redirectUrl) {
|
|
router.push(data.redirectUrl)
|
|
}
|
|
},
|
|
onError: (error) => {
|
|
toast.error(intl.formatMessage({ id: "Something went wrong!" }))
|
|
console.error("Component Signup error:", error)
|
|
},
|
|
})
|
|
|
|
const methods = useForm<SignUpSchema>({
|
|
defaultValues: {
|
|
firstName: "",
|
|
lastName: "",
|
|
email: "",
|
|
phoneNumber: "",
|
|
dateOfBirth: "",
|
|
address: {
|
|
countryCode: "",
|
|
zipCode: "",
|
|
},
|
|
password: "",
|
|
termsAccepted: false,
|
|
},
|
|
mode: "all",
|
|
criteriaMode: "all",
|
|
resolver: zodResolver(signUpSchema),
|
|
reValidateMode: "onChange",
|
|
shouldFocusError: true,
|
|
})
|
|
|
|
async function onSubmit(data: SignUpSchema) {
|
|
signup.mutate({ ...data, language: lang })
|
|
}
|
|
|
|
return (
|
|
<section className={styles.formWrapper}>
|
|
<Title as="h3">{title}</Title>
|
|
<FormProvider {...methods}>
|
|
<form
|
|
className={styles.form}
|
|
id="register"
|
|
onSubmit={methods.handleSubmit(onSubmit)}
|
|
>
|
|
<section className={styles.userInfo}>
|
|
<div className={styles.container}>
|
|
<header>
|
|
<Subtitle type="two">
|
|
{intl.formatMessage({ id: "Contact information" })}
|
|
</Subtitle>
|
|
</header>
|
|
<div className={styles.nameInputs}>
|
|
<Input
|
|
label={intl.formatMessage({ id: "First name" })}
|
|
name="firstName"
|
|
registerOptions={{ required: true }}
|
|
/>
|
|
<Input
|
|
label={intl.formatMessage({ id: "Last name" })}
|
|
name="lastName"
|
|
registerOptions={{ required: true }}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className={styles.dateField}>
|
|
<header>
|
|
<Caption type="bold">
|
|
{intl.formatMessage({ id: "Birth date" })}
|
|
</Caption>
|
|
</header>
|
|
<DateSelect
|
|
name="dateOfBirth"
|
|
registerOptions={{ required: true }}
|
|
/>
|
|
</div>
|
|
<div className={styles.container}>
|
|
<Input
|
|
label={zipCode}
|
|
name="address.zipCode"
|
|
registerOptions={{ required: true }}
|
|
/>
|
|
<CountrySelect
|
|
label={country}
|
|
name="address.countryCode"
|
|
registerOptions={{ required: true }}
|
|
/>
|
|
</div>
|
|
<Input
|
|
label={email}
|
|
name="email"
|
|
registerOptions={{ required: true }}
|
|
type="email"
|
|
/>
|
|
<Phone label={phoneNumber} name="phoneNumber" />
|
|
</section>
|
|
<section className={styles.password}>
|
|
<header>
|
|
<Subtitle type="two">
|
|
{intl.formatMessage({ id: "Password" })}
|
|
</Subtitle>
|
|
</header>
|
|
<NewPassword
|
|
name="password"
|
|
label={intl.formatMessage({ id: "Password" })}
|
|
/>
|
|
</section>
|
|
<section className={styles.terms}>
|
|
<header>
|
|
<Subtitle type="two">
|
|
{intl.formatMessage({ id: "Terms and conditions" })}
|
|
</Subtitle>
|
|
</header>
|
|
<Checkbox name="termsAccepted" registerOptions={{ required: true }}>
|
|
{intl.formatMessage({ id: "I accept" })}
|
|
</Checkbox>
|
|
{/* TODO: Update copy once ready */}
|
|
<Body>
|
|
{intl.formatMessage<React.ReactNode>(
|
|
{ id: "signupPage.terms" },
|
|
{
|
|
termsAndConditions: (str) => (
|
|
<Link
|
|
variant="underscored"
|
|
color="peach80"
|
|
target="_blank"
|
|
href={membershipTermsAndConditions[lang]}
|
|
>
|
|
{str}
|
|
</Link>
|
|
),
|
|
privacyPolicy: (str) => (
|
|
<Link
|
|
variant="underscored"
|
|
color="peach80"
|
|
target="_blank"
|
|
href={privacyPolicy[lang]}
|
|
>
|
|
{str}
|
|
</Link>
|
|
),
|
|
}
|
|
)}
|
|
</Body>
|
|
</section>
|
|
|
|
{/*
|
|
This is a manual validation trigger workaround:
|
|
- The Controller component (which Input uses) doesn't re-render on submit,
|
|
which prevents automatic error display.
|
|
- Future fix requires Input component refactoring (out of scope for now).
|
|
*/}
|
|
{!methods.formState.isValid ? (
|
|
<Button
|
|
className={styles.signUpButton}
|
|
type="submit"
|
|
theme="base"
|
|
intent="primary"
|
|
onClick={() => methods.trigger()}
|
|
data-testid="trigger-validation"
|
|
>
|
|
{signupButtonText}
|
|
</Button>
|
|
) : (
|
|
<Button
|
|
className={styles.signUpButton}
|
|
type="submit"
|
|
theme="base"
|
|
intent="primary"
|
|
disabled={methods.formState.isSubmitting || signup.isPending}
|
|
data-testid="submit"
|
|
>
|
|
{signupButtonText}
|
|
</Button>
|
|
)}
|
|
</form>
|
|
</FormProvider>
|
|
</section>
|
|
)
|
|
}
|