|
@@ -45,8 +45,12 @@ export default function MeetPage() {
|
|
|
const [loading, setLoading] = useState(true);
|
|
const [loading, setLoading] = useState(true);
|
|
|
const [accessDenied, setAccessDenied] = useState(false);
|
|
const [accessDenied, setAccessDenied] = useState(false);
|
|
|
const [denialReason, setDenialReason] = useState("");
|
|
const [denialReason, setDenialReason] = useState("");
|
|
|
|
|
+ const [jitsiToken, setJitsiToken] = useState<string | null>(null);
|
|
|
|
|
+ const [jitsiDomain, setJitsiDomain] = useState<string>("meet.jit.si");
|
|
|
|
|
+ const [jitsiRoomName, setJitsiRoomName] = useState<string>("");
|
|
|
|
|
+ const [useJWT, setUseJWT] = useState<boolean>(false);
|
|
|
|
|
|
|
|
- // Cargar información del appointment
|
|
|
|
|
|
|
+ // Cargar información del appointment y JWT token
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
const loadAppointment = async () => {
|
|
const loadAppointment = async () => {
|
|
|
try {
|
|
try {
|
|
@@ -54,18 +58,35 @@ export default function MeetPage() {
|
|
|
if (response.ok) {
|
|
if (response.ok) {
|
|
|
const data = await response.json();
|
|
const data = await response.json();
|
|
|
setAppointment(data);
|
|
setAppointment(data);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Validar acceso por tiempo
|
|
// Validar acceso por tiempo
|
|
|
const timeCheck = canJoinMeeting(data.fechaSolicitada);
|
|
const timeCheck = canJoinMeeting(data.fechaSolicitada);
|
|
|
if (!timeCheck.canJoin) {
|
|
if (!timeCheck.canJoin) {
|
|
|
setAccessDenied(true);
|
|
setAccessDenied(true);
|
|
|
setDenialReason(timeCheck.reason || "No puedes acceder a esta videollamada");
|
|
setDenialReason(timeCheck.reason || "No puedes acceder a esta videollamada");
|
|
|
|
|
+ setLoading(false);
|
|
|
|
|
+ return;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Validar que la cita esté aprobada
|
|
// Validar que la cita esté aprobada
|
|
|
if (data.estado !== "APROBADA" && data.estado !== "COMPLETADA") {
|
|
if (data.estado !== "APROBADA" && data.estado !== "COMPLETADA") {
|
|
|
setAccessDenied(true);
|
|
setAccessDenied(true);
|
|
|
setDenialReason("Esta cita no está aprobada");
|
|
setDenialReason("Esta cita no está aprobada");
|
|
|
|
|
+ setLoading(false);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Obtener JWT token para Jitsi
|
|
|
|
|
+ const tokenResponse = await fetch(`/api/appointments/${params.id}/jitsi-token`);
|
|
|
|
|
+ if (tokenResponse.ok) {
|
|
|
|
|
+ const tokenData = await tokenResponse.json();
|
|
|
|
|
+ setJitsiToken(tokenData.token || null);
|
|
|
|
|
+ setJitsiDomain(tokenData.domain || "meet.jit.si");
|
|
|
|
|
+ setJitsiRoomName(tokenData.roomName || `appointment-${params.id}`);
|
|
|
|
|
+ setUseJWT(tokenData.useJWT || false);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.warn("No se pudo obtener JWT token, usando configuración por defecto");
|
|
|
|
|
+ setJitsiRoomName(`appointment-${params.id}`);
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
setAccessDenied(true);
|
|
setAccessDenied(true);
|
|
@@ -108,13 +129,12 @@ export default function MeetPage() {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const initJitsi = useCallback(() => {
|
|
const initJitsi = useCallback(() => {
|
|
|
- if (!jitsiContainer.current || !session || isInitialized.current) return;
|
|
|
|
|
|
|
+ if (!jitsiContainer.current || !session || isInitialized.current || !jitsiRoomName) return;
|
|
|
|
|
|
|
|
isInitialized.current = true;
|
|
isInitialized.current = true;
|
|
|
|
|
|
|
|
- const domain = "meet.jit.si";
|
|
|
|
|
- const options = {
|
|
|
|
|
- roomName: `appointment-${params.id}`,
|
|
|
|
|
|
|
+ const options: Record<string, unknown> = {
|
|
|
|
|
+ roomName: jitsiRoomName,
|
|
|
width: "100%",
|
|
width: "100%",
|
|
|
height: 600,
|
|
height: 600,
|
|
|
parentNode: jitsiContainer.current,
|
|
parentNode: jitsiContainer.current,
|
|
@@ -142,12 +162,17 @@ export default function MeetPage() {
|
|
|
SHOW_WATERMARK_FOR_GUESTS: false,
|
|
SHOW_WATERMARK_FOR_GUESTS: false,
|
|
|
},
|
|
},
|
|
|
userInfo: {
|
|
userInfo: {
|
|
|
- displayName: session.user?.name || "Usuario",
|
|
|
|
|
|
|
+ displayName: `${session.user?.name || "Usuario"} ${session.user?.lastname || ""}`.trim(),
|
|
|
email: session.user?.email || undefined,
|
|
email: session.user?.email || undefined,
|
|
|
},
|
|
},
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- jitsiApi.current = new window.JitsiMeetExternalAPI(domain, options);
|
|
|
|
|
|
|
+ // Si se usa JWT, agregar el token
|
|
|
|
|
+ if (useJWT && jitsiToken) {
|
|
|
|
|
+ options.jwt = jitsiToken;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ jitsiApi.current = new window.JitsiMeetExternalAPI(jitsiDomain, options);
|
|
|
|
|
|
|
|
// Event listeners - Solo redirigir si el usuario salió desde Jitsi directamente
|
|
// Event listeners - Solo redirigir si el usuario salió desde Jitsi directamente
|
|
|
jitsiApi.current.addEventListener("videoConferenceLeft", () => {
|
|
jitsiApi.current.addEventListener("videoConferenceLeft", () => {
|
|
@@ -166,7 +191,7 @@ export default function MeetPage() {
|
|
|
}
|
|
}
|
|
|
}, 100);
|
|
}, 100);
|
|
|
});
|
|
});
|
|
|
- }, [session, params.id, router]);
|
|
|
|
|
|
|
+ }, [session, jitsiRoomName, jitsiDomain, jitsiToken, useJWT, router]);
|
|
|
|
|
|
|
|
const handleExitClick = () => {
|
|
const handleExitClick = () => {
|
|
|
setShowExitDialog(true);
|
|
setShowExitDialog(true);
|
|
@@ -205,11 +230,14 @@ export default function MeetPage() {
|
|
|
}, []);
|
|
}, []);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
- if (status === "loading" || !session || !jitsiContainer.current || isInitialized.current) return;
|
|
|
|
|
|
|
+ if (status === "loading" || !session || !jitsiContainer.current || isInitialized.current || !jitsiDomain || !jitsiRoomName) return;
|
|
|
|
|
+
|
|
|
|
|
+ // Construir la URL del script usando el dominio configurado
|
|
|
|
|
+ const scriptSrc = `https://${jitsiDomain}/external_api.js`;
|
|
|
|
|
|
|
|
// Verificar si el script ya está cargado
|
|
// Verificar si el script ya está cargado
|
|
|
- const existingScript = document.querySelector('script[src="https://meet.jit.si/external_api.js"]');
|
|
|
|
|
-
|
|
|
|
|
|
|
+ const existingScript = document.querySelector(`script[src="${scriptSrc}"]`);
|
|
|
|
|
+
|
|
|
if (existingScript) {
|
|
if (existingScript) {
|
|
|
// Si el script ya existe y window.JitsiMeetExternalAPI está disponible, inicializar directamente
|
|
// Si el script ya existe y window.JitsiMeetExternalAPI está disponible, inicializar directamente
|
|
|
if (window.JitsiMeetExternalAPI) {
|
|
if (window.JitsiMeetExternalAPI) {
|
|
@@ -218,11 +246,16 @@ export default function MeetPage() {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Cargar Jitsi script
|
|
|
|
|
|
|
+ // Cargar Jitsi script desde el dominio configurado
|
|
|
const script = document.createElement("script");
|
|
const script = document.createElement("script");
|
|
|
- script.src = "https://meet.jit.si/external_api.js";
|
|
|
|
|
|
|
+ script.src = scriptSrc;
|
|
|
script.async = true;
|
|
script.async = true;
|
|
|
script.onload = () => initJitsi();
|
|
script.onload = () => initJitsi();
|
|
|
|
|
+ script.onerror = () => {
|
|
|
|
|
+ console.error(`Error al cargar el script de Jitsi desde ${scriptSrc}`);
|
|
|
|
|
+ setAccessDenied(true);
|
|
|
|
|
+ setDenialReason("No se pudo conectar con el servidor de videollamadas");
|
|
|
|
|
+ };
|
|
|
document.body.appendChild(script);
|
|
document.body.appendChild(script);
|
|
|
|
|
|
|
|
return () => {
|
|
return () => {
|
|
@@ -233,7 +266,7 @@ export default function MeetPage() {
|
|
|
isInitialized.current = false;
|
|
isInitialized.current = false;
|
|
|
// No eliminar el script aquí para evitar conflictos
|
|
// No eliminar el script aquí para evitar conflictos
|
|
|
};
|
|
};
|
|
|
- }, [status, session, initJitsi]);
|
|
|
|
|
|
|
+ }, [status, session, jitsiDomain, jitsiRoomName, initJitsi]);
|
|
|
|
|
|
|
|
if (status === "loading" || loading) {
|
|
if (status === "loading" || loading) {
|
|
|
return (
|
|
return (
|