refactor: update menu and routing for ticket management
- Replaced references to "Solicitar Acesso" with "Abrir Chamado" across the application for consistency in terminology. - Updated routing logic to reflect the new ticket management flow, ensuring that the dashboard and sidebar components point to the correct paths. - Removed the obsolete "Solicitar Acesso" page, streamlining the user experience and reducing unnecessary navigation options. - Enhanced backend schema to support new ticket functionalities, including ticket creation and management.
This commit is contained in:
107
apps/web/src/lib/components/chamados/TicketCard.svelte
Normal file
107
apps/web/src/lib/components/chamados/TicketCard.svelte
Normal file
@@ -0,0 +1,107 @@
|
||||
<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-xs uppercase tracking-wide text-base-content/50">
|
||||
Ticket {ticket.numero}
|
||||
</p>
|
||||
<h3 class="text-lg font-semibold text-base-content">{ticket.titulo}</h3>
|
||||
</div>
|
||||
<span class={getStatusBadge(ticket.status)}>{getStatusLabel(ticket.status)}</span>
|
||||
</div>
|
||||
|
||||
<p class="text-base-content/60 mt-2 text-sm line-clamp-2">{ticket.descricao}</p>
|
||||
|
||||
<div class="mt-3 flex flex-wrap items-center gap-2 text-xs text-base-content/60">
|
||||
<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="mt-4 space-y-1 text-xs text-base-content/50">
|
||||
<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>
|
||||
|
||||
Reference in New Issue
Block a user