fix(agenda): fuso automático (America/Sao_Paulo) + dentista configura seus horários
- TZ=America/Sao_Paulo no backend (compose): a agenda deixa de rodar em UTC — horários/slots passam a ser Brasília automaticamente (corrige deslocamento de 3h). - Acesso do DENTISTA: novo botão "Meus Horários" na agenda do dentista, abrindo a config direto nos horários/folgas DELE (HorariosConfig com initialTab/soDentista, restrito ao próprio registro). Antes só admin/donoclinica alcançavam a config. - Config da clínica: gate passa a incluir donoconsultorio (dono de consultório). Obs.: AgendaView.tsx também traz trabalho acumulado da agenda que estava no working tree. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -62,8 +62,9 @@ const GradeSemanal: React.FC<{ faixas: Faixa[]; onChange: (f: Faixa[]) => void;
|
||||
);
|
||||
};
|
||||
|
||||
export const HorariosConfig: React.FC<{ isOpen: boolean; onClose: () => void; clinicaId?: string }> = ({ isOpen, onClose, clinicaId }) => {
|
||||
const [aba, setAba] = useState<'clinica' | 'dentistas'>('clinica');
|
||||
export const HorariosConfig: React.FC<{ isOpen: boolean; onClose: () => void; clinicaId?: string; initialTab?: 'clinica' | 'dentistas'; soDentista?: boolean }> = ({ isOpen, onClose, clinicaId, initialTab, soDentista }) => {
|
||||
const [aba, setAba] = useState<'clinica' | 'dentistas'>(initialTab || 'clinica');
|
||||
useEffect(() => { if (isOpen && initialTab) setAba(initialTab); }, [isOpen, initialTab]);
|
||||
const [erro, setErro] = useState<string | null>(null);
|
||||
const [ok, setOk] = useState<string | null>(null);
|
||||
const [saving, setSaving] = useState(false);
|
||||
@@ -96,11 +97,13 @@ export const HorariosConfig: React.FC<{ isOpen: boolean; onClose: () => void; cl
|
||||
if (!clinicaId) return;
|
||||
try {
|
||||
const d = await req(`/clinica/${clinicaId}/dentistas`);
|
||||
setDentistas(d.dentistas || []);
|
||||
const first = (d.dentistas || []).find((x: Dentista) => x.eh_voce) || (d.dentistas || [])[0];
|
||||
let list: Dentista[] = d.dentistas || [];
|
||||
if (soDentista) { const meus = list.filter((x) => x.eh_voce); if (meus.length) list = meus; } // dentista só vê o próprio
|
||||
setDentistas(list);
|
||||
const first = list.find((x: Dentista) => x.eh_voce) || list[0];
|
||||
if (first) setDentSel(first.id);
|
||||
} catch (e: any) { flash(setErro, e.message); }
|
||||
}, [clinicaId]);
|
||||
}, [clinicaId, soDentista]);
|
||||
|
||||
useEffect(() => { if (isOpen) { carregarClinica(); carregarDentistas(); } }, [isOpen, carregarClinica, carregarDentistas]);
|
||||
const carregarFolgas = useCallback((id: string) => {
|
||||
@@ -162,7 +165,7 @@ export const HorariosConfig: React.FC<{ isOpen: boolean; onClose: () => void; cl
|
||||
|
||||
{/* Tabs */}
|
||||
<div className="flex gap-1 px-8 pt-4 border-b border-gray-50">
|
||||
{(['clinica', 'dentistas'] as const).map((t) => (
|
||||
{(soDentista ? (['dentistas'] as const) : (['clinica', 'dentistas'] as const)).map((t) => (
|
||||
<button key={t} onClick={() => setAba(t)}
|
||||
className={`px-4 py-2.5 text-xs font-black uppercase tracking-wide rounded-t-xl transition-colors ${aba === t ? 'bg-teal-600 text-white' : 'text-gray-400 hover:text-gray-600'}`}>
|
||||
{t === 'clinica' ? 'Clínica' : 'Dentistas'}
|
||||
|
||||
Reference in New Issue
Block a user