Compare commits
2 Commits
9aefe892cf
...
f06a74891d
| Author | SHA1 | Date | |
|---|---|---|---|
| f06a74891d | |||
|
|
97b04e7593 |
@ -413,6 +413,13 @@ export default function AppointmentDetailPage() {
|
|||||||
evening: "Evening",
|
evening: "Evening",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Time slot order: morning, afternoon (lunchtime), evening
|
||||||
|
const timeSlotOrder: Record<string, number> = {
|
||||||
|
morning: 0,
|
||||||
|
afternoon: 1,
|
||||||
|
evening: 2,
|
||||||
|
};
|
||||||
|
|
||||||
// Group slots by date
|
// Group slots by date
|
||||||
const slotsByDate: Record<string, typeof appointment.selected_slots> = {};
|
const slotsByDate: Record<string, typeof appointment.selected_slots> = {};
|
||||||
appointment.selected_slots.forEach((slot: any) => {
|
appointment.selected_slots.forEach((slot: any) => {
|
||||||
@ -423,36 +430,52 @@ export default function AppointmentDetailPage() {
|
|||||||
slotsByDate[date].push(slot);
|
slotsByDate[date].push(slot);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Sort dates and slots within each date
|
||||||
|
const sortedDates = Object.keys(slotsByDate).sort((a, b) => {
|
||||||
|
return new Date(a).getTime() - new Date(b).getTime();
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{Object.entries(slotsByDate).map(([date, slots]) => (
|
{sortedDates.map((date) => {
|
||||||
<div key={date} className={`p-4 rounded-xl border ${isDark ? "bg-gray-700/50 border-gray-600" : "bg-gray-50 border-gray-200"}`}>
|
// Sort slots within this date by time slot order
|
||||||
<div className="mb-3">
|
const slots = slotsByDate[date].sort((a: any, b: any) => {
|
||||||
<p className={`text-base font-semibold ${isDark ? "text-white" : "text-gray-900"}`}>
|
const aSlot = String(a.time_slot).toLowerCase().trim();
|
||||||
{formatShortDate(date)}
|
const bSlot = String(b.time_slot).toLowerCase().trim();
|
||||||
</p>
|
const aOrder = timeSlotOrder[aSlot] ?? 999;
|
||||||
{slots.length > 0 && slots[0]?.day !== undefined && (
|
const bOrder = timeSlotOrder[bSlot] ?? 999;
|
||||||
<p className={`text-sm mt-1 ${isDark ? "text-gray-400" : "text-gray-500"}`}>
|
return aOrder - bOrder;
|
||||||
{dayNames[slots[0].day] || `Day ${slots[0].day}`}
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={date} className={`p-4 rounded-xl border ${isDark ? "bg-gray-700/50 border-gray-600" : "bg-gray-50 border-gray-200"}`}>
|
||||||
|
<div className="mb-3">
|
||||||
|
<p className={`text-base font-semibold ${isDark ? "text-white" : "text-gray-900"}`}>
|
||||||
|
{formatShortDate(date)}
|
||||||
</p>
|
</p>
|
||||||
)}
|
{slots.length > 0 && slots[0]?.day !== undefined && (
|
||||||
|
<p className={`text-sm mt-1 ${isDark ? "text-gray-400" : "text-gray-500"}`}>
|
||||||
|
{dayNames[slots[0].day] || `Day ${slots[0].day}`}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{slots.map((slot: any, idx: number) => {
|
||||||
|
const timeSlot = String(slot.time_slot).toLowerCase().trim();
|
||||||
|
const timeLabel = timeSlotLabels[timeSlot] || slot.time_slot;
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
key={idx}
|
||||||
|
className={`px-3 py-1.5 rounded-lg text-sm font-medium ${isDark ? "bg-green-500/20 text-green-300 border border-green-500/30" : "bg-green-50 text-green-700 border border-green-200"}`}
|
||||||
|
>
|
||||||
|
{timeLabel}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-wrap gap-2">
|
);
|
||||||
{slots.map((slot: any, idx: number) => {
|
})}
|
||||||
const timeSlot = String(slot.time_slot).toLowerCase().trim();
|
|
||||||
const timeLabel = timeSlotLabels[timeSlot] || slot.time_slot;
|
|
||||||
return (
|
|
||||||
<span
|
|
||||||
key={idx}
|
|
||||||
className={`px-3 py-1.5 rounded-lg text-sm font-medium ${isDark ? "bg-green-500/20 text-green-300 border border-green-500/30" : "bg-green-50 text-green-700 border border-green-200"}`}
|
|
||||||
>
|
|
||||||
{timeLabel}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})()}
|
})()}
|
||||||
|
|||||||
@ -154,12 +154,23 @@ export default function BookNowPage() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Convert Map values to array and sort by day number
|
// Time slot order: morning, afternoon (lunchtime), evening
|
||||||
|
const timeSlotOrder: Record<string, number> = {
|
||||||
|
morning: 0,
|
||||||
|
afternoon: 1,
|
||||||
|
evening: 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert Map values to array, sort slots, and sort by day number
|
||||||
return Array.from(dayMap.values())
|
return Array.from(dayMap.values())
|
||||||
.map(day => ({
|
.map(day => ({
|
||||||
day: day.day,
|
day: day.day,
|
||||||
dayName: day.dayName,
|
dayName: day.dayName,
|
||||||
availableSlots: Array.from(day.availableSlots),
|
availableSlots: Array.from(day.availableSlots).sort((a, b) => {
|
||||||
|
const aOrder = timeSlotOrder[a.toLowerCase().trim()] ?? 999;
|
||||||
|
const bOrder = timeSlotOrder[b.toLowerCase().trim()] ?? 999;
|
||||||
|
return aOrder - bOrder;
|
||||||
|
}),
|
||||||
}))
|
}))
|
||||||
.sort((a, b) => a.day - b.day);
|
.sort((a, b) => a.day - b.day);
|
||||||
}
|
}
|
||||||
@ -172,6 +183,13 @@ export default function BookNowPage() {
|
|||||||
: (weeklyAvailability as any)?.week;
|
: (weeklyAvailability as any)?.week;
|
||||||
|
|
||||||
if (weekArray && Array.isArray(weekArray)) {
|
if (weekArray && Array.isArray(weekArray)) {
|
||||||
|
// Time slot order: morning, afternoon (lunchtime), evening
|
||||||
|
const timeSlotOrder: Record<string, number> = {
|
||||||
|
morning: 0,
|
||||||
|
afternoon: 1,
|
||||||
|
evening: 2,
|
||||||
|
};
|
||||||
|
|
||||||
return weekArray
|
return weekArray
|
||||||
.filter(day => {
|
.filter(day => {
|
||||||
const dayNum = Number(day.day);
|
const dayNum = Number(day.day);
|
||||||
@ -186,7 +204,11 @@ export default function BookNowPage() {
|
|||||||
.map(day => ({
|
.map(day => ({
|
||||||
day: Number(day.day),
|
day: Number(day.day),
|
||||||
dayName: day.day_name || 'Unknown',
|
dayName: day.day_name || 'Unknown',
|
||||||
availableSlots: day.available_slots || [],
|
availableSlots: (day.available_slots || []).sort((a: string, b: string) => {
|
||||||
|
const aOrder = timeSlotOrder[String(a).toLowerCase().trim()] ?? 999;
|
||||||
|
const bOrder = timeSlotOrder[String(b).toLowerCase().trim()] ?? 999;
|
||||||
|
return aOrder - bOrder;
|
||||||
|
}),
|
||||||
}))
|
}))
|
||||||
.sort((a, b) => a.day - b.day);
|
.sort((a, b) => a.day - b.day);
|
||||||
}
|
}
|
||||||
@ -752,34 +774,6 @@ export default function BookNowPage() {
|
|||||||
<p className={`text-xs ${isDark ? 'text-gray-400' : 'text-gray-500'} mb-3`}>
|
<p className={`text-xs ${isDark ? 'text-gray-400' : 'text-gray-500'} mb-3`}>
|
||||||
Select one or more day-time combinations that work for you. You can select multiple time slots for the same day (e.g., Monday Morning and Monday Evening).
|
Select one or more day-time combinations that work for you. You can select multiple time slots for the same day (e.g., Monday Morning and Monday Evening).
|
||||||
</p>
|
</p>
|
||||||
{/* Selected Slots Summary */}
|
|
||||||
{formData.selectedSlots && formData.selectedSlots.length > 0 && (
|
|
||||||
<div className={`mb-4 p-3 rounded-lg border ${isDark ? 'bg-gray-800/50 border-gray-700' : 'bg-rose-50/50 border-rose-200'}`}>
|
|
||||||
<p className={`text-xs font-medium mb-2 ${isDark ? 'text-gray-300' : 'text-gray-700'}`}>
|
|
||||||
Selected: {formData.selectedSlots.length} time slot{formData.selectedSlots.length !== 1 ? 's' : ''}
|
|
||||||
</p>
|
|
||||||
<div className="flex flex-wrap gap-1.5">
|
|
||||||
{formData.selectedSlots.map((slot, idx) => {
|
|
||||||
const dayNames = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
|
|
||||||
const timeSlotLabels: Record<string, string> = {
|
|
||||||
morning: "Morning",
|
|
||||||
afternoon: "Lunchtime",
|
|
||||||
evening: "Evening",
|
|
||||||
};
|
|
||||||
const dayName = dayNames[slot.day] || `Day ${slot.day}`;
|
|
||||||
const timeLabel = timeSlotLabels[String(slot.time_slot).toLowerCase()] || slot.time_slot;
|
|
||||||
return (
|
|
||||||
<span
|
|
||||||
key={idx}
|
|
||||||
className={`px-2 py-1 rounded text-xs font-medium ${isDark ? 'bg-rose-600/30 text-rose-300 border border-rose-500/30' : 'bg-rose-100 text-rose-700 border border-rose-200'}`}
|
|
||||||
>
|
|
||||||
{dayName} {timeLabel}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{availableDaysOfWeek.map((dayInfo, dayIndex) => {
|
{availableDaysOfWeek.map((dayInfo, dayIndex) => {
|
||||||
// Ensure day is always a valid number (already validated in useMemo)
|
// Ensure day is always a valid number (already validated in useMemo)
|
||||||
|
|||||||
@ -352,6 +352,13 @@ export default function UserAppointmentDetailPage() {
|
|||||||
evening: "Evening",
|
evening: "Evening",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Time slot order: morning, afternoon (lunchtime), evening
|
||||||
|
const timeSlotOrder: Record<string, number> = {
|
||||||
|
morning: 0,
|
||||||
|
afternoon: 1,
|
||||||
|
evening: 2,
|
||||||
|
};
|
||||||
|
|
||||||
// Group slots by date
|
// Group slots by date
|
||||||
const slotsByDate: Record<string, typeof appointment.selected_slots> = {};
|
const slotsByDate: Record<string, typeof appointment.selected_slots> = {};
|
||||||
appointment.selected_slots.forEach((slot: any) => {
|
appointment.selected_slots.forEach((slot: any) => {
|
||||||
@ -362,36 +369,52 @@ export default function UserAppointmentDetailPage() {
|
|||||||
slotsByDate[date].push(slot);
|
slotsByDate[date].push(slot);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Sort dates and slots within each date
|
||||||
|
const sortedDates = Object.keys(slotsByDate).sort((a, b) => {
|
||||||
|
return new Date(a).getTime() - new Date(b).getTime();
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{Object.entries(slotsByDate).map(([date, slots]) => (
|
{sortedDates.map((date) => {
|
||||||
<div key={date} className={`p-4 rounded-xl border ${isDark ? "bg-gray-700/50 border-gray-600" : "bg-gray-50 border-gray-200"}`}>
|
// Sort slots within this date by time slot order
|
||||||
<div className="mb-3">
|
const slots = slotsByDate[date].sort((a: any, b: any) => {
|
||||||
<p className={`text-base font-semibold ${isDark ? "text-white" : "text-gray-900"}`}>
|
const aSlot = String(a.time_slot).toLowerCase().trim();
|
||||||
{formatShortDate(date)}
|
const bSlot = String(b.time_slot).toLowerCase().trim();
|
||||||
</p>
|
const aOrder = timeSlotOrder[aSlot] ?? 999;
|
||||||
{slots.length > 0 && slots[0]?.day !== undefined && (
|
const bOrder = timeSlotOrder[bSlot] ?? 999;
|
||||||
<p className={`text-sm mt-1 ${isDark ? "text-gray-400" : "text-gray-500"}`}>
|
return aOrder - bOrder;
|
||||||
{dayNames[slots[0].day] || `Day ${slots[0].day}`}
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={date} className={`p-4 rounded-xl border ${isDark ? "bg-gray-700/50 border-gray-600" : "bg-gray-50 border-gray-200"}`}>
|
||||||
|
<div className="mb-3">
|
||||||
|
<p className={`text-base font-semibold ${isDark ? "text-white" : "text-gray-900"}`}>
|
||||||
|
{formatShortDate(date)}
|
||||||
</p>
|
</p>
|
||||||
)}
|
{slots.length > 0 && slots[0]?.day !== undefined && (
|
||||||
|
<p className={`text-sm mt-1 ${isDark ? "text-gray-400" : "text-gray-500"}`}>
|
||||||
|
{dayNames[slots[0].day] || `Day ${slots[0].day}`}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{slots.map((slot: any, idx: number) => {
|
||||||
|
const timeSlot = String(slot.time_slot).toLowerCase().trim();
|
||||||
|
const timeLabel = timeSlotLabels[timeSlot] || slot.time_slot;
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
key={idx}
|
||||||
|
className={`px-3 py-1.5 rounded-lg text-sm font-medium ${isDark ? "bg-green-500/20 text-green-300 border border-green-500/30" : "bg-green-50 text-green-700 border border-green-200"}`}
|
||||||
|
>
|
||||||
|
{timeLabel}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-wrap gap-2">
|
);
|
||||||
{slots.map((slot: any, idx: number) => {
|
})}
|
||||||
const timeSlot = String(slot.time_slot).toLowerCase().trim();
|
|
||||||
const timeLabel = timeSlotLabels[timeSlot] || slot.time_slot;
|
|
||||||
return (
|
|
||||||
<span
|
|
||||||
key={idx}
|
|
||||||
className={`px-3 py-1.5 rounded-lg text-sm font-medium ${isDark ? "bg-green-500/20 text-green-300 border border-green-500/30" : "bg-green-50 text-green-700 border border-green-200"}`}
|
|
||||||
>
|
|
||||||
{timeLabel}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})()}
|
})()}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user