@fayz-ai/plugin-forms 0.15.14 → 0.15.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CustomFormsSettingsTab-EI4WKOYR.js +314 -0
- package/dist/CustomFormsSettingsTab-EI4WKOYR.js.map +1 -0
- package/dist/{FormBuilder-Q2Q42HAT.js → FormBuilder-7UXCXUOF.js} +7 -3
- package/dist/FormBuilder-7UXCXUOF.js.map +1 -0
- package/dist/PersonAnswerAlerts-MDBBY63K.js +98 -0
- package/dist/PersonAnswerAlerts-MDBBY63K.js.map +1 -0
- package/dist/PersonDocumentsWidget-RGN4UHS3.js +977 -0
- package/dist/PersonDocumentsWidget-RGN4UHS3.js.map +1 -0
- package/dist/chunk-5WW6FTNG.js +113 -0
- package/dist/chunk-5WW6FTNG.js.map +1 -0
- package/dist/chunk-66C3L4RE.js +17 -0
- package/dist/chunk-66C3L4RE.js.map +1 -0
- package/dist/chunk-BFXJLPKA.js +55 -0
- package/dist/chunk-BFXJLPKA.js.map +1 -0
- package/dist/chunk-RB7UYZLA.js +824 -0
- package/dist/chunk-RB7UYZLA.js.map +1 -0
- package/dist/chunk-X6CU44B4.js +223 -0
- package/dist/chunk-X6CU44B4.js.map +1 -0
- package/dist/chunk-YOFFKQD4.js +584 -0
- package/dist/chunk-YOFFKQD4.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +58 -1507
- package/dist/index.js.map +1 -1
- package/dist/views/CustomFormsSettingsTab.d.ts.map +1 -1
- package/package.json +5 -5
- package/dist/FormBuilder-Q2Q42HAT.js.map +0 -1
- package/dist/chunk-JRR7A5HN.js +0 -1678
- package/dist/chunk-JRR7A5HN.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/DocumentPreview.tsx","../src/components/DocumentList.tsx","../src/components/DocumentSkeleton.tsx","../src/components/DocumentFormDialog.tsx","../src/components/FormViewer.tsx","../src/components/AddDocumentDropdown.tsx","../src/components/PersonDocumentsWidget.tsx"],"names":["useTranslation","useState","useEffect","jsx","jsxs","Button","React","useCallback","ArrowLeft","useRef","useMemo","useLimitGuard","invalidateLimit","ImageIcon","Paperclip","Badge"],"mappings":"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","file":"PersonDocumentsWidget-RGN4UHS3.js","sourcesContent":["import React, { useEffect, useState } from 'react'\nimport { useTranslation } from '@fayz-ai/core'\nimport { Button } from '@fayz-ai/ui'\nimport type { FormsDataProvider } from '@fayz-ai/forms/data/provider'\nimport type { FormDocument } from '@fayz-ai/forms/domain/document'\nimport type { FormFieldDef, FormTemplate, MediaValue, RecommendationLine } from '@fayz-ai/forms/domain/template'\nimport { htmlToPlainText } from '../lib/plain-text'\nimport { isMedia } from './fields/media'\nimport { yesNoAnswer } from './fields/fields'\n\n// ---------------------------------------------------------------------------\n// O CONTEÚDO DO REGISTRO, DENTRO DA LINHA DO TEMPO.\n//\n// Uma evolução tem três linhas. Abrir uma tela inteira, ler três linhas e\n// voltar é a viagem que o olhinho existe para não cobrar — e numa consulta de\n// retorno o profissional lê as últimas três evoluções em sequência, o que pelo\n// caminho antigo eram seis navegações.\n//\n// PREVIEW, e não o formulário: só o que foi RESPONDIDO aparece, em pares\n// rótulo/valor. Campo em branco não entra — num molde de quarenta campos com\n// seis preenchidos, mostrar os trinta e quatro vazios esconde os seis.\n// ---------------------------------------------------------------------------\n\n/** Quantos pares cabem antes de a \"prévia\" virar a tela inteira. */\nconst MAX_FIELDS = 8\n/** Um texto longo vira resumo: o corpo inteiro no cartão empurra o próximo\n * registro para fora da tela, que é o oposto de ler em sequência. */\nconst MAX_CHARS = 280\n\nfunction isEmpty(value: unknown): boolean {\n if (value == null) return true\n if (typeof value === 'string') return value.trim() === ''\n if (Array.isArray(value)) return value.length === 0\n return false\n}\n\n/** O valor como texto. Marcação vinda de molde importado é decodificada pelo\n * mesmo caminho do placeholder (ver lib/plain-text). */\nfunction asText(value: unknown): string {\n if (Array.isArray(value)) return value.map((v) => String(v)).join(', ')\n if (typeof value === 'boolean') return value ? 'Sim' : 'Não'\n return htmlToPlainText(String(value)) ?? String(value)\n}\n\n/** Photos and signatures are paths in a private bucket: sign them with the provider we were given. */\nfunction PreviewMedia({ items, provider }: { items: MediaValue[]; provider: FormsDataProvider }) {\n const [urls, setUrls] = useState<Array<string | null>>([])\n useEffect(() => {\n let alive = true\n Promise.all(items.map((m) => Promise.resolve(provider.mediaUrl?.(m.path) ?? null).catch(() => null)))\n .then((u) => { if (alive) setUrls(u) })\n return () => { alive = false }\n // Keyed on the paths: `items` is rebuilt every render.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [items.map((m) => m.path).join('|'), provider])\n return (\n <div className=\"flex flex-wrap gap-2 pt-1\">\n {items.map((m, i) => (urls[i]\n ? m.type === 'video'\n ? <video key={m.path} src={urls[i]!} className=\"h-20 w-20 rounded-md border object-cover\" preload=\"metadata\" />\n : <img key={m.path} src={urls[i]!} alt=\"\" className={`h-20 rounded-md border object-cover ${m.type === 'signature' ? 'bg-white' : 'w-16'}`} />\n : <div key={m.path} className=\"h-20 w-16 animate-pulse rounded-md bg-muted\" />))}\n </div>\n )\n}\n\nfunction mediaOf(field: FormFieldDef, value: unknown): MediaValue[] | null {\n if (field.type === 'stencil_photo' || field.type === 'signature') return isMedia(value) ? [value] : null\n if (field.type === 'gallery') return Array.isArray(value) ? (value as MediaValue[]).filter(isMedia) : null\n return null\n}\n\nfunction fieldText(field: FormFieldDef, value: unknown): string {\n if (field.type === 'yes_no' || field.type === 'yes_no_text') {\n const a = yesNoAnswer(value)\n const extra = value && typeof value === 'object' ? (value as { text?: string }).text?.trim() : ''\n return `${a === 'sim' ? 'Sim' : a === 'nao' ? 'Não' : ''}${extra ? ` — ${extra}` : ''}`\n }\n if (field.type === 'recommendation' && Array.isArray(value)) {\n return (value as RecommendationLine[]).map((l) => `${l.quantity > 1 ? `${l.quantity}× ` : ''}${l.name}`).join(' · ')\n }\n return asText(value)\n}\n\nfunction truncate(text: string): string {\n return text.length > MAX_CHARS ? `${text.slice(0, MAX_CHARS).trimEnd()}…` : text\n}\n\nexport function DocumentPreview({\n document: doc,\n provider,\n onOpen,\n}: {\n document: FormDocument\n provider: FormsDataProvider\n /** \"Ver tudo\" quando a prévia cortou. */\n onOpen: () => void\n}) {\n const t = useTranslation()\n const [template, setTemplate] = useState<FormTemplate | null>(null)\n const [loading, setLoading] = useState(true)\n\n // O molde diz o RÓTULO e a ORDEM. Sem ele o `data` é um objeto de ids\n // (`{f_3: \"sim\"}`) — dado, não leitura.\n useEffect(() => {\n let alive = true\n if (!doc.templateId) { setLoading(false); return }\n void provider.getTemplateById(doc.templateId)\n .then((found) => { if (alive) { setTemplate(found); setLoading(false) } })\n .catch(() => { if (alive) setLoading(false) })\n return () => { alive = false }\n }, [doc.templateId, provider])\n\n // Arquivo não tem corpo de formulário: a imagem É o conteúdo.\n if (doc.kind === 'image' && doc.fileUrl) {\n return (\n <img\n src={doc.fileUrl}\n alt={doc.fileName ?? ''}\n className=\"max-h-64 rounded-lg object-contain\"\n />\n )\n }\n if (doc.kind === 'attachment') {\n return (\n <p className=\"text-xs text-muted-foreground\">\n {doc.fileName ?? t('customForms.documentFallbackTitle')}\n {doc.fileSize ? ` · ${(doc.fileSize / 1024).toFixed(1)} KB` : ''}\n </p>\n )\n }\n\n if (loading) {\n return (\n <div className=\"space-y-2\">\n <div className=\"h-3 w-1/3 animate-pulse rounded bg-muted\" />\n <div className=\"h-3 w-2/3 animate-pulse rounded bg-muted\" />\n </div>\n )\n }\n\n const fields = template?.schema?.fields ?? []\n const answered = fields\n .filter((f) => f.type !== 'title' && !isEmpty(doc.data?.[f.id]))\n .sort((a, b) => a.row - b.row || a.col - b.col)\n\n if (answered.length === 0) {\n return <p className=\"text-xs text-muted-foreground\">{t('customForms.previewEmpty')}</p>\n }\n\n const shown = answered.slice(0, MAX_FIELDS)\n const hidden = answered.length - shown.length\n\n return (\n <div className=\"space-y-2\">\n <dl className=\"grid gap-x-6 gap-y-2 sm:grid-cols-2\">\n {shown.map((field) => {\n const media = mediaOf(field, doc.data[field.id])\n const text = media ? '' : truncate(fieldText(field, doc.data[field.id]))\n // Uma evolução é um parágrafo, e meia largura a quebrava a cada seis\n // palavras — coluna de jornal onde devia haver prosa. Campo de texto\n // longo ocupa a linha inteira; o que é curto (data, sim/não, peso)\n // continua lado a lado, que é o que faz a grade valer a pena.\n const wide = field.type === 'memo' || field.type === 'richtext' || field.type === 'gallery' || text.length > 60\n return (\n <div key={field.id} className={`min-w-0 ${wide ? 'sm:col-span-2' : ''}`}>\n <dt className=\"text-[10px] uppercase tracking-wide text-muted-foreground\">\n {htmlToPlainText(field.label) ?? field.label}\n </dt>\n <dd className=\"whitespace-pre-wrap text-sm leading-6 text-foreground\">\n {media ? <PreviewMedia items={media} provider={provider} /> : text}\n </dd>\n </div>\n )\n })}\n </dl>\n {/* O que ficou de fora é dito, não escondido: uma prévia que corta em\n silêncio faz o leitor achar que leu o registro inteiro. */}\n {hidden > 0 && (\n <Button variant=\"bare\" size=\"bare\"\n type=\"button\"\n onClick={onOpen}\n className=\"text-xs font-medium text-primary hover:underline\"\n >\n {t('customForms.previewMore', { count: String(hidden) })}\n </Button>\n )}\n </div>\n )\n}\n","import React, { useEffect, useState, useCallback, useRef, useMemo } from 'react'\nimport { Archive, Eye, EyeOff, Upload, Paperclip, ClipboardList } from 'lucide-react'\nimport { Button, ConfirmDialog } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport type { FormsDataProvider } from '@fayz-ai/forms/data/provider'\nimport type { FormsStore } from '@fayz-ai/forms/store'\nimport { TimelineList, invalidateTabCounts } from '@fayz-ai/admin'\nimport type { TimelineItem } from '@fayz-ai/admin'\nimport type { FormDocument, DocumentCounts, DocumentStatus } from '@fayz-ai/forms/domain/document'\nimport type { TemplateCategory } from '@fayz-ai/forms/domain/template'\nimport { DocumentPreview } from './DocumentPreview'\nimport {\n CATEGORY_ORDER, categoryLabel, bucketOf, documentToTimelineItem,\n type DocumentBucket as Bucket,\n} from '../lib/categories'\n\ninterface DocumentListProps {\n personId: string\n provider: FormsDataProvider\n store: FormsStore\n onView: (doc: FormDocument) => void\n onFileDrop?: (files: File[]) => void\n /** Restringe a lista a estes tipos de `public.documents`. Ausente = tudo.\n * É o que separa o Prontuário (só `form`) dos Arquivos (imagem e anexo). */\n kinds?: string[]\n}\n\n/** O que a ficha mostra. `archived` fica de fora — arquivar é tirar da aba, não\n * apagar (ver `handleArchive`). */\nconst ACTIVE_STATUSES: DocumentStatus[] = ['draft', 'completed', 'signed']\n\nconst EXPAND_KEY = 'fayz.forms.documents.expandAll'\n\nexport function DocumentList({ personId, provider, store, onView, onFileDrop, kinds }: DocumentListProps) {\n // Arrastar arquivo é da aba de ARQUIVOS. No prontuário a moldura tracejada\n // convidava para um gesto cujo resultado ia parar na outra aba — e a\n // separação existe justamente para isso não acontecer.\n const acceptsFiles = Boolean(onFileDrop) && (!kinds || kinds.includes('attachment'))\n const t = useTranslation()\n const [documents, setDocuments] = useState<FormDocument[]>([])\n const [total, setTotal] = useState(0)\n const [page, setPage] = useState(1)\n const [loading, setLoading] = useState(true)\n const [loadingMore, setLoadingMore] = useState(false)\n const [counts, setCounts] = useState<DocumentCounts>({})\n const [bucket, setBucket] = useState<Bucket | undefined>(undefined)\n const [isDragOver, setIsDragOver] = useState(false)\n /**\n * O OLHINHO: ler sem clicar.\n *\n * Ligado, todo cartão abre o conteúdo do registro no lugar — é como se lê uma\n * evolução, que tem três linhas e não paga a viagem de ida e volta a uma tela\n * inteira. Desligado é a lista densa, para procurar.\n *\n * Preferência de quem está lendo, guardada na máquina dele: o psicólogo que\n * lê sempre não quer religar isso em cada paciente. Em aba anônima, onde o\n * acesso estoura, a lista simplesmente abre densa.\n */\n const [expandAll, setExpandAll] = useState(() => {\n try { return localStorage.getItem(EXPAND_KEY) === '1' } catch { return false }\n })\n const toggleExpandAll = useCallback(() => {\n setExpandAll((prev) => {\n try { localStorage.setItem(EXPAND_KEY, prev ? '0' : '1') } catch { /* sem storage, vale só esta sessão */ }\n return !prev\n })\n }, [])\n /** Abertos à mão, por cima do olhinho geral. */\n const [openIds, setOpenIds] = useState<Set<string>>(new Set())\n const dragCounter = useRef(0)\n\n /**\n * Quanto cabe numa leitura antes de \"Carregar mais\".\n *\n * Vinte e não os cinquenta que o provider assume por padrão: o cartão do\n * prontuário é alto (título, data, e o conteúdo quando aberto), e cinquenta\n * deles são cinco telas de rolagem antes do primeiro respiro.\n */\n const PAGE_SIZE = 20\n\n // O filtro vai para a CONSULTA, não para o resultado. Filtrar o que voltou\n // fazia a aba de arquivos de quem tem 110 registros e 3 fotos trazer 50\n // linhas de formulário e mostrar zero foto.\n const queryFor = useCallback((nextPage: number) => ({\n personId,\n kinds,\n templateCategory: bucket && bucket !== 'file' ? bucket : undefined,\n ...(bucket === 'file' ? { kinds: ['image', 'attachment'] } : {}),\n status: ACTIVE_STATUSES,\n page: nextPage,\n pageSize: PAGE_SIZE,\n }), [personId, kinds, bucket])\n\n const fetchDocs = useCallback(async () => {\n setLoading(true)\n try {\n const result = await provider.getDocuments(queryFor(1))\n setDocuments(result.data)\n setTotal(result.total)\n setPage(1)\n } finally {\n setLoading(false)\n }\n }, [provider, queryFor])\n\n /** Os totais REAIS, que a página não sabe: 110 registros com 20 carregados. */\n const fetchCounts = useCallback(async () => {\n try {\n setCounts(await provider.getDocumentCounts({ personId, kinds }))\n } catch {\n setCounts({})\n }\n }, [provider, personId, kinds])\n\n const loadMore = useCallback(async () => {\n setLoadingMore(true)\n try {\n const next = page + 1\n const result = await provider.getDocuments(queryFor(next))\n // Concatena por id: uma gravação entre duas páginas desloca a janela e\n // devolveria a mesma linha duas vezes.\n setDocuments((prev) => {\n const seen = new Set(prev.map((d) => d.id))\n return [...prev, ...result.data.filter((d) => !seen.has(d.id))]\n })\n setTotal(result.total)\n setPage(next)\n } finally {\n setLoadingMore(false)\n }\n }, [provider, queryFor, page])\n\n useEffect(() => {\n const timer = setTimeout(() => fetchDocs(), 50)\n return () => clearTimeout(timer)\n }, [fetchDocs])\n\n useEffect(() => { void fetchCounts() }, [fetchCounts])\n\n useEffect(() => {\n const unsub = store.subscribe(() => { void fetchDocs(); void fetchCounts() })\n return unsub\n }, [store, fetchDocs, fetchCounts])\n\n // Archive, not delete: a filled document is a record of what was signed —\n // it is moved out of the active list, never destroyed.\n //\n // A confirmação é um ConfirmDialog e não `window.confirm`: o nativo bloqueia a\n // aba inteira, ignora o tema e não cabe o NOME do registro — e \"Tem certeza?\"\n // sem dizer de qual anamnese se fala é a pergunta que ninguém consegue\n // responder.\n const [archiving, setArchiving] = useState<FormDocument | null>(null)\n\n const handleArchive = useCallback(async () => {\n const doc = archiving\n setArchiving(null)\n if (!doc) return\n await provider.updateDocument(doc.id, { status: 'archived' })\n setDocuments((prev) => prev.filter((d) => d.id !== doc.id))\n setTotal((n) => Math.max(0, n - 1))\n void fetchCounts()\n // O badge da aba vive fora deste componente.\n invalidateTabCounts()\n }, [provider, archiving, fetchCounts])\n\n // Drag and drop handlers\n const handleDragEnter = useCallback((e: React.DragEvent) => {\n e.preventDefault()\n dragCounter.current++\n setIsDragOver(true)\n }, [])\n\n const handleDragLeave = useCallback((e: React.DragEvent) => {\n e.preventDefault()\n dragCounter.current--\n if (dragCounter.current === 0) setIsDragOver(false)\n }, [])\n\n const handleDragOver = useCallback((e: React.DragEvent) => {\n e.preventDefault()\n }, [])\n\n const handleDrop = useCallback((e: React.DragEvent) => {\n e.preventDefault()\n dragCounter.current = 0\n setIsDragOver(false)\n const files = Array.from(e.dataTransfer.files)\n if (files.length > 0 && onFileDrop) {\n onFileDrop(files)\n }\n }, [onFileDrop])\n\n /**\n * As pastilhas saem do que EXISTE, nunca do enum — e do SERVIDOR, nunca da\n * página.\n *\n * Um consultório de psicologia que nunca emitiu laudo veria \"Laudo\" vazio\n * para sempre, e uma aba que oferece um filtro sem resultado ensina que a\n * tela mente. Contar a página dizia outra mentira: \"Tudo 50\" numa ficha com\n * 110 registros, porque o provider pagina em 50.\n */\n const buckets = useMemo(() => {\n const order: Bucket[] = [...CATEGORY_ORDER, 'file']\n return order\n .filter((b) => (counts[b] ?? 0) > 0)\n .map((b) => ({\n id: b,\n label: b === 'file' ? t('customForms.bucket.file') : categoryLabel(b),\n count: counts[b] ?? 0,\n }))\n }, [counts, t])\n\n const totalAll = useMemo(\n () => Object.values(counts).reduce((sum, n) => sum + n, 0),\n [counts],\n )\n\n // Uma pastilha que some (o último laudo foi arquivado) não pode deixar a\n // lista presa num filtro que não existe mais.\n useEffect(() => {\n if (bucket && !buckets.some((b) => b.id === bucket)) setBucket(undefined)\n }, [buckets, bucket])\n\n // A consulta já filtrou; aqui é só o nome do que está na tela.\n const visible = documents\n\n const items = useMemo(\n () => visible.map((doc) => documentToTimelineItem(doc, t('customForms.documentFallbackTitle'))),\n [visible, t],\n )\n\n const byId = useMemo(() => new Map(visible.map((d) => [d.id, d])), [visible])\n\n /**\n * Quem está aberto: o olhinho geral manda em todos, e `openIds` é a exceção\n * de quem foi clicado à mão.\n *\n * Com o geral LIGADO, `openIds` guarda quem foi FECHADO — senão ligar o\n * olhinho reabriria à força o item que a pessoa acabou de fechar.\n */\n const expandedIds = useMemo(() => {\n if (!expandAll) return openIds\n const open = new Set(visible.map((d) => d.id))\n for (const id of openIds) open.delete(id)\n return open\n }, [expandAll, openIds, visible])\n\n const toggleOne = useCallback((id: string) => {\n setOpenIds((prev) => {\n const next = new Set(prev)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n return next\n })\n }, [])\n\n // Trocar o sentido do olhinho geral zera as exceções: elas eram exceções ao\n // estado anterior, e mantê-las deixaria a lista em xadrez.\n useEffect(() => { setOpenIds(new Set()) }, [expandAll])\n\n if (loading) {\n return (\n <div className=\"space-y-4 py-4\">\n {Array.from({ length: 3 }).map((_, i) => (\n <div key={i} className=\"flex items-center gap-3\">\n <div className=\"h-9 w-9 rounded-lg bg-muted animate-pulse shrink-0\" />\n <div className=\"flex-1 space-y-1.5\">\n <div className=\"h-3.5 w-2/3 bg-muted animate-pulse rounded\" />\n <div className=\"h-2.5 w-1/3 bg-muted animate-pulse rounded\" />\n </div>\n </div>\n ))}\n </div>\n )\n }\n\n // Mesmo desenho das pastilhas da PersonTimeline, de propósito: as duas abas\n // ficam a um clique uma da outra na MESMA ficha, e dois filtros diferentes\n // para a mesma pergunta (\"mostre só isto\") custariam duas leituras.\n // Mesmo desenho das pastilhas da PersonTimeline, de propósito: as duas abas\n // ficam a um clique uma da outra na MESMA ficha, e dois filtros diferentes\n // para a mesma pergunta (\"mostre só isto\") custariam duas leituras.\n const filters = (buckets.length > 1 || totalAll > 0) && (\n <div className=\"mb-3 flex flex-wrap items-center gap-1.5\">\n {buckets.length > 1 && [{ id: undefined as Bucket | undefined, label: t('customForms.bucket.all'), count: totalAll }, ...buckets].map((chip) => {\n const active = chip.id === bucket\n return (\n <Button variant=\"bare\" size=\"bare\"\n key={chip.id ?? '__all__'}\n type=\"button\"\n onClick={() => setBucket(chip.id)}\n className={`gap-0 font-normal rounded-full border px-2.5 py-1 text-xs transition-colors ${\n active\n ? 'border-primary bg-primary/10 text-primary'\n : 'border-border text-muted-foreground hover:bg-muted hover:text-foreground'\n }`}\n >\n {chip.label}\n {/* A contagem é a pergunta do balcão: \"quantas evoluções ela já\n tem\". Vem do servidor, não da página carregada. */}\n <span className=\"ml-1.5 tabular-nums opacity-60\">{chip.count}</span>\n </Button>\n )\n })}\n {/* O olhinho, encostado à direita: ler sem clicar. */}\n <Button variant=\"bare\" size=\"bare\"\n type=\"button\"\n onClick={toggleExpandAll}\n aria-pressed={expandAll}\n title={t(expandAll ? 'customForms.hideContent' : 'customForms.showContent')}\n className={`font-normal ml-auto flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs transition-colors ${\n expandAll\n ? 'border-primary bg-primary/10 text-primary'\n : 'border-border text-muted-foreground hover:bg-muted hover:text-foreground'\n }`}\n >\n {expandAll ? <EyeOff className=\"h-3.5 w-3.5\" /> : <Eye className=\"h-3.5 w-3.5\" />}\n {t(expandAll ? 'customForms.hideContent' : 'customForms.showContent')}\n </Button>\n </div>\n )\n\n return (\n <div>\n {filters}\n <div\n className={`relative min-h-[200px] rounded-xl border-2 transition-colors ${\n isDragOver\n ? 'border-dashed border-primary bg-primary/5'\n : documents.length === 0 && acceptsFiles\n ? 'border-dashed border-border'\n : 'border-transparent'\n }`}\n {...(acceptsFiles ? {\n onDragEnter: handleDragEnter,\n onDragLeave: handleDragLeave,\n onDragOver: handleDragOver,\n onDrop: handleDrop,\n } : {})}\n >\n {/* Drag overlay */}\n {isDragOver && (\n <div className=\"absolute inset-0 z-10 flex flex-col items-center justify-center rounded-xl bg-primary/5\">\n <Upload className=\"h-8 w-8 text-primary/50 mb-2\" />\n <p className=\"text-sm font-medium text-primary/70\">{t('customForms.dropFilesHere')}</p>\n </div>\n )}\n\n {/* Filtrou e não sobrou nada ≠ não há nada. A segunda frase manda\n cadastrar; a primeira mandaria apagar um filtro que o leitor ligou. */}\n {documents.length > 0 && visible.length === 0 && (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <p className=\"text-sm text-muted-foreground\">{t('customForms.noDocumentsInFilter')}</p>\n </div>\n )}\n\n {/* Empty state */}\n {documents.length === 0 && !isDragOver && (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-muted mb-3\">\n {acceptsFiles\n ? <Paperclip className=\"h-5 w-5 text-muted-foreground\" />\n : <ClipboardList className=\"h-5 w-5 text-muted-foreground\" />}\n </div>\n <p className=\"text-sm font-medium\">\n {t(acceptsFiles ? 'customForms.noFiles' : 'customForms.noRecords')}\n </p>\n <p className=\"text-xs text-muted-foreground mt-1 max-w-xs\">\n {t(acceptsFiles ? 'customForms.noFilesDescription' : 'customForms.noRecordsDescription')}\n </p>\n {acceptsFiles && (\n <p className=\"text-[10px] text-muted-foreground mt-3 flex items-center gap-1\">\n <Upload className=\"h-3 w-3\" />\n {t('customForms.dragFilesHere')}\n </p>\n )}\n </div>\n )}\n\n {/* A MESMA linha do tempo da aba Atividade — `TimelineList` do\n @fayz-ai/admin. Esta lista tinha trilho próprio, cabeçalho de data\n próprio e cartão próprio para responder a mesma pergunta (\"o que\n aconteceu com esta pessoa, em ordem\") que a aba vizinha já respondia\n com outro desenho. Duas formas para uma pergunta é o leitor\n reaprendendo a ler a cada aba. */}\n {visible.length > 0 && (\n <TimelineList\n items={items}\n expandedIds={expandedIds}\n renderPreview={(it: TimelineItem) => {\n const doc = byId.get(it.id)\n return doc ? <DocumentPreview document={doc} provider={provider} onOpen={() => onView(doc)} /> : null\n }}\n // O cartão faz UMA coisa, e a seta à direita diz qual: abre o\n // registro. Fechar a prévia é o olhinho — dois gestos, dois\n // controles, nenhum deles adivinhado.\n onSelect={(it: TimelineItem) => {\n const doc = byId.get(it.id)\n if (doc) onView(doc)\n }}\n renderActions={(it: TimelineItem) => {\n const doc = byId.get(it.id)\n if (!doc) return null\n return (\n <>\n <Button variant=\"bare\" size=\"bare\"\n type=\"button\"\n onClick={(e) => { e.stopPropagation(); toggleOne(doc.id) }}\n className=\"rounded-md p-1.5 hover:bg-muted\"\n aria-label={t(expandedIds.has(doc.id) ? 'customForms.hideContent' : 'customForms.showContent')}\n aria-expanded={expandedIds.has(doc.id)}\n >\n {expandedIds.has(doc.id)\n ? <EyeOff className=\"h-3.5 w-3.5 text-muted-foreground\" />\n : <Eye className=\"h-3.5 w-3.5 text-muted-foreground\" />}\n </Button>\n <Button variant=\"bare\" size=\"bare\"\n type=\"button\"\n onClick={(e) => { e.stopPropagation(); setArchiving(doc) }}\n className=\"rounded-md p-1.5 hover:bg-muted\"\n aria-label={t('customForms.archive')}\n title={t('customForms.archive')}\n >\n <Archive className=\"h-3.5 w-3.5 text-muted-foreground\" />\n </Button>\n </>\n )\n }}\n />\n )}\n\n {/* Carregar mais, e não rolagem infinita: a ficha tem rodapé (a\n procedência do registro) e um carregamento automático o empurraria\n para sempre. O número diz quanto falta, para a decisão ser informada. */}\n {visible.length < total && (\n <div className=\"flex justify-center pt-4\">\n <Button variant=\"outline\" size=\"sm\" disabled={loadingMore} onClick={() => void loadMore()}>\n {loadingMore\n ? t('customForms.loadingMore')\n : t('customForms.loadMore', { count: String(total - visible.length) })}\n </Button>\n </div>\n )}\n </div>\n\n <ConfirmDialog\n open={archiving !== null}\n title={t('customForms.archiveTitle')}\n description={t('customForms.archiveDescription', {\n name: archiving?.templateName ?? archiving?.title ?? t('customForms.documentFallbackTitle'),\n })}\n confirmLabel={t('customForms.archive')}\n cancelLabel={t('common.cancel')}\n onConfirm={() => void handleArchive()}\n onCancel={() => setArchiving(null)}\n />\n </div>\n )\n}\n","import React from 'react'\n\n/**\n * O corpo do documento enquanto o modelo não chegou.\n *\n * Um spinner centralizado diz \"espere\" e nada mais: a área inteira colapsa numa\n * bolinha e, quando o modelo chega, a tela salta de 40px para uma página de\n * formulário. O esqueleto ocupa desde já a forma que vai ser preenchida — moldura,\n * rótulo, campo — então a chegada do conteúdo troca cinza por texto no lugar onde\n * o texto já estava.\n *\n * `rows` é uma aproximação e não tem como não ser: quantos campos o modelo tem é\n * justamente o que ainda está sendo carregado. Cinco é a altura de formulário\n * curto — erra para baixo de propósito, porque crescer ao carregar incomoda\n * menos do que encolher.\n */\nexport function DocumentBodySkeleton({ rows = 5 }: { rows?: number }) {\n return (\n <div className=\"space-y-4 rounded-xl border p-4\" aria-hidden>\n {Array.from({ length: rows }).map((_, i) => (\n <div key={i} className=\"space-y-1.5\">\n <div className=\"h-3 w-28 animate-pulse rounded bg-muted\" />\n <div className=\"h-9 w-full animate-pulse rounded-md bg-muted\" />\n </div>\n ))}\n </div>\n )\n}\n\n/** O cabeçalho, para quando nem o título do documento se sabe ainda. */\nexport function DocumentHeaderSkeleton() {\n return (\n <div className=\"flex items-center gap-3\" aria-hidden>\n <div className=\"h-3.5 w-3.5 shrink-0 animate-pulse rounded bg-muted\" />\n <div className=\"min-w-0 flex-1 space-y-1.5\">\n <div className=\"h-4 w-48 max-w-full animate-pulse rounded bg-muted\" />\n <div className=\"h-3 w-24 animate-pulse rounded bg-muted\" />\n </div>\n </div>\n )\n}\n","import React, { useState, useEffect, useCallback } from 'react'\nimport { ArrowLeft } from 'lucide-react'\nimport { Button, useSaveBar } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useLimitGuard, invalidateLimit } from '@fayz-ai/admin'\nimport type { FormsDataProvider } from '@fayz-ai/forms/data/provider'\nimport type { FormsStore } from '@fayz-ai/forms/store'\nimport type { FormDocument } from '@fayz-ai/forms/domain/document'\nimport type { FormTemplate } from '@fayz-ai/forms/domain/template'\nimport { FormRenderer } from './FormRenderer'\nimport { DocumentBodySkeleton, DocumentHeaderSkeleton } from './DocumentSkeleton'\nimport { prefillFromPerson } from '../lib/person-fields'\n\nfunction generateTitle(templateName: string, personName?: string): string {\n const date = new Date().toLocaleDateString()\n return personName\n ? `${templateName} — ${personName} — ${date}`\n : `${templateName} — ${date}`\n}\n\ninterface DocumentFormDialogProps {\n template: FormTemplate | null\n existingDocument?: FormDocument\n personId: string\n personName?: string\n /** Full person record — mapped fields are pre-filled from it on new documents. */\n person?: Record<string, unknown>\n provider: FormsDataProvider\n store: FormsStore\n onSaved: () => void\n onBack: () => void\n}\n\nexport function DocumentFormDialog({\n template: initialTemplate,\n existingDocument,\n personId,\n personName,\n person,\n provider,\n store,\n onSaved,\n onBack,\n}: DocumentFormDialogProps) {\n const t = useTranslation()\n const guardDocuments = useLimitGuard('documents_month')\n const [template, setTemplate] = useState<FormTemplate | null>(initialTemplate)\n const [data, setData] = useState<Record<string, unknown>>(() =>\n existingDocument\n ? existingDocument.data\n : prefillFromPerson(initialTemplate?.schema, person),\n )\n const [saving, setSaving] = useState(false)\n\n useEffect(() => {\n if (existingDocument && !template) {\n provider.getTemplateById(existingDocument.templateId).then(setTemplate)\n }\n }, [existingDocument, template, provider])\n\n // When creating from a template that arrives asynchronously, apply prefill\n // once the schema is known (guarded so it never clobbers user edits).\n const prefilled = React.useRef(!!initialTemplate || !!existingDocument)\n useEffect(() => {\n if (prefilled.current || !template || existingDocument) return\n prefilled.current = true\n setData((prev) => prefillFromPerson(template.schema, person, prev))\n }, [template, existingDocument, person])\n\n const handleSave = useCallback(\n async (status: 'draft' | 'completed') => {\n if (!template) return\n // Plan monthly-quota guard (client-side, before the provider call) — only\n // on create. Opens the global UpgradeModal and aborts when the cap is hit.\n if (!existingDocument && (await guardDocuments()) === 'blocked') return\n setSaving(true)\n try {\n const autoTitle = generateTitle(template.name, personName)\n if (existingDocument) {\n await store.getState().updateDocument(existingDocument.id, { data, status })\n } else {\n await store.getState().createDocument({\n templateId: template.id,\n personId,\n title: autoTitle,\n data,\n status,\n })\n invalidateLimit('documents_month')\n }\n onSaved()\n } finally {\n setSaving(false)\n }\n },\n [template, existingDocument, data, personId, personName, store, onSaved, guardDocuments],\n )\n\n // Dirty detection drives the floating SaveBar. The baseline is the document's\n // ORIGINAL saved data (empty for a brand-new document), so a new document that\n // arrives pre-filled from the person's record counts as dirty immediately and\n // the floating \"unsaved changes\" bar shows right away.\n const snapshot = React.useRef<string | null>(null)\n useEffect(() => {\n if (template && snapshot.current === null) {\n snapshot.current = JSON.stringify(existingDocument?.data ?? {})\n }\n }, [template, existingDocument])\n const dirty = snapshot.current !== null && JSON.stringify(data) !== snapshot.current\n\n useSaveBar({\n dirty,\n saving,\n onSave: () => { void handleSave('completed') },\n onDiscard: () => onBack(),\n saveLabel: t('customForms.saveAndComplete'),\n })\n\n if (!template) {\n // Editar um documento existente busca o modelo pelo id: o título já é\n // conhecido (está no documento) e só o corpo espera. Criar um novo a partir\n // de um modelo que ainda está vindo não conhece nem o título — aí o\n // cabeçalho também é esqueleto.\n return (\n <div className=\"space-y-4\">\n {existingDocument?.title ? (\n <div className=\"flex items-center gap-3\">\n <Button variant=\"bare\" size=\"bare\"\n onClick={onBack}\n className=\"flex items-center gap-1 text-sm text-muted-foreground transition-colors hover:text-foreground\"\n >\n <ArrowLeft className=\"h-3.5 w-3.5\" />\n </Button>\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"truncate text-sm font-semibold\">{existingDocument.title}</h3>\n <p className=\"text-xs text-muted-foreground\">\n {new Date(existingDocument.createdAt).toLocaleDateString()}\n </p>\n </div>\n </div>\n ) : (\n <DocumentHeaderSkeleton />\n )}\n <DocumentBodySkeleton\n rows={Math.min(Math.max(Object.keys(existingDocument?.data ?? {}).length, 3), 8)}\n />\n </div>\n )\n }\n\n return (\n <div className=\"space-y-4\">\n {/* Header */}\n <div className=\"flex items-center gap-3\">\n <Button variant=\"bare\" size=\"bare\"\n onClick={onBack}\n className=\"flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground transition-colors\"\n >\n <ArrowLeft className=\"h-3.5 w-3.5\" />\n </Button>\n <div className=\"flex-1 min-w-0\">\n <h3 className=\"font-semibold text-sm\">{template.name}</h3>\n <p className=\"text-xs text-muted-foreground\">\n {personName && <span>{personName} · </span>}\n {new Date().toLocaleDateString()}\n </p>\n </div>\n </div>\n\n {/* Form fields — saving is driven entirely by the floating SaveBar\n (unsaved-changes bar), matching the rest of the CRUD detail UX. */}\n <div className=\"rounded-xl border p-4\">\n <FormRenderer\n schema={template.schema}\n data={data}\n onChange={setData}\n />\n </div>\n </div>\n )\n}\n","import React, { useEffect, useState } from 'react'\nimport { ArrowLeft, Pencil, Printer } from 'lucide-react'\nimport { Button } from '@fayz-ai/ui'\nimport { Badge } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport type { FormsDataProvider } from '@fayz-ai/forms/data/provider'\nimport type { FormDocument } from '@fayz-ai/forms/domain/document'\nimport type { FormTemplate } from '@fayz-ai/forms/domain/template'\nimport { FormRenderer } from './FormRenderer'\nimport { DocumentBodySkeleton } from './DocumentSkeleton'\nimport { printDocument } from '../lib/print'\n\ninterface FormViewerProps {\n document: FormDocument\n provider: FormsDataProvider\n onBack: () => void\n onEdit?: (doc: FormDocument) => void\n}\n\nconst STATUS_COLORS: Record<string, string> = {\n draft: 'bg-warning-soft text-warning-soft-foreground',\n completed: 'bg-success-soft text-success-soft-foreground',\n signed: 'bg-info-soft text-info-soft-foreground',\n archived: 'bg-muted text-muted-foreground',\n}\n\nexport function FormViewer({ document: doc, provider, onBack, onEdit }: FormViewerProps) {\n const t = useTranslation()\n const [template, setTemplate] = useState<FormTemplate | null>(null)\n\n useEffect(() => {\n if (!doc.templateId) return\n const timer = setTimeout(() => {\n provider.getTemplateById(doc.templateId).then(setTemplate)\n }, 50)\n return () => clearTimeout(timer)\n }, [doc.templateId, provider])\n\n // O cabeçalho NÃO espera o modelo. Título, data e situação vêm do próprio\n // documento, que já está na mão desde o clique na lista — só o corpo depende\n // do schema. Segurar a tela inteira por ele fazia o cabeçalho já conhecido\n // aparecer depois de uma ida ao banco que não era sobre ele.\n return (\n <div className=\"space-y-4\">\n {/* Header */}\n <div className=\"flex items-center gap-3\">\n <Button variant=\"bare\" size=\"bare\"\n onClick={onBack}\n className=\"flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground transition-colors\"\n >\n <ArrowLeft className=\"h-3.5 w-3.5\" />\n </Button>\n <div className=\"flex-1 min-w-0\">\n <h3 className=\"font-semibold text-sm truncate\">\n {doc.title ?? template?.name ?? ''}\n </h3>\n <p className=\"text-xs text-muted-foreground\">\n {new Date(doc.createdAt).toLocaleDateString()}\n </p>\n </div>\n <Badge variant=\"secondary\" className={`text-[10px] ${STATUS_COLORS[doc.status] ?? ''}`}>\n {t(`customForms.status.${doc.status}`)}\n </Badge>\n {/* Desabilitado, não escondido: imprimir precisa do modelo, e um botão\n que aparece depois faz os vizinhos pularem de lugar. */}\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"h-8\"\n disabled={!template}\n onClick={() => template && printDocument(template, doc)}\n >\n <Printer className=\"h-3 w-3 mr-1\" />\n {t('customForms.printPdf')}\n </Button>\n {onEdit && doc.status === 'draft' && (\n <Button variant=\"outline\" size=\"sm\" className=\"h-8\" onClick={() => onEdit(doc)}>\n <Pencil className=\"h-3 w-3 mr-1\" />\n {t('common.edit')}\n </Button>\n )}\n </div>\n\n {/* Form content (read-only) */}\n {template ? (\n <div className=\"rounded-xl border p-4\">\n <FormRenderer\n schema={template.schema}\n data={doc.data}\n onChange={() => {}}\n readOnly\n />\n </div>\n ) : (\n // O documento já diz quantos campos tem: o esqueleto sai da altura certa\n // em vez de chutar, e a chegada do conteúdo não mexe no scroll.\n <DocumentBodySkeleton rows={Math.min(Math.max(Object.keys(doc.data ?? {}).length, 3), 8)} />\n )}\n </div>\n )\n}\n","import React, { useState, useCallback, useRef, useMemo, useEffect } from 'react'\nimport { Plus, ChevronDown, Search } from 'lucide-react'\nimport { Button, Input } from '@fayz-ai/ui'\nimport {\n Dropdown,\n DropdownTrigger,\n DropdownContent,\n DropdownLabel,\n DropdownSeparator,\n} from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { getAllDocumentTypes, type DocumentTypeOption } from '../lib/document-types'\n\ninterface AddDocumentDropdownProps {\n personId: string\n onSelect: (option: DocumentTypeOption) => void\n /**\n * Restringe o que este botão oferece.\n *\n * Sem isto, o Prontuário e os Arquivos — duas abas da mesma ficha —\n * ofereceriam o mesmo menu inteiro, e o leitor teria de saber que\n * \"Anexo\" no Prontuário grava no OUTRO lugar. Cada superfície oferece só\n * o que ela mesma lista.\n */\n optionFilter?: (option: DocumentTypeOption) => boolean\n /** Rótulo do botão. Padrão: \"Adicionar\". */\n label?: string\n}\n\n/** Below this many options the search box is noise, not help. */\nconst SEARCH_THRESHOLD = 8\n\nconst normalize = (s: string) =>\n s.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '').toLowerCase()\n\nexport function AddDocumentDropdown({ personId, onSelect, optionFilter, label }: AddDocumentDropdownProps) {\n const t = useTranslation()\n const [open, setOpen] = useState(false)\n const [options, setOptions] = useState<DocumentTypeOption[]>([])\n const [loaded, setLoaded] = useState(false)\n const [query, setQuery] = useState('')\n const [activeIndex, setActiveIndex] = useState(0)\n const loadingRef = useRef(false)\n const inputRef = useRef<HTMLInputElement>(null)\n const listRef = useRef<HTMLDivElement>(null)\n\n const handleOpenChange = useCallback((next: boolean) => {\n setOpen(next)\n if (!next) return\n setQuery('')\n setActiveIndex(0)\n if (loaded || loadingRef.current) return\n loadingRef.current = true\n getAllDocumentTypes(personId).then((opts) => {\n setOptions(optionFilter ? opts.filter(optionFilter) : opts)\n setLoaded(true)\n loadingRef.current = false\n })\n }, [personId, loaded, optionFilter])\n\n const filtered = useMemo(() => {\n const q = normalize(query.trim())\n if (!q) return options\n return options.filter(\n (o) =>\n normalize(o.label).includes(q) ||\n (o.description ? normalize(o.description).includes(q) : false)\n )\n }, [options, query])\n\n // Group the filtered list, keeping the source order of groups\n const groups = useMemo(() => {\n const acc: Array<{ label: string; items: DocumentTypeOption[] }> = []\n for (const opt of filtered) {\n let group = acc.find((g) => g.label === opt.group)\n if (!group) {\n group = { label: opt.group, items: [] }\n acc.push(group)\n }\n group.items.push(opt)\n }\n return acc\n }, [filtered])\n\n const showSearch = loaded && options.length > SEARCH_THRESHOLD\n\n // Radix focuses the content on open; take the focus to the search box instead\n useEffect(() => {\n if (!open || !showSearch) return\n const id = requestAnimationFrame(() => inputRef.current?.focus())\n return () => cancelAnimationFrame(id)\n }, [open, showSearch])\n\n // Keep the keyboard-highlighted row visible while arrowing through a long list\n useEffect(() => {\n listRef.current\n ?.querySelector(`[data-index=\"${activeIndex}\"]`)\n ?.scrollIntoView({ block: 'nearest' })\n }, [activeIndex])\n\n const choose = useCallback((opt: DocumentTypeOption) => {\n setOpen(false)\n onSelect(opt)\n }, [onSelect])\n\n const handleInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Escape') return // let the menu close\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n setActiveIndex((i) => Math.min(filtered.length - 1, i + 1))\n } else if (e.key === 'ArrowUp') {\n e.preventDefault()\n setActiveIndex((i) => Math.max(0, i - 1))\n } else if (e.key === 'Enter') {\n e.preventDefault()\n const opt = filtered[activeIndex]\n if (opt) choose(opt)\n }\n // Radix's menu typeahead would otherwise swallow characters typed here\n e.stopPropagation()\n }\n\n // Flat index across groups, so arrow keys walk the whole list\n let flatIndex = -1\n\n return (\n <Dropdown open={open} onOpenChange={handleOpenChange}>\n <DropdownTrigger asChild>\n <Button size=\"sm\" className=\"h-8\">\n <Plus className=\"h-3.5 w-3.5 mr-1\" />\n {label ?? t('customForms.addDocument')}\n <ChevronDown className=\"h-3 w-3 ml-1 opacity-50\" />\n </Button>\n </DropdownTrigger>\n <DropdownContent align=\"end\" className=\"w-72 p-0\">\n {showSearch && (\n <div className=\"flex items-center gap-2 border-b px-2.5 py-2\">\n <Search className=\"h-3.5 w-3.5 text-muted-foreground shrink-0\" />\n <Input\n ref={inputRef}\n value={query}\n onChange={(e) => {\n setQuery(e.target.value)\n setActiveIndex(0)\n }}\n onKeyDown={handleInputKeyDown}\n placeholder={t('customForms.searchDocumentTypes')}\n className=\"h-auto rounded-none border-0 bg-transparent p-0 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0\"\n />\n </div>\n )}\n\n <div ref={listRef} className=\"max-h-[min(60vh,20rem)] overflow-y-auto overscroll-contain p-1\">\n {groups.map((group, gi) => (\n <React.Fragment key={group.label}>\n {gi > 0 && <DropdownSeparator />}\n <DropdownLabel className=\"text-[10px] uppercase tracking-wider\">\n {group.label}\n </DropdownLabel>\n {group.items.map((opt) => {\n const Icon = opt.icon\n flatIndex += 1\n const index = flatIndex\n return (\n <Button variant=\"bare\" size=\"bare\"\n key={opt.id}\n type=\"button\"\n data-index={index}\n onClick={() => choose(opt)}\n onMouseEnter={() => setActiveIndex(index)}\n className={`font-normal justify-start relative flex w-full cursor-default select-none items-center gap-2 rounded-button px-2 py-1.5 text-left text-sm outline-none transition-colors ${\n index === activeIndex ? 'bg-muted' : ''\n }`}\n >\n <Icon className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm truncate\">{opt.label}</p>\n {opt.description && (\n <p className=\"text-[10px] text-muted-foreground truncate\">\n {opt.description}\n </p>\n )}\n </div>\n </Button>\n )\n })}\n </React.Fragment>\n ))}\n\n {!loaded && (\n <div className=\"flex items-center justify-center py-3\">\n <div className=\"h-4 w-4 border-2 border-primary border-t-transparent animate-spin rounded-full\" />\n </div>\n )}\n {loaded && options.length === 0 && (\n <div className=\"px-2 py-3 text-center text-xs text-muted-foreground\">\n {t('customForms.noTemplates')}\n </div>\n )}\n {loaded && options.length > 0 && filtered.length === 0 && (\n <div className=\"px-2 py-3 text-center text-xs text-muted-foreground\">\n {t('customForms.noResults')}\n </div>\n )}\n </div>\n </DropdownContent>\n </Dropdown>\n )\n}\n","import React, { useState, useCallback, useRef } from 'react'\nimport { ArrowLeft, Image as ImageIcon, Paperclip } from 'lucide-react'\nimport { Button, Badge } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useLimitGuard, invalidateLimit } from '@fayz-ai/admin'\nimport type { CustomFormsConfig } from '../config'\nimport type { FormsDataProvider } from '@fayz-ai/forms/data/provider'\nimport type { FormsStore } from '@fayz-ai/forms/store'\nimport type { FormDocument } from '@fayz-ai/forms/domain/document'\nimport type { FormTemplate } from '@fayz-ai/forms/domain/template'\nimport type { DocumentTypeOption } from '../lib/document-types'\nimport { DocumentList } from './DocumentList'\nimport { DocumentFormDialog } from './DocumentFormDialog'\nimport { FormViewer } from './FormViewer'\nimport { AddDocumentDropdown } from './AddDocumentDropdown'\n\n/**\n * Qual das duas abas da ficha este widget está desenhando.\n *\n * `records` é o PRONTUÁRIO: só resposta de formulário, agrupada por categoria\n * (anamnese, evolução, laudo, contrato). `files` é o armário: foto e anexo.\n *\n * Eram a mesma lista, e o resultado era uma anamnese disputando rolagem com a\n * foto do RG. O V1 nunca os misturou — lá são abas distintas desde sempre.\n */\nexport type DocumentSurface = 'records' | 'files'\n\nconst SURFACE_KINDS: Record<DocumentSurface, string[]> = {\n records: ['form'],\n files: ['image', 'attachment'],\n}\n\ninterface PersonDocumentsWidgetProps {\n item: { id: string; name?: string; [key: string]: any }\n config: CustomFormsConfig\n provider: FormsDataProvider\n store: FormsStore\n /** Padrão `records`: quem não declara superfície pediu o prontuário. */\n surface?: DocumentSurface\n}\n\ntype WidgetView =\n | { type: 'list' }\n | { type: 'fill'; template: FormTemplate }\n | { type: 'view'; document: FormDocument }\n | { type: 'edit'; document: FormDocument }\n\nexport function PersonDocumentsWidget({ item, config, provider, store, surface = 'records' }: PersonDocumentsWidgetProps) {\n const t = useTranslation()\n const kinds = SURFACE_KINDS[surface]\n // Cada aba oferece só o que ela própria lista — ver `optionFilter`.\n const optionFilter = useCallback(\n (o: DocumentTypeOption) => surface === 'records'\n ? o.id.startsWith('template:')\n : o.id === 'core:image' || o.id === 'core:attachment',\n [surface],\n )\n const guardDocuments = useLimitGuard('documents_month')\n const [view, setView] = useState<WidgetView>({ type: 'list' })\n const fileInputRef = useRef<HTMLInputElement>(null)\n const [pendingFileAccept, setPendingFileAccept] = useState<string>('*/*')\n\n const handleDocTypeSelect = useCallback(async (option: DocumentTypeOption) => {\n // Form template\n if (option.id.startsWith('template:')) {\n const templateId = option.id.replace('template:', '')\n const template = await provider.getTemplateById(templateId)\n if (template) {\n setView({ type: 'fill', template })\n }\n return\n }\n\n // Image — open file picker for images\n if (option.id === 'core:image') {\n setPendingFileAccept('image/*')\n setTimeout(() => fileInputRef.current?.click(), 0)\n return\n }\n\n // Attachment — open file picker for any file\n if (option.id === 'core:attachment') {\n setPendingFileAccept('*/*')\n setTimeout(() => fileInputRef.current?.click(), 0)\n return\n }\n }, [provider])\n\n const handleFiles = useCallback(async (files: File[]) => {\n // Plan monthly-quota guard (client-side, before the provider call) — count\n // the whole batch. Opens the global UpgradeModal and aborts when the cap\n // would be exceeded.\n if ((await guardDocuments(files.length)) === 'blocked') return\n for (const file of files) {\n const isImage = file.type.startsWith('image/')\n await store.getState().createDocument({\n kind: isImage ? 'image' : 'attachment',\n personId: item.id,\n title: file.name,\n fileName: file.name,\n fileSize: file.size,\n mimeType: file.type,\n status: 'completed',\n })\n }\n invalidateLimit('documents_month')\n }, [store, item.id, guardDocuments])\n\n const handleFileInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const files = Array.from(e.target.files ?? [])\n if (files.length > 0) handleFiles(files)\n e.target.value = ''\n }, [handleFiles])\n\n const handleViewDoc = useCallback((doc: FormDocument) => {\n setView({ type: 'view', document: doc })\n }, [])\n\n const handleEditDoc = useCallback((doc: FormDocument) => {\n setView({ type: 'edit', document: doc })\n }, [])\n\n const handleBack = useCallback(() => {\n setView({ type: 'list' })\n }, [])\n\n const handleSaved = useCallback(() => {\n setView({ type: 'list' })\n }, [])\n\n // Fill form\n if (view.type === 'fill') {\n return (\n <DocumentFormDialog\n template={view.template}\n personId={item.id}\n personName={item.name}\n person={item}\n provider={provider}\n store={store}\n onSaved={handleSaved}\n onBack={handleBack}\n />\n )\n }\n\n // View document — route by kind\n if (view.type === 'view') {\n const doc = view.document\n const isForm = doc.kind === 'form' || (!doc.kind && doc.templateId)\n\n if (!isForm) {\n // File document (image/attachment) — simple preview\n return (\n <FileDocumentViewer document={doc} onBack={handleBack} />\n )\n }\n\n return (\n <FormViewer\n document={doc}\n provider={provider}\n onBack={handleBack}\n onEdit={handleEditDoc}\n />\n )\n }\n\n // Edit document — only for form docs\n if (view.type === 'edit') {\n return (\n <DocumentFormDialog\n template={null}\n existingDocument={view.document}\n personId={item.id}\n personName={item.name}\n person={item}\n provider={provider}\n store={store}\n onSaved={handleSaved}\n onBack={handleBack}\n />\n )\n }\n\n // Default: list with dropdown + drag zone\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between\">\n <h3 className=\"text-sm font-semibold\">\n {t(surface === 'files' ? 'customForms.filesTitle' : 'customForms.recordsTitle')}\n </h3>\n <AddDocumentDropdown\n personId={item.id}\n onSelect={handleDocTypeSelect}\n optionFilter={optionFilter}\n label={t(surface === 'files' ? 'customForms.addFile' : 'customForms.addRecord')}\n />\n </div>\n <DocumentList\n personId={item.id}\n provider={provider}\n store={store}\n kinds={kinds}\n onView={handleViewDoc}\n onFileDrop={handleFiles}\n />\n {/* Hidden file input for image/attachment upload */}\n <input\n ref={fileInputRef}\n type=\"file\"\n className=\"hidden\"\n accept={pendingFileAccept}\n multiple\n onChange={handleFileInputChange}\n />\n </div>\n )\n}\n\nfunction FileDocumentViewer({ document: doc, onBack }: { document: FormDocument; onBack: () => void }) {\n const isImage = doc.kind === 'image' || doc.mimeType?.startsWith('image/')\n const Icon = isImage ? ImageIcon : Paperclip\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center gap-3\">\n <Button variant=\"bare\" size=\"bare\"\n onClick={onBack}\n className=\"flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground transition-colors\"\n >\n <ArrowLeft className=\"h-3.5 w-3.5\" />\n </Button>\n <div className=\"flex-1 min-w-0\">\n <h3 className=\"font-semibold text-sm truncate\">{doc.title ?? doc.fileName ?? 'Document'}</h3>\n <p className=\"text-xs text-muted-foreground\">\n {new Date(doc.createdAt).toLocaleDateString()}\n </p>\n </div>\n <Badge variant=\"secondary\" className=\"text-[10px] bg-success/15 text-success\">\n {doc.status === 'completed' ? 'Finalizado' : doc.status}\n </Badge>\n </div>\n\n <div className=\"rounded-xl border p-6 flex flex-col items-center gap-4\">\n {isImage && doc.fileUrl ? (\n <img src={doc.fileUrl} alt={doc.fileName ?? ''} className=\"max-w-full max-h-[500px] rounded-lg object-contain\" />\n ) : (\n <div className=\"flex flex-col items-center gap-3 py-8\">\n <div className=\"flex h-16 w-16 items-center justify-center rounded-full bg-muted\">\n <Icon className=\"h-7 w-7 text-muted-foreground\" />\n </div>\n <p className=\"text-sm font-medium\">{doc.fileName ?? doc.title ?? 'Arquivo'}</p>\n {doc.fileSize && (\n <p className=\"text-xs text-muted-foreground\">\n {(doc.fileSize / 1024).toFixed(1)} KB\n </p>\n )}\n </div>\n )}\n </div>\n </div>\n )\n}\n"]}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { tl } from '@fayz-ai/core';
|
|
2
|
+
import { FileText, FileSignature, FileCheck2, Activity, Camera, Stethoscope, ClipboardList } from 'lucide-react';
|
|
3
|
+
|
|
4
|
+
// src/lib/document-types.ts
|
|
5
|
+
var providers = [];
|
|
6
|
+
function registerDocumentTypeProvider(provider) {
|
|
7
|
+
if (providers.find((p) => p.id === provider.id)) return;
|
|
8
|
+
providers.push(provider);
|
|
9
|
+
}
|
|
10
|
+
async function getAllDocumentTypes(personId) {
|
|
11
|
+
const results = await Promise.all(
|
|
12
|
+
providers.map((p) => Promise.resolve(p.getTypes(personId)))
|
|
13
|
+
);
|
|
14
|
+
const all = results.flat();
|
|
15
|
+
all.sort((a, b) => (a.groupOrder ?? 50) - (b.groupOrder ?? 50) || (a.order ?? 0) - (b.order ?? 0));
|
|
16
|
+
return all;
|
|
17
|
+
}
|
|
18
|
+
var CATEGORY_ORDER = [
|
|
19
|
+
"anamnesis",
|
|
20
|
+
"evaluation",
|
|
21
|
+
"photos",
|
|
22
|
+
"evolution",
|
|
23
|
+
"report",
|
|
24
|
+
"contract",
|
|
25
|
+
"general"
|
|
26
|
+
];
|
|
27
|
+
var CATEGORY_GROUP_ORDER = {
|
|
28
|
+
anamnesis: 10,
|
|
29
|
+
evaluation: 12,
|
|
30
|
+
photos: 14,
|
|
31
|
+
evolution: 20,
|
|
32
|
+
report: 30,
|
|
33
|
+
contract: 40,
|
|
34
|
+
general: 50
|
|
35
|
+
};
|
|
36
|
+
var CATEGORY_ICONS = {
|
|
37
|
+
anamnesis: ClipboardList,
|
|
38
|
+
evaluation: Stethoscope,
|
|
39
|
+
photos: Camera,
|
|
40
|
+
evolution: Activity,
|
|
41
|
+
report: FileCheck2,
|
|
42
|
+
contract: FileSignature,
|
|
43
|
+
general: FileText
|
|
44
|
+
};
|
|
45
|
+
function categoryLabel(category) {
|
|
46
|
+
switch (category) {
|
|
47
|
+
case "anamnesis":
|
|
48
|
+
return tl("Anamnesis", "Anamnese");
|
|
49
|
+
case "evaluation":
|
|
50
|
+
return tl("Evaluation", "Avalia\xE7\xE3o");
|
|
51
|
+
case "photos":
|
|
52
|
+
return tl("Photos", "Fotos");
|
|
53
|
+
case "evolution":
|
|
54
|
+
return tl("Evolution", "Evolu\xE7\xE3o");
|
|
55
|
+
case "report":
|
|
56
|
+
return tl("Report", "Laudo");
|
|
57
|
+
case "contract":
|
|
58
|
+
return tl("Contract", "Contrato");
|
|
59
|
+
default:
|
|
60
|
+
return tl("General", "Geral");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function normalizeCategory(value) {
|
|
64
|
+
return CATEGORY_ORDER.includes(value) ? value : "general";
|
|
65
|
+
}
|
|
66
|
+
var CATEGORY_TIMELINE_ICON = {
|
|
67
|
+
anamnesis: "ClipboardList",
|
|
68
|
+
evaluation: "Stethoscope",
|
|
69
|
+
photos: "Camera",
|
|
70
|
+
evolution: "Activity",
|
|
71
|
+
report: "FileCheck2",
|
|
72
|
+
contract: "FileSignature",
|
|
73
|
+
general: "FileText"
|
|
74
|
+
};
|
|
75
|
+
var CATEGORY_TONE = {
|
|
76
|
+
anamnesis: "primary",
|
|
77
|
+
evaluation: "primary",
|
|
78
|
+
photos: "info",
|
|
79
|
+
evolution: "info",
|
|
80
|
+
report: "success",
|
|
81
|
+
contract: "warning",
|
|
82
|
+
general: "neutral"
|
|
83
|
+
};
|
|
84
|
+
function bucketOf(doc) {
|
|
85
|
+
if (doc.kind === "image" || doc.kind === "attachment") return "file";
|
|
86
|
+
return normalizeCategory(doc.templateCategory);
|
|
87
|
+
}
|
|
88
|
+
function subtitleFor(doc) {
|
|
89
|
+
const title = doc.title?.trim();
|
|
90
|
+
if (!title) return void 0;
|
|
91
|
+
const model = doc.templateName?.trim();
|
|
92
|
+
if (!model) return title;
|
|
93
|
+
if (title === model) return void 0;
|
|
94
|
+
return title.toLowerCase().startsWith(model.toLowerCase()) ? void 0 : title;
|
|
95
|
+
}
|
|
96
|
+
function documentToTimelineItem(doc, fallbackTitle) {
|
|
97
|
+
const b = bucketOf(doc);
|
|
98
|
+
const secondary = subtitleFor(doc);
|
|
99
|
+
return {
|
|
100
|
+
id: doc.id,
|
|
101
|
+
sourceId: b,
|
|
102
|
+
occurredAt: doc.createdAt,
|
|
103
|
+
title: doc.templateName ?? doc.title ?? fallbackTitle,
|
|
104
|
+
description: secondary,
|
|
105
|
+
badge: b === "file" ? void 0 : categoryLabel(b),
|
|
106
|
+
icon: b === "file" ? doc.kind === "image" ? "Image" : "Paperclip" : CATEGORY_TIMELINE_ICON[b],
|
|
107
|
+
tone: b === "file" ? "neutral" : CATEGORY_TONE[b]
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export { CATEGORY_GROUP_ORDER, CATEGORY_ICONS, CATEGORY_ORDER, categoryLabel, documentToTimelineItem, getAllDocumentTypes, normalizeCategory, registerDocumentTypeProvider };
|
|
112
|
+
//# sourceMappingURL=chunk-5WW6FTNG.js.map
|
|
113
|
+
//# sourceMappingURL=chunk-5WW6FTNG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/document-types.ts","../src/lib/categories.ts"],"names":[],"mappings":"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","file":"chunk-5WW6FTNG.js","sourcesContent":["import type React from 'react'\n\n// ============================================================\n// Document Type Registry — extensible pattern for plugins\n// to contribute document types to the \"Add Document\" dropdown\n// ============================================================\n\nexport interface DocumentTypeOption {\n /** Unique id, e.g. 'custom_forms:template:abc123' or 'core:image' */\n id: string\n label: string\n icon: React.ElementType\n /** Group label for dropdown sections (e.g. 'Formulários', 'Arquivos') */\n group: string\n /** Group sort order — lower groups appear first */\n groupOrder?: number\n /** Sort order within group */\n order?: number\n /** Description shown below label */\n description?: string\n}\n\nexport interface DocumentTypeProvider {\n /** Unique provider id, e.g. 'custom_forms', 'core_files' */\n id: string\n /** Returns available document types for a given person */\n getTypes(personId: string): DocumentTypeOption[] | Promise<DocumentTypeOption[]>\n}\n\n// ── Global registry ────────────────────────────────────────\n\nconst providers: DocumentTypeProvider[] = []\n\nexport function registerDocumentTypeProvider(provider: DocumentTypeProvider) {\n if (providers.find((p) => p.id === provider.id)) return\n providers.push(provider)\n}\n\nexport function getDocumentTypeProviders(): DocumentTypeProvider[] {\n return providers\n}\n\nexport async function getAllDocumentTypes(personId: string): Promise<DocumentTypeOption[]> {\n const results = await Promise.all(\n providers.map((p) => Promise.resolve(p.getTypes(personId))),\n )\n const all = results.flat()\n // Sort by groupOrder then order within group\n all.sort((a, b) => (a.groupOrder ?? 50) - (b.groupOrder ?? 50) || (a.order ?? 0) - (b.order ?? 0))\n return all\n}\n","import type React from 'react'\nimport { tl } from '@fayz-ai/core'\nimport {\n ClipboardList, Activity, FileCheck2, FileSignature, FileText, Stethoscope, Camera,\n} from 'lucide-react'\nimport type { TemplateCategory } from '@fayz-ai/forms/domain/template'\n\n// ---------------------------------------------------------------------------\n// A CATEGORIA É A COSTURA ENTRE OFÍCIOS.\n//\n// `plg_forms_templates.category` já existe desde a baseline (coluna NOT NULL,\n// índice por tenant, validada na RPC de upsert) e já é escolhida no\n// FormBuilder — mas a ficha da pessoa a ignorava, e o resultado era uma lista\n// só, chamada \"Documentos\", onde anamnese, evolução, laudo, contrato, foto e\n// anexo disputavam a mesma rolagem.\n//\n// Psicologia usa anamnese + evolução + contrato; nutrição troca contrato por\n// laudo; medicina usa as quatro. Nenhum desses consultórios precisa de código\n// próprio: o ofício semeia OS MODELOS com a categoria certa, e a tela se\n// organiza sozinha. Abas fixas por vertical seriam um release por consultório.\n// ---------------------------------------------------------------------------\n\n/** Ordem de leitura, não alfabética: é a ordem em que o prontuário acontece. */\nexport const CATEGORY_ORDER: TemplateCategory[] = [\n 'anamnesis', 'evaluation', 'photos', 'evolution', 'report', 'contract', 'general',\n]\n\n/** `groupOrder` do `Novo ▾`. Arquivos ficam em 90, depois de todo formulário. */\nexport const CATEGORY_GROUP_ORDER: Record<TemplateCategory, number> = {\n anamnesis: 10,\n evaluation: 12,\n photos: 14,\n evolution: 20,\n report: 30,\n contract: 40,\n general: 50,\n}\n\nexport const CATEGORY_ICONS: Record<TemplateCategory, React.ElementType> = {\n anamnesis: ClipboardList,\n evaluation: Stethoscope,\n photos: Camera,\n evolution: Activity,\n report: FileCheck2,\n contract: FileSignature,\n general: FileText,\n}\n\n/**\n * O rótulo FORA de React.\n *\n * `getTypes()` do registro de tipos de documento não é um componente, então não\n * pode usar `useTranslation`. `tl` lê o locale corrente e é o mesmo caminho que\n * o resto do SDK usa para texto fora de hook.\n */\nexport function categoryLabel(category: TemplateCategory): string {\n switch (category) {\n case 'anamnesis': return tl('Anamnesis', 'Anamnese')\n case 'evaluation': return tl('Evaluation', 'Avaliação')\n case 'photos': return tl('Photos', 'Fotos')\n case 'evolution': return tl('Evolution', 'Evolução')\n case 'report': return tl('Report', 'Laudo')\n case 'contract': return tl('Contract', 'Contrato')\n default: return tl('General', 'Geral')\n }\n}\n\n/** Categoria conhecida, ou `general`. Uma linha antiga com categoria vazia não\n * pode sumir da tela por não caber no enum. */\nexport function normalizeCategory(value: unknown): TemplateCategory {\n return CATEGORY_ORDER.includes(value as TemplateCategory)\n ? (value as TemplateCategory)\n : 'general'\n}\n\n/**\n * O ícone e a cor da bolha na linha do tempo.\n *\n * Nome de ícone (string) e não componente: é o que o `TimelineItem` do admin\n * pede, porque ele resolve contra o lucide inteiro — o mesmo caminho que aba\n * de ficha, linha de rail e widget de dashboard já usam.\n *\n * Os tons contam a leitura clínica: a anamnese é o começo (primária), a\n * evolução é o que anda (info), o laudo conclui (sucesso), o contrato\n * compromete (aviso).\n */\nexport const CATEGORY_TIMELINE_ICON: Record<TemplateCategory, string> = {\n anamnesis: 'ClipboardList',\n evaluation: 'Stethoscope',\n photos: 'Camera',\n evolution: 'Activity',\n report: 'FileCheck2',\n contract: 'FileSignature',\n general: 'FileText',\n}\n\nexport const CATEGORY_TONE: Record<TemplateCategory, 'primary' | 'info' | 'success' | 'warning' | 'neutral'> = {\n anamnesis: 'primary',\n evaluation: 'primary',\n photos: 'info',\n evolution: 'info',\n report: 'success',\n contract: 'warning',\n general: 'neutral',\n}\n\n/** A pastilha de um filtro do prontuário: a categoria de um formulário, ou\n * `file` para o que não tem modelo (foto, anexo). */\nexport type DocumentBucket = TemplateCategory | 'file'\n\n/** Um documento sem modelo não tem categoria — é foto ou anexo, e cai no balde\n * próprio em vez de fingir ser \"Geral\". */\nexport function bucketOf(doc: { kind?: string; templateCategory?: unknown }): DocumentBucket {\n if (doc.kind === 'image' || doc.kind === 'attachment') return 'file'\n return normalizeCategory(doc.templateCategory)\n}\n\n/**\n * O que o `title` do documento ACRESCENTA ao nome do modelo.\n *\n * A importação do V1 gravou títulos que são o registro inteiro em texto —\n * \"Evolução semanal_Principal (IMPORTADO) — JUNIA FERREIRA SIMÃO — 17/07/2026\"\n * — e o cartão passava a dizer três vezes a mesma coisa: o modelo já é o\n * título, a pessoa é a ficha aberta, e a data está à direita.\n *\n * Um título que COMEÇA pelo nome do modelo é etiqueta gerada, não informação:\n * não desce para a descrição. O que não começa por ele é coisa que alguém\n * escreveu (\"Retorno 12/09\") e vale a linha.\n */\nfunction subtitleFor(doc: { title?: string; templateName?: string }): string | undefined {\n const title = doc.title?.trim()\n if (!title) return undefined\n const model = doc.templateName?.trim()\n if (!model) return title\n if (title === model) return undefined\n return title.toLowerCase().startsWith(model.toLowerCase()) ? undefined : title\n}\n\n/**\n * De documento para item da linha do tempo — a MESMA `TimelineItem` que a aba\n * Atividade monta, para as duas abas desenharem igual.\n *\n * O TÍTULO é o modelo (\"Anamnese\", \"Evolução\"), não o título que o upload deu\n * ao arquivo: numa ficha clínica é o modelo que se procura. O `title` do\n * documento só desce para a descrição quando ACRESCENTA algo — senão a linha\n * diria a mesma coisa duas vezes.\n *\n * Pura de propósito: é o que dá para testar sem montar React nem banco.\n */\nexport function documentToTimelineItem(\n doc: {\n id: string; kind?: string; title?: string; templateName?: string\n templateCategory?: unknown; createdAt: string\n },\n fallbackTitle: string,\n) {\n const b = bucketOf(doc)\n const secondary = subtitleFor(doc)\n return {\n id: doc.id,\n sourceId: b,\n occurredAt: doc.createdAt,\n title: doc.templateName ?? doc.title ?? fallbackTitle,\n description: secondary,\n badge: b === 'file' ? undefined : categoryLabel(b),\n icon: b === 'file'\n ? (doc.kind === 'image' ? 'Image' : 'Paperclip')\n : CATEGORY_TIMELINE_ICON[b],\n tone: b === 'file' ? ('neutral' as const) : CATEGORY_TONE[b],\n }\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React, { createContext, useContext } from 'react';
|
|
2
|
+
|
|
3
|
+
// src/context.tsx
|
|
4
|
+
var Ctx = createContext(null);
|
|
5
|
+
function CustomFormsProvider({
|
|
6
|
+
value,
|
|
7
|
+
children
|
|
8
|
+
}) {
|
|
9
|
+
return React.createElement(Ctx.Provider, { value }, children);
|
|
10
|
+
}
|
|
11
|
+
function useOptionalCustomFormsContext() {
|
|
12
|
+
return useContext(Ctx);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { CustomFormsProvider, useOptionalCustomFormsContext };
|
|
16
|
+
//# sourceMappingURL=chunk-66C3L4RE.js.map
|
|
17
|
+
//# sourceMappingURL=chunk-66C3L4RE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/context.tsx"],"names":[],"mappings":";;;AAWA,IAAM,GAAA,GAAM,cAA8C,IAAI,CAAA;AAEvD,SAAS,mBAAA,CAAoB;AAAA,EAClC,KAAA;AAAA,EACA;AACF,CAAA,EAGG;AACD,EAAA,OAAO,MAAM,aAAA,CAAc,GAAA,CAAI,UAAU,EAAE,KAAA,IAAS,QAAQ,CAAA;AAC9D;AASO,SAAS,6BAAA,GAAgE;AAC9E,EAAA,OAAO,WAAW,GAAG,CAAA;AACvB","file":"chunk-66C3L4RE.js","sourcesContent":["import React, { createContext, useContext } from 'react'\nimport type { CustomFormsConfig } from './config'\nimport type { FormsDataProvider } from '@fayz-ai/forms/data/provider'\nimport type { FormsStore } from '@fayz-ai/forms/store'\n\nexport interface CustomFormsContextValue {\n config: CustomFormsConfig\n provider: FormsDataProvider\n store: FormsStore\n}\n\nconst Ctx = createContext<CustomFormsContextValue | null>(null)\n\nexport function CustomFormsProvider({\n value,\n children,\n}: {\n value: CustomFormsContextValue\n children: React.ReactNode\n}) {\n return React.createElement(Ctx.Provider, { value }, children)\n}\n\nexport function useCustomFormsContext(): CustomFormsContextValue {\n const ctx = useContext(Ctx)\n if (!ctx) throw new Error('useCustomFormsContext must be used within CustomFormsProvider')\n return ctx\n}\n\n/** For pieces that may render outside the plugin page (builder preview, a host's own frame). */\nexport function useOptionalCustomFormsContext(): CustomFormsContextValue | null {\n return useContext(Ctx)\n}\n"]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// src/lib/agent-tools.ts
|
|
2
|
+
var CATEGORY_ENUM = ["anamnesis", "evolution", "report", "contract", "general"];
|
|
3
|
+
var FIELD_SHAPE = "A field object: { type, label, required?, placeholder?, options?[] }. type \u2208 title|text|memo|richtext|date|select|radio|tags|checkbox|image|gallery|budget (title = section heading, no input). options are plain strings, only for select/radio/tags.";
|
|
4
|
+
var createOrUpdateFormTool = {
|
|
5
|
+
id: "custom_forms.createOrUpdateForm",
|
|
6
|
+
name: "createOrUpdateForm",
|
|
7
|
+
description: "Creates or edits a form template (anamnese, contrato, ficha\u2026). Persisted server-side, so it works from ANY page \u2014 the user does NOT need the form builder open. Omit templateId to CREATE (name required); pass templateId to EDIT an existing form. Send the FULL desired field list in `fields` (replaces all fields), or `append_fields` to add to what already exists. Layout is automatic \u2014 never send positions. Understand the intent and propose a sensible field set in one call rather than asking field by field. The user confirms before it is saved.",
|
|
8
|
+
icon: "FileText",
|
|
9
|
+
mode: "persist",
|
|
10
|
+
limitKey: "form_templates",
|
|
11
|
+
permission: { feature: "custom_forms", action: "create" },
|
|
12
|
+
execution: { plane: "server", kind: "rpc", rpc: "agent_forms_upsert_template" },
|
|
13
|
+
category: "Forms",
|
|
14
|
+
suggestions: [
|
|
15
|
+
{ label: "Monte um formul\xE1rio de anamnese" },
|
|
16
|
+
{ label: "Adicione um campo de alergias neste formul\xE1rio" }
|
|
17
|
+
],
|
|
18
|
+
parameters: {
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {
|
|
21
|
+
templateId: {
|
|
22
|
+
type: "string",
|
|
23
|
+
description: "Existing form id to EDIT (from context or listFormTemplates). Omit to create a new form."
|
|
24
|
+
},
|
|
25
|
+
name: { type: "string", description: "Form name \u2014 required when creating." },
|
|
26
|
+
category: {
|
|
27
|
+
type: "string",
|
|
28
|
+
enum: [...CATEGORY_ENUM],
|
|
29
|
+
description: "anamnesis | evolution | report | contract | general"
|
|
30
|
+
},
|
|
31
|
+
description: { type: "string", description: "Optional short description of the form." },
|
|
32
|
+
fields: {
|
|
33
|
+
type: "array",
|
|
34
|
+
description: `The FULL desired field list \u2014 REPLACES every existing field. Each item: ${FIELD_SHAPE}`,
|
|
35
|
+
items: { type: "object", description: FIELD_SHAPE }
|
|
36
|
+
},
|
|
37
|
+
append_fields: {
|
|
38
|
+
type: "array",
|
|
39
|
+
description: `Fields to ADD to the existing form, keeping current ones. Use this for incremental edits instead of \`fields\`. Each item: ${FIELD_SHAPE}`,
|
|
40
|
+
items: { type: "object", description: FIELD_SHAPE }
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
var FORM_BUILDER_INSTRUCTIONS = [
|
|
46
|
+
"Voc\xEA est\xE1 na tela do CONSTRUTOR DE FORMUL\xC1RIOS. Para montar ou editar formul\xE1rios use a tool createOrUpdateForm (ela persiste no backend e funciona mesmo fora desta tela).",
|
|
47
|
+
"O formul\xE1rio aberto agora \u2014 id, nome, categoria e campos com seus ids \u2014 est\xE1 no JSON da tela em contexto.",
|
|
48
|
+
"Para EDITAR este formul\xE1rio, passe o templateId do contexto. Para adicionar campos mantendo os atuais, use append_fields; para redefinir tudo, use fields com a lista completa.",
|
|
49
|
+
"Ao criar do zero: entenda a inten\xE7\xE3o e proponha um conjunto de campos enxuto numa \xFAnica chamada (n\xE3o pergunte campo a campo). Depois confirme em uma frase o que foi montado.",
|
|
50
|
+
"Tipos de campo: title (cabe\xE7alho de se\xE7\xE3o, sem input), text, memo (multilinha), richtext, date, select, radio, tags, checkbox, image, gallery, budget. Layout \xE9 autom\xE1tico."
|
|
51
|
+
].join(" ");
|
|
52
|
+
|
|
53
|
+
export { FORM_BUILDER_INSTRUCTIONS, createOrUpdateFormTool };
|
|
54
|
+
//# sourceMappingURL=chunk-BFXJLPKA.js.map
|
|
55
|
+
//# sourceMappingURL=chunk-BFXJLPKA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/agent-tools.ts"],"names":[],"mappings":";AAaA,IAAM,gBAAgB,CAAC,WAAA,EAAa,WAAA,EAAa,QAAA,EAAU,YAAY,SAAS,CAAA;AAEhF,IAAM,WAAA,GACJ,6PAAA;AAIK,IAAM,sBAAA,GAAuC;AAAA,EAClD,EAAA,EAAI,iCAAA;AAAA,EACJ,IAAA,EAAM,oBAAA;AAAA,EACN,WAAA,EACE,mjBAAA;AAAA,EAIF,IAAA,EAAM,UAAA;AAAA,EACN,IAAA,EAAM,SAAA;AAAA,EACN,QAAA,EAAU,gBAAA;AAAA,EACV,UAAA,EAAY,EAAE,OAAA,EAAS,cAAA,EAAgB,QAAQ,QAAA,EAAS;AAAA,EACxD,WAAW,EAAE,KAAA,EAAO,UAAU,IAAA,EAAM,KAAA,EAAO,KAAK,6BAAA,EAA8B;AAAA,EAC9E,QAAA,EAAU,OAAA;AAAA,EACV,WAAA,EAAa;AAAA,IACX,EAAE,OAAO,oCAAA,EAAkC;AAAA,IAC3C,EAAE,OAAO,mDAAA;AAAiD,GAC5D;AAAA,EACA,UAAA,EAAY;AAAA,IACV,IAAA,EAAM,QAAA;AAAA,IACN,UAAA,EAAY;AAAA,MACV,UAAA,EAAY;AAAA,QACV,IAAA,EAAM,QAAA;AAAA,QACN,WAAA,EAAa;AAAA,OACf;AAAA,MACA,IAAA,EAAM,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,0CAAA,EAAsC;AAAA,MAC3E,QAAA,EAAU;AAAA,QACR,IAAA,EAAM,QAAA;AAAA,QACN,IAAA,EAAM,CAAC,GAAG,aAAa,CAAA;AAAA,QACvB,WAAA,EAAa;AAAA,OACf;AAAA,MACA,WAAA,EAAa,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,yCAAA,EAA0C;AAAA,MACtF,MAAA,EAAQ;AAAA,QACN,IAAA,EAAM,OAAA;AAAA,QACN,WAAA,EAAa,gFAA2E,WAAW,CAAA,CAAA;AAAA,QACnG,KAAA,EAAO,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,WAAA;AAAY,OACpD;AAAA,MACA,aAAA,EAAe;AAAA,QACb,IAAA,EAAM,OAAA;AAAA,QACN,WAAA,EAAa,8HAA8H,WAAW,CAAA,CAAA;AAAA,QACtJ,KAAA,EAAO,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,WAAA;AAAY;AACpD;AACF;AAEJ;AAEO,IAAM,yBAAA,GAA4B;AAAA,EACvC,yLAAA;AAAA,EACA,2HAAA;AAAA,EACA,oLAAA;AAAA,EACA,2LAAA;AAAA,EACA;AACF,CAAA,CAAE,KAAK,GAAG","file":"chunk-BFXJLPKA.js","sourcesContent":["import type { PluginAITool } from '@fayz-ai/core'\n\n/**\n * The assistant's form-building tool. It is a SERVER-PLANE write (a pool RPC),\n * not a client-side surface mutation — so it works from any page and any\n * channel (in-app FAB, WhatsApp, MCP), and persists straight to the tenant's\n * form templates. This is the same pattern agenda/financial/marketing use.\n *\n * The builder surface (see FormBuilder) still publishes CONTEXT — which form is\n * open and its current fields with ids — so \"add an allergies field to THIS\n * form\" resolves to the right template. But the action itself is this tool.\n */\n\nconst CATEGORY_ENUM = ['anamnesis', 'evolution', 'report', 'contract', 'general'] as const\n\nconst FIELD_SHAPE =\n 'A field object: { type, label, required?, placeholder?, options?[] }. ' +\n 'type ∈ title|text|memo|richtext|date|select|radio|tags|checkbox|image|gallery|budget ' +\n '(title = section heading, no input). options are plain strings, only for select/radio/tags.'\n\nexport const createOrUpdateFormTool: PluginAITool = {\n id: 'custom_forms.createOrUpdateForm',\n name: 'createOrUpdateForm',\n description:\n 'Creates or edits a form template (anamnese, contrato, ficha…). Persisted server-side, so it works from ANY page — the user does NOT need the form builder open. ' +\n 'Omit templateId to CREATE (name required); pass templateId to EDIT an existing form. ' +\n 'Send the FULL desired field list in `fields` (replaces all fields), or `append_fields` to add to what already exists. ' +\n 'Layout is automatic — never send positions. Understand the intent and propose a sensible field set in one call rather than asking field by field. The user confirms before it is saved.',\n icon: 'FileText',\n mode: 'persist',\n limitKey: 'form_templates',\n permission: { feature: 'custom_forms', action: 'create' },\n execution: { plane: 'server', kind: 'rpc', rpc: 'agent_forms_upsert_template' },\n category: 'Forms',\n suggestions: [\n { label: 'Monte um formulário de anamnese' },\n { label: 'Adicione um campo de alergias neste formulário' },\n ],\n parameters: {\n type: 'object',\n properties: {\n templateId: {\n type: 'string',\n description: 'Existing form id to EDIT (from context or listFormTemplates). Omit to create a new form.',\n },\n name: { type: 'string', description: 'Form name — required when creating.' },\n category: {\n type: 'string',\n enum: [...CATEGORY_ENUM],\n description: 'anamnesis | evolution | report | contract | general',\n },\n description: { type: 'string', description: 'Optional short description of the form.' },\n fields: {\n type: 'array',\n description: `The FULL desired field list — REPLACES every existing field. Each item: ${FIELD_SHAPE}`,\n items: { type: 'object', description: FIELD_SHAPE },\n },\n append_fields: {\n type: 'array',\n description: `Fields to ADD to the existing form, keeping current ones. Use this for incremental edits instead of \\`fields\\`. Each item: ${FIELD_SHAPE}`,\n items: { type: 'object', description: FIELD_SHAPE },\n },\n },\n },\n}\n\nexport const FORM_BUILDER_INSTRUCTIONS = [\n 'Você está na tela do CONSTRUTOR DE FORMULÁRIOS. Para montar ou editar formulários use a tool createOrUpdateForm (ela persiste no backend e funciona mesmo fora desta tela).',\n 'O formulário aberto agora — id, nome, categoria e campos com seus ids — está no JSON da tela em contexto.',\n 'Para EDITAR este formulário, passe o templateId do contexto. Para adicionar campos mantendo os atuais, use append_fields; para redefinir tudo, use fields com a lista completa.',\n 'Ao criar do zero: entenda a intenção e proponha um conjunto de campos enxuto numa única chamada (não pergunte campo a campo). Depois confirme em uma frase o que foi montado.',\n 'Tipos de campo: title (cabeçalho de seção, sem input), text, memo (multilinha), richtext, date, select, radio, tags, checkbox, image, gallery, budget. Layout é automático.',\n].join(' ')\n"]}
|