From ef55d9bb24430610b60c1b77821307cd72c08c55 Mon Sep 17 00:00:00 2001 From: zwlucas Date: Sat, 25 Jul 2026 18:23:29 -0300 Subject: feat: upload of the project Signed-off-by: zwlucas --- web/src/pages/DashboardPage.module.css | 160 +++++++++++++ web/src/pages/DashboardPage.tsx | 224 ++++++++++++++++++ web/src/pages/LoginPage.module.css | 125 ++++++++++ web/src/pages/LoginPage.tsx | 124 ++++++++++ web/src/pages/NewTicketPage.module.css | 88 +++++++ web/src/pages/NewTicketPage.tsx | 203 +++++++++++++++++ web/src/pages/SettingsPage.module.css | 111 +++++++++ web/src/pages/SettingsPage.tsx | 63 +++++ web/src/pages/TicketDetailPage.module.css | 263 +++++++++++++++++++++ web/src/pages/TicketDetailPage.tsx | 366 ++++++++++++++++++++++++++++++ web/src/pages/UsersPage.module.css | 121 ++++++++++ web/src/pages/UsersPage.tsx | 290 +++++++++++++++++++++++ 12 files changed, 2138 insertions(+) create mode 100644 web/src/pages/DashboardPage.module.css create mode 100644 web/src/pages/DashboardPage.tsx create mode 100644 web/src/pages/LoginPage.module.css create mode 100644 web/src/pages/LoginPage.tsx create mode 100644 web/src/pages/NewTicketPage.module.css create mode 100644 web/src/pages/NewTicketPage.tsx create mode 100644 web/src/pages/SettingsPage.module.css create mode 100644 web/src/pages/SettingsPage.tsx create mode 100644 web/src/pages/TicketDetailPage.module.css create mode 100644 web/src/pages/TicketDetailPage.tsx create mode 100644 web/src/pages/UsersPage.module.css create mode 100644 web/src/pages/UsersPage.tsx (limited to 'web/src/pages') diff --git a/web/src/pages/DashboardPage.module.css b/web/src/pages/DashboardPage.module.css new file mode 100644 index 0000000..59e1a73 --- /dev/null +++ b/web/src/pages/DashboardPage.module.css @@ -0,0 +1,160 @@ +.page { + display: flex; + flex-direction: column; + gap: var(--space-6); +} + +.pageHeader { + display: flex; + align-items: flex-end; + justify-content: space-between; +} + +.heading { + font-size: var(--text-2xl); + font-weight: 700; + color: var(--color-text-primary); + letter-spacing: -0.03em; +} + +.total { + font-size: var(--text-sm); + color: var(--color-text-muted); + margin-top: var(--space-1); +} + +/* ── KPI Cards ─────────────────────────────────────────────────────────────── */ +.kpiGrid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: var(--space-4); + margin-bottom: var(--space-2); +} + +.kpiCard { + background: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: var(--radius-lg); + padding: var(--space-4); + display: flex; + flex-direction: column; + gap: var(--space-1); +} + +.kpiLabel { + font-size: var(--text-xs); + font-weight: 600; + color: var(--color-text-muted); + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.kpiValue { + font-size: var(--text-3xl); + font-weight: 700; + color: var(--color-text-primary); + line-height: 1; +} + +/* ── Filtros ───────────────────────────────────────────────────────────────── */ +.filters { + display: flex; + align-items: center; + gap: var(--space-3); + flex-wrap: wrap; +} + +/* ── Grid de tickets ───────────────────────────────────────────────────────── */ +.grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); + gap: var(--space-4); +} + +/* ── Skeleton ──────────────────────────────────────────────────────────────── */ +.skeleton { + background: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: var(--radius-lg); + padding: var(--space-5); + display: flex; + flex-direction: column; + gap: var(--space-3); + overflow: hidden; +} + +.skeletonLine { + border-radius: var(--radius-sm); + background: linear-gradient( + 90deg, + var(--color-surface-2) 25%, + var(--color-border) 50%, + var(--color-surface-2) 75% + ); + background-size: 200% 100%; + animation: shimmer 1.5s infinite; +} + +@keyframes shimmer { + 0% { background-position: 200% 0; } + 100% { background-position: -200% 0; } +} + +/* ── Estado vazio ──────────────────────────────────────────────────────────── */ +.emptyState { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: var(--space-3); + padding: var(--space-16) var(--space-8); + text-align: center; +} + +.emptyTitle { + font-size: var(--text-lg); + font-weight: 600; + color: var(--color-text-secondary); +} + +.emptyMessage { + font-size: var(--text-sm); + color: var(--color-text-muted); +} + +/* ── Estado de erro ────────────────────────────────────────────────────────── */ +.errorState { + padding: var(--space-6); + background: rgba(248, 113, 113, 0.08); + border: 1px solid rgba(248, 113, 113, 0.25); + border-radius: var(--radius-lg); + text-align: center; +} + +.errorTitle { + font-weight: 600; + color: var(--color-priority-critical); + margin-bottom: var(--space-1); +} + +.errorMessage { + font-size: var(--text-sm); + color: var(--color-text-secondary); +} + +/* ── Paginação ─────────────────────────────────────────────────────────────── */ +.pagination { + display: flex; + align-items: center; + justify-content: center; + gap: var(--space-4); + padding-top: var(--space-4); + border-top: 1px solid var(--color-border); +} + +.pageInfo { + font-size: var(--text-sm); + color: var(--color-text-secondary); + min-width: 120px; + text-align: center; +} diff --git a/web/src/pages/DashboardPage.tsx b/web/src/pages/DashboardPage.tsx new file mode 100644 index 0000000..fa7c5b5 --- /dev/null +++ b/web/src/pages/DashboardPage.tsx @@ -0,0 +1,224 @@ +/** + * DashboardPage.tsx + * + * Painel de fila de tickets — visão principal do agente de TI. + * Exibe todos os chamados com filtros por status e prioridade. + */ + +import { useState } from 'react'; +import { useQuery } from '@tanstack/react-query'; +import { api, type TicketStatus, type TicketPriority } from '@/lib/api'; +import { TicketCard } from '@/components/tickets/TicketCard'; +import styles from './DashboardPage.module.css'; + +// ─── Opções dos filtros ─────────────────────────────────────────────────────── + +const STATUS_OPTIONS: { value: TicketStatus | ''; label: string }[] = [ + { value: '', label: 'Todos os status' }, + { value: 'open', label: '🔵 Abertos' }, + { value: 'in_progress', label: '🟣 Em Andamento' }, + { value: 'waiting', label: '🟡 Aguardando' }, + { value: 'resolved', label: '🟢 Resolvidos' }, + { value: 'closed', label: '⚫ Fechados' }, +]; + +const PRIORITY_OPTIONS: { value: TicketPriority | ''; label: string }[] = [ + { value: '', label: 'Todas as prioridades' }, + { value: 'critical', label: '⚡ Crítica' }, + { value: 'high', label: '↑ Alta' }, + { value: 'medium', label: '→ Média' }, + { value: 'low', label: '↓ Baixa' }, +]; + +// ─── Skeleton de carregamento ───────────────────────────────────────────────── + +function TicketSkeleton() { + return ( +