feat(anexos): página de galeria de comprovantes e documentos

Adiciona rota `/attachments` com visualização de todos os anexos do
usuário em grade, visualização inline de imagem e PDF, navegação entre
arquivos do mesmo lançamento e download direto.

Inclui também:
- API REST em `/api/attachments` para servir os arquivos
- Actions `fetch-by-id` e `fetch-dialog-options` em transactions
- Item "Anexos" adicionado à navbar
- `formatBytes` extraído para `src/shared/utils/number.ts`
- Migrations de banco atualizadas
- Fix: uploads e remoções de anexo agora funcionam para todos os
  lançamentos, não apenas os pertencentes a séries

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Felipe Coutinho
2026-04-01 14:13:54 +00:00
parent cad41680eb
commit 0ab3298cef
19 changed files with 3898 additions and 3095 deletions

View File

@@ -41,6 +41,7 @@ export function TransactionDetailsDialog({
}: TransactionDetailsDialogProps) {
const [attachmentCount, setAttachmentCount] = useState<number | null>(null);
// biome-ignore lint/correctness/useExhaustiveDependencies: transaction?.id é trigger intencional para reset do contador
useEffect(() => {
setAttachmentCount(null);
}, [transaction?.id]);
@@ -87,7 +88,7 @@ export function TransactionDetailsDialog({
<p className="text-xs uppercase tracking-wide text-muted-foreground">
Resumo
</p>
<p className="mt-1 text-2xl font-semibold">
<p className="mt-1 text-2xl font-medium">
{currencyFormatter.format(valorTotal)}
</p>
</div>
@@ -235,14 +236,14 @@ export function TransactionDetailsDialog({
<Separator />
<DialogFooter>
{onEdit && !transaction.readonly && (
<Button variant="outline" onClick={handleEdit}>
Editar
</Button>
)}
<DialogClose asChild>
<Button type="button">Fechar</Button>
<Button type="button" variant="outline">
Fechar
</Button>
</DialogClose>
{onEdit && !transaction.readonly && (
<Button onClick={handleEdit}>Editar</Button>
)}
</DialogFooter>
</DialogContent>
</Dialog>