From 63134f172a99aba36fb9392154a68b20cb58ab85 Mon Sep 17 00:00:00 2001 From: Nitesh Yadav Date: Tue, 1 Sep 2026 18:40:59 +0530 Subject: [PATCH] fix(tasks): lay the checker inbox popup out properly The dialog rendered but read badly: the heading appeared twice, and every field ran together onto one line ("ID: 125Status: User: mifosAction: DELETE"). Cause was the global flex-40/flex-60/flex-fill utilities the template used -- they are sized for a full-width page, so inside a 680px dialog the label and value columns collapsed and wrapped into each other. Replaced them with a self-contained label-above-value grid that reflows to one column when narrow, so the same markup reads correctly as a page and as a popup. Also: moved the heading into the shared header so it is rendered once in both modes, gave the actions real buttons instead of Material raised buttons styled by two global overrides, put DELETE in a red tag so a destructive entry is visible at a glance, and dropped MatDivider/MatDialogModule from imports now that the markup no longer uses them. Co-Authored-By: Claude Opus 5 (1M context) --- .../view-checker-inbox.component.html | 214 ++++++++-------- .../view-checker-inbox.component.scss | 239 ++++++++++++++---- .../view-checker-inbox.component.ts | 7 +- 3 files changed, 302 insertions(+), 158 deletions(-) diff --git a/src/app/tasks/view-checker-inbox/view-checker-inbox.component.html b/src/app/tasks/view-checker-inbox/view-checker-inbox.component.html index ee89646b8..fa83e3693 100644 --- a/src/app/tasks/view-checker-inbox/view-checker-inbox.component.html +++ b/src/app/tasks/view-checker-inbox/view-checker-inbox.component.html @@ -6,125 +6,121 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/. --> -
- @if (isDialog) { -
- {{ 'labels.heading.View Checker Inbox' | translate }} - ✕ {{ 'labels.buttons.Close' | translate }} -
- } +
+ +
+ {{ 'labels.heading.View Checker Inbox' | translate }} + @if (isDialog) { + + } +
- + @if (loading) { -
{{ 'labels.heading.Loading' | translate }}…
+
+ + {{ 'labels.heading.Loading' | translate }}… +
} @if (checkerInboxDetail) { - @if (isProductEditEntry) { -
-
+
+ @if (isProductEditEntry) { +
This is a product edit awaiting approval. Approve or reject it from Approvals > Pending Product Edits instead — actioning it here would not release its lock.
-
- } @else { -
- - - -
- } + } @else { +
+ + + +
+ } -
- - -
-

{{ 'labels.heading.View Checker Inbox' | translate }}

- - - -

{{ 'labels.heading.Details' | translate }}

- - - -
- {{ 'labels.inputs.ID' | translate }}: - {{ checkerInboxDetail.id }} -
- -
- {{ 'labels.inputs.Status' | translate }}: - {{ checkerInboxDetail.processingResult }} -
- -
- {{ 'labels.inputs.User' | translate }}: - {{ checkerInboxDetail.maker }} -
- -
- {{ 'labels.inputs.Action' | translate }}: - {{ checkerInboxDetail.actionName }} -
- -
- {{ 'labels.inputs.Entity' | translate }}: - {{ checkerInboxDetail.entityName }} -
- - @if (checkerInboxDetail.resourceId) { -
- {{ 'labels.inputs.Resource ID' | translate }}: - {{ checkerInboxDetail.resourceId }} -
- } - -
- {{ 'labels.inputs.Date' | translate }}: - {{ checkerInboxDetail.madeOnDate | dateFormat }} -
- - @if (checkerInboxDetail.officeName) { -
- {{ 'labels.inputs.Office' | translate }}: - {{ checkerInboxDetail.officeName }} -
- } - - @if (checkerInboxDetail.savingsAccountNo) { -
- {{ 'labels.inputs.Savings Account Number' | translate }}: - {{ checkerInboxDetail.savingsAccountNo }} -
- } - - @if (checkerInboxDetail.groupLevelName) { -
- {{ checkerInboxDetail.groupLevelName }} - {{ checkerInboxDetail.groupName }} -
- } - - @if (displayJSONData) { -

{{ 'labels.heading.Command' | translate }}

- - @for (json of jsondata | keyvalue; track json) { -
- {{ json.key }}: - {{ json.value }} -
- } - } +
+
{{ 'labels.heading.Details' | translate }}
+ +
+
+
{{ 'labels.inputs.ID' | translate }}
+
{{ checkerInboxDetail.id }}
- - +
+
{{ 'labels.inputs.Status' | translate }}
+
{{ checkerInboxDetail.processingResult || '—' }}
+
+
+
{{ 'labels.inputs.User' | translate }}
+
{{ checkerInboxDetail.maker || '—' }}
+
+
+
{{ 'labels.inputs.Action' | translate }}
+
+ {{ + checkerInboxDetail.actionName + }} +
+
+
+
{{ 'labels.inputs.Entity' | translate }}
+
{{ checkerInboxDetail.entityName }}
+
+ @if (checkerInboxDetail.resourceId) { +
+
{{ 'labels.inputs.Resource ID' | translate }}
+
{{ checkerInboxDetail.resourceId }}
+
+ } +
+
{{ 'labels.inputs.Date' | translate }}
+
{{ checkerInboxDetail.madeOnDate | dateFormat }}
+
+ @if (checkerInboxDetail.officeName) { +
+
{{ 'labels.inputs.Office' | translate }}
+
{{ checkerInboxDetail.officeName }}
+
+ } + @if (checkerInboxDetail.savingsAccountNo) { +
+
{{ 'labels.inputs.Savings Account Number' | translate }}
+
{{ checkerInboxDetail.savingsAccountNo }}
+
+ } + @if (checkerInboxDetail.groupLevelName) { +
+
{{ checkerInboxDetail.groupLevelName }}
+
{{ checkerInboxDetail.groupName }}
+
+ } +
+
+ + @if (displayJSONData) { +
+
{{ 'labels.heading.Command' | translate }}
+
+ @for (json of jsondata | keyvalue; track json.key) { +
+
{{ json.key }}
+
{{ json.value }}
+
+ } +
+
+ }
}
diff --git a/src/app/tasks/view-checker-inbox/view-checker-inbox.component.scss b/src/app/tasks/view-checker-inbox/view-checker-inbox.component.scss index 5bf7407cd..0f6dc558c 100644 --- a/src/app/tasks/view-checker-inbox/view-checker-inbox.component.scss +++ b/src/app/tasks/view-checker-inbox/view-checker-inbox.component.scss @@ -6,45 +6,70 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -.mat-elevation-z1 { - margin: 1em 0 1.5em; +$success: #16a34a; +$danger: #dc2626; +$warning: #d97706; +$text-dark: #0d1b2a; +$text-mid: #475569; +$text-soft: #94a3b8; +$border: #e2e8f0; +$bg-page: #f8fafc; + +:host { + display: block; } -/* Opened as a popup rather than a full page — sizes to its own content (capped so a long command - payload still scrolls inside the dialog) instead of stretching to the viewport. */ -.vci--dialog { - width: min(720px, 92vw); - max-height: 85vh; - overflow-y: auto; +.vci { + background: #fff; - .container { - max-width: none; - padding: 0; + /* Opened as a popup rather than a full page: sized to its own content, capped so a long command + payload scrolls inside the dialog instead of pushing it off screen. As a route it stays a + normal page-width card. */ + &--dialog { + width: min(680px, 92vw); + max-height: 85vh; + overflow-y: auto; + border-radius: 10px; + } + + &:not(&--dialog) { + max-width: 900px; + margin: 20px auto; + border: 1px solid $border; + border-radius: 12px; + overflow: hidden; } } -.vci-dialog-bar { +// ── Header ─────────────────────────────────────────────────────────────────── +.vci-head { display: flex; align-items: center; - gap: 8px; - padding: 10px 16px; + gap: 12px; + padding: 14px 20px; + border-bottom: 1px solid $border; background: #fff; - border-bottom: 1px solid #e2e8f0; position: sticky; top: 0; z-index: 1; &__title { - font-size: 14px; + font-size: 15px; font-weight: 700; - color: #475569; + color: $text-dark; } &__close { margin-left: auto; - font-size: 12px; - font-weight: 500; - color: #94a3b8; + display: inline-flex; + align-items: center; + gap: 6px; + border: none; + background: none; + font-family: inherit; + font-size: 12.5px; + font-weight: 600; + color: $text-soft; cursor: pointer; padding: 6px 12px; border-radius: 6px; @@ -52,43 +77,169 @@ &:hover { background: #f1f5f9; - color: #475569; + color: $text-mid; } } } .vci-loading { + display: flex; + align-items: center; + justify-content: center; + gap: 10px; padding: 48px 24px; - text-align: center; font-size: 14px; - color: #94a3b8; + color: $text-soft; + + &__ic { + animation: vci-spin 1s linear infinite; + } } -h2, -h3, -h4 { +@keyframes vci-spin { + to { + transform: rotate(360deg); + } +} + +.vci-body { + padding: 16px 20px 20px; + display: flex; + flex-direction: column; + gap: 16px; +} + +// ── Actions ────────────────────────────────────────────────────────────────── +.vci-actions { + display: flex; + gap: 10px; + flex-wrap: wrap; +} + +.vci-btn { + display: inline-flex; + align-items: center; + gap: 7px; + height: 36px; + padding: 0 18px; + border-radius: 8px; + font-family: inherit; + font-size: 13.5px; + font-weight: 600; + cursor: pointer; + border: 1.5px solid transparent; + transition: all 0.15s; + + &--approve { + background: #f0fdf4; + color: $success; + border-color: #86efac; + + &:hover { + background: $success; + color: #fff; + border-color: $success; + } + } + + &--delete { + background: $danger; + color: #fff; + border-color: $danger; + + &:hover { + filter: brightness(1.08); + } + } + + &--reject { + background: #fff; + color: $text-mid; + border-color: $border; + + &:hover { + background: #f1f5f9; + color: $text-dark; + } + } +} + +.vci-notice { + padding: 12px 16px; + border-left: 4px solid $warning; + background: #fffbeb; + border-radius: 6px; + font-size: 13px; + line-height: 1.5; + color: #92400e; +} + +// ── Detail sections ────────────────────────────────────────────────────────── +.vci-section { + border: 1px solid $border; + border-radius: 10px; + overflow: hidden; + + &__title { + padding: 10px 16px; + background: $bg-page; + border-bottom: 1px solid $border; + font-size: 11px; + font-weight: 800; + text-transform: uppercase; + letter-spacing: 0.07em; + color: $text-mid; + } +} + +/* One label above its value, two pairs per row where there is room. This replaces the global + flex-40/flex-60 utilities, which are sized for a full-width page and ran every field together + onto a single line inside the dialog. */ +.vci-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: 14px 24px; margin: 0; - font-weight: 500; + padding: 16px; } -span { - margin: 0.5em 0; +.vci-kv { + display: flex; + flex-direction: column; + gap: 3px; + min-width: 0; + + dt { + font-size: 10.5px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.06em; + color: $text-soft; + } + + dd { + margin: 0; + font-size: 14px; + font-weight: 500; + color: $text-dark; + line-height: 1.35; + overflow-wrap: anywhere; + } } -.margin-t { - margin-top: 1em; -} +.vci-tag { + display: inline-flex; + align-items: center; + padding: 2px 10px; + border-radius: 20px; + background: #e0f2fe; + color: #0369a1; + font-size: 11.5px; + font-weight: 700; + letter-spacing: 0.04em; -mat-divider { - margin: 0 0 0.5em; -} - -.mat-raised-button.mat-success { - color: #fff; - background-color: #008000ab; -} - -.mat-raised-button.mat-reject { - color: #fff; - background-color: #ffca00; + &--danger { + background: #fee2e2; + color: #991b1b; + } } diff --git a/src/app/tasks/view-checker-inbox/view-checker-inbox.component.ts b/src/app/tasks/view-checker-inbox/view-checker-inbox.component.ts index 967a0e661..a329a7f43 100644 --- a/src/app/tasks/view-checker-inbox/view-checker-inbox.component.ts +++ b/src/app/tasks/view-checker-inbox/view-checker-inbox.component.ts @@ -10,7 +10,7 @@ import { Component, inject } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import * as _ from 'lodash'; -import { MatDialog, MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; +import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; /** Custom Services */ import { TasksService } from '../tasks.service'; @@ -19,7 +19,6 @@ import { TasksService } from '../tasks.service'; import { ConfirmationDialogComponent } from 'app/shared/confirmation-dialog/confirmation-dialog.component'; import { TranslateService } from '@ngx-translate/core'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; -import { MatDivider } from '@angular/material/divider'; import { KeyValuePipe } from '@angular/common'; import { DateFormatPipe } from '../../pipes/date-format.pipe'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; @@ -31,10 +30,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; imports: [ ...STANDALONE_SHARED_IMPORTS, FaIconComponent, - MatDivider, KeyValuePipe, - DateFormatPipe, - MatDialogModule + DateFormatPipe ] }) export class ViewCheckerInboxComponent {