Skip to content

Commit 9fd0112

Browse files
committed
feat: switch from valibot to zod
1 parent f81f0fa commit 9fd0112

39 files changed

+407
-478
lines changed

package-lock.json

Lines changed: 4 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@
114114
"react-i18next": "^15.5.1",
115115
"react-robot": "^1.2.0",
116116
"robot3": "^1.1.1",
117-
"valibot": "^0.42.1"
117+
"zod": "^3.25.17"
118118
},
119119
"sideEffects": [
120120
"**/*.scss",

src/components/Common/SignatureForm/SignatureForm.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
import * as v from 'valibot'
1+
import { z } from 'zod'
22
import { FormProvider, useForm, type UseFormProps } from 'react-hook-form'
3-
import { valibotResolver } from '@hookform/resolvers/valibot'
3+
import { zodResolver } from '@hookform/resolvers/zod'
44
import styles from './SignatureForm.module.scss'
55
import { Form } from '@/components/Common/Form'
66
import { Flex } from '@/components/Common'
77

8-
export const SignatureFormSchema = v.object({
9-
signature: v.pipe(v.string(), v.nonEmpty()),
10-
confirmSignature: v.literal(true),
8+
export const SignatureFormSchema = z.object({
9+
signature: z.string().min(1),
10+
confirmSignature: z.literal(true),
1111
})
1212

1313
const signatureFormDefaultValues = {
1414
signature: '',
1515
}
1616

17-
export type SignatureFormInputs = v.InferInput<typeof SignatureFormSchema>
17+
export type SignatureFormInputs = z.infer<typeof SignatureFormSchema>
1818

1919
interface SignatureFormProps {
2020
onSubmit: (data: SignatureFormInputs) => void | Promise<void>
@@ -24,7 +24,7 @@ interface SignatureFormProps {
2424

2525
export function SignatureForm({ onSubmit, children, formProps }: SignatureFormProps) {
2626
const methods = useForm<SignatureFormInputs>({
27-
resolver: valibotResolver(SignatureFormSchema),
27+
resolver: zodResolver(SignatureFormSchema),
2828
defaultValues: signatureFormDefaultValues,
2929
...formProps,
3030
})

src/components/Company/AssignSignatory/AssignSignatory.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import * as v from 'valibot'
1+
import { z } from 'zod'
22
import { FormProvider, useForm } from 'react-hook-form'
3-
import { valibotResolver } from '@hookform/resolvers/valibot'
3+
import { zodResolver } from '@hookform/resolvers/zod'
44
import { SignatoryForm } from './SignatoryForm'
55
import { Head } from './Head'
66
import { AssignSignatorySelection } from './AssignSignatorySelection'
@@ -30,14 +30,14 @@ export function AssignSignatory(props: AssignSignatoryProps & BaseComponentInter
3030
)
3131
}
3232

33-
const AssignSignatorySelectionSchema = v.object({
34-
signatoryAssignmentMode: v.union([
35-
v.literal(SignatoryAssignmentMode.createSignatory),
36-
v.literal(SignatoryAssignmentMode.inviteSignatory),
33+
const AssignSignatorySelectionSchema = z.object({
34+
signatoryAssignmentMode: z.union([
35+
z.literal(SignatoryAssignmentMode.createSignatory),
36+
z.literal(SignatoryAssignmentMode.inviteSignatory),
3737
]),
3838
})
3939

40-
type AssignSignatorySelectionInputs = v.InferInput<typeof AssignSignatorySelectionSchema>
40+
type AssignSignatorySelectionInputs = z.infer<typeof AssignSignatorySelectionSchema>
4141

4242
function Root({
4343
companyId,
@@ -50,7 +50,7 @@ function Root({
5050
const { onEvent } = useBase()
5151

5252
const formMethods = useForm<AssignSignatorySelectionInputs>({
53-
resolver: valibotResolver(AssignSignatorySelectionSchema),
53+
resolver: zodResolver(AssignSignatorySelectionSchema),
5454
defaultValues: {
5555
signatoryAssignmentMode: SignatoryAssignmentMode.createSignatory,
5656
},

src/components/Company/AssignSignatory/CreateSignatory/CreateSignatory.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { FormProvider, useForm } from 'react-hook-form'
2-
import { valibotResolver } from '@hookform/resolvers/valibot'
2+
import { zodResolver } from '@hookform/resolvers/zod'
33
import classNames from 'classnames'
44
import { useSignatoriesListSuspense } from '@gusto/embedded-api/react-query/signatoriesList'
55
import { useSignatoriesCreateMutation } from '@gusto/embedded-api/react-query/signatoriesCreate'
@@ -81,7 +81,7 @@ function Root({
8181
}
8282

8383
const formMethods = useForm<CreateSignatoryInputs>({
84-
resolver: valibotResolver(generateCreateSignatorySchema(currentSignatory?.hasSsn)),
84+
resolver: zodResolver(generateCreateSignatorySchema(currentSignatory?.hasSsn)),
8585
defaultValues: createSignatoryDefaultValues,
8686
})
8787

src/components/Company/AssignSignatory/CreateSignatory/CreateSignatoryForm.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useTranslation } from 'react-i18next'
2-
import type { InferInput } from 'valibot'
2+
import type { z } from 'zod'
33
import { useCreateSignatory } from './useCreateSignatory'
44
import type { generateCreateSignatorySchema } from './Schema'
55
import { TextInputField, Grid, Flex, SelectField, DatePickerField } from '@/components/Common'
@@ -9,7 +9,7 @@ import { TitleSelect } from '@/components/Company/AssignSignatory/TitleSelect'
99
import { commonMasks, useMaskedTransform } from '@/helpers/mask'
1010
import { useComponentContext } from '@/contexts/ComponentAdapter/useComponentContext'
1111

12-
export type CreateSignatoryInputs = InferInput<ReturnType<typeof generateCreateSignatorySchema>>
12+
export type CreateSignatoryInputs = z.infer<ReturnType<typeof generateCreateSignatorySchema>>
1313

1414
export const CreateSignatoryForm = () => {
1515
const Components = useComponentContext()
Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,33 @@
1-
import * as v from 'valibot'
1+
import { z } from 'zod'
22
import { nameValidation, zipValidation, SSN_REGEX, phoneValidation } from '@/helpers/validations'
33
import { removeNonDigits } from '@/helpers/formattedStrings'
44

55
const createSSNValidation = (hasSsn?: boolean) =>
6-
v.pipe(
7-
v.string(),
8-
v.custom(value => {
9-
// If they have an SSN on file and haven't modified the field (it's empty), it's valid
10-
if (hasSsn && !value) {
11-
return true
12-
}
6+
z.string().refine(value => {
7+
// If they have an SSN on file and haven't modified the field (it's empty), it's valid
8+
if (hasSsn && !value) {
9+
return true
10+
}
1311

14-
if (typeof value !== 'string') {
15-
return false
16-
}
12+
if (typeof value !== 'string') {
13+
return false
14+
}
1715

18-
return SSN_REGEX.test(removeNonDigits(value))
19-
}),
20-
)
16+
return SSN_REGEX.test(removeNonDigits(value))
17+
})
2118

2219
export const generateCreateSignatorySchema = (hasSsn?: boolean) =>
23-
v.object({
20+
z.object({
2421
firstName: nameValidation,
2522
lastName: nameValidation,
26-
email: v.pipe(v.string(), v.nonEmpty(), v.email()),
27-
title: v.pipe(v.string(), v.nonEmpty()),
23+
email: z.string().min(1).email(),
24+
title: z.string().min(1),
2825
phone: phoneValidation,
2926
ssn: createSSNValidation(hasSsn),
30-
birthday: v.instance(Date),
31-
street1: v.pipe(v.string(), v.nonEmpty()),
32-
street2: v.optional(v.string()),
33-
city: v.pipe(v.string(), v.nonEmpty()),
34-
state: v.pipe(v.string(), v.nonEmpty()),
27+
birthday: z.date(),
28+
street1: z.string().min(1),
29+
street2: z.string().optional(),
30+
city: z.string().min(1),
31+
state: z.string().min(1),
3532
zip: zipValidation,
3633
})

src/components/Company/AssignSignatory/InviteSignatory/InviteSignatory.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { FormProvider, useForm } from 'react-hook-form'
2-
import { valibotResolver } from '@hookform/resolvers/valibot'
2+
import { zodResolver } from '@hookform/resolvers/zod'
33
import classNames from 'classnames'
44
import { useSignatoriesListSuspense } from '@gusto/embedded-api/react-query/signatoriesList'
55
import { useSignatoriesInviteMutation } from '@gusto/embedded-api/react-query/signatoriesInvite'
@@ -57,7 +57,7 @@ function Root({ companyId, defaultValues, className, children }: InviteSignatory
5757
}
5858

5959
const formMethods = useForm<InviteSignatoryInputs>({
60-
resolver: valibotResolver(InviteSignatorySchema),
60+
resolver: zodResolver(InviteSignatorySchema),
6161
defaultValues: inviteSignatoryDefaultValues,
6262
})
6363

src/components/Company/AssignSignatory/InviteSignatory/InviteSignatoryForm.tsx

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as v from 'valibot'
1+
import { z } from 'zod'
22
import { useFormContext } from 'react-hook-form'
33
import { useTranslation } from 'react-i18next'
44
import { TextInputField, Grid, Flex } from '@/components/Common'
@@ -8,21 +8,20 @@ import { useComponentContext } from '@/contexts/ComponentAdapter/useComponentCon
88

99
const emailMismatchError = 'email_mismatch'
1010

11-
export const InviteSignatorySchema = v.pipe(
12-
v.object({
11+
export const InviteSignatorySchema = z
12+
.object({
1313
firstName: nameValidation,
1414
lastName: nameValidation,
15-
email: v.pipe(v.string(), v.nonEmpty(), v.email()),
16-
confirmEmail: v.pipe(v.string(), v.nonEmpty(), v.email()),
17-
title: v.pipe(v.string(), v.nonEmpty()),
18-
}),
19-
v.forward(
20-
v.check(({ email, confirmEmail }) => email === confirmEmail, emailMismatchError),
21-
['confirmEmail'],
22-
),
23-
)
15+
email: z.string().min(1).email(),
16+
confirmEmail: z.string().min(1).email(),
17+
title: z.string().min(1),
18+
})
19+
.refine(data => data.email === data.confirmEmail, {
20+
message: emailMismatchError,
21+
path: ['confirmEmail'],
22+
})
2423

25-
export type InviteSignatoryInputs = v.InferInput<typeof InviteSignatorySchema>
24+
export type InviteSignatoryInputs = z.infer<typeof InviteSignatorySchema>
2625

2726
export const InviteSignatoryForm = () => {
2827
const { t } = useTranslation('Company.AssignSignatory')

src/components/Company/BankAccount/BankAccountForm/BankAccountForm.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useBankAccountsCreateMutation } from '@gusto/embedded-api/react-query/bankAccountsCreate'
22
import { FormProvider, useForm } from 'react-hook-form'
3-
import { valibotResolver } from '@hookform/resolvers/valibot'
3+
import { zodResolver } from '@hookform/resolvers/zod'
44
import { Head } from './Head'
55
import type { BankAccountFormInputs } from './Form'
66
import { BankAccountFormSchema, Form } from './Form'
@@ -33,7 +33,7 @@ function Root({ companyId, className, children }: BankAccountFormProps) {
3333
useBankAccountsCreateMutation()
3434

3535
const { control, ...methods } = useForm<BankAccountFormInputs>({
36-
resolver: valibotResolver(BankAccountFormSchema),
36+
resolver: zodResolver(BankAccountFormSchema),
3737
defaultValues: { accountNumber: '', routingNumber: '' },
3838
})
3939

src/components/Company/BankAccount/BankAccountForm/Form.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
import type { InferInput } from 'valibot'
2-
import { object } from 'valibot'
1+
import { z } from 'zod'
32
import { useTranslation } from 'react-i18next'
43
import { accountNumberValidation, routingNumberValidation } from '@/helpers/validations'
54
import { Flex, TextInputField } from '@/components/Common'
65

7-
export const BankAccountFormSchema = object({
6+
export const BankAccountFormSchema = z.object({
87
routingNumber: routingNumberValidation,
98
accountNumber: accountNumberValidation,
109
})
1110

12-
export type BankAccountFormInputs = InferInput<typeof BankAccountFormSchema>
11+
export type BankAccountFormInputs = z.infer<typeof BankAccountFormSchema>
1312

1413
export function Form() {
1514
const { t } = useTranslation('Company.BankAccount')

src/components/Company/BankAccount/BankAccountVerify/BankAccountVerify.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { FormProvider, useForm } from 'react-hook-form'
2-
import { valibotResolver } from '@hookform/resolvers/valibot'
2+
import { zodResolver } from '@hookform/resolvers/zod'
33
import { useBankAccountsVerifyMutation } from '@gusto/embedded-api/react-query/bankAccountsVerify'
44
import { Head } from './Head'
55
import { BankAccountVerifyProvider } from './context'
@@ -32,7 +32,7 @@ function Root({ companyId, bankAccountId, className, children }: BankAccountVeri
3232
const { mutateAsync: verifyBankAccount, isPending } = useBankAccountsVerifyMutation()
3333

3434
const { control, ...methods } = useForm<BankAccountVerifyInputs>({
35-
resolver: valibotResolver(BankAccountVerifySchema),
35+
resolver: zodResolver(BankAccountVerifySchema),
3636
defaultValues: { deposit1: 0, deposit2: 0 },
3737
})
3838

src/components/Company/BankAccount/BankAccountVerify/Form.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
import type { InferInput } from 'valibot'
2-
import { minValue, number, object, pipe } from 'valibot'
1+
import { z } from 'zod'
32
import { useTranslation } from 'react-i18next'
43
import { Flex, NumberInputField } from '@/components/Common'
54

6-
export const BankAccountVerifySchema = object({
7-
deposit1: pipe(number(), minValue(0)),
8-
deposit2: pipe(number(), minValue(0)),
5+
export const BankAccountVerifySchema = z.object({
6+
deposit1: z.number().min(0),
7+
deposit2: z.number().min(0),
98
})
109

11-
export type BankAccountVerifyInputs = InferInput<typeof BankAccountVerifySchema>
10+
export type BankAccountVerifyInputs = z.infer<typeof BankAccountVerifySchema>
1211

1312
export function Form() {
1413
const { t } = useTranslation('Company.BankAccount')

src/components/Company/FederalTaxes/FederalTaxes.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type {
66
TaxPayerType,
77
} from '@gusto/embedded-api/models/operations/putv1companiescompanyidfederaltaxdetails'
88
import { FormProvider, useForm } from 'react-hook-form'
9-
import { valibotResolver } from '@hookform/resolvers/valibot'
9+
import { zodResolver } from '@hookform/resolvers/zod'
1010
import {
1111
FederalTaxesProvider,
1212
type FederalTaxFormInputs,
@@ -49,7 +49,7 @@ function Root({ companyId, children, className, defaultValues }: FederalTaxesPro
4949
const { mutateAsync: updateFederalTaxDetails, isPending } = useFederalTaxDetailsUpdateMutation()
5050

5151
const formMethods = useForm<FederalTaxFormInputs>({
52-
resolver: valibotResolver(FederalTaxFormSchema),
52+
resolver: zodResolver(FederalTaxFormSchema),
5353
defaultValues: {
5454
federalEin: federalTaxDetails.hasEin ? undefined : '',
5555
taxPayerType: federalTaxDetails.taxPayerType
@@ -69,8 +69,8 @@ function Root({ companyId, children, className, defaultValues }: FederalTaxesPro
6969
companyId: companyId,
7070
requestBody: {
7171
ein: payload.federalEin,
72-
taxPayerType: payload.taxPayerType,
73-
filingForm: payload.filingForm,
72+
taxPayerType: payload.taxPayerType as TaxPayerType | undefined,
73+
filingForm: payload.filingForm as FilingForm | undefined,
7474
legalName: payload.legalName,
7575
version: federalTaxDetails.version as string,
7676
},

0 commit comments

Comments
 (0)