Compare commits
2 Commits
a65d03ccdd
...
ace90b9e10
| Author | SHA1 | Date | |
|---|---|---|---|
| ace90b9e10 | |||
|
|
2d1409682f |
@ -367,13 +367,18 @@ export default function AppointmentDetailPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Selected Slots */}
|
||||
{/* Selected Slots (replacing Matching Slots) */}
|
||||
{appointment.selected_slots && Array.isArray(appointment.selected_slots) && appointment.selected_slots.length > 0 && (
|
||||
<div className={`rounded-2xl border shadow-sm overflow-hidden ${isDark ? "bg-gray-800 border-gray-700" : "bg-white border-gray-200"}`}>
|
||||
<div className={`px-6 py-4 border-b ${isDark ? "border-gray-700 bg-gray-800/50" : "border-gray-200 bg-gray-50/50"}`}>
|
||||
<h2 className={`text-lg font-semibold flex items-center gap-2 ${isDark ? "text-white" : "text-gray-900"}`}>
|
||||
<CalendarCheck className={`w-5 h-5 ${isDark ? "text-blue-400" : "text-blue-600"}`} />
|
||||
<CalendarCheck className={`w-5 h-5 ${isDark ? "text-green-400" : "text-green-600"}`} />
|
||||
Selected Time Slots
|
||||
{appointment.are_preferences_available !== undefined && (
|
||||
<span className={`ml-auto px-3 py-1 text-xs font-medium rounded-full ${appointment.are_preferences_available ? (isDark ? "bg-green-500/20 text-green-300 border border-green-500/30" : "bg-green-50 text-green-700 border border-green-200") : (isDark ? "bg-yellow-500/20 text-yellow-300 border border-yellow-500/30" : "bg-yellow-50 text-yellow-700 border border-yellow-200")}`}>
|
||||
{appointment.are_preferences_available ? "All Available" : "Partially Available"}
|
||||
</span>
|
||||
)}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
@ -400,14 +405,19 @@ export default function AppointmentDetailPage() {
|
||||
return (
|
||||
<div
|
||||
key={idx}
|
||||
className={`px-4 py-3 rounded-xl border ${isDark ? "bg-blue-500/10 border-blue-500/30" : "bg-blue-50 border-blue-200"}`}
|
||||
className={`px-4 py-3 rounded-xl border ${isDark ? "bg-green-500/10 border-green-500/30" : "bg-green-50 border-green-200"}`}
|
||||
>
|
||||
<p className={`text-sm font-semibold ${isDark ? "text-blue-300" : "text-blue-700"}`}>
|
||||
<p className={`text-sm font-semibold ${isDark ? "text-green-300" : "text-green-700"}`}>
|
||||
{dayName}
|
||||
</p>
|
||||
<p className={`text-xs mt-1 ${isDark ? "text-blue-400" : "text-blue-600"}`}>
|
||||
<p className={`text-xs mt-1 ${isDark ? "text-green-400" : "text-green-600"}`}>
|
||||
{timeLabel}
|
||||
</p>
|
||||
{slot.date && (
|
||||
<p className={`text-xs mt-1 ${isDark ? "text-gray-400" : "text-gray-500"}`}>
|
||||
{formatShortDate(slot.date)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
@ -416,128 +426,6 @@ export default function AppointmentDetailPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Matching Slots */}
|
||||
{(() => {
|
||||
// Check if matching_availability is a MatchingAvailability object with matching_slots
|
||||
const matchingAvailability = appointment.matching_availability as any;
|
||||
const hasMatchingSlots = matchingAvailability && matchingAvailability.matching_slots && Array.isArray(matchingAvailability.matching_slots) && matchingAvailability.matching_slots.length > 0;
|
||||
const isArrayFormat = Array.isArray(matchingAvailability) && matchingAvailability.length > 0;
|
||||
|
||||
if (!hasMatchingSlots && !isArrayFormat) return null;
|
||||
|
||||
const dayNames: Record<number, string> = {
|
||||
0: "Monday",
|
||||
1: "Tuesday",
|
||||
2: "Wednesday",
|
||||
3: "Thursday",
|
||||
4: "Friday",
|
||||
5: "Saturday",
|
||||
6: "Sunday",
|
||||
};
|
||||
const timeSlotLabels: Record<string, string> = {
|
||||
morning: "Morning",
|
||||
afternoon: "Lunchtime",
|
||||
evening: "Evening",
|
||||
};
|
||||
|
||||
// Get matching slots from MatchingAvailability object
|
||||
const matchingSlots = hasMatchingSlots ? matchingAvailability.matching_slots : null;
|
||||
const totalMatchingSlots = hasMatchingSlots ? matchingAvailability.total_matching_slots : null;
|
||||
const preferencesMatch = hasMatchingSlots ? matchingAvailability.preferences_match_availability : appointment.are_preferences_available;
|
||||
|
||||
return (
|
||||
<div className={`rounded-2xl border shadow-sm overflow-hidden ${isDark ? "bg-gray-800 border-gray-700" : "bg-white border-gray-200"}`}>
|
||||
<div className={`px-6 py-4 border-b ${isDark ? "border-gray-700 bg-gray-800/50" : "border-gray-200 bg-gray-50/50"}`}>
|
||||
<h2 className={`text-lg font-semibold flex items-center gap-2 ${isDark ? "text-white" : "text-gray-900"}`}>
|
||||
<CalendarCheck className={`w-5 h-5 ${isDark ? "text-green-400" : "text-green-600"}`} />
|
||||
Matching Slots
|
||||
{preferencesMatch !== undefined && (
|
||||
<span className={`ml-auto px-3 py-1 text-xs font-medium rounded-full ${preferencesMatch ? (isDark ? "bg-green-500/20 text-green-300 border border-green-500/30" : "bg-green-50 text-green-700 border border-green-200") : (isDark ? "bg-yellow-500/20 text-yellow-300 border border-yellow-500/30" : "bg-yellow-50 text-yellow-700 border border-yellow-200")}`}>
|
||||
{preferencesMatch ? "All Available" : "Partially Available"}
|
||||
</span>
|
||||
)}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
{hasMatchingSlots && totalMatchingSlots && (
|
||||
<p className={`text-sm mb-4 ${isDark ? "text-gray-400" : "text-gray-600"}`}>
|
||||
Found {totalMatchingSlots} matching time slot{totalMatchingSlots !== 1 ? 's' : ''} that match your selected preferences:
|
||||
</p>
|
||||
)}
|
||||
{!hasMatchingSlots && (
|
||||
<p className={`text-sm mb-4 ${isDark ? "text-gray-400" : "text-gray-600"}`}>
|
||||
These are the available time slots that match your selected preferences:
|
||||
</p>
|
||||
)}
|
||||
|
||||
{hasMatchingSlots ? (
|
||||
// Display matching_slots from MatchingAvailability object
|
||||
<div className="flex flex-wrap gap-3">
|
||||
{matchingSlots.map((slot: any, idx: number) => {
|
||||
const dayName = dayNames[slot.day] || `Day ${slot.day}`;
|
||||
const timeSlot = String(slot.time_slot).toLowerCase().trim();
|
||||
const timeLabel = timeSlotLabels[timeSlot] || slot.time_slot;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={idx}
|
||||
className={`px-4 py-3 rounded-xl border ${isDark ? "bg-green-500/10 border-green-500/30" : "bg-green-50 border-green-200"}`}
|
||||
>
|
||||
<p className={`text-sm font-semibold ${isDark ? "text-green-300" : "text-green-700"}`}>
|
||||
{dayName}
|
||||
</p>
|
||||
<p className={`text-xs mt-1 ${isDark ? "text-green-400" : "text-green-600"}`}>
|
||||
{timeLabel}
|
||||
</p>
|
||||
<p className={`text-xs mt-1 ${isDark ? "text-gray-400" : "text-gray-500"}`}>
|
||||
{formatShortDate(slot.date)}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
// Display array format (legacy)
|
||||
<div className="space-y-4">
|
||||
{(matchingAvailability as any[]).map((match: any, idx: number) => (
|
||||
<div
|
||||
key={idx}
|
||||
className={`p-4 rounded-xl border ${isDark ? "bg-gray-700/50 border-gray-600" : "bg-gray-50 border-gray-200"}`}
|
||||
>
|
||||
<div className="flex items-start justify-between mb-3">
|
||||
<div>
|
||||
<p className={`text-base font-semibold ${isDark ? "text-white" : "text-gray-900"}`}>
|
||||
{match.day_name || "Unknown Day"}
|
||||
</p>
|
||||
<p className={`text-sm mt-1 ${isDark ? "text-gray-400" : "text-gray-500"}`}>
|
||||
{formatShortDate(match.date || match.date_obj || "")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{match.available_slots && Array.isArray(match.available_slots) && match.available_slots.length > 0 && (
|
||||
<div className="flex flex-wrap gap-2 mt-3">
|
||||
{match.available_slots.map((slot: string, slotIdx: number) => {
|
||||
const normalizedSlot = String(slot).toLowerCase().trim();
|
||||
return (
|
||||
<span
|
||||
key={slotIdx}
|
||||
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"}`}
|
||||
>
|
||||
{timeSlotLabels[normalizedSlot] || slot}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
|
||||
{/* Reason */}
|
||||
{appointment.reason && (
|
||||
<div className={`rounded-2xl border shadow-sm overflow-hidden ${isDark ? "bg-gray-800 border-gray-700" : "bg-white border-gray-200"}`}>
|
||||
|
||||
@ -306,13 +306,18 @@ export default function UserAppointmentDetailPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Selected Slots */}
|
||||
{/* Selected Slots (replacing Matching Slots) */}
|
||||
{appointment.selected_slots && Array.isArray(appointment.selected_slots) && appointment.selected_slots.length > 0 && (
|
||||
<div className={`rounded-2xl border shadow-sm overflow-hidden ${isDark ? "bg-gray-800 border-gray-700" : "bg-white border-gray-200"}`}>
|
||||
<div className={`px-6 py-4 border-b ${isDark ? "border-gray-700 bg-gray-800/50" : "border-gray-200 bg-gray-50/50"}`}>
|
||||
<h2 className={`text-lg font-semibold flex items-center gap-2 ${isDark ? "text-white" : "text-gray-900"}`}>
|
||||
<CalendarCheck className={`w-5 h-5 ${isDark ? "text-blue-400" : "text-blue-600"}`} />
|
||||
<CalendarCheck className={`w-5 h-5 ${isDark ? "text-green-400" : "text-green-600"}`} />
|
||||
Selected Time Slots
|
||||
{appointment.are_preferences_available !== undefined && (
|
||||
<span className={`ml-auto px-3 py-1 text-xs font-medium rounded-full ${appointment.are_preferences_available ? (isDark ? "bg-green-500/20 text-green-300 border border-green-500/30" : "bg-green-50 text-green-700 border border-green-200") : (isDark ? "bg-yellow-500/20 text-yellow-300 border border-yellow-500/30" : "bg-yellow-50 text-yellow-700 border border-yellow-200")}`}>
|
||||
{appointment.are_preferences_available ? "All Available" : "Partially Available"}
|
||||
</span>
|
||||
)}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
@ -339,14 +344,19 @@ export default function UserAppointmentDetailPage() {
|
||||
return (
|
||||
<div
|
||||
key={idx}
|
||||
className={`px-4 py-3 rounded-xl border ${isDark ? "bg-blue-500/10 border-blue-500/30" : "bg-blue-50 border-blue-200"}`}
|
||||
className={`px-4 py-3 rounded-xl border ${isDark ? "bg-green-500/10 border-green-500/30" : "bg-green-50 border-green-200"}`}
|
||||
>
|
||||
<p className={`text-sm font-semibold ${isDark ? "text-blue-300" : "text-blue-700"}`}>
|
||||
<p className={`text-sm font-semibold ${isDark ? "text-green-300" : "text-green-700"}`}>
|
||||
{dayName}
|
||||
</p>
|
||||
<p className={`text-xs mt-1 ${isDark ? "text-blue-400" : "text-blue-600"}`}>
|
||||
<p className={`text-xs mt-1 ${isDark ? "text-green-400" : "text-green-600"}`}>
|
||||
{timeLabel}
|
||||
</p>
|
||||
{slot.date && (
|
||||
<p className={`text-xs mt-1 ${isDark ? "text-gray-400" : "text-gray-500"}`}>
|
||||
{formatShortDate(slot.date)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
@ -355,128 +365,6 @@ export default function UserAppointmentDetailPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Matching Slots */}
|
||||
{(() => {
|
||||
// Check if matching_availability is a MatchingAvailability object with matching_slots
|
||||
const matchingAvailability = appointment.matching_availability as any;
|
||||
const hasMatchingSlots = matchingAvailability && matchingAvailability.matching_slots && Array.isArray(matchingAvailability.matching_slots) && matchingAvailability.matching_slots.length > 0;
|
||||
const isArrayFormat = Array.isArray(matchingAvailability) && matchingAvailability.length > 0;
|
||||
|
||||
if (!hasMatchingSlots && !isArrayFormat) return null;
|
||||
|
||||
const dayNames: Record<number, string> = {
|
||||
0: "Monday",
|
||||
1: "Tuesday",
|
||||
2: "Wednesday",
|
||||
3: "Thursday",
|
||||
4: "Friday",
|
||||
5: "Saturday",
|
||||
6: "Sunday",
|
||||
};
|
||||
const timeSlotLabels: Record<string, string> = {
|
||||
morning: "Morning",
|
||||
afternoon: "Lunchtime",
|
||||
evening: "Evening",
|
||||
};
|
||||
|
||||
// Get matching slots from MatchingAvailability object
|
||||
const matchingSlots = hasMatchingSlots ? matchingAvailability.matching_slots : null;
|
||||
const totalMatchingSlots = hasMatchingSlots ? matchingAvailability.total_matching_slots : null;
|
||||
const preferencesMatch = hasMatchingSlots ? matchingAvailability.preferences_match_availability : appointment.are_preferences_available;
|
||||
|
||||
return (
|
||||
<div className={`rounded-2xl border shadow-sm overflow-hidden ${isDark ? "bg-gray-800 border-gray-700" : "bg-white border-gray-200"}`}>
|
||||
<div className={`px-6 py-4 border-b ${isDark ? "border-gray-700 bg-gray-800/50" : "border-gray-200 bg-gray-50/50"}`}>
|
||||
<h2 className={`text-lg font-semibold flex items-center gap-2 ${isDark ? "text-white" : "text-gray-900"}`}>
|
||||
<CalendarCheck className={`w-5 h-5 ${isDark ? "text-green-400" : "text-green-600"}`} />
|
||||
Matching Slots
|
||||
{preferencesMatch !== undefined && (
|
||||
<span className={`ml-auto px-3 py-1 text-xs font-medium rounded-full ${preferencesMatch ? (isDark ? "bg-green-500/20 text-green-300 border border-green-500/30" : "bg-green-50 text-green-700 border border-green-200") : (isDark ? "bg-yellow-500/20 text-yellow-300 border border-yellow-500/30" : "bg-yellow-50 text-yellow-700 border border-yellow-200")}`}>
|
||||
{preferencesMatch ? "All Available" : "Partially Available"}
|
||||
</span>
|
||||
)}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
{hasMatchingSlots && totalMatchingSlots && (
|
||||
<p className={`text-sm mb-4 ${isDark ? "text-gray-400" : "text-gray-600"}`}>
|
||||
Found {totalMatchingSlots} matching time slot{totalMatchingSlots !== 1 ? 's' : ''} that match your selected preferences:
|
||||
</p>
|
||||
)}
|
||||
{!hasMatchingSlots && (
|
||||
<p className={`text-sm mb-4 ${isDark ? "text-gray-400" : "text-gray-600"}`}>
|
||||
These are the available time slots that match your selected preferences:
|
||||
</p>
|
||||
)}
|
||||
|
||||
{hasMatchingSlots ? (
|
||||
// Display matching_slots from MatchingAvailability object
|
||||
<div className="flex flex-wrap gap-3">
|
||||
{matchingSlots.map((slot: any, idx: number) => {
|
||||
const dayName = dayNames[slot.day] || `Day ${slot.day}`;
|
||||
const timeSlot = String(slot.time_slot).toLowerCase().trim();
|
||||
const timeLabel = timeSlotLabels[timeSlot] || slot.time_slot;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={idx}
|
||||
className={`px-4 py-3 rounded-xl border ${isDark ? "bg-green-500/10 border-green-500/30" : "bg-green-50 border-green-200"}`}
|
||||
>
|
||||
<p className={`text-sm font-semibold ${isDark ? "text-green-300" : "text-green-700"}`}>
|
||||
{dayName}
|
||||
</p>
|
||||
<p className={`text-xs mt-1 ${isDark ? "text-green-400" : "text-green-600"}`}>
|
||||
{timeLabel}
|
||||
</p>
|
||||
<p className={`text-xs mt-1 ${isDark ? "text-gray-400" : "text-gray-500"}`}>
|
||||
{formatShortDate(slot.date)}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
// Display array format (legacy)
|
||||
<div className="space-y-4">
|
||||
{(matchingAvailability as any[]).map((match: any, idx: number) => (
|
||||
<div
|
||||
key={idx}
|
||||
className={`p-4 rounded-xl border ${isDark ? "bg-gray-700/50 border-gray-600" : "bg-gray-50 border-gray-200"}`}
|
||||
>
|
||||
<div className="flex items-start justify-between mb-3">
|
||||
<div>
|
||||
<p className={`text-base font-semibold ${isDark ? "text-white" : "text-gray-900"}`}>
|
||||
{match.day_name || "Unknown Day"}
|
||||
</p>
|
||||
<p className={`text-sm mt-1 ${isDark ? "text-gray-400" : "text-gray-500"}`}>
|
||||
{formatShortDate(match.date || match.date_obj || "")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{match.available_slots && Array.isArray(match.available_slots) && match.available_slots.length > 0 && (
|
||||
<div className="flex flex-wrap gap-2 mt-3">
|
||||
{match.available_slots.map((slot: string, slotIdx: number) => {
|
||||
const normalizedSlot = String(slot).toLowerCase().trim();
|
||||
return (
|
||||
<span
|
||||
key={slotIdx}
|
||||
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"}`}
|
||||
>
|
||||
{timeSlotLabels[normalizedSlot] || slot}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
|
||||
{/* Reason */}
|
||||
{appointment.reason && (
|
||||
<div className={`rounded-2xl border shadow-sm overflow-hidden ${isDark ? "bg-gray-800 border-gray-700" : "bg-white border-gray-200"}`}>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user