Refactor FileUpload component and improve type safety

- Rename imported File icon to FileIcon to avoid naming conflicts
- Update onUpload type to use globalThis.File
- Reformat loadExistingFile and related code for better readability
- Add stricter typing for funcionarioId and related data in documentos
  and editar pages
- Improve error handling and response validation in file upload logic
- Add keyed each blocks for better Svelte list rendering stability
- Fix minor formatting issues in breadcrumb links
This commit is contained in:
2025-11-13 00:12:16 -03:00
parent bd574aedc0
commit 4ffa403c46
3 changed files with 81 additions and 74 deletions

View File

@@ -11,15 +11,16 @@
categoriasDocumentos,
getDocumentosByCategoria
} from '$lib/utils/documentos';
import type { Id, Doc } from '@sgse-app/backend/convex/_generated/dataModel';
const client = useConvexClient();
let funcionarioId = $derived($page.params.funcionarioId as string);
let funcionarioId = $derived($page.params.funcionarioId as Id<'funcionarios'>);
let funcionario = $state<any>(null);
let funcionario = $state<Doc<'funcionarios'> | null>(null);
let documentosStorage = $state<Record<string, string | undefined>>({});
let loading = $state(true);
let filtro = $state<string>('todos'); // todos, enviados, pendentes
let filtro = $state<'todos' | 'enviados' | 'pendentes'>('todos'); // todos, enviados, pendentes
async function load() {
try {
@@ -27,7 +28,7 @@
// Carregar dados do funcionário
const data = await client.query(api.funcionarios.getById, {
id: funcionarioId as any
id: funcionarioId
});
if (!data) {
@@ -39,8 +40,10 @@
// Mapear storage IDs dos documentos
documentos.forEach((doc) => {
if ((data as any)[doc.campo]) {
documentosStorage[doc.campo] = (data as any)[doc.campo];
const campo = doc.campo as keyof Doc<'funcionarios'>;
const valor = data[campo];
if (typeof valor === 'string') {
documentosStorage[doc.campo] = valor;
}
});
} catch (err) {
@@ -63,13 +66,23 @@
body: file
});
const { storageId } = await result.json();
const uploadResponse = await result.json();
if (
!uploadResponse ||
typeof uploadResponse !== 'object' ||
!('storageId' in uploadResponse) ||
typeof uploadResponse.storageId !== 'string'
) {
throw new Error('Resposta inválida ao fazer upload');
}
const storageId = uploadResponse.storageId;
// Atualizar documento no funcionário
await client.mutation(api.documentos.updateDocumento, {
funcionarioId: funcionarioId as any,
funcionarioId,
campo,
storageId: storageId as any
storageId: storageId as Id<'_storage'>
});
// Atualizar localmente
@@ -77,8 +90,11 @@
// Recarregar
await load();
} catch (err: any) {
throw new Error(err?.message || 'Erro ao fazer upload');
} catch (err) {
if (err instanceof Error && err.message) {
throw err;
}
throw new Error('Erro ao fazer upload');
}
}
@@ -86,7 +102,7 @@
try {
// Atualizar documento no funcionário (set to null)
await client.mutation(api.documentos.updateDocumento, {
funcionarioId: funcionarioId as any,
funcionarioId,
campo,
storageId: null
});
@@ -96,8 +112,10 @@
// Recarregar
await load();
} catch (err: any) {
alert('Erro ao remover documento: ' + (err?.message || ''));
} catch (err) {
const mensagem =
err instanceof Error && err.message ? err.message : 'Erro ao remover documento';
alert('Erro ao remover documento: ' + mensagem);
}
}
@@ -130,7 +148,9 @@
<div class="breadcrumbs mb-4 text-sm">
<ul>
<li>
<a href={resolve('/recursos-humanos')} class="text-primary hover:underline">Recursos Humanos</a>
<a href={resolve('/recursos-humanos')} class="text-primary hover:underline"
>Recursos Humanos</a
>
</li>
<li>
<a href={resolve('/recursos-humanos/funcionarios')} class="text-primary hover:underline"
@@ -305,7 +325,7 @@
</div>
<!-- Documentos por Categoria -->
{#each categoriasDocumentos as categoria}
{#each categoriasDocumentos as categoria (categoria)}
{@const docsCategoria = getDocumentosByCategoria(categoria).filter((doc) => {
const temDocumento = !!documentosStorage[doc.campo];
if (filtro === 'enviados') return temDocumento;
@@ -322,7 +342,7 @@
</h2>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
{#each docsCategoria as doc}
{#each docsCategoria as doc (doc.campo)}
<FileUpload
label={doc.nome}
helpUrl={doc.helpUrl}

View File

@@ -483,7 +483,9 @@
<div class="breadcrumbs mb-4 text-sm">
<ul>
<li>
<a href={resolve('/recursos-humanos')} class="text-primary hover:underline">Recursos Humanos</a>
<a href={resolve('/recursos-humanos')} class="text-primary hover:underline"
>Recursos Humanos</a
>
</li>
<li>
<a href={resolve('/recursos-humanos/funcionarios')} class="text-primary hover:underline"