-
Notifications
You must be signed in to change notification settings - Fork 6
add travel reimbursement form #226
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
300c4d0
575468b
2c1a162
8f8fba1
9c79e13
090fd90
05da33f
02bce7e
d10aa09
6588fed
3c28492
0fb9614
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| "use client" | ||
|
|
||
| export { FormLoadingError as default } from "@/components/dashboard/form-loading-error" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| "use client" | ||
|
|
||
| import { zodResolver } from "@hookform/resolvers/zod" | ||
| import { useRouter } from "next/navigation" | ||
| import * as React from "react" | ||
| import { useForm } from "react-hook-form" | ||
| import { z } from "zod" | ||
|
|
||
| import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@durhack/web-components/ui/form" | ||
| import { Input } from "@durhack/web-components/ui/input" | ||
| import { | ||
| Select, | ||
| SelectContent, | ||
| SelectItem, | ||
| SelectTrigger, | ||
| SelectValue, | ||
| SelectValueClipper, | ||
| } from "@durhack/web-components/ui/select" | ||
|
|
||
| import { FormSkeleton } from "@/components/dashboard/form-skeleton" | ||
| import { FormSubmitButton } from "@/components/dashboard/form-submit-button" | ||
| import type { Application } from "@/hooks/use-application" | ||
| import { useApplicationContext } from "@/hooks/use-application-context" | ||
| import { isLoaded } from "@/lib/is-loaded" | ||
| import { updateApplication } from "@/lib/update-application" | ||
|
|
||
| type travelReimbursmentFormFields = { | ||
| firstNames: string | ||
| lastNames: string | ||
| email: string | ||
| phoneNumber: string | ||
| travelFromCity: string | ||
| travelDate1: string | ||
| travelDate2: string | ||
| transport: string | ||
| returnJourney: boolean | ||
| } | ||
|
|
||
| const travelReimbursmentFormSchema = z.object({ | ||
| firstNames: z.string().trim().min(1, { message: "Please provide your first name(s)" }).max(256), | ||
| lastNames: z.string().trim().min(1, { message: "Please provide your last name(s)" }).max(256), | ||
| email: z.string().trim().min(1,{ message: "Please provide your email address" }).max(256), | ||
| phoneNumber:z.string().trim().min(1,{ message: "Please provide your phone number" }).max(15), | ||
| travelFromCity: z.string().trim().min(1, { message: "Please provide the city you are travelling from" }).max(256), | ||
| travelDate1: z.string().trim().min(1, { message: "Please provide the date you are travelling to Durham in the format DD/MM/YYYY" }).max(256), | ||
| travelDate2: z.string().trim().optional(), | ||
| transport: z.enum(["train", "bus", "car", "other"]), | ||
| returnJourney: z.boolean({required_error: "Please indicate if you require a return journey",}), | ||
| }) | ||
|
|
||
| /** | ||
| * This component accepts <code>application</code> via props, rather than via | ||
| * <code>useApplicationContext</code>, because it requires the application to already be loaded before being rendered. | ||
| */ | ||
| function travelReimbursmentForm({ application }: { application: Application }) { | ||
| const router = useRouter() | ||
| const { mutateApplication } = useApplicationContext() | ||
|
|
||
| const form = useForm<travelReimbursmentFormFields, unknown, z.infer<typeof travelReimbursmentFormSchema>>({ | ||
| resolver: zodResolver(travelReimbursmentFormSchema), | ||
| defaultValues: { | ||
| firstNames: application.firstNames ?? "", | ||
| lastNames: application.lastNames ?? "", | ||
| }, | ||
| }) | ||
|
|
||
| async function onSubmit(values: z.infer<typeof travelReimbursmentFormSchema>): Promise<void> { | ||
| await updateApplication("personal", values) | ||
|
||
| await mutateApplication({ ...application, ...values }) | ||
| if (application.age == null) router.push("/dashboard/contact") | ||
| } | ||
|
|
||
| return ( | ||
| <Form {...form}> | ||
| <form onSubmit={form.handleSubmit(onSubmit)}> | ||
| <div className="lg:columns-2"> | ||
| <div className="mb-4"> | ||
| <FormField | ||
| control={form.control} | ||
| name="firstNames" | ||
| render={({ field }) => ( | ||
| <FormItem> | ||
| <FormLabel>First name(s)</FormLabel> | ||
| <FormControl> | ||
| <Input {...field} placeholder="Enter first name(s)..." /> | ||
| </FormControl> | ||
| <FormMessage /> | ||
| </FormItem> | ||
| )} | ||
| /> | ||
| </div> | ||
| <div className="mb-4"> | ||
| <FormField | ||
| control={form.control} | ||
| name="lastNames" | ||
| render={({ field }) => ( | ||
| <FormItem> | ||
| <FormLabel>Last name(s)</FormLabel> | ||
| <FormControl> | ||
| <Input {...field} placeholder="Enter last name(s)..." /> | ||
| </FormControl> | ||
| <FormMessage /> | ||
| </FormItem> | ||
| )} | ||
| /> | ||
| </div> | ||
| </div> | ||
| <div className="mt-16 flex justify-center"> | ||
| <FormSubmitButton type="submit">Save Progress</FormSubmitButton> | ||
|
||
| </div> | ||
| </form> | ||
| </Form> | ||
| ) | ||
| } | ||
|
|
||
| function TravelReimbursmentFormSkeleton() { | ||
| return <FormSkeleton rows={3} className="mt-2" /> | ||
|
||
| } | ||
|
|
||
| export default function TravelReimbursmentForm() { | ||
| const { application, applicationIsLoading } = useApplicationContext() | ||
|
|
||
| if (!isLoaded(application, applicationIsLoading)) { | ||
| return <TravelReimbursmentFormSkeleton /> | ||
| } | ||
|
|
||
| return <TravelReimbursmentFormSkeleton application={application} /> | ||
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import type * as React from "react" | ||
|
|
||
| export default function PostTravelReimbursmentFormLayout({ children }: { children: React.ReactNode }) { | ||
| return ( | ||
| <> | ||
| <h2 className="text-2xl">Post Travel Reimbursement Form | ||
| </h2> | ||
| {children} | ||
| </> | ||
| ) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
React component names must be named in PascalCase