From 698f690315c25b3c2a68910c6a133816c2c6d326 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 12:57:58 -0300 Subject: [PATCH 01/32] =?UTF-8?q?Define=20Relat=C3=B3rios=20como=20p=C3=A1?= =?UTF-8?q?gina=20inicial=20ap=C3=B3s=20login?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/components/header/header.html | 13 ++++++------- src/app/pages/login/login.ts | 10 +++++----- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/app/components/header/header.html b/src/app/components/header/header.html index 92c2497..8407e71 100644 --- a/src/app/components/header/header.html +++ b/src/app/components/header/header.html @@ -8,7 +8,7 @@ - +
@@ -62,7 +62,7 @@ (click)="$event.stopPropagation()" >
- @@ -73,6 +73,10 @@
+ + Relatórios + + Geral @@ -96,10 +100,5 @@ Dados dos Usuários - - - - Relatórios -
diff --git a/src/app/pages/login/login.ts b/src/app/pages/login/login.ts index b9e6f67..52b8c48 100644 --- a/src/app/pages/login/login.ts +++ b/src/app/pages/login/login.ts @@ -117,18 +117,18 @@ export class LoginComponent { const nome = this.getNameFromToken(token); console.log('👤 Nome extraído:', nome); - console.log('🔄 Tentando ir para /geral...'); - this.router.navigate(['/geral'], { + console.log('🔄 Tentando ir para /relatorios...'); + this.router.navigate(['/relatorios'], { state: { toastMessage: `Bem-vindo, ${nome}!` } }).then(sucesso => { if (sucesso) console.log('✅ Navegação funcionou!'); - else console.error('❌ Navegação falhou! A rota "/geral" existe?'); + else console.error('❌ Navegação falhou! A rota "/relatorios" existe?'); }); } catch (e) { console.error('❌ Erro ao processar token ou navegar:', e); // Força a ida mesmo se o nome falhar - this.router.navigate(['/geral']); + this.router.navigate(['/relatorios']); } }, error: (err) => { @@ -145,4 +145,4 @@ export class LoginComponent { if (error) return control.touched && control.hasError(error); return !!(control.touched && control.invalid); } -} \ No newline at end of file +} From a73276211f5928f252d9d3fbac69df53e17db308 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 13:11:13 -0300 Subject: [PATCH 02/32] =?UTF-8?q?Refina=20estilo=20das=20tabelas=20de=20re?= =?UTF-8?q?lat=C3=B3rios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/pages/relatorios/relatorios.scss | 52 +++++++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/src/app/pages/relatorios/relatorios.scss b/src/app/pages/relatorios/relatorios.scss index 5c3a1f0..447fae8 100644 --- a/src/app/pages/relatorios/relatorios.scss +++ b/src/app/pages/relatorios/relatorios.scss @@ -299,21 +299,25 @@ /* Table */ .table-wrap { - padding: 10px 12px 14px; + padding: 12px 12px 16px; overflow-x: auto; + background: rgba(255, 255, 255, 0.7); + border-radius: 16px; + border: 1px solid rgba(0, 0, 0, 0.06); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.6); } .tablex { width: 100%; - border-collapse: collapse; + border-collapse: separate; + border-spacing: 0 8px; min-width: 720px; } .tablex th, .tablex td { - padding: 10px 10px; - border-bottom: 1px solid rgba(0, 0, 0, 0.06); - font-weight: 800; + padding: 12px 12px; + font-weight: 700; color: rgba(17, 18, 20, 0.8); text-align: left; white-space: nowrap; @@ -322,11 +326,47 @@ .tablex th { color: rgba(17, 18, 20, 0.65); font-size: 12px; + text-transform: uppercase; + letter-spacing: 0.04em; + padding-bottom: 6px; +} + +.tablex tbody tr { + background: #fff; + box-shadow: 0 8px 16px rgba(17, 18, 20, 0.06); + transition: transform 160ms ease, box-shadow 160ms ease; +} + +.tablex tbody tr:hover { + transform: translateY(-1px); + box-shadow: 0 12px 22px rgba(17, 18, 20, 0.12); +} + +.tablex tbody td { + border-top: 1px solid rgba(17, 18, 20, 0.06); + border-bottom: 1px solid rgba(17, 18, 20, 0.06); + background: rgba(255, 255, 255, 0.96); +} + +.tablex tbody td:first-child { + border-left: 1px solid rgba(17, 18, 20, 0.06); + border-top-left-radius: 12px; + border-bottom-left-radius: 12px; +} + +.tablex tbody td:last-child { + border-right: 1px solid rgba(17, 18, 20, 0.06); + border-top-right-radius: 12px; + border-bottom-right-radius: 12px; +} + +.tablex tbody tr:nth-child(even) td { + background: rgba(248, 249, 255, 0.9); } .muted { color: rgba(17, 18, 20, 0.55); - font-weight: 800; + font-weight: 700; } .cell-strong { From 0f950d9d4d458a4b998f7cc8771d29923a578738 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 13:27:40 -0300 Subject: [PATCH 03/32] =?UTF-8?q?Alinha=20paleta=20dos=20gr=C3=A1ficos=20a?= =?UTF-8?q?os=20tons=20do=20sistema?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/pages/relatorios/relatorios.scss | 26 ++++++-- src/app/pages/relatorios/relatorios.ts | 81 ++++++++++++++---------- 2 files changed, 68 insertions(+), 39 deletions(-) diff --git a/src/app/pages/relatorios/relatorios.scss b/src/app/pages/relatorios/relatorios.scss index 447fae8..a2546d1 100644 --- a/src/app/pages/relatorios/relatorios.scss +++ b/src/app/pages/relatorios/relatorios.scss @@ -2,6 +2,18 @@ display: block; width: 100%; overflow-x: hidden; + --brand-primary: #E33DCF; + --brand-blue: #030FAA; + --brand-deep: #B832A8; + --brand-violet: #6A55FF; + --brand-soft: rgba(227, 61, 207, 0.2); + --brand-blue-soft: rgba(3, 15, 170, 0.2); + --chart-pink: var(--brand-primary); + --chart-pink-dark: var(--brand-deep); + --chart-pink-soft: #F3B0E8; + --chart-blue: var(--brand-blue); + --chart-blue-soft: var(--brand-blue-soft); + --chart-violet: var(--brand-violet); } /* ✅ remove footer nessa página */ @@ -239,7 +251,7 @@ /* se quiser tirar o rosa do total, troque aqui */ .metric.total .meta .v { - color: #ff2d95; + color: var(--chart-pink); } .dot { @@ -250,12 +262,12 @@ } /* ✅ DOTS COM CORES "PADRÃO DE DASHBOARD" */ -.dot.d1 { background: #ff2d95; } /* total (mantém rosa no card de total, se você quiser) */ -.dot.d2 { background: #2E7D32; } /* Ativos - verde */ -.dot.d3 { background: #D32F2F; } /* Perda/Roubo - vermelho */ -.dot.d4 { background: #F57C00; } /* 120 dias - laranja */ -.dot.d5 { background: #1976D2; } /* Reservas - azul */ -.dot.d6 { background: #607D8B; } /* Outros - cinza */ +.dot.d1 { background: var(--chart-pink); } +.dot.d2 { background: var(--chart-blue); } +.dot.d3 { background: var(--chart-pink-dark); } +.dot.d4 { background: var(--chart-violet); } +.dot.d5 { background: var(--chart-pink-soft); } +.dot.d6 { background: var(--chart-blue-soft); } .meta .k { font-weight: 900; diff --git a/src/app/pages/relatorios/relatorios.ts b/src/app/pages/relatorios/relatorios.ts index 39e6358..ee40fce 100644 --- a/src/app/pages/relatorios/relatorios.ts +++ b/src/app/pages/relatorios/relatorios.ts @@ -164,26 +164,10 @@ export class Relatorios implements OnInit, AfterViewInit, OnDestroy { private readonly baseApi: string; - // ✅ Paletas "padrão de dashboard" (fácil de entender) - private readonly STATUS_COLORS = { - ativos: '#2E7D32', // verde - perdaRoubo: '#D32F2F', // vermelho - bloq120: '#F57C00', // laranja - reservas: '#1976D2', // azul - outros: '#607D8B', // cinza - }; - - private readonly VIG_COLORS = { - vencidos: '#D32F2F', // vermelho - d0a30: '#F57C00', // laranja - d31a60: '#FBC02D', // amarelo - d61a90: '#1976D2', // azul - acima90: '#2E7D32', // verde - }; - constructor( private http: HttpClient, - @Inject(PLATFORM_ID) private platformId: object + @Inject(PLATFORM_ID) private platformId: object, + private hostRef: ElementRef ) { const raw = (environment.apiUrl || 'https://localhost:7205').replace(/\/+$/, ''); this.baseApi = raw.toLowerCase().endsWith('/api') ? raw : `${raw}/api`; @@ -299,7 +283,9 @@ export class Relatorios implements OnInit, AfterViewInit, OnDestroy { this.destroyCharts(); - // ✅ Status das linhas (paleta padrão) + const palette = this.getPalette(); + + // ✅ Status das linhas (paleta do sistema) const cP = this.chartStatusPie?.nativeElement; if (cP) { this.chartPie = new Chart(cP, { @@ -322,11 +308,11 @@ export class Relatorios implements OnInit, AfterViewInit, OnDestroy { ], borderWidth: 1, backgroundColor: [ - this.STATUS_COLORS.ativos, - this.STATUS_COLORS.perdaRoubo, - this.STATUS_COLORS.bloq120, - this.STATUS_COLORS.reservas, - this.STATUS_COLORS.outros, + palette.status.ativos, + palette.status.perdaRoubo, + palette.status.bloq120, + palette.status.reservas, + palette.status.outros, ], }], }, @@ -355,7 +341,7 @@ export class Relatorios implements OnInit, AfterViewInit, OnDestroy { label: 'Encerramentos', data: this.vigenciaValues, borderWidth: 0, - backgroundColor: '#1976D2', // azul padrão + backgroundColor: palette.series.vigencia, borderRadius: 10, }], }, @@ -388,11 +374,11 @@ export class Relatorios implements OnInit, AfterViewInit, OnDestroy { ], borderWidth: 1, backgroundColor: [ - this.VIG_COLORS.vencidos, - this.VIG_COLORS.d0a30, - this.VIG_COLORS.d31a60, - this.VIG_COLORS.d61a90, - this.VIG_COLORS.acima90, + palette.vigencia.vencidos, + palette.vigencia.d0a30, + palette.vigencia.d31a60, + palette.vigencia.d61a90, + palette.vigencia.acima90, ], }], }, @@ -421,7 +407,7 @@ export class Relatorios implements OnInit, AfterViewInit, OnDestroy { label: 'MUREG', data: this.muregValues, borderWidth: 0, - backgroundColor: '#6A1B9A', // roxo (bem comum em dashboards) + backgroundColor: palette.series.mureg, borderRadius: 10, }], }, @@ -448,7 +434,7 @@ export class Relatorios implements OnInit, AfterViewInit, OnDestroy { label: 'Troca', data: this.trocaValues, borderWidth: 0, - backgroundColor: '#00897B', // teal (bem comum) + backgroundColor: palette.series.troca, borderRadius: 10, }], }, @@ -482,4 +468,35 @@ export class Relatorios implements OnInit, AfterViewInit, OnDestroy { private formatInt(v: number) { return (v || 0).toLocaleString('pt-BR'); } + + private getPalette() { + return { + status: { + ativos: this.readCssVar('--chart-blue', '#030FAA'), + perdaRoubo: this.readCssVar('--chart-pink-dark', '#B832A8'), + bloq120: this.readCssVar('--chart-violet', '#6A55FF'), + reservas: this.readCssVar('--chart-pink-soft', '#F3B0E8'), + outros: this.readCssVar('--chart-blue-soft', 'rgba(3, 15, 170, 0.2)'), + }, + vigencia: { + vencidos: this.readCssVar('--chart-pink', '#E33DCF'), + d0a30: this.readCssVar('--chart-violet', '#6A55FF'), + d31a60: this.readCssVar('--chart-blue', '#030FAA'), + d61a90: this.readCssVar('--chart-pink-dark', '#B832A8'), + acima90: this.readCssVar('--chart-pink-soft', '#F3B0E8'), + }, + series: { + vigencia: this.readCssVar('--chart-blue', '#030FAA'), + mureg: this.readCssVar('--chart-pink', '#E33DCF'), + troca: this.readCssVar('--chart-violet', '#6A55FF'), + }, + }; + } + + private readCssVar(name: string, fallback: string) { + if (!isPlatformBrowser(this.platformId)) return fallback; + const styles = getComputedStyle(this.hostRef.nativeElement); + const value = styles.getPropertyValue(name).trim(); + return value || fallback; + } } From e1744bb20256869e95e4c5007557a8c19ab7e329 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 13:33:16 -0300 Subject: [PATCH 04/32] Remove faixa promocional do header na home --- src/app/components/header/header.html | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/app/components/header/header.html b/src/app/components/header/header.html index 8407e71..97763e0 100644 --- a/src/app/components/header/header.html +++ b/src/app/components/header/header.html @@ -45,10 +45,6 @@ - -
- Somos a escolha certa para estar sempre conectado! -
From c9c2f2fffb563ef0749a7d5f1059d66ee956a385 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 14:03:58 -0300 Subject: [PATCH 05/32] =?UTF-8?q?Renomeia=20Relat=C3=B3rios=20para=20Dashb?= =?UTF-8?q?oard=20e=20adiciona=20menu=20de=20op=C3=A7=C3=B5es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/app.routes.ts | 8 +- src/app/app.ts | 2 +- src/app/components/header/header.html | 63 +++++++--- src/app/components/header/header.scss | 117 ++++++++++++++++-- src/app/components/header/header.ts | 26 +++- .../dashboard.html} | 4 +- .../dashboard.scss} | 2 +- .../relatorios.ts => dashboard/dashboard.ts} | 20 +-- src/app/pages/login/login.ts | 8 +- 9 files changed, 200 insertions(+), 50 deletions(-) rename src/app/pages/{relatorios/relatorios.html => dashboard/dashboard.html} (98%) rename src/app/pages/{relatorios/relatorios.scss => dashboard/dashboard.scss} (99%) rename src/app/pages/{relatorios/relatorios.ts => dashboard/dashboard.ts} (96%) diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 06022b9..5d2acd6 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -11,7 +11,7 @@ import { authGuard } from './guards/auth.guard'; import { DadosUsuarios } from './pages/dados-usuarios/dados-usuarios'; import { VigenciaComponent } from './pages/vigencia/vigencia'; import { TrocaNumero } from './pages/troca-numero/troca-numero'; -import { Relatorios } from './pages/relatorios/relatorios'; +import { Dashboard } from './pages/dashboard/dashboard'; export const routes: Routes = [ { path: '', component: Home }, @@ -26,10 +26,10 @@ export const routes: Routes = [ { path: 'trocanumero', component: TrocaNumero, canActivate: [authGuard] }, // ✅ rota correta - { path: 'relatorios', component: Relatorios, canActivate: [authGuard] }, + { path: 'dashboard', component: Dashboard, canActivate: [authGuard] }, - // ✅ compatibilidade: se alguém acessar /portal/relatorios, manda pra /relatorios - { path: 'portal/relatorios', redirectTo: 'relatorios', pathMatch: 'full' }, + // ✅ compatibilidade: se alguém acessar /portal/dashboard, manda pra /dashboard + { path: 'portal/dashboard', redirectTo: 'dashboard', pathMatch: 'full' }, { path: '**', redirectTo: '' }, ]; diff --git a/src/app/app.ts b/src/app/app.ts index f4b13c7..93920fa 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -33,7 +33,7 @@ export class AppComponent { '/dadosusuarios', '/vigencia', '/trocanumero', - '/relatorios', // ✅ ADICIONADO: esconde footer na página de relatórios + '/dashboard', // ✅ ADICIONADO: esconde footer na página de dashboard ]; constructor( diff --git a/src/app/components/header/header.html b/src/app/components/header/header.html index 97763e0..81d7242 100644 --- a/src/app/components/header/header.html +++ b/src/app/components/header/header.html @@ -3,19 +3,54 @@ -
- +
+
+ - - + +
+ + + LIVE + + + + +
+ + +
+ + Perfil + + +
-
- LineGestão -
- +
@@ -58,7 +93,7 @@ (click)="$event.stopPropagation()" >
- @@ -69,8 +104,8 @@
- - Relatórios + + Dashboard diff --git a/src/app/components/header/header.scss b/src/app/components/header/header.scss index 0275bf3..d9449af 100644 --- a/src/app/components/header/header.scss +++ b/src/app/components/header/header.scss @@ -30,6 +30,20 @@ gap: 12px; } +.logged-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + width: 100%; +} + +.logged-actions { + display: flex; + align-items: center; + gap: 10px; +} + /* Logo */ .logo-area { display: flex; @@ -123,22 +137,99 @@ } } -/* Faixa home */ -.header-bar { - margin-top: 10px; - width: 100%; - height: 34px; - display: flex; +/* ✅ Status e opções (logado) */ +.status-pill { + display: inline-flex; align-items: center; - justify-content: center; - background: linear-gradient(90deg, #0B2BD6 0%, #6A55FF 40%, #E33DCF 100%); + gap: 8px; + padding: 6px 12px; + border-radius: 999px; + background: rgba(16, 185, 129, 0.12); + color: #0f766e; + font-weight: 800; + font-size: 12px; + letter-spacing: 0.06em; } -.header-bar-text { - color: #ffffff; - font-size: 15px; - font-weight: 800; - font-family: 'Poppins', sans-serif; +.status-dot { + width: 10px; + height: 10px; + border-radius: 50%; + background: #22c55e; + box-shadow: 0 0 0 4px rgba(34, 197, 94, 0.18); +} + +.btn-bell { + width: 42px; + height: 42px; + border-radius: 12px; + + i { + font-size: 18px; + } +} + +.options-menu { + position: relative; + display: flex; + align-items: center; +} + +.options-trigger { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 8px 14px; + border-radius: 12px; + border: 1px solid rgba(0,0,0,0.1); + background: #fff; + font-weight: 700; + color: var(--text-main); + cursor: pointer; + transition: border-color 0.2s ease, box-shadow 0.2s ease; + + i { + font-size: 12px; + } + + &:hover { + border-color: rgba(227, 61, 207, 0.35); + box-shadow: 0 12px 22px rgba(0,0,0,0.08); + } +} + +.options-dropdown { + position: absolute; + right: 0; + top: calc(100% + 8px); + min-width: 200px; + padding: 8px 0; + border-radius: 14px; + border: 1px solid rgba(0,0,0,0.08); + background: #fff; + box-shadow: 0 18px 40px rgba(0,0,0,0.12); + z-index: 1200; +} + +.options-item { + display: flex; + align-items: center; + width: 100%; + padding: 10px 16px; + font-weight: 700; + color: rgba(17, 18, 20, 0.85); + text-decoration: none; + background: transparent; + border: none; + cursor: pointer; + + &:hover { + background: rgba(227, 61, 207, 0.08); + } + + &.danger { + color: #c2410c; + } } /* ========================= */ diff --git a/src/app/components/header/header.ts b/src/app/components/header/header.ts index ebbc5ba..37c52b5 100644 --- a/src/app/components/header/header.ts +++ b/src/app/components/header/header.ts @@ -3,6 +3,7 @@ import { RouterLink, Router, NavigationEnd } from '@angular/router'; import { CommonModule, isPlatformBrowser } from '@angular/common'; import { PLATFORM_ID } from '@angular/core'; import { filter } from 'rxjs/operators'; +import { AuthService } from '../../services/auth.service'; @Component({ selector: 'app-header', @@ -15,6 +16,7 @@ export class Header { isScrolled = false; menuOpen = false; + optionsOpen = false; isLoggedHeader = false; isHome = false; @@ -25,11 +27,12 @@ export class Header { '/dadosusuarios', '/vigencia', '/trocanumero', - '/relatorios', // ✅ ADICIONADO + '/dashboard', // ✅ ADICIONADO ]; constructor( private router: Router, + private authService: AuthService, @Inject(PLATFORM_ID) private platformId: object ) { // ✅ resolve no carregamento inicial @@ -42,6 +45,7 @@ export class Header { const rawUrl = event.urlAfterRedirects || event.url; this.syncHeaderState(rawUrl); this.menuOpen = false; + this.optionsOpen = false; }); } @@ -63,15 +67,35 @@ export class Header { this.menuOpen = false; } + toggleOptions() { + this.optionsOpen = !this.optionsOpen; + } + + closeOptions() { + this.optionsOpen = false; + } + + logout() { + this.authService.logout(); + this.optionsOpen = false; + this.router.navigate(['/']); + } + @HostListener('window:scroll', []) onWindowScroll() { if (!isPlatformBrowser(this.platformId)) return; this.isScrolled = window.scrollY > 10; } + @HostListener('document:click', []) + onDocumentClick() { + this.optionsOpen = false; + } + @HostListener('document:keydown.escape', []) onEsc() { if (!isPlatformBrowser(this.platformId)) return; this.closeMenu(); + this.closeOptions(); } } diff --git a/src/app/pages/relatorios/relatorios.html b/src/app/pages/dashboard/dashboard.html similarity index 98% rename from src/app/pages/relatorios/relatorios.html rename to src/app/pages/dashboard/dashboard.html index 5088116..35a2e2e 100644 --- a/src/app/pages/relatorios/relatorios.html +++ b/src/app/pages/dashboard/dashboard.html @@ -1,10 +1,10 @@ -
+
- Relatórios + Dashboard

Resumo e indicadores do ambiente.

diff --git a/src/app/pages/relatorios/relatorios.scss b/src/app/pages/dashboard/dashboard.scss similarity index 99% rename from src/app/pages/relatorios/relatorios.scss rename to src/app/pages/dashboard/dashboard.scss index a2546d1..18a401f 100644 --- a/src/app/pages/relatorios/relatorios.scss +++ b/src/app/pages/dashboard/dashboard.scss @@ -24,7 +24,7 @@ display: none !important; } -.relatorios-page { +.dashboard-page { width: 100%; overflow-x: hidden; } diff --git a/src/app/pages/relatorios/relatorios.ts b/src/app/pages/dashboard/dashboard.ts similarity index 96% rename from src/app/pages/relatorios/relatorios.ts rename to src/app/pages/dashboard/dashboard.ts index ee40fce..ae3ad0f 100644 --- a/src/app/pages/relatorios/relatorios.ts +++ b/src/app/pages/dashboard/dashboard.ts @@ -88,7 +88,7 @@ type DashboardKpisDto = { userDataComEmail: number; }; -type RelatoriosDashboardDto = { +type DashboardDto = { kpis: DashboardKpisDto; topClientes: TopClienteDto[]; @@ -105,13 +105,13 @@ type RelatoriosDashboardDto = { }; @Component({ - selector: 'app-relatorios', + selector: 'app-dashboard', standalone: true, imports: [CommonModule], - templateUrl: './relatorios.html', - styleUrls: ['./relatorios.scss'], + templateUrl: './dashboard.html', + styleUrls: ['./dashboard.scss'], }) -export class Relatorios implements OnInit, AfterViewInit, OnDestroy { +export class Dashboard implements OnInit, AfterViewInit, OnDestroy { @ViewChild('chartMureg12') chartMureg12?: ElementRef; @ViewChild('chartTroca12') chartTroca12?: ElementRef; @ViewChild('chartStatusPie') chartStatusPie?: ElementRef; @@ -202,17 +202,17 @@ export class Relatorios implements OnInit, AfterViewInit, OnDestroy { } catch { this.loading = false; this.errorMsg = - 'Falha ao carregar Relatórios. Verifique se a API está rodando e o endpoint /api/relatorios/dashboard está acessível.'; + 'Falha ao carregar Dashboard. Verifique se a API está rodando e o endpoint /api/dashboard está acessível.'; } } - private async fetchDashboardReal(): Promise { + private async fetchDashboardReal(): Promise { if (!isPlatformBrowser(this.platformId)) throw new Error('SSR não suportado para charts'); - const url = `${this.baseApi}/relatorios/dashboard`; - return await firstValueFrom(this.http.get(url)); + const url = `${this.baseApi}/dashboard`; + return await firstValueFrom(this.http.get(url)); } - private applyDto(dto: RelatoriosDashboardDto) { + private applyDto(dto: DashboardDto) { const k = dto.kpis; this.kpis = [ diff --git a/src/app/pages/login/login.ts b/src/app/pages/login/login.ts index 52b8c48..34ef817 100644 --- a/src/app/pages/login/login.ts +++ b/src/app/pages/login/login.ts @@ -117,18 +117,18 @@ export class LoginComponent { const nome = this.getNameFromToken(token); console.log('👤 Nome extraído:', nome); - console.log('🔄 Tentando ir para /relatorios...'); - this.router.navigate(['/relatorios'], { + console.log('🔄 Tentando ir para /dashboard...'); + this.router.navigate(['/dashboard'], { state: { toastMessage: `Bem-vindo, ${nome}!` } }).then(sucesso => { if (sucesso) console.log('✅ Navegação funcionou!'); - else console.error('❌ Navegação falhou! A rota "/relatorios" existe?'); + else console.error('❌ Navegação falhou! A rota "/dashboard" existe?'); }); } catch (e) { console.error('❌ Erro ao processar token ou navegar:', e); // Força a ida mesmo se o nome falhar - this.router.navigate(['/relatorios']); + this.router.navigate(['/dashboard']); } }, error: (err) => { From 6c243ef2c5fadd28eba8af5ce420ac9cfe82d08e Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 14:11:59 -0300 Subject: [PATCH 06/32] =?UTF-8?q?Restaura=20endpoint=20de=20relat=C3=B3rio?= =?UTF-8?q?s=20no=20dashboard?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/pages/dashboard/dashboard.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/pages/dashboard/dashboard.ts b/src/app/pages/dashboard/dashboard.ts index ae3ad0f..d059397 100644 --- a/src/app/pages/dashboard/dashboard.ts +++ b/src/app/pages/dashboard/dashboard.ts @@ -202,13 +202,13 @@ export class Dashboard implements OnInit, AfterViewInit, OnDestroy { } catch { this.loading = false; this.errorMsg = - 'Falha ao carregar Dashboard. Verifique se a API está rodando e o endpoint /api/dashboard está acessível.'; + 'Falha ao carregar Dashboard. Verifique se a API está rodando e o endpoint /api/relatorios/dashboard está acessível.'; } } private async fetchDashboardReal(): Promise { if (!isPlatformBrowser(this.platformId)) throw new Error('SSR não suportado para charts'); - const url = `${this.baseApi}/dashboard`; + const url = `${this.baseApi}/relatorios/dashboard`; return await firstValueFrom(this.http.get(url)); } From 1eac19177c76d5cb2af2c674453043df302948e1 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 14:53:02 -0300 Subject: [PATCH 07/32] =?UTF-8?q?Remove=20status=20LIVE=20e=20ajusta=20a?= =?UTF-8?q?=C3=A7=C3=A3o=20de=20Perfil?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/components/header/header.html | 9 ++------- src/app/components/header/header.scss | 22 +--------------------- 2 files changed, 3 insertions(+), 28 deletions(-) diff --git a/src/app/components/header/header.html b/src/app/components/header/header.html index 81d7242..ce0151e 100644 --- a/src/app/components/header/header.html +++ b/src/app/components/header/header.html @@ -20,11 +20,6 @@
- - - LIVE - - @@ -42,9 +37,9 @@
- + diff --git a/src/app/components/header/header.scss b/src/app/components/header/header.scss index d9449af..512248e 100644 --- a/src/app/components/header/header.scss +++ b/src/app/components/header/header.scss @@ -137,27 +137,7 @@ } } -/* ✅ Status e opções (logado) */ -.status-pill { - display: inline-flex; - align-items: center; - gap: 8px; - padding: 6px 12px; - border-radius: 999px; - background: rgba(16, 185, 129, 0.12); - color: #0f766e; - font-weight: 800; - font-size: 12px; - letter-spacing: 0.06em; -} - -.status-dot { - width: 10px; - height: 10px; - border-radius: 50%; - background: #22c55e; - box-shadow: 0 0 0 4px rgba(34, 197, 94, 0.18); -} +/* ✅ Opções (logado) */ .btn-bell { width: 42px; From 29348e54ae1bac0632eb766d7496ec2a46a6a51e Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 15:34:00 -0300 Subject: [PATCH 08/32] =?UTF-8?q?Adiciona=20notifica=C3=A7=C3=B5es=20no=20?= =?UTF-8?q?header=20e=20p=C3=A1gina=20dedicada?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/app.routes.ts | 2 + src/app/app.ts | 1 + src/app/components/header/header.html | 46 ++++++- src/app/components/header/header.scss | 120 +++++++++++++++++ src/app/components/header/header.ts | 54 ++++++++ src/app/pages/notificacoes/notificacoes.html | 41 ++++++ src/app/pages/notificacoes/notificacoes.scss | 130 +++++++++++++++++++ src/app/pages/notificacoes/notificacoes.ts | 48 +++++++ src/app/services/notifications.service.ts | 37 ++++++ 9 files changed, 476 insertions(+), 3 deletions(-) create mode 100644 src/app/pages/notificacoes/notificacoes.html create mode 100644 src/app/pages/notificacoes/notificacoes.scss create mode 100644 src/app/pages/notificacoes/notificacoes.ts create mode 100644 src/app/services/notifications.service.ts diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 5d2acd6..a6ea6af 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -12,6 +12,7 @@ import { DadosUsuarios } from './pages/dados-usuarios/dados-usuarios'; import { VigenciaComponent } from './pages/vigencia/vigencia'; import { TrocaNumero } from './pages/troca-numero/troca-numero'; import { Dashboard } from './pages/dashboard/dashboard'; +import { Notificacoes } from './pages/notificacoes/notificacoes'; export const routes: Routes = [ { path: '', component: Home }, @@ -24,6 +25,7 @@ export const routes: Routes = [ { path: 'dadosusuarios', component: DadosUsuarios, canActivate: [authGuard] }, { path: 'vigencia', component: VigenciaComponent, canActivate: [authGuard] }, { path: 'trocanumero', component: TrocaNumero, canActivate: [authGuard] }, + { path: 'notificacoes', component: Notificacoes, canActivate: [authGuard] }, // ✅ rota correta { path: 'dashboard', component: Dashboard, canActivate: [authGuard] }, diff --git a/src/app/app.ts b/src/app/app.ts index 93920fa..021813a 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -34,6 +34,7 @@ export class AppComponent { '/vigencia', '/trocanumero', '/dashboard', // ✅ ADICIONADO: esconde footer na página de dashboard + '/notificacoes', ]; constructor( diff --git a/src/app/components/header/header.html b/src/app/components/header/header.html index ce0151e..de807c6 100644 --- a/src/app/components/header/header.html +++ b/src/app/components/header/header.html @@ -20,9 +20,49 @@
- +
+ + +
+
+ Notificações + Ver todas +
+ +
+
+ Carregando... +
+
+ Falha ao carregar notificações. +
+
+ Nenhuma notificação por aqui. +
+ +
+ + {{ n.tipo === 'Vencido' ? 'Vencido' : 'A vencer' }} + +
{{ n.titulo }}
+
{{ n.mensagem }}
+ +
+
+
+
+
+ +
+
+
+
diff --git a/src/app/pages/notificacoes/notificacoes.scss b/src/app/pages/notificacoes/notificacoes.scss new file mode 100644 index 0000000..e2455b8 --- /dev/null +++ b/src/app/pages/notificacoes/notificacoes.scss @@ -0,0 +1,130 @@ +:host { + display: block; +} + +.notificacoes-page { + width: 100%; +} + +.wrap { + padding: 24px 0 32px; +} + +.container { + width: 100%; + max-width: 1100px; + margin: 0 auto; + padding: 0 16px; +} + +.page-head { + display: flex; + align-items: flex-end; + justify-content: space-between; + margin-bottom: 20px; + + h2 { + font-size: 24px; + font-weight: 800; + margin: 0 0 4px; + } + + p { + margin: 0; + color: rgba(17, 18, 20, 0.6); + font-weight: 600; + } +} + +.state { + padding: 12px 14px; + border-radius: 12px; + background: rgba(255, 255, 255, 0.7); + border: 1px solid rgba(0,0,0,0.08); + font-weight: 700; + color: rgba(17, 18, 20, 0.6); +} + +.state.warn { + color: #b45309; +} + +.notifications-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 16px; +} + +.notification-card { + background: #fff; + border-radius: 16px; + border: 1px solid rgba(0,0,0,0.08); + padding: 16px; + box-shadow: 0 18px 36px rgba(0,0,0,0.08); + + h3 { + margin: 12px 0 8px; + font-size: 16px; + font-weight: 800; + color: rgba(17, 18, 20, 0.92); + } + + p { + margin: 0 0 12px; + font-size: 13px; + color: rgba(17, 18, 20, 0.68); + } +} + +.card-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; +} + +.tag { + display: inline-flex; + align-items: center; + padding: 4px 10px; + border-radius: 999px; + font-size: 11px; + font-weight: 800; + background: rgba(3, 15, 170, 0.12); + color: #1f2937; +} + +.tag.warn { + background: rgba(227, 61, 207, 0.16); + color: #8b2a7d; +} + +.tag.danger { + background: rgba(239, 68, 68, 0.16); + color: #b91c1c; +} + +.date { + font-size: 12px; + color: rgba(17, 18, 20, 0.55); + font-weight: 700; +} + +.card-meta { + display: grid; + gap: 4px; + font-size: 12px; + color: rgba(17, 18, 20, 0.7); + font-weight: 700; +} + +.mark-read { + margin-top: 12px; + padding: 8px 12px; + border-radius: 10px; + border: 1px solid rgba(0,0,0,0.08); + background: #fff; + font-size: 12px; + font-weight: 700; + cursor: pointer; +} diff --git a/src/app/pages/notificacoes/notificacoes.ts b/src/app/pages/notificacoes/notificacoes.ts new file mode 100644 index 0000000..be6168b --- /dev/null +++ b/src/app/pages/notificacoes/notificacoes.ts @@ -0,0 +1,48 @@ +import { Component, OnInit } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { NotificationsService, NotificationDto } from '../../services/notifications.service'; + +@Component({ + selector: 'app-notificacoes', + standalone: true, + imports: [CommonModule], + templateUrl: './notificacoes.html', + styleUrls: ['./notificacoes.scss'], +}) +export class Notificacoes implements OnInit { + notifications: NotificationDto[] = []; + loading = false; + error = false; + + constructor(private notificationsService: NotificationsService) {} + + ngOnInit(): void { + this.loadNotifications(); + } + + markAsRead(notification: NotificationDto) { + if (notification.lida) return; + this.notificationsService.markAsRead(notification.id).subscribe({ + next: () => { + notification.lida = true; + notification.lidaEm = new Date().toISOString(); + }, + }); + } + + private loadNotifications() { + this.loading = true; + this.error = false; + this.notificationsService.list().subscribe({ + next: (data) => { + this.notifications = data || []; + this.loading = false; + }, + error: () => { + this.error = true; + this.loading = false; + }, + }); + } +} diff --git a/src/app/services/notifications.service.ts b/src/app/services/notifications.service.ts new file mode 100644 index 0000000..a2ba36a --- /dev/null +++ b/src/app/services/notifications.service.ts @@ -0,0 +1,37 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { environment } from '../../environments/environment'; + +export type NotificationTipo = 'AVencer' | 'Vencido'; + +export type NotificationDto = { + id: string; + tipo: NotificationTipo; + titulo: string; + mensagem: string; + data: string; + referenciaData?: string | null; + diasParaVencer?: number | null; + lida: boolean; + lidaEm?: string | null; + vigenciaLineId?: string | null; + cliente?: string | null; + linha?: string | null; +}; + +@Injectable({ providedIn: 'root' }) +export class NotificationsService { + private readonly baseUrl = `${environment.apiUrl}/notifications`; + + constructor(private http: HttpClient) {} + + list(): Observable { + return this.http.get(this.baseUrl); + } + + markAsRead(id: string): Observable { + return this.http.patch(`${this.baseUrl}/${id}/read`, {}); + } +} From cce651eef9b11c28d25f636b11cb2b5071fcd34a Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:06:41 -0300 Subject: [PATCH 09/32] =?UTF-8?q?Corrige=20base=20da=20API=20de=20notifica?= =?UTF-8?q?=C3=A7=C3=B5es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/services/notifications.service.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/app/services/notifications.service.ts b/src/app/services/notifications.service.ts index a2ba36a..2852737 100644 --- a/src/app/services/notifications.service.ts +++ b/src/app/services/notifications.service.ts @@ -23,15 +23,18 @@ export type NotificationDto = { @Injectable({ providedIn: 'root' }) export class NotificationsService { - private readonly baseUrl = `${environment.apiUrl}/notifications`; + private readonly baseApi: string; - constructor(private http: HttpClient) {} + constructor(private http: HttpClient) { + const raw = (environment.apiUrl || '').replace(/\/+$/, ''); + this.baseApi = raw.toLowerCase().endsWith('/api') ? raw : `${raw}/api`; + } list(): Observable { - return this.http.get(this.baseUrl); + return this.http.get(`${this.baseApi}/notifications`); } markAsRead(id: string): Observable { - return this.http.patch(`${this.baseUrl}/${id}/read`, {}); + return this.http.patch(`${this.baseApi}/notifications/${id}/read`, {}); } } From 8a12a2e0d07d5eec6411fc7da36494f0bbd26652 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:35:19 -0300 Subject: [PATCH 10/32] =?UTF-8?q?Aprimora=20UI=20das=20notifica=C3=A7?= =?UTF-8?q?=C3=B5es=20e=20adiciona=20filtros?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/components/header/header.scss | 13 ++++++ src/app/pages/notificacoes/notificacoes.html | 33 +++++++++++++- src/app/pages/notificacoes/notificacoes.scss | 46 +++++++++++++++++++- src/app/pages/notificacoes/notificacoes.ts | 15 +++++++ 4 files changed, 104 insertions(+), 3 deletions(-) diff --git a/src/app/components/header/header.scss b/src/app/components/header/header.scss index bd85f77..e9e85b8 100644 --- a/src/app/components/header/header.scss +++ b/src/app/components/header/header.scss @@ -191,6 +191,7 @@ justify-content: space-between; font-weight: 800; color: rgba(17, 18, 20, 0.9); + border-bottom: 1px solid rgba(0,0,0,0.06); } .see-all { @@ -222,6 +223,12 @@ border-radius: 12px; padding: 10px 12px; margin-bottom: 10px; + transition: transform 0.2s ease, box-shadow 0.2s ease; + + &:hover { + transform: translateY(-1px); + box-shadow: 0 10px 20px rgba(0,0,0,0.08); + } } .notification-tag { @@ -267,6 +274,12 @@ font-size: 12px; font-weight: 700; cursor: pointer; + color: rgba(17, 18, 20, 0.8); + + &:hover { + border-color: rgba(3, 15, 170, 0.35); + color: #030faa; + } } .options-menu { diff --git a/src/app/pages/notificacoes/notificacoes.html b/src/app/pages/notificacoes/notificacoes.html index d4ef48e..9453576 100644 --- a/src/app/pages/notificacoes/notificacoes.html +++ b/src/app/pages/notificacoes/notificacoes.html @@ -6,6 +6,32 @@

Notificações

Acompanhe vencimentos e avisos recentes.

+
+ + + +
Carregando notificações...
@@ -13,9 +39,12 @@
Nenhuma notificação encontrada.
+
+ Nenhuma notificação para o filtro selecionado. +
-
-
+
+
{{ n.tipo === 'Vencido' ? 'Vencido' : 'A vencer' }} diff --git a/src/app/pages/notificacoes/notificacoes.scss b/src/app/pages/notificacoes/notificacoes.scss index e2455b8..1e58776 100644 --- a/src/app/pages/notificacoes/notificacoes.scss +++ b/src/app/pages/notificacoes/notificacoes.scss @@ -19,9 +19,11 @@ .page-head { display: flex; - align-items: flex-end; + align-items: center; justify-content: space-between; margin-bottom: 20px; + gap: 16px; + flex-wrap: wrap; h2 { font-size: 24px; @@ -36,6 +38,42 @@ } } +.filters { + display: flex; + gap: 10px; + flex-wrap: wrap; +} + +.filter-btn { + border: 1px solid rgba(0,0,0,0.08); + background: #fff; + padding: 8px 14px; + border-radius: 999px; + font-weight: 700; + font-size: 12px; + color: rgba(17, 18, 20, 0.7); + cursor: pointer; + transition: all 0.2s ease; + + &.active { + border-color: rgba(3, 15, 170, 0.4); + background: rgba(3, 15, 170, 0.08); + color: #030faa; + } + + &.warning.active { + border-color: rgba(227, 61, 207, 0.45); + background: rgba(227, 61, 207, 0.12); + color: #8b2a7d; + } + + &.danger.active { + border-color: rgba(239, 68, 68, 0.45); + background: rgba(239, 68, 68, 0.12); + color: #b91c1c; + } +} + .state { padding: 12px 14px; border-radius: 12px; @@ -61,6 +99,12 @@ border: 1px solid rgba(0,0,0,0.08); padding: 16px; box-shadow: 0 18px 36px rgba(0,0,0,0.08); + transition: transform 0.2s ease, box-shadow 0.2s ease; + + &:hover { + transform: translateY(-2px); + box-shadow: 0 22px 44px rgba(0,0,0,0.12); + } h3 { margin: 12px 0 8px; diff --git a/src/app/pages/notificacoes/notificacoes.ts b/src/app/pages/notificacoes/notificacoes.ts index be6168b..e246808 100644 --- a/src/app/pages/notificacoes/notificacoes.ts +++ b/src/app/pages/notificacoes/notificacoes.ts @@ -12,6 +12,7 @@ import { NotificationsService, NotificationDto } from '../../services/notificati }) export class Notificacoes implements OnInit { notifications: NotificationDto[] = []; + filter: 'todas' | 'vencidas' | 'aVencer' = 'todas'; loading = false; error = false; @@ -31,6 +32,20 @@ export class Notificacoes implements OnInit { }); } + setFilter(value: 'todas' | 'vencidas' | 'aVencer') { + this.filter = value; + } + + get filteredNotifications() { + if (this.filter === 'vencidas') { + return this.notifications.filter(n => n.tipo === 'Vencido'); + } + if (this.filter === 'aVencer') { + return this.notifications.filter(n => n.tipo === 'AVencer'); + } + return this.notifications; + } + private loadNotifications() { this.loading = true; this.error = false; From 72a79479a8cded0101ab1b3eb9875d521b41f7f6 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:56:54 -0300 Subject: [PATCH 11/32] =?UTF-8?q?Refina=20layout=20dos=20cards=20de=20noti?= =?UTF-8?q?fica=C3=A7=C3=B5es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/components/header/header.html | 31 +++++++++-- src/app/components/header/header.scss | 49 +++++++++++++++++ src/app/components/header/header.ts | 56 +++++++++++++++++++- src/app/pages/notificacoes/notificacoes.html | 12 ++--- src/app/pages/notificacoes/notificacoes.scss | 28 ++++------ 5 files changed, 145 insertions(+), 31 deletions(-) diff --git a/src/app/components/header/header.html b/src/app/components/header/header.html index de807c6..6eeb294 100644 --- a/src/app/components/header/header.html +++ b/src/app/components/header/header.html @@ -50,11 +50,17 @@
- - {{ n.tipo === 'Vencido' ? 'Vencido' : 'A vencer' }} - -
{{ n.titulo }}
-
{{ n.mensagem }}
+
+ + {{ n.tipo === 'Vencido' ? 'Vencido' : 'A vencer' }} + + {{ n.linha || '-' }} +
+
+
Linha: {{ n.linha || '-' }}
+
Cliente: {{ n.cliente || '-' }}
+
{{ n.tipo === 'Vencido' ? 'Venceu em' : 'Vence em' }}: {{ n.referenciaData ? (n.referenciaData | date:'dd/MM/yyyy') : '-' }}
+
@@ -117,6 +123,21 @@ +
+
+
+ Vigência próxima + +
+
+ A linha {{ toastItem.linha || '-' }} vence em 5 dias. + +
+
+
+ diff --git a/src/app/components/header/header.scss b/src/app/components/header/header.scss index e9e85b8..70aa3da 100644 --- a/src/app/components/header/header.scss +++ b/src/app/components/header/header.scss @@ -242,6 +242,31 @@ background: rgba(3, 15, 170, 0.12); } +.notification-top { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; +} + +.notification-line { + font-weight: 800; + font-size: 12px; + color: rgba(17, 18, 20, 0.65); +} + +.notification-info { + margin-top: 8px; + display: grid; + gap: 4px; + font-size: 12px; + color: rgba(17, 18, 20, 0.75); + + strong { + color: rgba(17, 18, 20, 0.9); + } +} + .notification-tag.warn { background: rgba(227, 61, 207, 0.16); color: #8b2a7d; @@ -282,6 +307,30 @@ } } +.notification-toast { + border-radius: 14px; + border: 1px solid rgba(0,0,0,0.08); + box-shadow: 0 18px 36px rgba(0,0,0,0.16); +} + +.notification-toast .toast-header { + border-bottom: 1px solid rgba(0,0,0,0.06); + font-weight: 800; +} + +.btn-aware { + display: inline-flex; + align-items: center; + margin-top: 10px; + padding: 6px 12px; + border-radius: 10px; + border: 1px solid rgba(0,0,0,0.1); + background: #fff; + font-size: 12px; + font-weight: 700; + cursor: pointer; +} + .options-menu { position: relative; display: flex; diff --git a/src/app/components/header/header.ts b/src/app/components/header/header.ts index 78fca54..ed041d4 100644 --- a/src/app/components/header/header.ts +++ b/src/app/components/header/header.ts @@ -1,4 +1,4 @@ -import { Component, HostListener, Inject } from '@angular/core'; +import { Component, HostListener, Inject, ElementRef, ViewChild } from '@angular/core'; import { RouterLink, Router, NavigationEnd } from '@angular/router'; import { CommonModule, isPlatformBrowser } from '@angular/common'; import { PLATFORM_ID } from '@angular/core'; @@ -24,6 +24,8 @@ export class Header { notifications: NotificationDto[] = []; notificationsLoading = false; notificationsError = false; + private notificationsLoaded = false; + @ViewChild('notifToast') notifToast?: ElementRef; private readonly loggedPrefixes = [ '/geral', @@ -54,7 +56,13 @@ export class Header { this.menuOpen = false; this.optionsOpen = false; this.notificationsOpen = false; + if (this.isLoggedHeader) { + this.ensureNotificationsLoaded(); + } }); + if (this.isLoggedHeader) { + this.ensureNotificationsLoaded(); + } } private syncHeaderState(rawUrl: string) { @@ -137,6 +145,18 @@ export class Header { this.closeNotifications(); } + acknowledgeNotification(notification: NotificationDto) { + if (!isPlatformBrowser(this.platformId)) return; + const acknowledged = this.getAcknowledgedIds(); + acknowledged.add(notification.id); + localStorage.setItem('vigenciaAcknowledgedIds', JSON.stringify(Array.from(acknowledged))); + } + + private ensureNotificationsLoaded() { + if (this.notificationsLoaded || this.notificationsLoading) return; + this.loadNotifications(); + } + private loadNotifications() { if (!isPlatformBrowser(this.platformId)) return; this.notificationsLoading = true; @@ -144,7 +164,9 @@ export class Header { this.notificationsService.list().subscribe({ next: (data) => { this.notifications = data || []; + this.notificationsLoaded = true; this.notificationsLoading = false; + this.maybeShowVigenciaToast(); }, error: () => { this.notificationsError = true; @@ -152,4 +174,36 @@ export class Header { }, }); } + + private async maybeShowVigenciaToast() { + if (!this.notifToast || !isPlatformBrowser(this.platformId)) return; + const pending = this.getPendingVigenciaToast(); + if (!pending) return; + + const bs = await import('bootstrap'); + const toast = new bs.Toast(this.notifToast.nativeElement, { autohide: false }); + toast.show(); + } + + get toastNotification() { + return this.getPendingVigenciaToast(); + } + + private getPendingVigenciaToast() { + const acknowledged = this.getAcknowledgedIds(); + return this.notifications.find( + n => n.tipo === 'AVencer' && n.diasParaVencer === 5 && !acknowledged.has(n.id) + ); + } + + private getAcknowledgedIds() { + if (!isPlatformBrowser(this.platformId)) return new Set(); + try { + const raw = localStorage.getItem('vigenciaAcknowledgedIds'); + const ids = raw ? (JSON.parse(raw) as string[]) : []; + return new Set(ids); + } catch { + return new Set(); + } + } } diff --git a/src/app/pages/notificacoes/notificacoes.html b/src/app/pages/notificacoes/notificacoes.html index 9453576..9bddcb7 100644 --- a/src/app/pages/notificacoes/notificacoes.html +++ b/src/app/pages/notificacoes/notificacoes.html @@ -49,15 +49,13 @@ {{ n.tipo === 'Vencido' ? 'Vencido' : 'A vencer' }} - {{ n.data | date:'dd/MM/yyyy' }} + {{ n.linha || '-' }}
-

{{ n.titulo }}

-

{{ n.mensagem }}

- -
- Cliente: {{ n.cliente }} - Linha: {{ n.linha }} +
+
Linha: {{ n.linha || '-' }}
+
Cliente: {{ n.cliente || '-' }}
+
{{ n.tipo === 'Vencido' ? 'Venceu em' : 'Vence em' }}: {{ n.referenciaData ? (n.referenciaData | date:'dd/MM/yyyy') : '-' }}
+
+ {{ n.linha || '-' }} - {{ n.usuario || n.cliente || '-' }} +
Linha: {{ n.linha || '-' }}
+
Usuário: {{ n.usuario || '-' }}
Cliente: {{ n.cliente || '-' }}
{{ n.tipo === 'Vencido' ? 'Venceu em' : 'Vence em' }}: {{ n.referenciaData ? (n.referenciaData | date:'dd/MM/yyyy') : '-' }}
diff --git a/src/app/pages/notificacoes/notificacoes.html b/src/app/pages/notificacoes/notificacoes.html index 9bddcb7..74013a9 100644 --- a/src/app/pages/notificacoes/notificacoes.html +++ b/src/app/pages/notificacoes/notificacoes.html @@ -52,8 +52,13 @@ {{ n.linha || '-' }}
+
+ {{ n.linha || '-' }} - {{ n.usuario || n.cliente || '-' }} +
+
Linha: {{ n.linha || '-' }}
+
Usuário: {{ n.usuario || '-' }}
Cliente: {{ n.cliente || '-' }}
{{ n.tipo === 'Vencido' ? 'Venceu em' : 'Vence em' }}: {{ n.referenciaData ? (n.referenciaData | date:'dd/MM/yyyy') : '-' }}
diff --git a/src/app/pages/notificacoes/notificacoes.scss b/src/app/pages/notificacoes/notificacoes.scss index b5d7fda..7381235 100644 --- a/src/app/pages/notificacoes/notificacoes.scss +++ b/src/app/pages/notificacoes/notificacoes.scss @@ -119,6 +119,12 @@ } } +.card-title { + margin-top: 10px; + font-weight: 800; + color: rgba(17, 18, 20, 0.92); +} + .card-head { display: flex; align-items: center; diff --git a/src/app/services/notifications.service.ts b/src/app/services/notifications.service.ts index 2852737..07e16e8 100644 --- a/src/app/services/notifications.service.ts +++ b/src/app/services/notifications.service.ts @@ -19,6 +19,7 @@ export type NotificationDto = { vigenciaLineId?: string | null; cliente?: string | null; linha?: string | null; + usuario?: string | null; }; @Injectable({ providedIn: 'root' }) From 173d8570c96a3b1036b9289acbf9253435570b66 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:23:19 -0300 Subject: [PATCH 13/32] =?UTF-8?q?Adiciona=20filtro=20de=20notifica=C3=A7?= =?UTF-8?q?=C3=B5es=20lidas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/pages/notificacoes/notificacoes.html | 8 ++++++++ src/app/pages/notificacoes/notificacoes.scss | 6 ++++++ src/app/pages/notificacoes/notificacoes.ts | 7 +++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/app/pages/notificacoes/notificacoes.html b/src/app/pages/notificacoes/notificacoes.html index 74013a9..a90bf0a 100644 --- a/src/app/pages/notificacoes/notificacoes.html +++ b/src/app/pages/notificacoes/notificacoes.html @@ -31,6 +31,14 @@ > Vencidas +
diff --git a/src/app/pages/notificacoes/notificacoes.scss b/src/app/pages/notificacoes/notificacoes.scss index 7381235..e071c74 100644 --- a/src/app/pages/notificacoes/notificacoes.scss +++ b/src/app/pages/notificacoes/notificacoes.scss @@ -72,6 +72,12 @@ background: rgba(239, 68, 68, 0.12); color: #b91c1c; } + + &.neutral.active { + border-color: rgba(15, 23, 42, 0.35); + background: rgba(15, 23, 42, 0.08); + color: #0f172a; + } } .state { diff --git a/src/app/pages/notificacoes/notificacoes.ts b/src/app/pages/notificacoes/notificacoes.ts index e246808..6c2b0c1 100644 --- a/src/app/pages/notificacoes/notificacoes.ts +++ b/src/app/pages/notificacoes/notificacoes.ts @@ -12,7 +12,7 @@ import { NotificationsService, NotificationDto } from '../../services/notificati }) export class Notificacoes implements OnInit { notifications: NotificationDto[] = []; - filter: 'todas' | 'vencidas' | 'aVencer' = 'todas'; + filter: 'todas' | 'vencidas' | 'aVencer' | 'lidas' = 'todas'; loading = false; error = false; @@ -32,7 +32,7 @@ export class Notificacoes implements OnInit { }); } - setFilter(value: 'todas' | 'vencidas' | 'aVencer') { + setFilter(value: 'todas' | 'vencidas' | 'aVencer' | 'lidas') { this.filter = value; } @@ -43,6 +43,9 @@ export class Notificacoes implements OnInit { if (this.filter === 'aVencer') { return this.notifications.filter(n => n.tipo === 'AVencer'); } + if (this.filter === 'lidas') { + return this.notifications.filter(n => n.lida); + } return this.notifications; } From 2a2ec3d48762d0ce186667b293b9426273886297 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:23:43 -0300 Subject: [PATCH 14/32] Atualiza estilo da logo para visual SaaS --- src/app/components/header/header.scss | 60 ++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/src/app/components/header/header.scss b/src/app/components/header/header.scss index 70aa3da..6c36e6f 100644 --- a/src/app/components/header/header.scss +++ b/src/app/components/header/header.scss @@ -51,24 +51,47 @@ gap: 10px; text-decoration: none; color: var(--text-main); + transition: transform 0.2s ease; .logo-icon { - width: 36px; - height: 36px; - background: linear-gradient(135deg, var(--brand-primary), #6A55FF); + width: 38px; + height: 38px; + background: conic-gradient( + from 210deg, + #1c38c9 0deg, + #3555ff 90deg, + #e33dcf 180deg, + #ff6b6b 250deg, + #2ecc71 320deg, + #1c38c9 360deg + ); color: #fff; - border-radius: 10px; + border-radius: 50%; display: grid; place-items: center; font-size: 18px; flex: 0 0 auto; + box-shadow: 0 10px 24px rgba(28, 56, 201, 0.25); } .logo-text { font-size: 20px; - font-weight: 700; - letter-spacing: -0.5px; - .highlight { color: var(--text-main); } + font-weight: 800; + letter-spacing: -0.4px; + text-transform: lowercase; + + .highlight { + background: linear-gradient(90deg, #1c38c9 0%, #6a55ff 45%, #e33dcf 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + text-transform: none; + margin-left: 4px; + font-weight: 700; + } + } + + &:hover { + transform: translateY(-1px); } } @@ -447,11 +470,19 @@ .side-logo-icon { width: 38px; height: 38px; - border-radius: 12px; + border-radius: 50%; display: grid; place-items: center; color: #fff; - background: linear-gradient(135deg, var(--brand-primary), #6A55FF); + background: conic-gradient( + from 210deg, + #1c38c9 0deg, + #3555ff 90deg, + #e33dcf 180deg, + #ff6b6b 250deg, + #2ecc71 320deg, + #1c38c9 360deg + ); i { font-size: 18px; } } @@ -459,7 +490,16 @@ font-weight: 900; font-size: 18px; letter-spacing: -0.4px; - .highlight { color: var(--text-main); } + text-transform: lowercase; + + .highlight { + background: linear-gradient(90deg, #1c38c9 0%, #6a55ff 45%, #e33dcf 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + text-transform: none; + margin-left: 4px; + font-weight: 700; + } } } From 91c695cc688bd70bc88e5f1c497d7b5ffa9cc707 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:38:45 -0300 Subject: [PATCH 15/32] Add Mureg delete confirmation modal --- src/app/pages/mureg/mureg.html | 44 +++++++++++++++++++++++++++++- src/app/pages/mureg/mureg.scss | 5 +++- src/app/pages/mureg/mureg.ts | 49 ++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 2 deletions(-) diff --git a/src/app/pages/mureg/mureg.html b/src/app/pages/mureg/mureg.html index 7c30f18..41b3367 100644 --- a/src/app/pages/mureg/mureg.html +++ b/src/app/pages/mureg/mureg.html @@ -184,6 +184,9 @@ + @@ -223,7 +226,7 @@ - + @@ -467,3 +470,42 @@ + + + + + diff --git a/src/app/pages/mureg/mureg.scss b/src/app/pages/mureg/mureg.scss index 8ca24e1..b5fb326 100644 --- a/src/app/pages/mureg/mureg.scss +++ b/src/app/pages/mureg/mureg.scss @@ -267,6 +267,7 @@ color: rgba(17,18,20,0.5); transition: all 0.2s; cursor: pointer; &:hover { background: rgba(17,18,20,0.05); color: var(--text); transform: translateY(-1px); } &.primary:hover { color: var(--blue); background: rgba(3,15,170,0.1); } + &.danger:hover { color: #dc3545; background: rgba(220, 53, 69, 0.12); } } /* FOOTER */ @@ -278,11 +279,13 @@ .modal-backdrop-custom { position: fixed; inset: 0; background: rgba(0,0,0,0.45); z-index: 9990; backdrop-filter: blur(4px); } .modal-custom { position: fixed; inset: 0; display: flex; align-items: center; justify-content: center; z-index: 9995; padding: 16px; } .modal-card { background: #ffffff; border: 1px solid rgba(255,255,255,0.8); border-radius: 20px; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); overflow: hidden; display: flex; flex-direction: column; animation: modalPop 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); width: min(850px, 100%); max-height: 90vh; } +.modal-card.modal-sm { width: min(480px, 100%); } @keyframes modalPop { from { opacity: 0; transform: scale(0.95) translateY(10px); } to { opacity: 1; transform: scale(1) translateY(0); } } .modal-header { padding: 16px 24px; border-bottom: 1px solid rgba(0,0,0,0.06); background: #fff; display: flex; justify-content: space-between; align-items: center; .modal-title { font-size: 1.1rem; font-weight: 800; color: var(--text); display: flex; align-items: center; gap: 12px; } .icon-bg { width: 32px; height: 32px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 16px; &.primary-soft { background: rgba(3, 15, 170, 0.1); color: var(--blue); } &.brand-soft { background: rgba(227, 61, 207, 0.1); color: var(--brand); } /* Adicionado */ + &.danger-soft { background: rgba(220, 53, 69, 0.12); color: #dc3545; } } .btn-icon { color: var(--muted); background: transparent; font-size: 1.2rem; border:none; cursor: pointer; &:hover { color: var(--brand); } } } @@ -307,4 +310,4 @@ div.box-body { padding: 16px; } .form-control { border-radius: 8px; border: 1px solid rgba(17,18,20,0.15); &:focus { border-color: var(--brand); box-shadow: 0 0 0 2px rgba(227,61,207,0.15); outline: none; } -} \ No newline at end of file +} diff --git a/src/app/pages/mureg/mureg.ts b/src/app/pages/mureg/mureg.ts index 0572137..b6b05c5 100644 --- a/src/app/pages/mureg/mureg.ts +++ b/src/app/pages/mureg/mureg.ts @@ -129,6 +129,11 @@ export class Mureg implements AfterViewInit { editSaving = false; editModel: any = null; + // ====== DELETE MODAL ====== + deleteOpen = false; + deleteSaving = false; + deleteTarget: MuregRow | null = null; + // ====== CREATE MODAL ====== createOpen = false; createSaving = false; @@ -638,6 +643,50 @@ export class Mureg implements AfterViewInit { }); } + // ======================================================================= + // DELETE MODAL + // ======================================================================= + onDelete(row: MuregRow) { + this.deleteTarget = row; + this.deleteOpen = true; + this.deleteSaving = false; + } + + closeDelete() { + this.deleteOpen = false; + this.deleteTarget = null; + this.deleteSaving = false; + } + + confirmDelete() { + if (!this.deleteTarget?.id) return; + + this.deleteSaving = true; + const targetId = this.deleteTarget.id; + const currentGroup = this.expandedGroup; + + this.http.delete(`${this.apiBase}/${targetId}`).subscribe({ + next: async () => { + this.deleteSaving = false; + await this.showToast('Mureg excluída com sucesso!'); + this.closeDelete(); + this.loadForGroups(); + + if (currentGroup) { + setTimeout(() => { + this.expandedGroup = currentGroup; + this.toggleGroup(currentGroup); + }, 400); + } + }, + error: async (err) => { + this.deleteSaving = false; + const msg = this.extractApiMessage(err) ?? 'Erro ao excluir Mureg.'; + await this.showToast(msg); + } + }); + } + // ======================================================================= // Helpers // ======================================================================= From 058322521aec1fdb156558c74ec52637c883b97e Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:46:52 -0300 Subject: [PATCH 16/32] Add Mureg detail modal --- src/app/pages/mureg/mureg.html | 98 +++++++++++++++++++++++++++++++++- src/app/pages/mureg/mureg.scss | 14 +++++ src/app/pages/mureg/mureg.ts | 31 +++++++++++ 3 files changed, 142 insertions(+), 1 deletion(-) diff --git a/src/app/pages/mureg/mureg.html b/src/app/pages/mureg/mureg.html index 41b3367..334239c 100644 --- a/src/app/pages/mureg/mureg.html +++ b/src/app/pages/mureg/mureg.html @@ -181,6 +181,9 @@
+ @@ -226,7 +229,7 @@
- + @@ -471,6 +474,99 @@ + + + + + diff --git a/src/app/pages/mureg/mureg.scss b/src/app/pages/mureg/mureg.scss index b5fb326..01e44d5 100644 --- a/src/app/pages/mureg/mureg.scss +++ b/src/app/pages/mureg/mureg.scss @@ -267,6 +267,7 @@ color: rgba(17,18,20,0.5); transition: all 0.2s; cursor: pointer; &:hover { background: rgba(17,18,20,0.05); color: var(--text); transform: translateY(-1px); } &.primary:hover { color: var(--blue); background: rgba(3,15,170,0.1); } + &.info:hover { color: var(--brand); background: rgba(227, 61, 207, 0.12); } &.danger:hover { color: #dc3545; background: rgba(220, 53, 69, 0.12); } } @@ -279,6 +280,7 @@ .modal-backdrop-custom { position: fixed; inset: 0; background: rgba(0,0,0,0.45); z-index: 9990; backdrop-filter: blur(4px); } .modal-custom { position: fixed; inset: 0; display: flex; align-items: center; justify-content: center; z-index: 9995; padding: 16px; } .modal-card { background: #ffffff; border: 1px solid rgba(255,255,255,0.8); border-radius: 20px; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); overflow: hidden; display: flex; flex-direction: column; animation: modalPop 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); width: min(850px, 100%); max-height: 90vh; } +.modal-card.modal-xl-custom { width: min(1100px, 95vw); max-height: 85vh; } .modal-card.modal-sm { width: min(480px, 100%); } @keyframes modalPop { from { opacity: 0; transform: scale(0.95) translateY(10px); } to { opacity: 1; transform: scale(1) translateY(0); } } .modal-header { padding: 16px 24px; border-bottom: 1px solid rgba(0,0,0,0.06); background: #fff; display: flex; justify-content: space-between; align-items: center; .modal-title { font-size: 1.1rem; font-weight: 800; color: var(--text); display: flex; align-items: center; gap: 12px; } @@ -297,6 +299,18 @@ div.detail-box { background: #fff; border-radius: 16px; border: 1px solid rgba(0 div.box-header { padding: 10px 16px; font-size: 0.8rem; font-weight: 800; text-transform: uppercase; color: var(--muted); border-bottom: 1px solid rgba(0,0,0,0.04); background: #fdfdfd; display: flex; align-items: center; } div.box-body { padding: 16px; } +/* INFO GRID (detalhes) */ +.info-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; padding: 0; } +.info-item { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 6px 10px; background: rgba(245, 245, 247, 0.5); border-radius: 12px; border: 1px solid rgba(0,0,0,0.03); transition: background 0.2s; + &:hover { background: #fff; box-shadow: 0 2px 8px rgba(0,0,0,0.05); } + &.span-2 { grid-column: span 2; } + .lbl { font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.05em; font-weight: 800; color: var(--muted); margin-bottom: 2px; } + .val { font-size: 0.9rem; font-weight: 700; color: var(--text); word-break: break-word; line-height: 1.2; + &.fs-4 { font-size: 1.1rem !important; } + &.small-text { font-size: 0.75rem; font-family: monospace; } + } +} + /* EDIT FORM STYLES */ .form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; diff --git a/src/app/pages/mureg/mureg.ts b/src/app/pages/mureg/mureg.ts index b6b05c5..fa633b6 100644 --- a/src/app/pages/mureg/mureg.ts +++ b/src/app/pages/mureg/mureg.ts @@ -129,6 +129,11 @@ export class Mureg implements AfterViewInit { editSaving = false; editModel: any = null; + // ====== DETAIL MODAL ====== + detailOpen = false; + detailLoading = false; + detailData: MuregDetailDto | null = null; + // ====== DELETE MODAL ====== deleteOpen = false; deleteSaving = false; @@ -643,6 +648,32 @@ export class Mureg implements AfterViewInit { }); } + // ======================================================================= + // DETAIL MODAL + // ======================================================================= + onView(row: MuregRow) { + this.detailOpen = true; + this.detailLoading = true; + this.detailData = null; + + this.http.get(`${this.apiBase}/${row.id}`).subscribe({ + next: (data) => { + this.detailData = data; + this.detailLoading = false; + }, + error: async () => { + this.detailLoading = false; + await this.showToast('Erro ao carregar detalhes da Mureg.'); + } + }); + } + + closeDetail() { + this.detailOpen = false; + this.detailLoading = false; + this.detailData = null; + } + // ======================================================================= // DELETE MODAL // ======================================================================= From 6ff62463e8b71fcc3d677e32dad547d382b08cc6 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:51:15 -0300 Subject: [PATCH 17/32] Adjust Mureg detail modal width --- src/app/pages/mureg/mureg.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/pages/mureg/mureg.scss b/src/app/pages/mureg/mureg.scss index 01e44d5..f320218 100644 --- a/src/app/pages/mureg/mureg.scss +++ b/src/app/pages/mureg/mureg.scss @@ -280,7 +280,7 @@ .modal-backdrop-custom { position: fixed; inset: 0; background: rgba(0,0,0,0.45); z-index: 9990; backdrop-filter: blur(4px); } .modal-custom { position: fixed; inset: 0; display: flex; align-items: center; justify-content: center; z-index: 9995; padding: 16px; } .modal-card { background: #ffffff; border: 1px solid rgba(255,255,255,0.8); border-radius: 20px; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); overflow: hidden; display: flex; flex-direction: column; animation: modalPop 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); width: min(850px, 100%); max-height: 90vh; } -.modal-card.modal-xl-custom { width: min(1100px, 95vw); max-height: 85vh; } +.modal-card.modal-xl-custom { width: min(980px, 92vw); max-height: 82vh; } .modal-card.modal-sm { width: min(480px, 100%); } @keyframes modalPop { from { opacity: 0; transform: scale(0.95) translateY(10px); } to { opacity: 1; transform: scale(1) translateY(0); } } .modal-header { padding: 16px 24px; border-bottom: 1px solid rgba(0,0,0,0.06); background: #fff; display: flex; justify-content: space-between; align-items: center; .modal-title { font-size: 1.1rem; font-weight: 800; color: var(--text); display: flex; align-items: center; gap: 12px; } From 7877ef1ff8e996a487ce0ae460ff6f63f096a941 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:55:15 -0300 Subject: [PATCH 18/32] Remove Geral info from Mureg detail modal --- src/app/pages/mureg/mureg.html | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/app/pages/mureg/mureg.html b/src/app/pages/mureg/mureg.html index 334239c..f688235 100644 --- a/src/app/pages/mureg/mureg.html +++ b/src/app/pages/mureg/mureg.html @@ -528,33 +528,7 @@ ICCID {{ detailData.iccid || '-' }} - - - - -
-
- Informações da Geral -
-
-
- Linha Atual na Geral - {{ detailData.linhaAtualNaGeral || '-' }} -
-
- Chip na Geral - {{ detailData.chipNaGeral || '-' }} -
-
- Conta na Geral - {{ detailData.contaNaGeral || '-' }} -
-
- Status na Geral - {{ detailData.statusNaGeral || '-' }} -
-
Skil {{ detailData.skil || '-' }}
From 128c573f0a0eddf4718f7d30e25aee4abfdaa935 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:59:34 -0300 Subject: [PATCH 19/32] Shrink Mureg detail modal --- src/app/pages/mureg/mureg.scss | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/app/pages/mureg/mureg.scss b/src/app/pages/mureg/mureg.scss index f320218..3e30c8f 100644 --- a/src/app/pages/mureg/mureg.scss +++ b/src/app/pages/mureg/mureg.scss @@ -280,7 +280,7 @@ .modal-backdrop-custom { position: fixed; inset: 0; background: rgba(0,0,0,0.45); z-index: 9990; backdrop-filter: blur(4px); } .modal-custom { position: fixed; inset: 0; display: flex; align-items: center; justify-content: center; z-index: 9995; padding: 16px; } .modal-card { background: #ffffff; border: 1px solid rgba(255,255,255,0.8); border-radius: 20px; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); overflow: hidden; display: flex; flex-direction: column; animation: modalPop 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); width: min(850px, 100%); max-height: 90vh; } -.modal-card.modal-xl-custom { width: min(980px, 92vw); max-height: 82vh; } +.modal-card.modal-xl-custom { width: min(920px, 90vw); max-height: 78vh; } .modal-card.modal-sm { width: min(480px, 100%); } @keyframes modalPop { from { opacity: 0; transform: scale(0.95) translateY(10px); } to { opacity: 1; transform: scale(1) translateY(0); } } .modal-header { padding: 16px 24px; border-bottom: 1px solid rgba(0,0,0,0.06); background: #fff; display: flex; justify-content: space-between; align-items: center; .modal-title { font-size: 1.1rem; font-weight: 800; color: var(--text); display: flex; align-items: center; gap: 12px; } @@ -291,7 +291,7 @@ } .btn-icon { color: var(--muted); background: transparent; font-size: 1.2rem; border:none; cursor: pointer; &:hover { color: var(--brand); } } } -.modal-body { padding: 24px; overflow-y: auto; &.bg-light-gray { background-color: #f8f9fa; } } +.modal-body { padding: 20px; overflow-y: auto; &.bg-light-gray { background-color: #f8f9fa; } } /* FORM & DETAILS */ .details-dashboard { display: grid; grid-template-columns: 1fr; gap: 20px; } @@ -300,14 +300,14 @@ div.box-header { padding: 10px 16px; font-size: 0.8rem; font-weight: 800; text-t div.box-body { padding: 16px; } /* INFO GRID (detalhes) */ -.info-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; padding: 0; } -.info-item { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 6px 10px; background: rgba(245, 245, 247, 0.5); border-radius: 12px; border: 1px solid rgba(0,0,0,0.03); transition: background 0.2s; +.info-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; padding: 0; } +.info-item { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 5px 8px; background: rgba(245, 245, 247, 0.5); border-radius: 10px; border: 1px solid rgba(0,0,0,0.03); transition: background 0.2s; &:hover { background: #fff; box-shadow: 0 2px 8px rgba(0,0,0,0.05); } &.span-2 { grid-column: span 2; } - .lbl { font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.05em; font-weight: 800; color: var(--muted); margin-bottom: 2px; } - .val { font-size: 0.9rem; font-weight: 700; color: var(--text); word-break: break-word; line-height: 1.2; - &.fs-4 { font-size: 1.1rem !important; } - &.small-text { font-size: 0.75rem; font-family: monospace; } + .lbl { font-size: 0.6rem; text-transform: uppercase; letter-spacing: 0.05em; font-weight: 800; color: var(--muted); margin-bottom: 2px; } + .val { font-size: 0.85rem; font-weight: 700; color: var(--text); word-break: break-word; line-height: 1.2; + &.fs-4 { font-size: 1rem !important; } + &.small-text { font-size: 0.7rem; font-family: monospace; } } } From 6ab5b476e37c1d024a06b5a885b2479f1b77ba3a Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:08:41 -0300 Subject: [PATCH 20/32] Fix faturamento table scrolling --- src/app/pages/faturamento/faturamento.scss | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/pages/faturamento/faturamento.scss b/src/app/pages/faturamento/faturamento.scss index 4326aa4..2371d12 100644 --- a/src/app/pages/faturamento/faturamento.scss +++ b/src/app/pages/faturamento/faturamento.scss @@ -97,7 +97,7 @@ position: relative; display: flex; flex-direction: column; - max-height: calc(100vh - 18px) !important; + max-height: calc(100vh - 80px) !important; min-height: 0; &::before { @@ -471,7 +471,8 @@ .groups-container { padding: 16px; overflow-y: auto; - height: 100%; + flex: 1; + min-height: 0; } .group-list { From 80a3926c256cc2c246aaff244a2393b49ee64476 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:20:49 -0300 Subject: [PATCH 21/32] Adjust faturamento table layout sizing --- src/app/pages/faturamento/faturamento.scss | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/app/pages/faturamento/faturamento.scss b/src/app/pages/faturamento/faturamento.scss index 2371d12..7ba4df7 100644 --- a/src/app/pages/faturamento/faturamento.scss +++ b/src/app/pages/faturamento/faturamento.scss @@ -80,7 +80,7 @@ .container-fat { width: 100%; - max-width: 1180px; + max-width: 1240px; position: relative; z-index: 1; margin-top: var(--page-top-gap); @@ -97,8 +97,9 @@ position: relative; display: flex; flex-direction: column; - max-height: calc(100vh - 80px) !important; - min-height: 0; + height: auto !important; + min-height: 80vh; + max-height: none !important; &::before { content: ''; @@ -473,6 +474,7 @@ overflow-y: auto; flex: 1; min-height: 0; + height: 100%; } .group-list { From a476843ae0d09efb85bd25821dad2edf65e57b6d Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:34:31 -0300 Subject: [PATCH 22/32] Stack Total Vivo/Line KPI labels --- src/app/pages/faturamento/faturamento.html | 4 ++-- src/app/pages/faturamento/faturamento.scss | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/app/pages/faturamento/faturamento.html b/src/app/pages/faturamento/faturamento.html index 0beb345..ea6d0c3 100644 --- a/src/app/pages/faturamento/faturamento.html +++ b/src/app/pages/faturamento/faturamento.html @@ -131,7 +131,7 @@
-
+
Total Vivo @@ -139,7 +139,7 @@
-
+
Total Line diff --git a/src/app/pages/faturamento/faturamento.scss b/src/app/pages/faturamento/faturamento.scss index 7ba4df7..b366b33 100644 --- a/src/app/pages/faturamento/faturamento.scss +++ b/src/app/pages/faturamento/faturamento.scss @@ -449,6 +449,21 @@ } } +.kpi-stack { + flex-direction: column; + align-items: flex-start; + gap: 6px; + + .lbl, + .val { + white-space: normal; + } + + .val { + line-height: 1.1; + } +} + .kpi-wide { min-width: 220px; padding: 14px 18px; From 1d2e2346208ccd5fb7d1cdc15852b3f84afb4387 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:48:23 -0300 Subject: [PATCH 23/32] Center stacked Vivo/Line KPIs --- src/app/pages/faturamento/faturamento.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/pages/faturamento/faturamento.scss b/src/app/pages/faturamento/faturamento.scss index b366b33..9f50a8e 100644 --- a/src/app/pages/faturamento/faturamento.scss +++ b/src/app/pages/faturamento/faturamento.scss @@ -451,8 +451,9 @@ .kpi-stack { flex-direction: column; - align-items: flex-start; + align-items: center; gap: 6px; + text-align: center; .lbl, .val { From d76ca6fbc997dce3fbf92d98a87a36f7d7e3267a Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:57:47 -0300 Subject: [PATCH 24/32] Stack Lucro KPI label --- src/app/pages/faturamento/faturamento.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/pages/faturamento/faturamento.html b/src/app/pages/faturamento/faturamento.html index ea6d0c3..f6ec934 100644 --- a/src/app/pages/faturamento/faturamento.html +++ b/src/app/pages/faturamento/faturamento.html @@ -147,7 +147,7 @@
-
+
Lucro From e4426d6b119f93921eff3470cad1342546d345e3 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 19:04:51 -0300 Subject: [PATCH 25/32] Compact Total Clientes/Linhas KPIs --- src/app/pages/faturamento/faturamento.html | 4 ++-- src/app/pages/faturamento/faturamento.scss | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/app/pages/faturamento/faturamento.html b/src/app/pages/faturamento/faturamento.html index f6ec934..46764d3 100644 --- a/src/app/pages/faturamento/faturamento.html +++ b/src/app/pages/faturamento/faturamento.html @@ -115,7 +115,7 @@
-
+
Total Clientes @@ -123,7 +123,7 @@
-
+
Total Linhas diff --git a/src/app/pages/faturamento/faturamento.scss b/src/app/pages/faturamento/faturamento.scss index 9f50a8e..ff7d4e7 100644 --- a/src/app/pages/faturamento/faturamento.scss +++ b/src/app/pages/faturamento/faturamento.scss @@ -465,6 +465,15 @@ } } +.kpi-compact { + padding: 8px 14px; + min-height: auto; + + .val { + font-size: 1.05rem; + } +} + .kpi-wide { min-width: 220px; padding: 14px 18px; From ce3eba920a8a946eaacf554d9f23729969aabd20 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 19:15:53 -0300 Subject: [PATCH 26/32] Reduce height of Clientes/Linhas KPIs --- src/app/pages/faturamento/faturamento.scss | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/app/pages/faturamento/faturamento.scss b/src/app/pages/faturamento/faturamento.scss index ff7d4e7..4e76be3 100644 --- a/src/app/pages/faturamento/faturamento.scss +++ b/src/app/pages/faturamento/faturamento.scss @@ -466,11 +466,16 @@ } .kpi-compact { - padding: 8px 14px; - min-height: auto; + padding: 6px 12px; + min-height: 56px; + align-items: center; .val { - font-size: 1.05rem; + font-size: 1rem; + } + + .lbl { + font-size: 0.68rem; } } From b559c34ef96495b0c242f812fd5437659f133cc4 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 19:25:17 -0300 Subject: [PATCH 27/32] Refine faturamento inner table styling --- src/app/pages/faturamento/faturamento.html | 2 +- src/app/pages/faturamento/faturamento.scss | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/app/pages/faturamento/faturamento.html b/src/app/pages/faturamento/faturamento.html index 46764d3..637b502 100644 --- a/src/app/pages/faturamento/faturamento.html +++ b/src/app/pages/faturamento/faturamento.html @@ -229,7 +229,7 @@
-
+
Registros do Cliente Clique no “olho” para ver todos os detalhes
diff --git a/src/app/pages/faturamento/faturamento.scss b/src/app/pages/faturamento/faturamento.scss index 4e76be3..d0d1f5a 100644 --- a/src/app/pages/faturamento/faturamento.scss +++ b/src/app/pages/faturamento/faturamento.scss @@ -585,6 +585,16 @@ to { opacity: 1; transform: translateY(0); } } +.group-actions-row { + display: flex; + justify-content: space-between; + align-items: center; + padding: 12px 16px; + background: #fff; + border-bottom: 1px solid rgba(17,18,20,0.06); + gap: 12px; +} + .chip-muted { display: inline-flex; align-items: center; @@ -598,7 +608,11 @@ border: 1px solid rgba(17,18,20,0.06); } -.inner-table-wrap { max-height: 520px; overflow: auto; } +.inner-table-wrap { + max-height: none; + height: auto; + overflow-y: visible; +} /* TABLE */ .table-wrap { overflow: auto; height: 100%; } @@ -624,6 +638,9 @@ text-transform: uppercase; white-space: nowrap; text-align: center !important; + transition: color 0.2s ease; + + &:hover { color: var(--brand); } } tbody tr { From 5c7cc3a8274dd41b1d08478c79b565d34a005f4f Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 19:40:57 -0300 Subject: [PATCH 28/32] Remove sort carets from faturamento table --- src/app/pages/faturamento/faturamento.html | 14 +++++++------- src/app/pages/faturamento/faturamento.scss | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/app/pages/faturamento/faturamento.html b/src/app/pages/faturamento/faturamento.html index 637b502..38c97f3 100644 --- a/src/app/pages/faturamento/faturamento.html +++ b/src/app/pages/faturamento/faturamento.html @@ -238,12 +238,12 @@ - @@ -254,19 +254,19 @@ diff --git a/src/app/pages/faturamento/faturamento.scss b/src/app/pages/faturamento/faturamento.scss index d0d1f5a..766119a 100644 --- a/src/app/pages/faturamento/faturamento.scss +++ b/src/app/pages/faturamento/faturamento.scss @@ -664,6 +664,7 @@ .sort-caret { width: 14px; opacity: 0.3; &.active { opacity: 1; color: var(--brand); } } .td-clip { overflow: hidden; text-overflow: ellipsis; max-width: 260px; } .empty-state { background: rgba(255,255,255,0.4); } +.th-item .th-content { justify-content: center; } /* ACTIONS */ .action-group { display: flex; justify-content: center; gap: 6px; } From 4b9796cb0ea995cd73387aac2cdf8b3bcc5ee351 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 19:46:02 -0300 Subject: [PATCH 29/32] Shrink compact faturamento KPIs --- src/app/pages/faturamento/faturamento.scss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/pages/faturamento/faturamento.scss b/src/app/pages/faturamento/faturamento.scss index 766119a..5da7ce0 100644 --- a/src/app/pages/faturamento/faturamento.scss +++ b/src/app/pages/faturamento/faturamento.scss @@ -466,16 +466,16 @@ } .kpi-compact { - padding: 6px 12px; - min-height: 56px; + padding: 4px 10px; + min-height: 46px; align-items: center; .val { - font-size: 1rem; + font-size: 0.95rem; } .lbl { - font-size: 0.68rem; + font-size: 0.64rem; } } From df1bc45d32f8105234c3754a3b5b985b97ea346f Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 19:50:37 -0300 Subject: [PATCH 30/32] Restore compact KPI sizing --- src/app/pages/faturamento/faturamento.scss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/pages/faturamento/faturamento.scss b/src/app/pages/faturamento/faturamento.scss index 5da7ce0..766119a 100644 --- a/src/app/pages/faturamento/faturamento.scss +++ b/src/app/pages/faturamento/faturamento.scss @@ -466,16 +466,16 @@ } .kpi-compact { - padding: 4px 10px; - min-height: 46px; + padding: 6px 12px; + min-height: 56px; align-items: center; .val { - font-size: 0.95rem; + font-size: 1rem; } .lbl { - font-size: 0.64rem; + font-size: 0.68rem; } } From 9f08fac60a0563b7b587801208a8f2eac2ce2674 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 19:56:48 -0300 Subject: [PATCH 31/32] Stack Clientes/Linhas KPI labels --- src/app/pages/faturamento/faturamento.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/pages/faturamento/faturamento.html b/src/app/pages/faturamento/faturamento.html index 38c97f3..aac77fe 100644 --- a/src/app/pages/faturamento/faturamento.html +++ b/src/app/pages/faturamento/faturamento.html @@ -115,7 +115,7 @@
-
+
Total Clientes @@ -123,7 +123,7 @@
-
+
Total Linhas From 864ec5baf037d3b617094097eb1b77da31c5e4d5 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Thu, 22 Jan 2026 20:03:47 -0300 Subject: [PATCH 32/32] Tighten KPI label/value spacing --- src/app/pages/faturamento/faturamento.html | 6 +++--- src/app/pages/faturamento/faturamento.scss | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/app/pages/faturamento/faturamento.html b/src/app/pages/faturamento/faturamento.html index aac77fe..af9e6c1 100644 --- a/src/app/pages/faturamento/faturamento.html +++ b/src/app/pages/faturamento/faturamento.html @@ -115,7 +115,7 @@
-
+
Total Clientes @@ -123,7 +123,7 @@
-
+
Total Linhas @@ -147,7 +147,7 @@
-
+
Lucro diff --git a/src/app/pages/faturamento/faturamento.scss b/src/app/pages/faturamento/faturamento.scss index 766119a..ed96d9b 100644 --- a/src/app/pages/faturamento/faturamento.scss +++ b/src/app/pages/faturamento/faturamento.scss @@ -465,6 +465,10 @@ } } +.kpi-stack-tight { + gap: 2px; +} + .kpi-compact { padding: 6px 12px; min-height: 56px;
-
ITEM {{ sortBy==='item' && sortDir==='desc' ? '▼' : '▲' }}
+
+
ITEM
-
QTD LINHAS {{ sortBy==='qtdlinhas' && sortDir==='desc' ? '▼' : '▲' }}
+
QTD LINHAS
VIVO
-
FRANQUIA {{ sortBy==='franquiavivo' && sortDir==='desc' ? '▼' : '▲' }}
+
FRANQUIA
-
VALOR (R$) {{ sortBy==='valorcontratovivo' && sortDir==='desc' ? '▼' : '▲' }}
+
VALOR (R$)
-
FRANQUIA {{ sortBy==='franquialine' && sortDir==='desc' ? '▼' : '▲' }}
+
FRANQUIA
-
VALOR (R$) {{ sortBy==='valorcontratoline' && sortDir==='desc' ? '▼' : '▲' }}
+
VALOR (R$)