import React, { useState, useEffect } from 'react'; import { Monitor, Plus, Copy, Download, CheckCircle2, Loader2, Wifi, WifiOff, RefreshCw, Tag, Server, Save, KeyRound, Link2, AlertTriangle } from 'lucide-react'; import { HybridBackend } from '../services/backend.ts'; import { PageHeader } from '../components/PageHeader.tsx'; import { useToast } from '../contexts/ToastContext.tsx'; export const RxConfigView: React.FC = () => { const workspace = HybridBackend.getActiveWorkspace(); const currentRole = HybridBackend.getCurrentRole(); const isSuperadmin = currentRole === 'superadmin'; const { addToast } = useToast(); // Escopo da lista de dispositivos: superadmin vê tudo; clínica vê os seus. const clinicaId: string = workspace?.id || ''; const clinicName: string = workspace?.nome || workspace?.name || ''; const [devices, setDevices] = useState([]); const [loadingDevices, setLoadingDevices] = useState(true); const [newPcName, setNewPcName] = useState(''); const [newEmail, setNewEmail] = useState(''); const [newPassword, setNewPassword] = useState(''); const [creating, setCreating] = useState(false); const [newToken, setNewToken] = useState<{ token: string; pcName: string } | null>(null); const [copied, setCopied] = useState(false); const [rxVersion, setRxVersion] = useState<{ server: string; client: string; client_url: string } | null>(null); // Configuração GLOBAL de conexão (definida pelo superadmin). const [rxUrl, setRxUrl] = useState('https://rx.scoreodonto.com'); const [apiToken, setApiToken] = useState(''); const [hasToken, setHasToken] = useState(false); const [configured, setConfigured] = useState(false); const [savingCfg, setSavingCfg] = useState(false); const fetchDevices = async () => { setLoadingDevices(true); // Superadmin: todos os dispositivos; clínica: só os da sua clinicaId. const list = await HybridBackend.getRxDevices(isSuperadmin ? '' : clinicaId); setDevices(Array.isArray(list) ? list : []); setLoadingDevices(false); }; const fetchConfig = async () => { const cfg = await HybridBackend.getRxConfig(); if (!cfg) return; setRxUrl(cfg.rx_url || 'https://rx.scoreodonto.com'); setHasToken(!!cfg.has_token); setConfigured(!!cfg.configured); if (cfg.rx_url) { try { const res = await fetch(`${cfg.rx_url}/api/version`); if (res.ok) setRxVersion(await res.json()); } catch (_) {} } }; useEffect(() => { fetchConfig(); fetchDevices(); }, [clinicaId, isSuperadmin]); const handleSaveConfig = async (e: React.FormEvent) => { e.preventDefault(); if (!isSuperadmin) return; if (!rxUrl.trim() || (!apiToken.trim() && !hasToken)) { addToast('Informe a URL e o token de API do servidor RX.', 'error'); return; } setSavingCfg(true); const r = await HybridBackend.putRxConfig({ rx_url: rxUrl.trim(), ...(apiToken.trim() ? { api_token: apiToken.trim() } : {}), }); setSavingCfg(false); if (!r.success) { addToast(r.message || 'Erro ao salvar configuração.', 'error'); return; } setApiToken(''); setHasToken(true); setConfigured(!!r.configured); addToast('Configuração geral do RX salva.', 'success'); fetchConfig(); fetchDevices(); }; const handleCreate = async (e: React.FormEvent) => { e.preventDefault(); if (!newPcName.trim() || !clinicaId) return; if (!configured) { addToast('O RX ainda não foi configurado pelo superadmin.', 'error'); return; } setCreating(true); const result = await HybridBackend.createRxDevice(clinicaId, newPcName.trim(), { email: newEmail.trim() || undefined, password: newPassword.trim() || undefined, }); setCreating(false); if (!result.success) { addToast(result.message || 'Erro ao criar dispositivo.', 'error'); return; } setNewToken({ token: result.machine_token!, pcName: newPcName.trim() }); setNewPcName(''); setNewEmail(''); setNewPassword(''); fetchDevices(); }; const copyToken = (token: string) => { navigator.clipboard.writeText(token).then(() => { setCopied(true); addToast('Token copiado!', 'success'); setTimeout(() => setCopied(false), 2000); }); }; return (
{/* Configuração GERAL do servidor RX — só o superadmin edita */}

CONFIGURAÇÃO GERAL DO RX

{configured ? <> CONECTADO : <> NÃO CONFIGURADO}
{isSuperadmin ? (

Token estático da conta-mestre. Vale para todas as clínicas; o token não é exibido depois de salvo.

) : (

{configured ? 'O servidor RX está configurado pelo superadmin. Você já pode cadastrar PCs abaixo.' : 'Aguardando o superadmin configurar o servidor RX. Sem isso não é possível cadastrar PCs.'}

)}
{/* Token gerado */} {newToken && (

PC "{newToken.pcName}" CADASTRADO!

Cole este token no client Windows ao configurar. Ele só aparece uma vez.

{newToken.token}
)} {/* Download client */}

PC-RX CLIENT WINDOWS

{rxVersion?.client && ( v{rxVersion.client} )}

Instale no computador do consultório. Use o token gerado para configurar.

{rxVersion?.server && (

Servidor RX v{rxVersion.server}

)}
BAIXAR{rxVersion?.client ? ` v${rxVersion.client}` : ' CLIENT'}
{/* Adicionar novo PC — só para usuários de clínica (têm workspace) */} {!isSuperadmin && clinicaId && (

ADICIONAR PC

{!configured && (

O RX ainda não foi configurado pelo superadmin.

)}
setNewPcName(e.target.value)} placeholder="Nome do PC (ex: CONSULTÓRIO 1)" className="w-full px-4 py-2 border border-gray-300 rounded-lg text-sm font-medium focus:ring-2 focus:ring-teal-500 outline-none uppercase" />
setNewEmail(e.target.value)} placeholder="E-mail de contato (opcional)" autoComplete="off" className="w-full px-4 py-2 border border-gray-300 rounded-lg text-sm font-medium focus:ring-2 focus:ring-teal-500 outline-none" /> setNewPassword(e.target.value)} placeholder="Senha de acesso (opcional)" autoComplete="new-password" className="w-full px-4 py-2 border border-gray-300 rounded-lg text-sm font-medium focus:ring-2 focus:ring-teal-500 outline-none" />

Clínica: {clinicName || clinicaId}. E-mail/senha em branco usam um padrão por clínica.

)} {/* Lista de dispositivos */}

{isSuperadmin ? 'PCS DE TODAS AS CLÍNICAS' : 'PCS CADASTRADOS'} ({devices.length})

{loadingDevices ? (
) : devices.length === 0 ? (

Nenhum PC cadastrado ainda

) : (
{devices.map((d: any) => (
{d.is_active ? : }

{d.pc_name}

{isSuperadmin && d.clinic_name ? `Clínica: ${d.clinic_name} · ` : ''} {d.last_ip ? `Último acesso: ${d.last_ip}` : 'Nunca conectou'} · {d.is_active ? 'ATIVO' : 'INATIVO'}

{d.is_active ? 'ATIVO' : 'INATIVO'}
))}
)}
); };