diff --git a/src/features/documents/components/DocumentSignatureDialog.vue b/src/features/documents/components/DocumentSignatureDialog.vue index 1383638..430c5ee 100644 --- a/src/features/documents/components/DocumentSignatureDialog.vue +++ b/src/features/documents/components/DocumentSignatureDialog.vue @@ -17,6 +17,7 @@ import { listSignatures, getSignatureStatus } from '@/services/DocumentSignatures.service' +import { createShareLink, buildShareUrl } from '@/services/DocumentShareLinks.service' const props = defineProps({ visible: { type: Boolean, default: false }, @@ -42,6 +43,11 @@ const TIPOS_SIGNATARIO = [ const signatarios = ref([]) const patientEmails = ref([]) +// Geracao de share link p/ assinatura via portal/whatsapp +const generateLink = ref(true) +const linkExpiracaoHoras = ref(168) // 7 dias default +const generatedShareUrl = ref('') + function addSignatario() { signatarios.value.push({ tipo: 'paciente', nome: '', email: '' }) } @@ -81,6 +87,7 @@ function useEmail(email) { watch(() => props.visible, async (v) => { if (v && props.doc) { signatarios.value = [] + generatedShareUrl.value = '' loading.value = true try { const [sigs, status] = await Promise.all([ @@ -99,6 +106,13 @@ watch(() => props.visible, async (v) => { } }) +function copyShareUrl() { + if (!generatedShareUrl.value) return + navigator.clipboard.writeText(generatedShareUrl.value) + .then(() => toast.add({ severity: 'success', summary: 'Link copiado', life: 1800 })) + .catch(() => toast.add({ severity: 'warn', summary: 'Falha ao copiar', detail: 'Copie manualmente.', life: 2200 })) +} + // ── Status badge ──────────────────────────────────────────── const statusColor = computed(() => { @@ -146,9 +160,39 @@ async function submit() { saving.value = true try { const result = await createSignatureRequests(props.doc.id, signatarios.value) - toast.add({ severity: 'success', summary: 'Solicitação enviada', detail: `${result.length} signatário(s) adicionado(s).`, life: 3000 }) - emit('requested', result) - emit('update:visible', false) + + // Gera share link público quando habilitado — o paciente abre /shared/document/:token + // e assina via fluxo público (RPC sign_document_by_token captura IP/UA server-side). + if (generateLink.value) { + try { + const link = await createShareLink(props.doc.id, { + expiracaoHoras: Number(linkExpiracaoHoras.value) || 168, + usosMax: Math.max(signatarios.value.length * 3, 5) + }) + generatedShareUrl.value = buildShareUrl(link.token) + toast.add({ + severity: 'success', + summary: 'Solicitação criada', + detail: `${result.length} signatário(s). Link de assinatura gerado.`, + life: 3500 + }) + } catch (linkErr) { + toast.add({ + severity: 'warn', + summary: 'Signatários criados, mas falhou o link', + detail: linkErr?.message || 'Tente gerar o link na ação "Compartilhar".', + life: 4500 + }) + } + } else { + toast.add({ severity: 'success', summary: 'Solicitação enviada', detail: `${result.length} signatário(s) adicionado(s).`, life: 3000 }) + } + + emit('requested', { signatures: result, shareUrl: generatedShareUrl.value }) + + // Mantém dialog aberto se gerou link — pra terapeuta copiar. + // Fecha automaticamente se não gerou link. + if (!generatedShareUrl.value) emit('update:visible', false) } catch (e) { toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Falha ao solicitar assinatura.' }) } finally { @@ -263,6 +307,49 @@ function close() { + +
+ +
+ +
+ Cria um link em /shared/document/<token> pra enviar via WhatsApp, e-mail ou copiar. O paciente assina sem precisar logar (IP, navegador e timestamp são registrados server-side). +
+
+ +