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:
86
apps/web/src/lib/components/chamados/TicketTimeline.svelte
Normal file
86
apps/web/src/lib/components/chamados/TicketTimeline.svelte
Normal file
@@ -0,0 +1,86 @@
|
||||
<script lang="ts">
|
||||
import type { Doc } from "@sgse-app/backend/convex/_generated/dataModel";
|
||||
import {
|
||||
formatarData,
|
||||
formatarTimelineEtapa,
|
||||
prazoRestante,
|
||||
timelineStatus,
|
||||
} from "$lib/utils/chamados";
|
||||
|
||||
type Ticket = Doc<"tickets">;
|
||||
type TimelineEntry = NonNullable<Ticket["timeline"]>[number];
|
||||
|
||||
interface Props {
|
||||
timeline?: Array<TimelineEntry>;
|
||||
}
|
||||
|
||||
const props = $props<Props>();
|
||||
const timeline = $derived<Array<TimelineEntry>>(props.timeline ?? []);
|
||||
|
||||
const badgeClasses: Record<string, string> = {
|
||||
success: "bg-success/20 text-success border-success/40",
|
||||
warning: "bg-warning/20 text-warning border-warning/40",
|
||||
error: "bg-error/20 text-error border-error/40",
|
||||
info: "bg-info/20 text-info border-info/40",
|
||||
};
|
||||
|
||||
function getBadgeClass(entry: TimelineEntry) {
|
||||
const status = timelineStatus(entry);
|
||||
return badgeClasses[status] ?? badgeClasses.info;
|
||||
}
|
||||
|
||||
function getStatusLabel(entry: TimelineEntry) {
|
||||
if (entry.status === "concluido") return "Concluído";
|
||||
if (entry.status === "em_andamento") return "Em andamento";
|
||||
if (entry.status === "vencido") return "Vencido";
|
||||
return "Pendente";
|
||||
}
|
||||
|
||||
function getPrazoDescricao(entry: TimelineEntry) {
|
||||
if (entry.status === "concluido" && entry.concluidoEm) {
|
||||
return `Concluído em ${formatarData(entry.concluidoEm)}`;
|
||||
}
|
||||
if (!entry.prazo) return "Sem prazo definido";
|
||||
return `${formatarData(entry.prazo)} • ${prazoRestante(entry.prazo) ?? ""}`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="space-y-4">
|
||||
{#if timeline.length === 0}
|
||||
<div class="alert alert-info">
|
||||
<span>Nenhuma etapa registrada ainda.</span>
|
||||
</div>
|
||||
{:else}
|
||||
{#each timeline as entry (entry.etapa + entry.prazo)}
|
||||
<div class="flex gap-3">
|
||||
<div class="relative flex flex-col items-center">
|
||||
<div class={`badge border ${getBadgeClass(entry)}`}>
|
||||
{formatarTimelineEtapa(entry.etapa)}
|
||||
</div>
|
||||
{#if entry !== timeline[timeline.length - 1]}
|
||||
<div class="bg-base-200/80 mt-2 h-full w-px flex-1"></div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex-1 rounded-2xl border border-base-200 bg-base-100/80 p-4 shadow-sm">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<span class="text-sm font-semibold text-base-content">
|
||||
{getStatusLabel(entry)}
|
||||
</span>
|
||||
{#if entry.status !== "concluido" && entry.prazo}
|
||||
<span class="badge badge-sm badge-outline">
|
||||
{prazoRestante(entry.prazo)}
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
{#if entry.observacao}
|
||||
<p class="text-base-content/70 mt-2 text-sm">{entry.observacao}</p>
|
||||
{/if}
|
||||
<p class="text-base-content/50 mt-3 text-xs uppercase tracking-wide">
|
||||
{getPrazoDescricao(entry)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user