import { useState, useEffect } from "react"; import { useAuth } from "../../_assets/utils/AuthProvider"; import API_KEY from "../../_assets/utils/apiKeys"; import { GetDoctorByName } from '../../_assets/utils/Functions-Endpoints/Doctor'; import "../../_assets/css/components/agendamento/FormAgendamento.css"; const ENDPOINT_CRIAR_EXCECAO = "https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctor_exceptions"; const FormCriarExcecao = ({ onCancel, doctorID }) => { const { getAuthorizationHeader, user, getUserInfo } = useAuth(); // mantemos apenas os campos realmente necessários no formulário; // profissional (id) e created_by serão preenchidos automaticamente a partir do usuário logado const [dadosAtendimento, setDadosAtendimento] = useState({ profissional: doctorID || '', tipoAtendimento: '', dataAtendimento: '', inicio: '', termino: '', motivo: '' }); const handleAtendimentoChange = (e) => { const { value, name } = e.target; setDadosAtendimento(prev => ({ ...prev, [name]: value })); }; // preencher automaticamente o id do profissional (doctor_id) vindo do user/prop useEffect(() => { const resolvedDoctorId = doctorID || user?.doctor_id || user?.id || ''; setDadosAtendimento(prev => ({ ...prev, profissional: prev.profissional || resolvedDoctorId })); }, [doctorID, user]); const ALLOWED_KINDS = ['disponibilidade_extra', 'bloqueio']; // helper: normalize and validate Authorization header -> "Bearer " const resolveAuthHeader = () => { try { const maybe = getAuthorizationHeader ? getAuthorizationHeader() : null; console.log('[DEBUG] getAuthorizationHeader() ->', maybe); let raw = null; if (!maybe) { // fallback localStorage try { const stored = localStorage.getItem('user') || localStorage.getItem('auth') || null; if (stored) { const parsed = JSON.parse(stored); raw = parsed?.access_token || parsed?.token || parsed?.auth?.access_token || null; } } catch (e) { console.warn('[DEBUG] parse localStorage failed', e); } } else if (typeof maybe === 'string') { raw = maybe; } else if (typeof maybe === 'object') { raw = maybe.Authorization || maybe.authorization || maybe.access_token || maybe.token || null; } if (!raw) return null; // remove any leading "bearer " (case-insensitive) and possible duplicated prefixes raw = String(raw).trim().replace(/^(?:bearer\s*)+/i, ''); console.log('[DEBUG] resolved raw token ->', raw); // basic JWT structure check if (typeof raw !== 'string' || raw.split('.').length !== 3) { console.error('[DEBUG] token not a JWT:', raw); return null; } return `Bearer ${raw}`; } catch (err) { console.warn('resolveAuthHeader error', err); return null; } }; const getUidFromAuthHeader = (authHeader) => { try { if (!authHeader) return null; const token = String(authHeader).replace(/Bearer\s+/i, '').trim(); if (!token || token.split('.').length !== 3) return null; // decode base64url payload const payloadBase64 = token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/'); const padded = payloadBase64 + '='.repeat((4 - (payloadBase64.length % 4)) % 4); const json = atob(padded); const payload = JSON.parse(json); return payload.sub || payload.user_id || payload.uid || payload.id || null; } catch (err) { console.warn('Não foi possível decodificar JWT para obter uid:', err); return null; } }; const handleSubmitExcecao = async (e) => { e.preventDefault(); console.log('[DEBUG] submit dadosAtendimento ->', dadosAtendimento); const authHeader = resolveAuthHeader(); console.log('[DEBUG] authHeader to send ->', authHeader); if (!authHeader) { alert('Sessão inválida ou token ausente / inválido. Faça logout e login novamente.'); return; } let { profissional, dataAtendimento, tipoAtendimento, inicio, termino, motivo } = dadosAtendimento; // tenta resolver profissional automaticamente se ainda não definido profissional = profissional || doctorID || user?.doctor_id || user?.id || null; // extrai uid do token (se policy do Supabase exigir auth.uid()) const authUid = getUidFromAuthHeader(authHeader) || user?.id || null; // se a policy exige que doctor_id seja igual ao auth.uid(), force o valor aqui if (authUid && !profissional) { profissional = authUid; setDadosAtendimento(prev => ({ ...prev, profissional })); } // created_by também deve refletir o uid do usuário autenticado (se policy exigir) let createdBy = authUid || user?.id || null; if (!profissional || !dataAtendimento || !tipoAtendimento || !motivo) { alert("Por favor, verifique: médico, data, tipo e motivo são obrigatórios."); return; } const mappedKind = tipoAtendimento; if (!ALLOWED_KINDS.includes(mappedKind)) { alert(`Tipo inválido: "${tipoAtendimento}". Tipos aceitos: ${ALLOWED_KINDS.join(', ')}`); return; } const startTime = inicio ? inicio + ":00" : null; const endTime = termino ? termino + ":00" : null; const payload = { doctor_id: profissional, date: dataAtendimento, kind: mappedKind, start_time: startTime, end_time: endTime, reason: motivo, created_by: createdBy }; // monta headers do POST usando authHeader já normalizado const myHeaders = new Headers(); myHeaders.append('Content-Type', 'application/json'); myHeaders.append('Authorization', authHeader); if (API_KEY) myHeaders.append('apikey', API_KEY); // envia try { const response = await fetch(ENDPOINT_CRIAR_EXCECAO, { method: 'POST', headers: myHeaders, body: JSON.stringify(payload), redirect: 'follow' }); const text = await response.text(); let result; try { result = JSON.parse(text); } catch { result = { message: text }; } if (response.ok || response.status === 201) { alert(`Exceção criada com sucesso.`); onCancel(true); } else { console.error("Erro ao criar exceção:", result); alert(`Erro ao criar exceção. Status: ${response.status}. ${result.message || ''}`); } } catch (error) { console.error("Erro na requisição para criar exceção:", error); alert("Erro de comunicação com o servidor."); } }; // exibimos informações do médico logado de forma somente leitura (preenchidas automaticamente) const [displayDoctorName, setDisplayDoctorName] = useState(user?.full_name || user?.name || ''); const displayDoctorId = doctorID || user?.doctor_id || user?.id || ''; // preenche dados do médico usando a função de informações do usuário (UserInfos / getUserInfo) useEffect(() => { let cancelled = false; const resolvedDoctorId = doctorID || user?.doctor_id || user?.id || null; const userName = user?.full_name || user?.name || user?.username || ''; const tryFillFromUserInfo = async () => { try { // primeiro, tenta usar getUserInfo() se disponível let info = null; if (typeof getUserInfo === 'function') { try { // se getUserInfo precisa de header, passe-o; caso contrário, a função interna deve usar auth const authHeader = resolveAuthHeader(); // se getUserInfo aceita header, você pode adaptar; aqui tentamos chamar sem args info = await getUserInfo(); } catch (e) { // fallback: sem info } } // se não veio info, use user const profile = info || user || {}; const profileId = profile.doctor_id || profile.id || resolvedDoctorId; const profileName = profile.full_name || profile.name || userName; if (!cancelled && profileName) setDisplayDoctorName(profileName); if (!cancelled && profileId) { setDadosAtendimento(prev => ({ ...prev, profissional: prev.profissional || profileId })); return; } // fallback: tentar buscar por nome via endpoint de médicos (usa auth header normalizado) if (userName) { const authHeader = resolveAuthHeader(); if (!authHeader) { console.warn('No auth header available for GetDoctorByName lookup'); } else { const doctor = await GetDoctorByName(userName, authHeader); if (!cancelled && doctor) { setDisplayDoctorName(doctor.full_name || doctor.name || userName); setDadosAtendimento(prev => ({ ...prev, profissional: doctor.id || doctor.doctor_id || prev.profissional })); return; } } } // último fallback if (!cancelled) { setDisplayDoctorName(userName || ''); if (resolvedDoctorId) setDadosAtendimento(prev => ({ ...prev, profissional: prev.profissional || resolvedDoctorId })); } } catch (err) { if (cancelled) return; console.warn('Erro ao preencher dados do médico via UserInfos/getUserInfo:', err); setDisplayDoctorName(userName || ''); if (resolvedDoctorId) setDadosAtendimento(prev => ({ ...prev, profissional: prev.profissional || resolvedDoctorId })); } }; tryFillFromUserInfo(); return () => { cancelled = true; }; }, [doctorID, user, getUserInfo, getAuthorizationHeader]); return (

Informações da Nova Exceção

{/* Médico agora não é editável/visível — dados preenchidos automaticamente */}
); }; export default FormCriarExcecao;