feat(equipe): conectar Google Agenda do funcionário no painel de Equipe
- botão Conectar (GoogleConnectButton, ownerId=userId do membro) no modal de edição do membro - status de conexão por membro via /api/auth/google/status - conexão 'na hora' (quem tem a senha do Gmail autoriza); sem auto-conexão na área do funcionário Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ import { Users, Building, Briefcase, Plus, Trash2, Edit2, X, Check, UserPlus, Sh
|
||||
import { HybridBackend } from '../services/backend.ts';
|
||||
import { useToast } from '../contexts/ToastContext.tsx';
|
||||
import { PageHeader } from '../components/PageHeader.tsx';
|
||||
import { GoogleConnectButton } from '../components/GoogleConnectButton.tsx';
|
||||
|
||||
type Tab = 'usuarios' | 'setores' | 'funcoes';
|
||||
|
||||
@@ -149,6 +150,17 @@ const UsuariosTab: React.FC<{ clinicaId: string; isOwner: boolean; myNivel: numb
|
||||
|
||||
useEffect(() => { load(); }, [load]);
|
||||
|
||||
// Status do Google da clínica (qual membro tem o calendário conectado).
|
||||
const [googleAccounts, setGoogleAccounts] = useState<any[]>([]);
|
||||
const loadGoogleStatus = useCallback(async () => {
|
||||
try {
|
||||
const r = await fetch(`/api/auth/google/status?clinicaId=${clinicaId}`);
|
||||
const d = await r.json();
|
||||
setGoogleAccounts(Array.isArray(d) ? d : []);
|
||||
} catch { /* ignore */ }
|
||||
}, [clinicaId]);
|
||||
useEffect(() => { loadGoogleStatus(); }, [loadGoogleStatus]);
|
||||
|
||||
const handleAdd = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setSaving(true);
|
||||
@@ -376,6 +388,21 @@ const UsuariosTab: React.FC<{ clinicaId: string; isOwner: boolean; myNivel: numb
|
||||
{funcoes.filter(f => isOwner || (typeof f.nivel === 'number' ? f.nivel : 1) < myNivel).map(f => <option key={f.id} value={f.id}>{f.nome}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{/* Google Agenda do funcionário — conectado AQUI (quem tem a senha do Gmail autoriza na hora). */}
|
||||
<div className="border-t border-gray-100 pt-4">
|
||||
<label className="text-[10px] font-black text-gray-500 uppercase block mb-1">GOOGLE AGENDA DESTE FUNCIONÁRIO</label>
|
||||
<p className="text-[10px] text-gray-400 mb-2 leading-snug">
|
||||
Conecta o calendário do Gmail desta pessoa: os agendamentos viram cópia de backup e o paciente recebe convite + lembretes. Autorize com a conta dela (precisa da senha do Gmail).
|
||||
</p>
|
||||
<GoogleConnectButton
|
||||
ownerId={editing.id}
|
||||
clinicaId={clinicaId}
|
||||
isConnected={googleAccounts.some(a => a.owner_id === editing.id)}
|
||||
onStatusChange={loadGoogleStatus}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-3 pt-2">
|
||||
<button onClick={() => setEditing(null)}
|
||||
className="flex-1 py-2.5 border border-gray-200 rounded-xl text-[11px] font-black uppercase hover:bg-gray-50 transition-colors">
|
||||
|
||||
Reference in New Issue
Block a user