Skip to content

Commit 3b1074f

Browse files
committed
create and connect trip.create mutation, map form values to API input, add success notify.
1 parent ce69dbc commit 3b1074f

File tree

1 file changed

+59
-54
lines changed

1 file changed

+59
-54
lines changed

src/app/_components/agencycomponents/agency-interactive-area.tsx

Lines changed: 59 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,32 @@ interface Props {
2222
const GOOGLE_MAPS_LIBRARIES_ARRAY: Libraries = ["places"]; //Add more to this array if you need to import more libraries from the API
2323
const CHERRY_RED = "#A03145";
2424

25-
export const BookingInteractiveArea = ({ initialViewMode = ViewMode.CALENDAR }: Props) => {
25+
export const BookingInteractiveArea = ({
26+
initialViewMode = ViewMode.CALENDAR,
27+
}: Props) => {
2628
const [viewMode, setViewMode] = useState<ViewMode>(initialViewMode);
2729
const [showBookingModal, setShowBookingModal] = useState<boolean>(false);
28-
// eventually this loading state will be replacted with a tanstack mutation loading state
29-
const [loading, setLoading] = useState<boolean>(false);
3030
const [currentDate, setCurrentDate] = useState<Date>(new Date());
3131
const [isDayView, setIsDayView] = useState<boolean>(false);
32-
const [validationAddressGood, setValidationAddressGood] = useState<boolean>(false);
32+
const [validationAddressGood, setValidationAddressGood] =
33+
useState<boolean>(false);
3334

3435
const {
3536
data: bookings,
3637
isLoading: isLoadingBookings,
3738
isError: isErrorBookings,
3839
} = api.bookings.getAll.useQuery();
40+
const createBookingMutation = api.trip.create.useMutation({
41+
onSuccess: () => {
42+
notify.success("Booking successfully created");
43+
form.reset();
44+
setShowBookingModal(false);
45+
setValidationAddressGood(false);
46+
},
47+
onError: (error) => {
48+
notify.error(error.message || "Failed to create a booking");
49+
},
50+
});
3951

4052
//Define a variable that react will reassign its value on runtime
4153
//Starts off as null but will equal (through inputElement.current) an HTML input element when assigned at runtime
@@ -64,12 +76,18 @@ export const BookingInteractiveArea = ({ initialViewMode = ViewMode.CALENDAR }:
6476

6577
validate: {
6678
title: (value) => (value.trim().length > 0 ? null : "Title is required"),
67-
residentName: (value) => (value.trim().length > 0 ? null : "Resident name is required"),
68-
contactInfo: (value) => (value.trim().length > 0 ? null : "Contact info is required"),
69-
startTime: (value) => (value.trim().length > 0 ? null : "Date and time is required"),
70-
endTime: (value) => (value.trim().length > 0 ? null : "Date and time is required"),
71-
purpose: (value) => (value.trim().length > 0 ? null : "Purpose is required"),
72-
pickupAddress: (value) => (value.trim().length > 0 ? null : "Pickup address is required"),
79+
residentName: (value) =>
80+
value.trim().length > 0 ? null : "Resident name is required",
81+
contactInfo: (value) =>
82+
value.trim().length > 0 ? null : "Contact info is required",
83+
startTime: (value) =>
84+
value.trim().length > 0 ? null : "Date and time is required",
85+
endTime: (value) =>
86+
value.trim().length > 0 ? null : "Date and time is required",
87+
purpose: (value) =>
88+
value.trim().length > 0 ? null : "Purpose is required",
89+
pickupAddress: (value) =>
90+
value.trim().length > 0 ? null : "Pickup address is required",
7391
destinationAddress: (value) =>
7492
value.trim().length > 0 ? null : "Destination address is required",
7593
},
@@ -79,14 +97,21 @@ export const BookingInteractiveArea = ({ initialViewMode = ViewMode.CALENDAR }:
7997
// biome-ignore lint: inputElement.current does change and needs to be changed in order for useEffect() to run
8098
useEffect(() => {
8199
//Do not run the code within the useEffect if the api or mantine form hasn't fully loaded
82-
if (!isLoaded || google.maps.places === null || inputElement.current === null) {
100+
if (
101+
!isLoaded ||
102+
google.maps.places === null ||
103+
inputElement.current === null
104+
) {
83105
return;
84106
}
85107

86108
//Make the google auto complete element and attach it to inputElement (requires an HTML input element to mount to)
87-
const googleAutoCompleteElement = new google.maps.places.Autocomplete(inputElement.current, {
88-
types: ["address"],
89-
});
109+
const googleAutoCompleteElement = new google.maps.places.Autocomplete(
110+
inputElement.current,
111+
{
112+
types: ["address"],
113+
}
114+
);
90115

91116
//Places bounds on what locations google will suggest
92117
googleAutoCompleteElement.setComponentRestrictions({
@@ -122,54 +147,34 @@ export const BookingInteractiveArea = ({ initialViewMode = ViewMode.CALENDAR }:
122147
};
123148
}, [inputElement.current]);
124149

125-
const handleConfirm = async () => {
126-
setLoading(true);
150+
const handleConfirm = () => {
127151
const validation = form.validate();
128152
const hasErrors = Object.keys(validation.errors).length > 0;
129153

130154
if (hasErrors) {
131155
notify.error("Please fix the errors in the form before submitting");
132-
setLoading(false);
133156
return;
134157
}
135158

136-
const values = form.values;
137-
console.log("submit", values);
138-
139-
// enter an actual api call here like a tanstack mutation
140-
// when calling the backend to verify form and update the db, must manually pass the destination address
141-
// do NOT use the mantine field form as it will not contain the destination address
142-
// use instead -> [inputElement.current?.value || ""]
143-
// see the below code for a sample usage of calling the backend to verify destination address
144-
/*
145-
//Define backend endpoint (if you need to directly call this api - probably won't though, put at the top of the file, under useStates)
146-
const validateDestinationAddressAPI = api.form.validateDestinationAddress.useMutation();
147-
148-
if (validationAddressGood) {
149-
//Call the backend
150-
const result = await validateDestinationAddressAPI.mutateAsync({
151-
regionCode: "ca",
152-
destinationAddress: [inputElement.current?.value || ""],
153-
});
154-
155-
//Evaluate the result from the back-end
156-
if (result === null) {
157-
//Manually adds an error field to the mantine form
158-
form.setFieldError("destinationAddress", "Destination address is too vague");
159-
} else{
160-
// use -> result passed from funct call as address that goes into db
161-
// update db with result var
162-
console.log("Backend is happy with input");
163-
}
164-
}
165-
*/
159+
if (!validationAddressGood) {
160+
form.setFieldError(
161+
"destinationAddress",
162+
"Please select a valid address from the dropdown"
163+
);
164+
return;
165+
}
166166

167-
setTimeout(() => {
168-
setLoading(false);
169-
setShowBookingModal(false);
170-
notify.success("Booking successfully created");
171-
form.reset();
172-
}, 2000);
167+
createBookingMutation.mutate({
168+
title: form.values.title,
169+
residentName: form.values.residentName,
170+
contactInfo: form.values.contactInfo,
171+
additionalInfo: form.values.additionalInfo,
172+
pickupAddress: form.values.pickupAddress,
173+
destinationAddress: inputElement.current?.value || "",
174+
startTime: new Date(form.values.startTime).toISOString(),
175+
endTime: new Date(form.values.endTime).toISOString(),
176+
purpose: form.values.purpose,
177+
});
173178
};
174179

175180
//If the script hasn't loaded yet, don't render anything until it does
@@ -228,7 +233,7 @@ export const BookingInteractiveArea = ({ initialViewMode = ViewMode.CALENDAR }:
228233
size="xl"
229234
showDefaultFooter
230235
confirmText="Confirm Booking"
231-
loading={loading}
236+
loading={createBookingMutation.isPending}
232237
>
233238
<AgencyForm form={form} destinationAddressRef={inputElement} />
234239
</Modal>

0 commit comments

Comments
 (0)