diff --git a/src/app/components/header/header.html b/src/app/components/header/header.html index 9aead02..fa1e907 100644 --- a/src/app/components/header/header.html +++ b/src/app/components/header/header.html @@ -340,7 +340,20 @@ - + @@ -430,6 +443,14 @@
-
- -
@@ -270,13 +270,18 @@
-
+
-
- +
+ +
@@ -286,15 +291,19 @@
-
-
-
-
-
+
+
+ + + Gerado automaticamente pelo sistema +
+
+
+
-
-
+
+
@@ -327,13 +336,18 @@
-
+
-
- +
+ +
@@ -343,17 +357,21 @@
-
-
-
+
+
+ + + Gerado automaticamente pelo sistema +
+
-
+
-
+
@@ -364,10 +382,10 @@
-
+
-
-
+
+
diff --git a/src/app/pages/dados-usuarios/dados-usuarios.scss b/src/app/pages/dados-usuarios/dados-usuarios.scss index 6723c90..5ac4967 100644 --- a/src/app/pages/dados-usuarios/dados-usuarios.scss +++ b/src/app/pages/dados-usuarios/dados-usuarios.scss @@ -192,6 +192,74 @@ /* Controls */ .controls { display: flex; gap: 12px; align-items: center; justify-content: space-between; flex-wrap: wrap; } + +.filter-tabs { + display: flex; + gap: 4px; + padding: 4px; + background: rgba(255, 255, 255, 0.62); + border: 1px solid rgba(17, 18, 20, 0.08); + border-radius: 12px; + backdrop-filter: blur(8px); + box-shadow: 0 2px 8px rgba(17, 18, 20, 0.04); +} + +.filter-tab { + border: 1px solid transparent; + background: transparent; + padding: 8px 14px; + border-radius: 8px; + font-size: 0.84rem; + font-weight: 800; + color: rgba(17, 18, 20, 0.62); + transition: all 0.2s ease; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 6px; + white-space: nowrap; + min-height: 34px; + + &:hover { + color: var(--text); + background: rgba(255, 255, 255, 0.72); + border-color: rgba(17, 18, 20, 0.08); + transform: translateY(-1px); + } + + &:focus-visible { + outline: none; + box-shadow: 0 0 0 3px rgba(227, 61, 207, 0.14); + } + + &.active { + background: #fff; + color: var(--brand); + border-color: rgba(227, 61, 207, 0.16); + box-shadow: 0 2px 8px rgba(227, 61, 207, 0.15); + } +} + +.tipo-filter-tabs { + .filter-tab { + min-width: 122px; + } +} + +@media (max-width: 700px) { + .tipo-filter-tabs { + width: 100%; + justify-content: stretch; + } + + .tipo-filter-tabs .filter-tab { + flex: 1 1 0; + min-width: 0; + padding: 8px 10px; + font-size: 0.8rem; + } +} + .search-group { max-width: 270px; border-radius: 12px; overflow: hidden; display: flex; align-items: stretch; background: #fff; border: 1px solid rgba(17, 18, 20, 0.15); box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04); transition: all 0.2s ease; &:focus-within { border-color: var(--brand); box-shadow: 0 4px 12px rgba(227, 61, 207, 0.15); transform: translateY(-1px); } @@ -326,6 +394,122 @@ .modal-body { padding: 16px; } .modal-card.create-modal .modal-footer { flex-direction: column-reverse; } .modal-card.create-modal .modal-footer .btn { width: 100%; min-width: 0; } + + .modal-card.create-modal summary.box-header { + padding: 10px 12px; + + span { + font-size: 0.72rem; + line-height: 1.2; + gap: 7px; + } + + i:not(.transition-icon) { + width: 20px; + height: 20px; + border-radius: 6px; + font-size: 0.8rem; + } + } + + .form-field.field-line { + order: initial; + grid-column: span 2; + } + + .form-field.field-line .form-control { + min-height: 42px; + font-size: 0.95rem; + font-weight: 700; + letter-spacing: 0.02em; + font-variant-numeric: tabular-nums; + } + + .form-field.field-item { + align-items: flex-start; + } + + .form-field.field-item .form-control { + width: 100%; + max-width: none; + min-height: 38px; + text-align: left; + font-size: 0.82rem; + font-weight: 800; + font-variant-numeric: tabular-nums; + } + + .user-modal-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)) !important; + gap: 10px; + } + + .user-modal-grid .span-2, + .user-modal-grid .field-tipo, + .user-modal-grid .field-line, + .user-modal-grid .field-rg { + grid-column: span 2 !important; + } + + .user-modal-grid .field-item, + .user-modal-grid .field-cpf-cnpj, + .user-modal-grid .field-celular, + .user-modal-grid .field-telefone { + grid-column: span 1 !important; + min-width: 0; + } + + .user-modal-grid .field-item .field-hint { + display: none; + } + + .user-modal-grid .field-tipo .form-control { + appearance: none; + -webkit-appearance: none; + -moz-appearance: none; + min-height: 42px; + border-radius: 12px; + border-color: rgba(3, 15, 170, 0.18); + background: + linear-gradient(180deg, rgba(255,255,255,0.98), rgba(247,248,251,0.98)); + box-shadow: 0 2px 8px rgba(3, 15, 170, 0.06); + padding-right: 34px; + font-weight: 800; + color: var(--blue); + background-image: + linear-gradient(45deg, transparent 50%, rgba(17,18,20,0.55) 50%), + linear-gradient(135deg, rgba(17,18,20,0.55) 50%, transparent 50%); + background-position: + calc(100% - 16px) calc(50% - 2px), + calc(100% - 11px) calc(50% - 2px); + background-size: 5px 5px, 5px 5px; + background-repeat: no-repeat; + } + + .user-modal-grid .field-tipo .form-control:focus { + border-color: var(--brand); + box-shadow: 0 0 0 3px rgba(227,61,207,0.14); + } + + .user-modal-grid .field-cpf-cnpj .form-control, + .user-modal-grid .field-item .form-control { + min-height: 40px; + font-size: 0.84rem; + font-variant-numeric: tabular-nums; + } + + .user-modal-grid .field-rg .form-control { + min-height: 40px; + font-size: 0.88rem; + max-width: 100%; + } + + .contact-modal-grid .field-celular .form-control, + .contact-modal-grid .field-telefone .form-control { + width: 100%; + min-width: 0; + min-height: 40px; + } } /* FORM & DETAILS */ @@ -353,6 +537,8 @@ summary.box-header { cursor: pointer; user-select: none; list-style: none; + border-radius: 14px 14px 0 0; + transition: background 0.2s ease, color 0.2s ease; i:not(.transition-icon) { color: var(--brand); @@ -362,6 +548,41 @@ summary.box-header { &::-webkit-details-marker { display: none; } } +.modal-card.create-modal summary.box-header { + padding: 11px 14px; + border-bottom-color: rgba(227, 61, 207, 0.08); + background: linear-gradient(135deg, rgba(227, 61, 207, 0.10), rgba(3, 15, 170, 0.06)); + + span { + display: inline-flex; + align-items: center; + gap: 8px; + min-width: 0; + font-size: 0.76rem; + line-height: 1.2; + color: rgba(17, 18, 20, 0.84); + text-transform: uppercase; + letter-spacing: 0.04em; + font-weight: 900; + white-space: normal; + overflow-wrap: anywhere; + } + + i:not(.transition-icon) { + width: 22px; + height: 22px; + margin-right: 0; + border-radius: 7px; + display: inline-flex; + align-items: center; + justify-content: center; + background: rgba(255, 255, 255, 0.7); + border: 1px solid rgba(227, 61, 207, 0.12); + color: var(--brand); + flex-shrink: 0; + } +} + .transition-icon { transition: transform 0.25s ease, color 0.25s ease; color: var(--muted); } details[open] .transition-icon { transform: rotate(180deg); color: var(--brand); } @@ -391,6 +612,24 @@ details[open] .transition-icon { transform: rotate(180deg); color: var(--brand); &.span-2 { grid-column: span 2; } } +.field-hint { + display: block; + font-size: 0.66rem; + line-height: 1.2; + color: rgba(17, 18, 20, 0.52); + font-weight: 700; +} + +.form-field.field-auto .form-control { + background: rgba(245, 245, 247, 0.9); + border-color: rgba(17, 18, 20, 0.1); + color: rgba(17, 18, 20, 0.72); +} + +.form-field.field-auto .form-control[readonly] { + cursor: default; +} + .details-dashboard .form-field > div { border: 1px solid rgba(17, 18, 20, 0.08); border-radius: 12px; diff --git a/src/app/pages/dados-usuarios/dados-usuarios.ts b/src/app/pages/dados-usuarios/dados-usuarios.ts index 58c4b50..aa917b9 100644 --- a/src/app/pages/dados-usuarios/dados-usuarios.ts +++ b/src/app/pages/dados-usuarios/dados-usuarios.ts @@ -15,6 +15,7 @@ import { } from '../../services/dados-usuarios.service'; import { AuthService } from '../../services/auth.service'; import { LinesService, MobileLineDetail } from '../../services/lines.service'; +import { confirmDeletionWithTyping } from '../../utils/destructive-confirmation'; type ViewMode = 'lines' | 'groups'; @@ -26,6 +27,11 @@ interface LineOptionDto { label?: string; } +interface SimpleOption { + label: string; + value: string; +} + @Component({ selector: 'app-dados-usuarios', standalone: true, @@ -90,6 +96,10 @@ export class DadosUsuarios implements OnInit { createDateNascimento = ''; clientsFromGeral: string[] = []; lineOptionsCreate: LineOptionDto[] = []; + readonly tipoPessoaOptions: SimpleOption[] = [ + { label: 'Pessoa Física', value: 'PF' }, + { label: 'Pessoa Jurídica', value: 'PJ' }, + ]; createClientsLoading = false; createLinesLoading = false; @@ -532,8 +542,9 @@ export class DadosUsuarios implements OnInit { this.deleteTarget = null; } - confirmDelete() { + async confirmDelete() { if (!this.deleteTarget) return; + if (!(await confirmDeletionWithTyping('este registro de dados do usuário'))) return; const id = this.deleteTarget.id; this.service.remove(id).subscribe({ next: () => { diff --git a/src/app/pages/faturamento/faturamento.ts b/src/app/pages/faturamento/faturamento.ts index 4764397..889a440 100644 --- a/src/app/pages/faturamento/faturamento.ts +++ b/src/app/pages/faturamento/faturamento.ts @@ -24,6 +24,7 @@ import { BillingUpdateRequest } from '../../services/billing'; import { AuthService } from '../../services/auth.service'; +import { confirmDeletionWithTyping } from '../../utils/destructive-confirmation'; interface BillingClientGroup { cliente: string; @@ -695,8 +696,9 @@ export class Faturamento implements AfterViewInit, OnDestroy { this.cdr.detectChanges(); } - confirmDelete() { + async confirmDelete() { if (!this.deleteTarget) return; + if (!(await confirmDeletionWithTyping('este registro de faturamento'))) return; const id = this.deleteTarget.id; this.billing.remove(id).subscribe({ next: () => { diff --git a/src/app/pages/geral/geral.html b/src/app/pages/geral/geral.html index 80a145b..063ec89 100644 --- a/src/app/pages/geral/geral.html +++ b/src/app/pages/geral/geral.html @@ -302,7 +302,7 @@
Gerenciar Grupo -
diff --git a/src/app/pages/geral/geral.scss b/src/app/pages/geral/geral.scss index 4151b81..3cec0d6 100644 --- a/src/app/pages/geral/geral.scss +++ b/src/app/pages/geral/geral.scss @@ -287,6 +287,55 @@ .group-toggle-icon { font-size: 1.2rem; color: var(--muted); transition: transform 0.3s ease; } .client-group-card.expanded .group-toggle-icon { transform: rotate(180deg); color: var(--brand); } .group-body { border-top: 1px solid rgba(17,18,20,0.06); background: #fbfbfc; animation: slideDown 0.3s cubic-bezier(0.16, 1, 0.3, 1); } +.btn-add-line-group { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 34px; + border: 1px solid transparent; + border-radius: 12px; + padding: 0.42rem 0.85rem; + line-height: 1; + white-space: nowrap; + font-weight: 800; + letter-spacing: 0.01em; + color: #fff; + background: + linear-gradient(135deg, rgba(227, 61, 207, 0.95), rgba(3, 15, 170, 0.95)); + background-clip: padding-box; + box-shadow: + 0 10px 22px rgba(3, 15, 170, 0.16), + inset 0 1px 0 rgba(255,255,255,0.2); + transition: transform 0.18s ease, box-shadow 0.18s ease, filter 0.18s ease; + + i { + font-weight: 900; + } + + &:hover { + color: #fff; + transform: translateY(-1px); + filter: saturate(1.05) brightness(1.02); + box-shadow: + 0 14px 26px rgba(227, 61, 207, 0.18), + 0 8px 18px rgba(3, 15, 170, 0.14); + } + + &:focus-visible { + outline: none; + box-shadow: + 0 0 0 3px rgba(255, 255, 255, 0.95), + 0 0 0 6px rgba(227, 61, 207, 0.28), + 0 12px 24px rgba(3, 15, 170, 0.16); + } + + &:active { + transform: translateY(0); + box-shadow: + 0 8px 16px rgba(3, 15, 170, 0.14), + inset 0 1px 0 rgba(255,255,255,0.16); + } +} @keyframes slideDown { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } /* Inner Table Destravada */ diff --git a/src/app/pages/geral/geral.ts b/src/app/pages/geral/geral.ts index 1c3ece0..3bbc7b2 100644 --- a/src/app/pages/geral/geral.ts +++ b/src/app/pages/geral/geral.ts @@ -4,6 +4,7 @@ import { ViewChild, Inject, PLATFORM_ID, + OnInit, AfterViewInit, ChangeDetectorRef, OnDestroy, @@ -22,6 +23,7 @@ import { PlanAutoFillService } from '../../services/plan-autofill.service'; import { AuthService } from '../../services/auth.service'; import { firstValueFrom, Subscription, filter } from 'rxjs'; import { environment } from '../../../environments/environment'; +import { confirmDeletionWithTyping } from '../../utils/destructive-confirmation'; type SortDir = 'asc' | 'desc'; type CreateMode = 'NEW_CLIENT' | 'NEW_LINE_IN_GROUP'; @@ -127,7 +129,7 @@ interface AccountCompanyOption { templateUrl: './geral.html', styleUrls: ['./geral.scss'] }) -export class Geral implements AfterViewInit, OnDestroy { +export class Geral implements OnInit, AfterViewInit, OnDestroy { toastMessage = ''; @ViewChild('successToast', { static: false }) successToast!: ElementRef; @@ -413,10 +415,13 @@ export class Geral implements AfterViewInit, OnDestroy { this.navigationSub?.unsubscribe(); } + ngOnInit(): void { + if (!isPlatformBrowser(this.platformId)) return; + this.isAdmin = this.authService.hasRole('admin'); + } + async ngAfterViewInit() { if (!isPlatformBrowser(this.platformId)) return; - - this.isAdmin = this.authService.hasRole('admin'); this.initAnimations(); setTimeout(() => { @@ -1646,7 +1651,7 @@ export class Geral implements AfterViewInit, OnDestroy { return; } - if (!confirm(`Remover linha ${r.linha}?`)) return; + if (!(await confirmDeletionWithTyping(`a linha ${r.linha}`))) return; this.loading = true; diff --git a/src/app/pages/historico/historico.scss b/src/app/pages/historico/historico.scss index 3dbbf74..3cc55ae 100644 --- a/src/app/pages/historico/historico.scss +++ b/src/app/pages/historico/historico.scss @@ -674,6 +674,396 @@ @media (max-width: 700px) { .filters-grid { grid-template-columns: 1fr; } .search-group { width: 100%; max-width: 100%; } - .entity-cell { flex-direction: column; align-items: flex-start; } - .expand-btn { align-self: flex-end; } + .entity-cell { + flex-direction: row; + align-items: center; + justify-content: flex-start; + gap: 6px; + } + .entity-label { flex: 1 1 auto; min-width: 0; } + .expand-btn { align-self: center; flex-shrink: 0; } +} + +@media (max-width: 768px) { + .historico-page { + padding: 0 8px; + } + + .container-geral-responsive { + width: calc(100vw - 16px) !important; + margin-top: 18px; + margin-bottom: 28px; + } + + .page-blob { + opacity: 0.28; + filter: blur(40px); + + &.blob-1, + &.blob-2, + &.blob-3, + &.blob-4 { + width: 240px; + height: 240px; + } + } + + .geral-card { + min-height: auto; + border-radius: 16px; + } + + .geral-header { + padding: 12px; + } + + .title { + font-size: 22px; + margin-top: 0; + line-height: 1.15; + } + + .subtitle { + font-size: 12px; + text-align: center; + line-height: 1.35; + } + + .header-actions { + width: 100%; + justify-self: stretch; + display: flex; + } + + .header-actions .btn { + width: 100%; + justify-content: center; + } + + .filters-card { + padding: 12px; + gap: 12px; + border-radius: 14px; + } + + .filters-head { + align-items: stretch; + } + + .filters-title { + width: 100%; + justify-content: center; + text-align: center; + } + + .filters-actions { + width: 100%; + display: grid; + grid-template-columns: 1fr 1fr; + gap: 8px; + } + + .filters-actions .btn-primary, + .filters-actions .btn-ghost { + width: 100%; + justify-content: center; + min-width: 0; + padding: 0 10px; + } + + .filters-grid { + grid-template-columns: 1fr !important; + gap: 10px; + } + + .filter-search { + grid-column: span 1; + } + + .filter-field { + min-width: 0; + } + + .filter-field input { + width: 100%; + min-width: 0; + font-size: 13px; + } + + .filter-field app-select, + .filter-field .select-glass { + width: 100%; + min-width: 0; + display: block; + } + + .search-group { + max-width: 100%; + min-width: 0; + min-height: 40px; + align-items: center; + } + + .search-group .form-control { + min-width: 0; + height: 40px; + padding: 0; + font-size: 16px; + line-height: 1.2; + } + + .search-group .input-group-text, + .search-group .btn-clear { + height: 40px; + min-height: 40px; + padding-top: 0; + padding-bottom: 0; + display: inline-flex; + align-items: center; + line-height: 1; + } + + .search-group .input-group-text { + padding-left: 10px; + padding-right: 6px; + } + + .search-group .btn-clear { + padding-left: 8px; + padding-right: 10px; + } + + .geral-body { + min-width: 0; + } + + .table-wrap { + width: 100%; + max-width: 100%; + overflow-x: auto; + overflow-y: visible; + -webkit-overflow-scrolling: touch; + } + + .table-modern { + min-width: 860px !important; + } + + .table-modern thead th, + .table-modern td { + padding: 10px 8px; + font-size: 0.78rem; + } + + .table-modern th:nth-child(2), + .table-modern td:nth-child(2) { + min-width: 190px; + } + + .table-modern th:nth-child(5), + .table-modern td:nth-child(5) { + min-width: 210px; + } + + .td-clip { + max-width: 180px; + } + + .entity-cell { + justify-content: flex-start; + gap: 6px; + } + + .entity-label { + min-width: 0; + flex: 1 1 auto; + } + + .entity-id { + margin-top: 2px; + line-height: 1.2; + } + + .details-row td { + padding: 0 8px 12px; + } + + .details-panel { + padding: 10px; + gap: 10px; + border-radius: 14px; + max-width: 640px; + margin: 0 auto; + } + + .section-title { + font-size: 0.82rem; + flex-wrap: wrap; + line-height: 1.25; + } + + .change-item { + padding: 8px 10px; + } + + .change-head { + align-items: flex-start; + flex-wrap: wrap; + } + + .change-field { + min-width: 0; + overflow-wrap: break-word; + } + + .change-values { + flex-direction: row; + align-items: center; + gap: 6px; + font-size: 0.75rem; + line-height: 1.2; + } + + .change-values i { + transform: none; + font-size: 0.7rem; + flex-shrink: 0; + } + + .change-values .old, + .change-values .new { + min-width: 0; + white-space: normal; + overflow-wrap: anywhere; + word-break: break-word; + } + + .tech-grid { + grid-template-columns: 1fr; + gap: 8px; + } + + .tech-value { + font-size: 13px; + } + + .alert.alert-danger { + margin: 12px !important; + display: grid; + gap: 8px; + } + + .alert.alert-danger .btn { + margin-left: 0 !important; + width: 100%; + } + + .geral-footer { + padding: 12px; + gap: 10px; + } + + .footer-meta { + flex-direction: column; + align-items: stretch; + gap: 10px; + } + + .footer-meta > .small { + text-align: center; + } + + .page-size { + width: 100%; + justify-content: space-between; + } + + .select-wrapper { + min-width: 110px; + } + + .geral-footer nav { + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + + .pagination-modern { + flex-wrap: nowrap; + width: max-content; + min-width: 100%; + justify-content: center; + padding-bottom: 2px; + } + + .pagination-modern .page-link { + white-space: nowrap; + font-size: 12px; + padding: 0.35rem 0.6rem; + } +} + +@media (max-width: 480px) { + .title-badge { + font-size: 12px; + padding: 6px 10px; + gap: 8px; + } + + .title { + font-size: 20px; + } + + .filters-actions { + grid-template-columns: 1fr; + } + + .btn-primary, + .btn-ghost { + width: 100%; + justify-content: center; + } + + .table-modern { + min-width: 760px !important; + } + + .td-clip { + max-width: 140px; + } + + .table-modern th:nth-child(2), + .table-modern td:nth-child(2) { + min-width: 170px; + } + + .table-modern th:nth-child(5), + .table-modern td:nth-child(5) { + min-width: 180px; + } + + .details-panel { + max-width: 520px; + padding: 8px; + gap: 8px; + } + + .change-item { + padding: 7px 8px; + } + + .change-values { + font-size: 0.72rem; + gap: 5px; + } + + .entity-cell { + gap: 6px; + } + + .expand-btn { + width: 30px; + height: 30px; + border-radius: 8px; + } } diff --git a/src/app/pages/mureg/mureg.ts b/src/app/pages/mureg/mureg.ts index 48e0e6c..a09f8f8 100644 --- a/src/app/pages/mureg/mureg.ts +++ b/src/app/pages/mureg/mureg.ts @@ -13,6 +13,7 @@ import { HttpClient, HttpParams } from '@angular/common/http'; import { LinesService } from '../../services/lines.service'; import { CustomSelectComponent } from '../../components/custom-select/custom-select'; import { environment } from '../../../environments/environment'; +import { confirmDeletionWithTyping } from '../../utils/destructive-confirmation'; type MuregKey = 'item' | 'linhaAntiga' | 'linhaNova' | 'iccid' | 'dataDaMureg' | 'cliente'; @@ -698,8 +699,9 @@ export class Mureg implements AfterViewInit { this.deleteSaving = false; } - confirmDelete() { + async confirmDelete() { if (!this.deleteTarget?.id) return; + if (!(await confirmDeletionWithTyping('esta Mureg'))) return; this.deleteSaving = true; const targetId = this.deleteTarget.id; diff --git a/src/app/pages/parcelamentos/parcelamentos.ts b/src/app/pages/parcelamentos/parcelamentos.ts index d601b91..278e75b 100644 --- a/src/app/pages/parcelamentos/parcelamentos.ts +++ b/src/app/pages/parcelamentos/parcelamentos.ts @@ -33,6 +33,7 @@ import { ParcelamentoCreateModalComponent, ParcelamentoCreateModel, } from './components/parcelamento-create-modal/parcelamento-create-modal'; +import { confirmDeletionWithTyping } from '../../utils/destructive-confirmation'; type MonthOption = { value: number; label: string }; type ParcelamentoStatus = 'ativos' | 'futuros' | 'finalizados'; @@ -452,8 +453,9 @@ export class Parcelamentos implements OnInit, OnDestroy { this.deleteTarget = null; } - confirmDelete(): void { + async confirmDelete(): Promise { if (!this.deleteTarget || this.deleteLoading) return; + if (!(await confirmDeletionWithTyping('este parcelamento'))) return; const id = this.getItemId(this.deleteTarget); if (!id) return; this.deleteLoading = true; diff --git a/src/app/pages/resumo/resumo.scss b/src/app/pages/resumo/resumo.scss index d2bce06..80a7539 100644 --- a/src/app/pages/resumo/resumo.scss +++ b/src/app/pages/resumo/resumo.scss @@ -69,6 +69,16 @@ transform: translateY(0); } +@media (max-width: 768px) { + .wrap { + padding-top: 12px; + } + + :host(.animate-ready) [data-animate] { + transform: translateY(8px); + } +} + /* Header */ .page-head { display: flex; @@ -253,6 +263,27 @@ } } +@media (max-width: 768px) { + .tab-bar { + width: 100%; + max-width: 100%; + min-width: 0; + flex-wrap: nowrap; + justify-content: flex-start; + overflow-x: auto; + overflow-y: hidden; + -webkit-overflow-scrolling: touch; + overscroll-behavior-x: contain; + scrollbar-width: thin; + padding-bottom: 6px; + } + + .tab-btn { + flex: 0 0 auto; + white-space: nowrap; + } +} + /* Hero Section */ .section-hero { background: white; diff --git a/src/app/pages/vigencia/vigencia.html b/src/app/pages/vigencia/vigencia.html index 1ad0ba4..31d5fbf 100644 --- a/src/app/pages/vigencia/vigencia.html +++ b/src/app/pages/vigencia/vigencia.html @@ -51,8 +51,12 @@ ` + : '' + } + +
+ `; + + overlay.appendChild(card); + document.body.appendChild(overlay); + activeOverlay = overlay; + const prevOverflow = document.body.style.overflow; + document.body.style.overflow = 'hidden'; + + const input = hasInput ? (card.querySelector('input') as HTMLInputElement | null) : null; + const confirmBtn = card.querySelector('.js-confirm') as HTMLButtonElement | null; + const cancelBtn = card.querySelector('.js-cancel') as HTMLButtonElement | null; + const requiredText = (options.requiredText || '').trim().toUpperCase(); + + const cleanup = (result: boolean) => { + document.removeEventListener('keydown', onKeyDown); + overlay.remove(); + if (activeOverlay === overlay) activeOverlay = null; + document.body.style.overflow = prevOverflow; + resolve(result); + }; + + const canConfirm = () => { + if (!hasInput) return true; + return (input?.value || '').trim().toUpperCase() === requiredText; + }; + + const updateConfirmState = () => { + if (!confirmBtn) return; + confirmBtn.disabled = !canConfirm(); + }; + + const onKeyDown = (event: KeyboardEvent) => { + if (event.key === 'Escape') { + event.preventDefault(); + cleanup(false); + } + if (event.key === 'Enter') { + if (document.activeElement === cancelBtn) return; + if (canConfirm()) { + event.preventDefault(); + cleanup(true); + } + } + }; + + overlay.addEventListener('click', (event) => { + if (event.target === overlay) cleanup(false); + }); + + cancelBtn?.addEventListener('click', () => cleanup(false)); + confirmBtn?.addEventListener('click', () => cleanup(canConfirm())); + input?.addEventListener('input', updateConfirmState); + input?.addEventListener('paste', () => setTimeout(updateConfirmState)); + document.addEventListener('keydown', onKeyDown); + + const focusTarget = input ?? cancelBtn ?? confirmBtn; + setTimeout(() => focusTarget?.focus(), 0); + }); +} + +function ensureStyles() { + if (stylesInjected || typeof document === 'undefined') return; + + const style = document.createElement('style'); + style.id = 'lgx-confirm-modal-styles'; + style.textContent = ` + .lgx-confirm-overlay { + position: fixed; + inset: 0; + background: rgba(15, 23, 42, 0.5); + backdrop-filter: blur(2px); + display: grid; + place-items: center; + z-index: 5000; + padding: 16px; + animation: lgxFadeIn .12s ease-out; + } + .lgx-confirm-card { + width: min(460px, calc(100vw - 32px)); + background: #fff; + border: 1px solid #e5e7eb; + border-radius: 16px; + box-shadow: 0 24px 60px rgba(15, 23, 42, 0.18); + padding: 18px; + animation: lgxScaleIn .14s ease-out; + font-family: inherit; + color: #111827; + } + .lgx-confirm-head { + display: grid; + grid-template-columns: 40px 1fr; + gap: 12px; + align-items: start; + } + .lgx-confirm-icon { + width: 40px; + height: 40px; + border-radius: 999px; + display: grid; + place-items: center; + font-size: 18px; + font-weight: 700; + background: #f3f4f6; + color: #374151; + } + .lgx-confirm-card h3 { + margin: 2px 0 6px; + font-size: 16px; + font-weight: 700; + line-height: 1.2; + } + .lgx-confirm-card p { + margin: 0; + font-size: 13px; + color: #6b7280; + line-height: 1.4; + } + .lgx-confirm-field { + margin-top: 14px; + display: grid; + gap: 6px; + } + .lgx-confirm-field label { + font-size: 12px; + font-weight: 600; + color: #111827; + } + .lgx-confirm-field input { + height: 40px; + border: 1px solid #d1d5db; + border-radius: 10px; + padding: 0 12px; + font-size: 14px; + outline: none; + transition: border-color .15s ease, box-shadow .15s ease; + } + .lgx-confirm-field input:focus { + border-color: #dc2626; + box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.12); + } + .lgx-confirm-field small { + font-size: 11px; + color: #6b7280; + } + .lgx-confirm-actions { + margin-top: 16px; + display: flex; + justify-content: flex-end; + gap: 10px; + } + .lgx-btn { + height: 38px; + border-radius: 10px; + border: 1px solid transparent; + padding: 0 14px; + font-size: 13px; + font-weight: 600; + cursor: pointer; + } + .lgx-btn.ghost { + background: #fff; + color: #374151; + border-color: #d1d5db; + } + .lgx-btn.ghost:hover { background: #f9fafb; } + .lgx-btn.primary { + background: #1d4ed8; + color: #fff; + border-color: #1d4ed8; + } + .lgx-btn.primary:hover:not(:disabled) { background: #1e40af; border-color: #1e40af; } + .lgx-btn.danger { + background: #dc2626; + color: #fff; + border-color: #dc2626; + } + .lgx-btn.danger:hover:not(:disabled) { background: #b91c1c; border-color: #b91c1c; } + .lgx-btn:disabled { + opacity: .6; + cursor: not-allowed; + } + .lgx-confirm-card.tone-danger .lgx-confirm-icon { + background: #fee2e2; + color: #b91c1c; + } + .lgx-confirm-card.tone-warning .lgx-confirm-icon { + background: #fef3c7; + color: #b45309; + } + .lgx-confirm-card.tone-warning .lgx-btn.primary { + background: #d97706; + border-color: #d97706; + } + .lgx-confirm-card.tone-warning .lgx-btn.primary:hover:not(:disabled) { + background: #b45309; + border-color: #b45309; + } + @keyframes lgxFadeIn { from { opacity: 0; } to { opacity: 1; } } + @keyframes lgxScaleIn { from { opacity: 0; transform: translateY(6px) scale(.98); } to { opacity: 1; transform: translateY(0) scale(1); } } + `; + + document.head.appendChild(style); + stylesInjected = true; +} + +function getToneIcon(tone: BaseDialogOptions['tone']): string { + if (tone === 'danger') return '!'; + if (tone === 'warning') return '!'; + return 'i'; +} + +function escapeHtml(value: string): string { + return value + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); +} diff --git a/src/styles.scss b/src/styles.scss index 55b2fe5..ac5ae4d 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -90,20 +90,35 @@ select.form-control-sm { /* Empurra o conteúdo pra baixo do header fixo */ .app-main.has-header { position: relative; - padding-top: 76px; /* evita vão visual entre o header fixo e o conteúdo */ + padding-top: var(--app-header-offset, 76px); /* sincroniza com a altura real do header */ background: transparent; } @media (max-width: 600px) { .app-main.has-header { - padding-top: 88px; + padding-top: var(--app-header-offset, 88px); } } +html, +body { + width: 100%; + max-width: 100%; + overflow-x: hidden; +} + +img, +svg, +canvas, +video { + max-width: 100%; + height: auto; +} + /* Ajuste para monitores grandes: elimina o "vão" visual entre header e corpo. */ @media (min-width: 1400px) { .app-main.has-header { - padding-top: 76px; + padding-top: var(--app-header-offset, 76px); } } @@ -116,7 +131,9 @@ select.form-control-sm { .container-fat, .container-mureg, .container-troca, -.container-geral-responsive { +.container-geral-responsive, +.container-dashboard, +.container-chips { max-width: 1100px !important; /* Largura controlada */ width: 96% !important; /* Margem segura em telas menores */ margin-left: auto !important; @@ -321,3 +338,386 @@ app-header .modal-card .btn-secondary:hover { box-shadow: none !important; } } + +/* Títulos de cliente no agrupamento: não herdar o "td-clip" das tabelas */ +.client-group-card .group-header { + gap: 12px; +} + +.client-group-card .group-header .group-info { + flex: 1 1 auto; + min-width: 0; +} + +.client-group-card .group-header .group-info > h6, +.client-group-card .group-header .group-info > h6.td-clip { + min-width: 0; + max-width: none !important; + overflow: visible !important; + text-overflow: clip !important; + white-space: normal !important; + word-break: normal !important; + overflow-wrap: break-word; + line-height: 1.25; +} + +.client-group-card .group-header .group-toggle-icon { + flex: 0 0 auto; +} + +/* ========================================================== */ +/* Ajustes globais de responsividade (mobile-first) */ +/* ========================================================== */ + +@media (min-width: 1600px) { + .container-geral, + .container-fat, + .container-mureg, + .container-troca, + .container-geral-responsive, + .container-dashboard, + .container-chips { + max-width: 1240px !important; + } +} + +@media (min-width: 2200px) { + .container-geral, + .container-fat, + .container-mureg, + .container-troca, + .container-geral-responsive, + .container-dashboard, + .container-chips { + max-width: 1360px !important; + } +} + +@media (max-width: 1024px) { + .container-geral, + .container-fat, + .container-mureg, + .container-troca, + .container-geral-responsive, + .container-dashboard, + .container-chips { + width: min(100%, calc(100vw - 20px)) !important; + } + + .header-actions, + .filters-actions { + flex-wrap: wrap; + gap: 8px !important; + } + + .controls, + .filters-row { + display: flex; + flex-wrap: wrap; + gap: 10px; + align-items: stretch; + } + + .search-group, + .input-group.search-group { + min-width: 0; + flex: 1 1 280px; + } + + .page-size { + margin-left: 0 !important; + flex: 0 1 auto; + } +} + +@media (max-width: 768px) { + .app-main.has-header { + padding-top: var(--app-header-offset, 84px); + } + + .geral-card, + .fat-card, + .mureg-card, + .troca-card, + .vigencia-page .geral-card { + min-height: auto !important; + margin-bottom: 20px !important; + } + + .header-row-top { + gap: 12px !important; + } + + .header-actions { + width: 100%; + justify-content: stretch !important; + } + + .header-actions .btn, + .header-actions button.btn { + flex: 1 1 220px; + } + + .filters-head, + .filters-meta { + align-items: stretch !important; + } + + .filters-actions { + width: 100%; + justify-content: stretch !important; + } + + .filters-actions .btn-primary, + .filters-actions .btn-ghost, + .filters-actions .btn, + .filters-actions button { + flex: 1 1 160px; + justify-content: center; + } + + .filters-grid { + grid-template-columns: 1fr !important; + gap: 10px !important; + } + + .filter-tabs { + width: 100%; + display: flex; + flex-wrap: nowrap; + gap: 8px; + overflow-x: auto; + padding-bottom: 4px; + -webkit-overflow-scrolling: touch; + scrollbar-width: thin; + } + + .filter-tabs .filter-tab { + flex: 0 0 auto; + white-space: nowrap; + } + + .client-filter-wrap, + .additional-filter-wrap, + .search-group, + .input-group.search-group, + .search-box, + .page-size { + width: 100% !important; + max-width: 100% !important; + min-width: 0 !important; + } + + .chips-container { + max-width: 100% !important; + } + + .btn-client-filter { + width: 100%; + min-height: 40px; + justify-content: space-between; + gap: 8px; + } + + .client-dropdown, + .additional-dropdown { + width: min(100%, calc(100vw - 24px)) !important; + max-width: calc(100vw - 24px) !important; + right: auto !important; + left: 0 !important; + } + + .controls .page-size { + justify-content: space-between !important; + } + + .table-wrap, + .table-wrap-tall, + .inner-table-wrap, + .parcelamentos-table-wrap { + width: 100%; + max-width: 100%; + overflow-x: auto !important; + overflow-y: visible !important; + -webkit-overflow-scrolling: touch; + } + + .table-wrap table.table-modern, + .inner-table-wrap table.table-modern, + .table-wrap .table-modern, + .parcelamentos-table-wrap .table-modern, + table.table-modern { + width: max-content !important; + min-width: max(100%, 920px) !important; + } + + .table-modern thead th, + .table-modern td { + padding: 10px 8px !important; + } + + .table-modern thead th { + font-size: 0.7rem !important; + } + + .table-modern td { + font-size: 0.8rem !important; + } + + .td-clip { + max-width: 180px !important; + } + + .actions-col { + min-width: 120px !important; + } + + .modal-custom, + .lg-modal, + .macrophony-modal, + .grouped-modal { + padding: 8px !important; + align-items: center !important; + justify-content: center !important; + } + + .modal-card, + .lg-modal-card, + .macrophony-card, + .grouped-card { + width: min(100%, calc(100vw - 16px)) !important; + max-width: calc(100vw - 16px) !important; + max-height: min(92dvh, calc(100vh - 16px)) !important; + border-radius: 14px !important; + min-height: 0; + } + + .modal-header, + .lg-modal-card .modal-header, + .detail-head { + padding: 12px 14px !important; + gap: 10px; + flex-wrap: wrap; + } + + .modal-title, + .lg-modal-card .modal-title { + min-width: 0; + flex: 1 1 auto; + } + + .modal-header h3, + .detail-head h4 { + font-size: 15px !important; + line-height: 1.3; + } + + .modal-body, + .modern-body, + .lg-modal-card .modal-body, + .macrophony-modal-body, + .grouped-modal-body { + padding: 14px !important; + overflow-y: auto; + } + + .modal-footer, + .modal-actions, + .lg-modal-card .modal-footer, + .manage-actions-footer { + display: flex !important; + flex-wrap: wrap !important; + gap: 8px !important; + justify-content: stretch !important; + align-items: stretch !important; + } + + .modal-footer .btn, + .modal-footer button, + .modal-actions .btn, + .modal-actions button, + .lg-modal-card .modal-footer .btn, + .manage-actions-footer .btn, + .manage-actions-footer button { + flex: 1 1 180px; + min-width: 0 !important; + justify-content: center; + } + + .manage-actions-footer .btn-delete-permanent-left { + margin-right: 0 !important; + } + + .form-grid, + .edit-grid, + .info-grid, + .details-2col, + .finance-dashboard { + grid-template-columns: 1fr !important; + } + + .details-dashboard { + grid-template-columns: 1fr !important; + gap: 12px !important; + } + + .macrophony-summary, + .grouped-summary-bar { + padding: 12px 14px !important; + gap: 12px !important; + } + + .toast-container { + left: 8px !important; + right: 8px !important; + width: auto !important; + padding: 8px !important; + } + + .toast-container .toast { + width: 100% !important; + } +} + +@media (max-width: 480px) { + .container-geral, + .container-fat, + .container-mureg, + .container-troca, + .container-geral-responsive, + .container-dashboard, + .container-chips { + width: calc(100vw - 14px) !important; + } + + .title-badge, + .header-title .title { + word-break: break-word; + } + + .header-actions .btn, + .header-actions button.btn, + .filters-actions .btn-primary, + .filters-actions .btn-ghost, + .filters-actions .btn, + .filters-actions button, + .modal-footer .btn, + .modal-footer button, + .modal-actions .btn, + .modal-actions button { + width: 100%; + flex-basis: 100%; + } + + .table-wrap table.table-modern, + .inner-table-wrap table.table-modern, + .table-wrap .table-modern, + .parcelamentos-table-wrap .table-modern, + table.table-modern { + min-width: max(100%, 820px) !important; + } + + .td-clip { + max-width: 140px !important; + } +}