Refactor Booking component to improve rendering of preferred availability and time slots. Update appointment model to support both string and array formats for preferred_dates and preferred_time_slots, enhancing flexibility in data handling.
This commit is contained in:
parent
8d0088f555
commit
80882c80bc
@ -607,7 +607,7 @@ export default function Booking() {
|
|||||||
Status
|
Status
|
||||||
</th>
|
</th>
|
||||||
<th className={`px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium uppercase tracking-wider hidden lg:table-cell ${isDark ? "text-gray-400" : "text-gray-500"}`}>
|
<th className={`px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium uppercase tracking-wider hidden lg:table-cell ${isDark ? "text-gray-400" : "text-gray-500"}`}>
|
||||||
Preferred Dates
|
Preferred Availability
|
||||||
</th>
|
</th>
|
||||||
<th className={`px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium uppercase tracking-wider hidden xl:table-cell ${isDark ? "text-gray-400" : "text-gray-500"}`}>
|
<th className={`px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium uppercase tracking-wider hidden xl:table-cell ${isDark ? "text-gray-400" : "text-gray-500"}`}>
|
||||||
Created
|
Created
|
||||||
@ -678,25 +678,71 @@ export default function Booking() {
|
|||||||
{formatStatus(appointment.status)}
|
{formatStatus(appointment.status)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className={`px-3 sm:px-4 md:px-6 py-4 whitespace-nowrap text-xs sm:text-sm hidden lg:table-cell ${isDark ? "text-gray-400" : "text-gray-500"}`}>
|
<td className={`px-3 sm:px-4 md:px-6 py-4 text-xs sm:text-sm hidden lg:table-cell ${isDark ? "text-gray-400" : "text-gray-500"}`}>
|
||||||
{appointment.preferred_dates ? (
|
{(() => {
|
||||||
<div className="flex flex-col gap-1">
|
// Handle preferred_dates
|
||||||
{Array.isArray(appointment.preferred_dates) ? (
|
const dates = Array.isArray(appointment.preferred_dates)
|
||||||
<>
|
? appointment.preferred_dates
|
||||||
{(appointment.preferred_dates as string[]).slice(0, 2).map((date, idx) => (
|
: appointment.preferred_dates
|
||||||
<span key={idx}>{formatDate(date)}</span>
|
? [appointment.preferred_dates]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
// Handle preferred_time_slots
|
||||||
|
const timeSlots = Array.isArray(appointment.preferred_time_slots)
|
||||||
|
? appointment.preferred_time_slots
|
||||||
|
: appointment.preferred_time_slots
|
||||||
|
? [appointment.preferred_time_slots]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
// Time slot labels
|
||||||
|
const timeSlotLabels: Record<string, string> = {
|
||||||
|
morning: "Morning",
|
||||||
|
afternoon: "Lunchtime",
|
||||||
|
evening: "Evening",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (dates.length === 0 && timeSlots.length === 0) {
|
||||||
|
return <span>-</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-1.5">
|
||||||
|
{dates.length > 0 && (
|
||||||
|
<div className="flex flex-col gap-0.5">
|
||||||
|
{dates.slice(0, 2).map((date, idx) => (
|
||||||
|
<span key={idx} className="font-medium">
|
||||||
|
{formatDate(date)}
|
||||||
|
</span>
|
||||||
))}
|
))}
|
||||||
{appointment.preferred_dates.length > 2 && (
|
{dates.length > 2 && (
|
||||||
<span className="text-xs">+{appointment.preferred_dates.length - 2} more</span>
|
<span className="text-xs opacity-75">
|
||||||
)}
|
+{dates.length - 2} more date{dates.length - 2 > 1 ? 's' : ''}
|
||||||
</>
|
</span>
|
||||||
) : (
|
|
||||||
<span>{appointment.preferred_dates_display || appointment.preferred_dates}</span>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
|
||||||
"-"
|
|
||||||
)}
|
)}
|
||||||
|
{timeSlots.length > 0 && (
|
||||||
|
<div className="flex flex-wrap gap-1">
|
||||||
|
{timeSlots.map((slot, idx) => {
|
||||||
|
const normalizedSlot = String(slot).toLowerCase().trim();
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
key={idx}
|
||||||
|
className={`px-2 py-0.5 rounded text-xs font-medium ${
|
||||||
|
isDark
|
||||||
|
? "bg-blue-500/20 text-blue-300 border border-blue-500/30"
|
||||||
|
: "bg-blue-50 text-blue-700 border border-blue-200"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{timeSlotLabels[normalizedSlot] || slot}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
</td>
|
</td>
|
||||||
<td className={`px-3 sm:px-4 md:px-6 py-4 whitespace-nowrap text-xs sm:text-sm hidden xl:table-cell ${isDark ? "text-gray-400" : "text-gray-500"}`}>
|
<td className={`px-3 sm:px-4 md:px-6 py-4 whitespace-nowrap text-xs sm:text-sm hidden xl:table-cell ${isDark ? "text-gray-400" : "text-gray-500"}`}>
|
||||||
{formatDate(appointment.created_at)}
|
{formatDate(appointment.created_at)}
|
||||||
|
|||||||
@ -7,8 +7,8 @@ export interface Appointment {
|
|||||||
email: string;
|
email: string;
|
||||||
phone?: string;
|
phone?: string;
|
||||||
reason?: string;
|
reason?: string;
|
||||||
preferred_dates?: string; // YYYY-MM-DD format (legacy) - API returns as string, not array
|
preferred_dates?: string | string[]; // YYYY-MM-DD format - API can return as string or array
|
||||||
preferred_time_slots?: string; // "morning", "afternoon", "evening" (legacy) - API returns as string
|
preferred_time_slots?: string | string[]; // "morning", "afternoon", "evening" - API can return as string or array
|
||||||
selected_slots?: SelectedSlot[]; // New format: day-time combinations
|
selected_slots?: SelectedSlot[]; // New format: day-time combinations
|
||||||
status: "pending_review" | "scheduled" | "rejected" | "completed" | "cancelled";
|
status: "pending_review" | "scheduled" | "rejected" | "completed" | "cancelled";
|
||||||
created_at: string;
|
created_at: string;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user