Compare commits

...

2 Commits

5 changed files with 60 additions and 50 deletions

View File

@ -494,7 +494,7 @@ export default function AppointmentDetailPage() {
)} )}
{/* Meeting Information */} {/* Meeting Information */}
{appointment.jitsi_meet_url && ( {appointment.moderator_join_url && (
<div className={`rounded-2xl border shadow-sm overflow-hidden ${isDark ? "bg-gradient-to-br from-blue-900/20 to-purple-900/20 border-blue-800/30" : "bg-gradient-to-br from-blue-50 to-purple-50 border-blue-200"}`}> <div className={`rounded-2xl border shadow-sm overflow-hidden ${isDark ? "bg-gradient-to-br from-blue-900/20 to-purple-900/20 border-blue-800/30" : "bg-gradient-to-br from-blue-50 to-purple-50 border-blue-200"}`}>
<div className={`px-6 py-4 border-b ${isDark ? "border-blue-800/30" : "border-blue-200"}`}> <div className={`px-6 py-4 border-b ${isDark ? "border-blue-800/30" : "border-blue-200"}`}>
<h2 className={`text-lg font-semibold flex items-center gap-2 ${isDark ? "text-white" : "text-gray-900"}`}> <h2 className={`text-lg font-semibold flex items-center gap-2 ${isDark ? "text-white" : "text-gray-900"}`}>
@ -513,10 +513,10 @@ export default function AppointmentDetailPage() {
{appointment.jitsi_room_id} {appointment.jitsi_room_id}
</p> </p>
<button <button
onClick={() => appointment.can_join_meeting && copyToClipboard(appointment.jitsi_room_id!, "Room ID")} onClick={() => appointment.can_join_as_moderator && copyToClipboard(appointment.jitsi_room_id!, "Room ID")}
disabled={!appointment.can_join_meeting} disabled={!appointment.can_join_as_moderator}
className={`p-2 rounded-lg transition-colors ${appointment.can_join_meeting ? (isDark ? "hover:bg-gray-700" : "hover:bg-gray-100") : (isDark ? "opacity-50 cursor-not-allowed" : "opacity-50 cursor-not-allowed")}`} className={`p-2 rounded-lg transition-colors ${appointment.can_join_as_moderator ? (isDark ? "hover:bg-gray-700" : "hover:bg-gray-100") : (isDark ? "opacity-50 cursor-not-allowed" : "opacity-50 cursor-not-allowed")}`}
title={appointment.can_join_meeting ? "Copy room ID" : "Meeting not available"} title={appointment.can_join_as_moderator ? "Copy room ID" : "Meeting not available"}
> >
<Copy className={`w-4 h-4 ${isDark ? "text-gray-400" : "text-gray-500"}`} /> <Copy className={`w-4 h-4 ${isDark ? "text-gray-400" : "text-gray-500"}`} />
</button> </button>
@ -525,21 +525,21 @@ export default function AppointmentDetailPage() {
)} )}
<div> <div>
<p className={`text-xs font-medium mb-2 uppercase tracking-wider ${isDark ? "text-gray-400" : "text-gray-500"}`}> <p className={`text-xs font-medium mb-2 uppercase tracking-wider ${isDark ? "text-gray-400" : "text-gray-500"}`}>
Meeting Link Moderator Meeting Link
</p> </p>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{appointment.can_join_meeting ? ( {appointment.can_join_as_moderator ? (
<> <>
<a <a
href={appointment.jitsi_meet_url} href={appointment.moderator_join_url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className={`flex-1 text-sm px-3 py-2 rounded-lg truncate ${isDark ? "bg-gray-800 text-blue-400 hover:bg-gray-700" : "bg-white text-blue-600 hover:bg-gray-50 border border-gray-200"}`} className={`flex-1 text-sm px-3 py-2 rounded-lg truncate ${isDark ? "bg-gray-800 text-blue-400 hover:bg-gray-700" : "bg-white text-blue-600 hover:bg-gray-50 border border-gray-200"}`}
> >
{appointment.jitsi_meet_url} {appointment.moderator_join_url}
</a> </a>
<a <a
href={appointment.jitsi_meet_url} href={appointment.moderator_join_url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className={`px-4 py-2 rounded-lg font-medium transition-colors ${isDark ? "bg-blue-600 hover:bg-blue-700 text-white" : "bg-blue-600 hover:bg-blue-700 text-white"}`} className={`px-4 py-2 rounded-lg font-medium transition-colors ${isDark ? "bg-blue-600 hover:bg-blue-700 text-white" : "bg-blue-600 hover:bg-blue-700 text-white"}`}
@ -550,7 +550,7 @@ export default function AppointmentDetailPage() {
) : ( ) : (
<> <>
<div className={`flex-1 text-sm px-3 py-2 rounded-lg truncate ${isDark ? "bg-gray-800/50 text-gray-500 border border-gray-700" : "bg-gray-100 text-gray-400 border border-gray-300"}`}> <div className={`flex-1 text-sm px-3 py-2 rounded-lg truncate ${isDark ? "bg-gray-800/50 text-gray-500 border border-gray-700" : "bg-gray-100 text-gray-400 border border-gray-300"}`}>
{appointment.jitsi_meet_url} {appointment.moderator_join_url}
</div> </div>
<button <button
disabled disabled
@ -562,11 +562,11 @@ export default function AppointmentDetailPage() {
)} )}
</div> </div>
</div> </div>
{appointment.can_join_meeting !== undefined && ( {appointment.can_join_as_moderator !== undefined && (
<div className={`flex items-center gap-2 px-4 py-3 rounded-lg ${appointment.can_join_meeting ? (isDark ? "bg-green-500/20 border border-green-500/30" : "bg-green-50 border border-green-200") : (isDark ? "bg-gray-800 border border-gray-700" : "bg-gray-50 border border-gray-200")}`}> <div className={`flex items-center gap-2 px-4 py-3 rounded-lg ${appointment.can_join_as_moderator ? (isDark ? "bg-green-500/20 border border-green-500/30" : "bg-green-50 border border-green-200") : (isDark ? "bg-gray-800 border border-gray-700" : "bg-gray-50 border border-gray-200")}`}>
<div className={`h-2 w-2 rounded-full ${appointment.can_join_meeting ? (isDark ? "bg-green-400" : "bg-green-600") : (isDark ? "bg-gray-500" : "bg-gray-400")}`} /> <div className={`h-2 w-2 rounded-full ${appointment.can_join_as_moderator ? (isDark ? "bg-green-400" : "bg-green-600") : (isDark ? "bg-gray-500" : "bg-gray-400")}`} />
<p className={`text-sm font-medium ${appointment.can_join_meeting ? (isDark ? "text-green-300" : "text-green-700") : (isDark ? "text-gray-400" : "text-gray-500")}`}> <p className={`text-sm font-medium ${appointment.can_join_as_moderator ? (isDark ? "text-green-300" : "text-green-700") : (isDark ? "text-gray-400" : "text-gray-500")}`}>
{appointment.can_join_meeting ? "Meeting is active - You can join now" : "Meeting is not available yet"} {appointment.can_join_as_moderator ? "Meeting is active - You can join as moderator" : "Meeting is not available yet"}
</p> </p>
</div> </div>
)} )}
@ -636,18 +636,18 @@ export default function AppointmentDetailPage() {
)} )}
{/* Join Meeting Button (if scheduled) */} {/* Join Meeting Button (if scheduled) */}
{appointment.status === "scheduled" && appointment.jitsi_meet_url && ( {appointment.status === "scheduled" && appointment.moderator_join_url && (
<div className={`rounded-2xl border shadow-sm overflow-hidden ${isDark ? "bg-gradient-to-br from-blue-900/20 to-purple-900/20 border-blue-800/30" : "bg-gradient-to-br from-blue-50 to-purple-50 border-blue-200"}`}> <div className={`rounded-2xl border shadow-sm overflow-hidden ${isDark ? "bg-gradient-to-br from-blue-900/20 to-purple-900/20 border-blue-800/30" : "bg-gradient-to-br from-blue-50 to-purple-50 border-blue-200"}`}>
<div className="p-6"> <div className="p-6">
{appointment.can_join_meeting ? ( {appointment.can_join_as_moderator ? (
<a <a
href={appointment.jitsi_meet_url} href={appointment.moderator_join_url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className={`flex items-center justify-center gap-2 w-full bg-blue-600 hover:bg-blue-700 text-white h-12 rounded-lg text-base font-medium transition-colors`} className={`flex items-center justify-center gap-2 w-full bg-blue-600 hover:bg-blue-700 text-white h-12 rounded-lg text-base font-medium transition-colors`}
> >
<Video className="w-5 h-5" /> <Video className="w-5 h-5" />
Join Meeting Join Meeting as Moderator
</a> </a>
) : ( ) : (
<button <button

View File

@ -802,13 +802,13 @@ export default function Booking() {
</button> </button>
</> </>
)} )}
{appointment.jitsi_meet_url && ( {appointment.moderator_join_url && (
<a <a
href={appointment.jitsi_meet_url} href={appointment.moderator_join_url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className={`p-1.5 sm:p-2 rounded-lg transition-colors ${isDark ? "text-gray-300 hover:text-white hover:bg-gray-700" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100"}`} className={`p-1.5 sm:p-2 rounded-lg transition-colors ${isDark ? "text-gray-300 hover:text-white hover:bg-gray-700" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100"}`}
title="Join Meeting" title="Join Meeting as Moderator"
> >
<Video className="w-4 h-4" /> <Video className="w-4 h-4" />
</a> </a>

View File

@ -433,7 +433,7 @@ export default function UserAppointmentDetailPage() {
)} )}
{/* Meeting Information */} {/* Meeting Information */}
{appointment.jitsi_meet_url && ( {appointment.participant_join_url && (
<div className={`rounded-2xl border shadow-sm overflow-hidden ${isDark ? "bg-gradient-to-br from-blue-900/20 to-purple-900/20 border-blue-800/30" : "bg-gradient-to-br from-blue-50 to-purple-50 border-blue-200"}`}> <div className={`rounded-2xl border shadow-sm overflow-hidden ${isDark ? "bg-gradient-to-br from-blue-900/20 to-purple-900/20 border-blue-800/30" : "bg-gradient-to-br from-blue-50 to-purple-50 border-blue-200"}`}>
<div className={`px-6 py-4 border-b ${isDark ? "border-blue-800/30" : "border-blue-200"}`}> <div className={`px-6 py-4 border-b ${isDark ? "border-blue-800/30" : "border-blue-200"}`}>
<h2 className={`text-lg font-semibold flex items-center gap-2 ${isDark ? "text-white" : "text-gray-900"}`}> <h2 className={`text-lg font-semibold flex items-center gap-2 ${isDark ? "text-white" : "text-gray-900"}`}>
@ -452,10 +452,10 @@ export default function UserAppointmentDetailPage() {
{appointment.jitsi_room_id} {appointment.jitsi_room_id}
</p> </p>
<button <button
onClick={() => appointment.can_join_meeting && copyToClipboard(appointment.jitsi_room_id!, "Room ID")} onClick={() => appointment.can_join_as_participant && copyToClipboard(appointment.jitsi_room_id!, "Room ID")}
disabled={!appointment.can_join_meeting} disabled={!appointment.can_join_as_participant}
className={`p-2 rounded-lg transition-colors ${appointment.can_join_meeting ? (isDark ? "hover:bg-gray-700" : "hover:bg-gray-100") : (isDark ? "opacity-50 cursor-not-allowed" : "opacity-50 cursor-not-allowed")}`} className={`p-2 rounded-lg transition-colors ${appointment.can_join_as_participant ? (isDark ? "hover:bg-gray-700" : "hover:bg-gray-100") : (isDark ? "opacity-50 cursor-not-allowed" : "opacity-50 cursor-not-allowed")}`}
title={appointment.can_join_meeting ? "Copy room ID" : "Meeting not available"} title={appointment.can_join_as_participant ? "Copy room ID" : "Meeting not available"}
> >
<Copy className={`w-4 h-4 ${isDark ? "text-gray-400" : "text-gray-500"}`} /> <Copy className={`w-4 h-4 ${isDark ? "text-gray-400" : "text-gray-500"}`} />
</button> </button>
@ -467,18 +467,18 @@ export default function UserAppointmentDetailPage() {
Meeting Link Meeting Link
</p> </p>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{appointment.can_join_meeting ? ( {appointment.can_join_as_participant ? (
<> <>
<a <a
href={appointment.jitsi_meet_url} href={appointment.participant_join_url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className={`flex-1 text-sm px-3 py-2 rounded-lg truncate ${isDark ? "bg-gray-800 text-blue-400 hover:bg-gray-700" : "bg-white text-blue-600 hover:bg-gray-50 border border-gray-200"}`} className={`flex-1 text-sm px-3 py-2 rounded-lg truncate ${isDark ? "bg-gray-800 text-blue-400 hover:bg-gray-700" : "bg-white text-blue-600 hover:bg-gray-50 border border-gray-200"}`}
> >
{appointment.jitsi_meet_url} {appointment.participant_join_url}
</a> </a>
<a <a
href={appointment.jitsi_meet_url} href={appointment.participant_join_url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className={`px-4 py-2 rounded-lg font-medium transition-colors ${isDark ? "bg-blue-600 hover:bg-blue-700 text-white" : "bg-blue-600 hover:bg-blue-700 text-white"}`} className={`px-4 py-2 rounded-lg font-medium transition-colors ${isDark ? "bg-blue-600 hover:bg-blue-700 text-white" : "bg-blue-600 hover:bg-blue-700 text-white"}`}
@ -489,7 +489,7 @@ export default function UserAppointmentDetailPage() {
) : ( ) : (
<> <>
<div className={`flex-1 text-sm px-3 py-2 rounded-lg truncate ${isDark ? "bg-gray-800/50 text-gray-500 border border-gray-700" : "bg-gray-100 text-gray-400 border border-gray-300"}`}> <div className={`flex-1 text-sm px-3 py-2 rounded-lg truncate ${isDark ? "bg-gray-800/50 text-gray-500 border border-gray-700" : "bg-gray-100 text-gray-400 border border-gray-300"}`}>
{appointment.jitsi_meet_url} {appointment.participant_join_url}
</div> </div>
<button <button
disabled disabled
@ -501,11 +501,11 @@ export default function UserAppointmentDetailPage() {
)} )}
</div> </div>
</div> </div>
{appointment.can_join_meeting !== undefined && ( {appointment.can_join_as_participant !== undefined && (
<div className={`flex items-center gap-2 px-4 py-3 rounded-lg ${appointment.can_join_meeting ? (isDark ? "bg-green-500/20 border border-green-500/30" : "bg-green-50 border border-green-200") : (isDark ? "bg-gray-800 border border-gray-700" : "bg-gray-50 border border-gray-200")}`}> <div className={`flex items-center gap-2 px-4 py-3 rounded-lg ${appointment.can_join_as_participant ? (isDark ? "bg-green-500/20 border border-green-500/30" : "bg-green-50 border border-green-200") : (isDark ? "bg-gray-800 border border-gray-700" : "bg-gray-50 border border-gray-200")}`}>
<div className={`h-2 w-2 rounded-full ${appointment.can_join_meeting ? (isDark ? "bg-green-400" : "bg-green-600") : (isDark ? "bg-gray-500" : "bg-gray-400")}`} /> <div className={`h-2 w-2 rounded-full ${appointment.can_join_as_participant ? (isDark ? "bg-green-400" : "bg-green-600") : (isDark ? "bg-gray-500" : "bg-gray-400")}`} />
<p className={`text-sm font-medium ${appointment.can_join_meeting ? (isDark ? "text-green-300" : "text-green-700") : (isDark ? "text-gray-400" : "text-gray-500")}`}> <p className={`text-sm font-medium ${appointment.can_join_as_participant ? (isDark ? "text-green-300" : "text-green-700") : (isDark ? "text-gray-400" : "text-gray-500")}`}>
{appointment.can_join_meeting ? "Meeting is active - You can join now" : "Meeting is not available yet"} {appointment.can_join_as_participant ? "Meeting is active - You can join now" : "Meeting is not available yet"}
</p> </p>
</div> </div>
)} )}
@ -552,12 +552,12 @@ export default function UserAppointmentDetailPage() {
</div> </div>
{/* Join Meeting Button */} {/* Join Meeting Button */}
{appointment.status === "scheduled" && appointment.jitsi_meet_url && ( {appointment.status === "scheduled" && appointment.participant_join_url && (
<div className={`rounded-2xl border shadow-sm overflow-hidden ${isDark ? "bg-gradient-to-br from-blue-900/20 to-purple-900/20 border-blue-800/30" : "bg-gradient-to-br from-blue-50 to-purple-50 border-blue-200"}`}> <div className={`rounded-2xl border shadow-sm overflow-hidden ${isDark ? "bg-gradient-to-br from-blue-900/20 to-purple-900/20 border-blue-800/30" : "bg-gradient-to-br from-blue-50 to-purple-50 border-blue-200"}`}>
<div className="p-6"> <div className="p-6">
{appointment.can_join_meeting ? ( {appointment.can_join_as_participant ? (
<a <a
href={appointment.jitsi_meet_url} href={appointment.participant_join_url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className={`flex items-center justify-center gap-2 w-full bg-blue-600 hover:bg-blue-700 text-white h-12 rounded-lg text-base font-medium transition-colors`} className={`flex items-center justify-center gap-2 w-full bg-blue-600 hover:bg-blue-700 text-white h-12 rounded-lg text-base font-medium transition-colors`}

View File

@ -458,13 +458,13 @@ export default function UserDashboard() {
</td> </td>
<td className="px-3 sm:px-4 md:px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> <td className="px-3 sm:px-4 md:px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<div className="flex items-center justify-end gap-1 sm:gap-2"> <div className="flex items-center justify-end gap-1 sm:gap-2">
{appointment.jitsi_meet_url && ( {appointment.participant_join_url && (
<a <a
href={appointment.jitsi_meet_url} href={appointment.participant_join_url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className={`p-1.5 sm:p-2 rounded-lg transition-colors ${ className={`p-1.5 sm:p-2 rounded-lg transition-colors ${
appointment.can_join_meeting appointment.can_join_as_participant
? isDark ? isDark
? "bg-blue-600 hover:bg-blue-700 text-white" ? "bg-blue-600 hover:bg-blue-700 text-white"
: "bg-blue-600 hover:bg-blue-700 text-white" : "bg-blue-600 hover:bg-blue-700 text-white"
@ -472,17 +472,17 @@ export default function UserDashboard() {
? "text-gray-400 hover:text-gray-300 hover:bg-gray-700" ? "text-gray-400 hover:text-gray-300 hover:bg-gray-700"
: "text-gray-500 hover:text-gray-700 hover:bg-gray-100" : "text-gray-500 hover:text-gray-700 hover:bg-gray-100"
}`} }`}
title={appointment.can_join_meeting ? "Join Meeting" : "Meeting Not Available"} title={appointment.can_join_as_participant ? "Join Meeting" : "Meeting Not Available"}
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
if (!appointment.can_join_meeting) { if (!appointment.can_join_as_participant) {
e.preventDefault(); e.preventDefault();
} }
}} }}
> >
<Video className="w-4 h-4" /> <Video className="w-4 h-4" />
</a> </a>
)} )}
</div> </div>
</td> </td>
</tr> </tr>

View File

@ -18,8 +18,17 @@ export interface Appointment {
rejection_reason?: string; rejection_reason?: string;
jitsi_meet_url?: string; jitsi_meet_url?: string;
jitsi_room_id?: string; jitsi_room_id?: string;
jitsi_meeting_created?: boolean;
meeting_started_at?: string;
meeting_ended_at?: string;
meeting_duration_actual?: number;
meeting_info?: any;
has_jitsi_meeting?: boolean | string; has_jitsi_meeting?: boolean | string;
can_join_meeting?: boolean | string; can_join_meeting?: boolean | string;
can_join_as_moderator?: boolean | string;
can_join_as_participant?: boolean | string;
moderator_join_url?: string;
participant_join_url?: string;
meeting_status?: string; meeting_status?: string;
matching_availability?: MatchingAvailability | Array<{ matching_availability?: MatchingAvailability | Array<{
date: string; date: string;
@ -39,6 +48,7 @@ export interface Appointment {
export interface SelectedSlot { export interface SelectedSlot {
day: number; // 0-6 (Monday-Sunday) day: number; // 0-6 (Monday-Sunday)
date?: string; // YYYY-MM-DD format
time_slot: "morning" | "afternoon" | "evening"; time_slot: "morning" | "afternoon" | "evening";
} }