Skip to content

Commit 18d4571

Browse files
committed
replace date input with datepicker
1 parent 0516064 commit 18d4571

1 file changed

Lines changed: 84 additions & 40 deletions

File tree

src/app/trips/[id]/itinerary/_components/TripDetailsCard.tsx

Lines changed: 84 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,57 @@ import { Input } from "~/_components/ui/input";
1313
import { DeleteTripButton } from "~/app/trips/_components/DeleteTripButton";
1414
import { Label } from "~/_components/ui/label";
1515
import { api } from "~/trpc/react";
16+
import { DatePicker } from "~/_components/ui/datepicker";
17+
import { Controller, useForm } from "react-hook-form";
18+
import * as yup from "yup";
19+
import { yupResolver } from "@hookform/resolvers/yup";
20+
21+
type FormData = {
22+
title: string;
23+
destination: string;
24+
startDate: Date;
25+
endDate: Date;
26+
};
1627

1728
function TripDetailsCard({ trip }: { trip: Trip }) {
1829
const [isEditing, setIsEditing] = useState(false);
19-
const [formData, setFormData] = useState<Partial<Trip>>(trip);
2030
const utils = api.useUtils();
2131

22-
const handleChange = (
23-
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
24-
) => {
25-
const { name, value } = e.target;
26-
setFormData((prev) => ({ ...prev, [name]: value }));
27-
};
32+
const validationSchema = yup.object({
33+
title: yup.string().required("Title is required"),
34+
destination: yup.string().required("Destination is required"),
35+
startDate: yup.date().required("Start Date is required"),
36+
endDate: yup
37+
.date()
38+
.required("End Date is required")
39+
.min(yup.ref("startDate"), "End Date cannot be before Start Date")
40+
.test(
41+
"max-trip-length",
42+
"Trip cannot be longer than 30 days",
43+
function (value) {
44+
const { startDate } = this.parent as { startDate?: Date };
45+
if (!value || !startDate) return true;
46+
47+
const diff =
48+
(value.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24);
49+
return diff <= 30;
50+
},
51+
),
52+
});
53+
54+
const {
55+
control,
56+
handleSubmit,
57+
formState: { errors },
58+
} = useForm<FormData>({
59+
defaultValues: {
60+
title: trip.title,
61+
destination: trip.destination,
62+
startDate: trip.startDate,
63+
endDate: trip.endDate,
64+
},
65+
resolver: yupResolver(validationSchema),
66+
});
2867

2968
const updateTripDetails = api.trip.update.useMutation({
3069
onSuccess: async () => {
@@ -35,8 +74,7 @@ function TripDetailsCard({ trip }: { trip: Trip }) {
3574
},
3675
});
3776

38-
const handleSubmit = async (e: React.FormEvent) => {
39-
e.preventDefault();
77+
const onSubmit = async (formData: FormData) => {
4078
if (!trip?.id) return;
4179

4280
updateTripDetails.mutate({
@@ -55,55 +93,61 @@ function TripDetailsCard({ trip }: { trip: Trip }) {
5593
<Card className="w-full rounded-lg border bg-white text-black shadow-lg dark:border-gray-700 dark:bg-gray-800">
5694
<CardContent>
5795
{isEditing ? (
58-
<form onSubmit={handleSubmit} className="space-y-4">
96+
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
5997
<div>
6098
<Label htmlFor="title">Title</Label>
61-
<Input
62-
id="title"
63-
name="title"
64-
value={formData.title ?? ""}
65-
onChange={handleChange}
66-
/>
99+
<Input id="title" {...control.register("title")} />
100+
</div>
101+
<div>
102+
<Label htmlFor="destination">Destination</Label>
103+
<Input id="destination" {...control.register("destination")} />
67104
</div>
68105

69106
<div>
70107
<Label htmlFor="destination">Destination</Label>
71-
<Input
72-
id="destination"
73-
name="destination"
74-
value={formData.destination ?? ""}
75-
onChange={handleChange}
76-
/>
108+
<Input id="destination" {...control.register("destination")} />
77109
</div>
78110

79111
<div className="flex gap-4">
80112
<div>
81113
<Label htmlFor="startDate">Start Date</Label>
82-
<Input
83-
id="startDate"
114+
<Controller
115+
control={control}
84116
name="startDate"
85-
type="date"
86-
value={
87-
formData.startDate
88-
? new Date(formData.startDate).toISOString().split("T")[0]
89-
: ""
90-
}
91-
onChange={handleChange}
117+
render={({ field }) => (
118+
<DatePicker
119+
value={field.value}
120+
onChange={(date) => {
121+
field.onChange(date?.toISOString() ?? "");
122+
}}
123+
/>
124+
)}
92125
/>
126+
{errors.startDate && (
127+
<p className="text-sm text-red-500">
128+
{errors.startDate.message}
129+
</p>
130+
)}
93131
</div>
94132
<div>
95133
<Label htmlFor="endDate">End Date</Label>
96-
<Input
97-
id="endDate"
134+
<Controller
135+
control={control}
98136
name="endDate"
99-
type="date"
100-
value={
101-
formData.endDate
102-
? new Date(formData.endDate).toISOString().split("T")[0]
103-
: ""
104-
}
105-
onChange={handleChange}
137+
render={({ field }) => (
138+
<DatePicker
139+
value={field.value}
140+
onChange={(date) => {
141+
field.onChange(date?.toISOString() ?? "");
142+
}}
143+
/>
144+
)}
106145
/>
146+
{errors.endDate && (
147+
<p className="text-sm text-red-500">
148+
{errors.endDate.message}
149+
</p>
150+
)}
107151
</div>
108152
</div>
109153

0 commit comments

Comments
 (0)