Skip to content

Commit fa49840

Browse files
committed
add agency booking form validation
1 parent 3b1074f commit fa49840

File tree

2 files changed

+68
-15
lines changed

2 files changed

+68
-15
lines changed

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

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { env } from "@/env";
1111
import { notify } from "@/lib/notifications";
1212
import { api } from "@/trpc/react";
1313
import { ViewMode } from "@/types/types";
14+
import { validateStringLength, validateTimeRange } from "@/types/validation";
1415
import TableView from "../agencypage/table-view";
1516
import CalendarView from "../calendar-view";
1617
import styles from "./agency-interactive-area.module.scss";
@@ -75,21 +76,24 @@ export const BookingInteractiveArea = ({
7576
},
7677

7778
validate: {
78-
title: (value) => (value.trim().length > 0 ? null : "Title 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",
91-
destinationAddress: (value) =>
92-
value.trim().length > 0 ? null : "Destination address is required",
79+
title: (value) => validateStringLength(value, 1, 150, "Booking name"),
80+
residentName: (value) => validateStringLength(value, 1, 100, "Resident name"),
81+
contactInfo: (value) => validateStringLength(value, 1, 150, "Contact information"),
82+
additionalInfo: (value) => {
83+
// Optional field, only validate max length if provided
84+
if (value.trim().length === 0) return null;
85+
return validateStringLength(value, 0, 500, "Additional information");
86+
},
87+
startTime: (value) => (value.trim().length > 0 ? null : "Date and time is required"),
88+
endTime: (value, values) => {
89+
// First check if required
90+
if (value.trim().length === 0) return "Date and time is required";
91+
// Then validate time range
92+
return validateTimeRange(values.startTime, value);
93+
},
94+
purpose: (value) => validateStringLength(value, 1, 500, "Purpose of transport"),
95+
pickupAddress: (value) => validateStringLength(value, 1, 300, "Pickup address"),
96+
destinationAddress: (value) => validateStringLength(value, 1, 300, "Destination address"),
9397
},
9498
});
9599

src/types/validation.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,52 @@ export const passwordSchema = z
88
.regex(/[0-9]/, "Password must contain at least one number");
99

1010
export const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
11+
12+
/**
13+
* Validates a string's length with both minimum and maximum constraints.
14+
* @param value - The string value to validate
15+
* @param minLength - Minimum required length (default: 1)
16+
* @param maxLength - Maximum allowed length
17+
* @param fieldName - Human-readable field name for error messages
18+
* @returns Error message string or null if valid
19+
*/
20+
export const validateStringLength = (
21+
value: string,
22+
minLength: number,
23+
maxLength: number,
24+
fieldName: string,
25+
): string | null => {
26+
const trimmedValue = value.trim();
27+
28+
if (trimmedValue.length < minLength) {
29+
return `${fieldName} is required`;
30+
}
31+
32+
if (trimmedValue.length > maxLength) {
33+
return `${fieldName} cannot exceed ${maxLength} characters`;
34+
}
35+
36+
return null;
37+
};
38+
39+
/**
40+
* Validates that an end time is after a start time.
41+
* @param startTime - ISO date string for start time
42+
* @param endTime - ISO date string for end time
43+
* @returns Error message string or null if valid
44+
*/
45+
export const validateTimeRange = (startTime: string, endTime: string): string | null => {
46+
// Don't validate if either field is empty (let required validation handle that)
47+
if (!startTime || !endTime) {
48+
return null;
49+
}
50+
51+
const start = new Date(startTime);
52+
const end = new Date(endTime);
53+
54+
if (end <= start) {
55+
return "End time must be after start time";
56+
}
57+
58+
return null;
59+
};

0 commit comments

Comments
 (0)