Files
sgse-app/apps/web/src/lib/components/chamados/TicketCard.svelte

107 lines
3.2 KiB
Svelte

<script lang="ts">
import type { Doc, Id } from '@sgse-app/backend/convex/_generated/dataModel';
import {
corPrazo,
formatarData,
getStatusBadge,
getStatusDescription,
getStatusLabel,
prazoRestante
} from '$lib/utils/chamados';
import { createEventDispatcher } from 'svelte';
type Ticket = Doc<'tickets'>;
interface Props {
ticket: Ticket;
selected?: boolean;
}
const dispatch = createEventDispatcher<{ select: { ticketId: Id<'tickets'> } }>();
const props: Props = $props();
const ticket = $derived(props.ticket);
const selected = $derived(props.selected ?? false);
const prioridadeClasses: Record<string, string> = {
baixa: 'badge badge-sm bg-base-200 text-base-content/70',
media: 'badge badge-sm badge-info badge-outline',
alta: 'badge badge-sm badge-warning',
critica: 'badge badge-sm badge-error'
};
function handleSelect() {
dispatch('select', { ticketId: ticket._id });
}
function getPrazoBadges() {
const badges: Array<{ label: string; classe: string }> = [];
if (ticket.prazoResposta) {
const cor = corPrazo(ticket.prazoResposta);
badges.push({
label: `Resposta ${prazoRestante(ticket.prazoResposta) ?? ''}`,
classe: `badge badge-xs ${
cor === 'error' ? 'badge-error' : cor === 'warning' ? 'badge-warning' : 'badge-success'
}`
});
}
if (ticket.prazoConclusao) {
const cor = corPrazo(ticket.prazoConclusao);
badges.push({
label: `Conclusão ${prazoRestante(ticket.prazoConclusao) ?? ''}`,
classe: `badge badge-xs ${
cor === 'error' ? 'badge-error' : cor === 'warning' ? 'badge-warning' : 'badge-success'
}`
});
}
return badges;
}
</script>
<article
class={`rounded-2xl border p-4 transition-all duration-200 ${
selected
? 'border-primary bg-primary/5 shadow-lg'
: 'border-base-200 bg-base-100/70 hover:border-primary/40 hover:shadow-md'
}`}
>
<button class="w-full text-left" type="button" onclick={handleSelect}>
<div class="flex items-start justify-between gap-3">
<div>
<p class="text-base-content/50 text-xs tracking-wide uppercase">
Ticket {ticket.numero}
</p>
<h3 class="text-base-content text-lg font-semibold">{ticket.titulo}</h3>
</div>
<span class={getStatusBadge(ticket.status)}>{getStatusLabel(ticket.status)}</span>
</div>
<p class="text-base-content/60 mt-2 line-clamp-2 text-sm">{ticket.descricao}</p>
<div class="text-base-content/60 mt-3 flex flex-wrap items-center gap-2 text-xs">
<span class={prioridadeClasses[ticket.prioridade] ?? 'badge badge-sm'}>
Prioridade {ticket.prioridade}
</span>
<span class="badge badge-xs badge-outline">
{ticket.tipo.charAt(0).toUpperCase() + ticket.tipo.slice(1)}
</span>
{#if ticket.setorResponsavel}
<span class="badge badge-xs badge-outline badge-ghost">
{ticket.setorResponsavel}
</span>
{/if}
</div>
<div class="text-base-content/50 mt-4 space-y-1 text-xs">
<p>
Última interação: {formatarData(ticket.ultimaInteracaoEm)}
</p>
<p>{getStatusDescription(ticket.status)}</p>
<div class="flex flex-wrap gap-2">
{#each getPrazoBadges() as badge (badge.label)}
<span class={badge.classe}>{badge.label}</span>
{/each}
</div>
</div>
</button>
</article>