-
I'm new to Remix, coming from NextJS, and have seen similar discussions on this forum on the topic of string <-> date issues, but nothing that really covers fundamentally an end-to-end solution. I would've thought this was a common use-case, so I'm hoping someone can point me at a canonical way to do this... Using Remix, Prisma and Zod, I need to load a record with a Date field from the database via a Loader, show it in the UI in a date picker inside a form (or even a text input field), then submit that form via an Action to update the date in the database with the new value. I understand the point about the json serialisation converting a Javascript Date from a Prisma model type into a string for transport from the server to the client, and I know I could use remix-typedjson in my Loader, but that would only cover part of the story. Prisma documentation states that by-design the model classes it generates use a Javascript Date rather than an ISO string, and this cannot be changed. I'd happily just use strings everywhere, it seems simpler, but I seemingly can't do that. I know also that I could coerce a string to a Date in my Zod schema definition. But I just can't get an end-to-end solution going here. I end up with mismatched Prisma model types and Zod schema definitions, or invalid data type errors when validating the form data in my action. So could anyone please suggest an end-to-end example showing how to do this? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
I've tried here to pick out the bare minimum of what I ended up doing to make this all work. Hopefully this can help someone else. I've left out error handling and imports. If anyone has suggestions for improvements, please let me know... Prisma/data model
// model.ts
type Account = {
userId: string
dateOfBirth: Date
} Zod validation schema// account-schema.ts
export const accountSchema = z.object({
dateOfBirth: z.coerce.date() // will invoke new Date(isoStringFromFormData)
})
export type AccountSchema = z.infer<typeof accountSchema> Remix route// app/routes/my-account.tsx
export const loader = async ({ request }: LoaderArgs) {
const userId = await requireUserId(request); // pull current user from session cookie (remix-auth)
const account = await prisma.account.findUniqueOrThrow({
where: {
userId
}
})
return typedjson(account) // use remix-typedjson instead of regular json
}
const resolver = zodResolver(accountSchema)
export const action = async ({ request }: ActionArgs) {
const userId = await requireUserId(request); // pull current user from session cookie (remix-auth)
const {
errors,
data,
receivedValues: defaultValues
} = await getValidatedFormData<AccountSchema>(request, resolver) // use remix-hook-form with Zod to validate
if (errors) {
return json({ errors, defaultValues }) // standard property names for react-hook-form
}
const result = await prisma.account.update({
where: {
userId
},
data: {
lastSignIn: data.lastSignIn
}
})
return typedjson(result) // use remix-typedjson instead of regular json
}
export default function AccountPage() {
const account = useTypedLoaderData<typeof loader>() // use remix-typedjson hook instead of useLoaderData
const {
handleSubmit,
register,
formState: { errors }
} = useRemixForm<AccountSchema>({ // From remix-hook-form rather than react-hook-form
resolver: zodResolver(accountSchema)
})
return (
<Form onSubmit={handleSubmit} method='POST'>
<input type='text' name='dateOfBirth' {...register('dateOfBirth')}/>
<span>{errors.dateOfBirth}</span>
</Form>
)
} |
Beta Was this translation helpful? Give feedback.
-
Here’s how I went about it, since I need only (Same as you I think? Unless you care about timezones in date of birth?) model Event {
dateExample String
…
} z.object({
dateExample: z.string().date(),
…
}) <input
type="date"
name="dateExample"
defaultValue={event?.dateExample}
placeholder="yyyy-mm-dd"
/> export async function action({ params, request }: ActionFunctionArgs) {
await requireUserSession(request);
const formData = await request.formData();
const data = Object.fromEntries(formData);
const result = await eventFormSchema.safeParse(data);
if (!result.success) {
return result.error.flatten();
}
await prisma.event.update({
data: { dateExample: data.dateExample },
where: { id: params.id },
});
return redirect(`/events/${result.data.id}`);
} <span>new Date(dateStart).toDateString()</span> |
Beta Was this translation helpful? Give feedback.
I've tried here to pick out the bare minimum of what I ended up doing to make this all work.
Hopefully this can help someone else.
I've left out error handling and imports.
If anyone has suggestions for improvements, please let me know...
Prisma/data model
Zod validation schema
Remix route