feat: implement template retrieval by ID and enhance error handling in template display for improved user experience

This commit is contained in:
2025-12-01 19:54:33 -03:00
parent 8fabb4149c
commit 6e836e9eb5
3 changed files with 72 additions and 19 deletions

View File

@@ -3,6 +3,7 @@
import { api } from '@sgse-app/backend/convex/_generated/api'; import { api } from '@sgse-app/backend/convex/_generated/api';
import type { FunctionReference } from 'convex/server'; import type { FunctionReference } from 'convex/server';
import type { Id, Doc } from '@sgse-app/backend/convex/_generated/dataModel'; import type { Id, Doc } from '@sgse-app/backend/convex/_generated/dataModel';
import { resolve } from '$app/paths';
const client = useConvexClient(); const client = useConvexClient();
const currentUser = useQuery(api.auth.getCurrentUser as FunctionReference<'query'>); const currentUser = useQuery(api.auth.getCurrentUser as FunctionReference<'query'>);
@@ -191,7 +192,7 @@
<div class="card-body"> <div class="card-body">
<div class="mb-4 flex items-center justify-between"> <div class="mb-4 flex items-center justify-between">
<h2 class="card-title">Templates ({templatesFiltrados.length})</h2> <h2 class="card-title">Templates ({templatesFiltrados.length})</h2>
<a href="/ti/notificacoes/templates/novo" class="btn btn-primary gap-2"> <a href={resolve('/ti/notificacoes/templates/novo')} class="btn btn-primary gap-2">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5" class="h-5 w-5"
@@ -263,7 +264,7 @@
<td> <td>
<div class="flex gap-2"> <div class="flex gap-2">
<a <a
href="/ti/notificacoes/templates/{template._id}" href={resolve(`/ti/notificacoes/templates/${template._id}`)}
class="btn btn-sm btn-ghost" class="btn btn-sm btn-ghost"
title="Editar" title="Editar"
> >

View File

@@ -3,29 +3,51 @@
import { useConvexClient, useQuery } from 'convex-svelte'; import { useConvexClient, useQuery } from 'convex-svelte';
import { api } from '@sgse-app/backend/convex/_generated/api'; import { api } from '@sgse-app/backend/convex/_generated/api';
import type { FunctionReference } from 'convex/server'; import type { FunctionReference } from 'convex/server';
import type { Doc } from '@sgse-app/backend/convex/_generated/dataModel'; import type { Doc, Id } from '@sgse-app/backend/convex/_generated/dataModel';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { resolve } from '$app/paths'; import { resolve } from '$app/paths';
const client = useConvexClient(); const client = useConvexClient();
const currentUser = useQuery(api.auth.getCurrentUser as FunctionReference<'query'>); const currentUser = useQuery(api.auth.getCurrentUser as FunctionReference<'query'>);
const templatesQuery = useQuery(api.templatesMensagens.listarTemplates, {});
const templateIdParam = $derived($page.params.id ?? '');
const params = $derived($page.params);
const templateIdParam = $derived(params.id ?? ''); // Query específica para buscar o template por ID
const templateQuery = useQuery(
const templates = $derived.by(() => { api.templatesMensagens.obterTemplatePorId,
if (templatesQuery === undefined || templatesQuery === null) return []; () => {
if ('data' in templatesQuery && templatesQuery.data !== undefined) { if (!templateIdParam) return 'skip';
return Array.isArray(templatesQuery.data) ? templatesQuery.data : []; // Validar se o ID tem o formato correto do Convex
if (typeof templateIdParam === 'string' && templateIdParam.length > 0) {
return { templateId: templateIdParam as Id<'templatesMensagens'> };
}
return 'skip';
} }
if (Array.isArray(templatesQuery)) return templatesQuery; );
return [];
// Extrair template da query
const template = $derived.by(() => {
if (templateQuery === undefined || templateQuery === null) return null;
// useQuery retorna os dados diretamente
if (templateQuery && typeof templateQuery === 'object') {
// Se tem propriedade data, usar ela
if ('data' in templateQuery && templateQuery.data !== undefined && templateQuery.data !== null) {
return templateQuery.data as Doc<'templatesMensagens'> | null;
}
// Caso contrário, assumir que é o próprio template
if (!('data' in templateQuery)) {
return templateQuery as Doc<'templatesMensagens'> | null;
}
}
return null;
}); });
const template = $derived.by(() => { const carregandoTemplate = $derived(templateQuery === undefined || templateQuery === null);
const lista = templates as Doc<'templatesMensagens'>[]; const erroTemplate = $derived.by(() => {
return lista.find((t) => String(t._id) === templateIdParam) ?? null; if (templateQuery && typeof templateQuery === 'object' && 'error' in templateQuery) {
return templateQuery.error as Error | string | null;
}
return null;
}); });
let nome = $state(''); let nome = $state('');
@@ -143,9 +165,25 @@
<a href={resolve('/ti/notificacoes/templates')} class="btn btn-outline"> Voltar </a> <a href={resolve('/ti/notificacoes/templates')} class="btn btn-outline"> Voltar </a>
</div> </div>
{#if !template} {#if carregandoTemplate}
<div class="flex flex-col items-center justify-center gap-4 py-10">
<span class="loading loading-spinner loading-lg"></span>
<p class="text-base-content/60 text-sm">Carregando template...</p>
</div>
{:else if erroTemplate}
<div class="alert alert-error"> <div class="alert alert-error">
<span>Template não encontrado.</span> <span>Erro ao carregar template: {typeof erroTemplate === 'string' ? erroTemplate : erroTemplate?.message || 'Erro desconhecido'}</span>
<a href={resolve('/ti/notificacoes/templates')} class="btn btn-sm btn-outline">
Voltar para Templates
</a>
</div>
{:else if !template}
<div class="alert alert-error">
<span>Template não encontrado. Verifique se o ID está correto.</span>
<div class="text-xs mt-2 opacity-70">ID: {templateIdParam}</div>
<a href={resolve('/ti/notificacoes/templates')} class="btn btn-sm btn-outline mt-2">
Voltar para Templates
</a>
</div> </div>
{:else} {:else}
{#if mensagem} {#if mensagem}
@@ -279,6 +317,7 @@
{/if} {/if}
</button> </button>
</div> </div>
</div>
</div> </div>
{/if} {/if}
</div> </div>

View File

@@ -32,6 +32,19 @@ export const obterTemplatePorCodigo = query({
}, },
}); });
/**
* Obter template por ID
*/
export const obterTemplatePorId = query({
args: {
templateId: v.id("templatesMensagens"),
},
handler: async (ctx, args) => {
const template = await ctx.db.get(args.templateId);
return template;
},
});
/** /**
* Criar template customizado (apenas TI_MASTER) * Criar template customizado (apenas TI_MASTER)
*/ */