Bỏ qua

Page Design: DISPUTED Workflow Screens

Follows MASTER.md — Dialog + List patterns with destructive/warning theming. Applies to: SCR-MAP-40, SCR-MAP-41, SCR-MAP-42, SCR-MAP-43 Users: Data Owner (mark DISPUTED), Manager (mark DISPUTED), Approver (resolve + approve)


SCR-MAP-40: Popup Đánh dấu DISPUTED

Trigger: Data Owner/Manager clicks "Đánh dấu tranh chấp" on matrix cell (SCR-MAP-10)

Layout

+------------------------------------------+
| ⚠️ "Đánh dấu tranh chấp"               |
| Cell: [DE name] × [Unit name]            |
+------------------------------------------+
| Trạng thái hiện tại: [DATABASE] ●        |
|                                          |
| Lý do tranh chấp: *                      |
| [Textarea — min 20 ký tự]               |
| "0/20 ký tự tối thiểu"                  |
+------------------------------------------+
|          [Hủy] [Đánh dấu DISPUTED]      |
+------------------------------------------+

Components

/* Dialog — max-w-lg, warning-themed header */
bg-card rounded-3xl border border-border shadow-xl max-w-lg

/* Header — warning/destructive accent */
px-8 py-6 border-b border-border bg-destructive/5
  div.flex.items-center.gap-3
    AlertTriangle.h-5.w-5.text-destructive
    h2.text-xl.font-bold.text-destructive  "Đánh dấu tranh chấp"
  div.flex.items-center.gap-2.mt-2
    Badge(variant="outline")  /* DE name */
    X.h-3.w-3.text-muted-foreground
    Badge(variant="outline")  /* Unit name */

/* Current status display */
flex items-center gap-3 p-4 bg-muted/50 rounded-2xl
  /* Colored dot */ + /* Status label */

/* Reason textarea — REQUIRED, min 20 chars */
Textarea.rounded-2xl.min-h-[120px]
  placeholder="Nhập lý do tranh chấp (tối thiểu 20 ký tự)..."

/* Character counter */
text-xs.font-medium.mt-1
  /* < 20 chars: text-destructive */  "12/20 ký tự tối thiểu"
  /* >= 20 chars: text-success */     "25 ký tự ✓"

/* Footer */
px-8 py-4 border-t border-border flex justify-end gap-3
  Button(variant="outline")  "Hủy"
  Button(variant="destructive", disabled={charCount < 20})
    Flag.h-4.w-4.mr-2  "Đánh dấu DISPUTED"

Business Rules

  • Data Owner: Only cells in own unit column (org_id match)
  • Manager: Any cell
  • Min 20 chars: Button disabled until textarea >= 20 chars
  • Save: Cell status → DISPUTED, color → red, toast "Ô đã được đánh dấu tranh chấp"
  • Audit: Logged with user, timestamp, reason

SCR-MAP-41: Danh sách ô DISPUTED

Route: /[locale]/current-state-map/disputed Users: Approver (primary), Manager (view)

Layout

+-----------------------------------------------------------+
| "Danh sách ô tranh chấp (DISPUTED)"                       |
| Badge: "3 ô cần giải quyết"                               |
+-----------------------------------------------------------+
| Table                                                      |
| ┌──────────┬──────────┬────────────┬──────────┬──────────┐|
| │Data Elem │ Đơn vị   │ Người đánh │ Lý do    │ Ngày     │|
| │          │          │ dấu        │          │          │|
| ├──────────┼──────────┼────────────┼──────────┼──────────┤|
| │ Số CCCD  │ Sở TC    │ Chị Lan    │ "Đơn vị  │ 24/03/26 │|
| │          │          │ (Data Owner)│ không..."│          │|
| └──────────┴──────────┴────────────┴──────────┴──────────┘|
+-----------------------------------------------------------+

Components

/* Page header */
flex items-center gap-4 mb-6
  h1.text-2xl.font-bold.text-foreground
  Badge.bg-destructive.text-destructive-foreground.text-sm.font-black
    "3 ô cần giải quyết"

/* DISPUTED table — MASTER.md table pattern */
bg-card rounded-3xl border border-border overflow-hidden shadow-sm

/* Columns */
th: Data Element | Đơn vị | Người đánh dấu |  do | Ngày | Thao tác

/* Row — each DISPUTED cell */
hover:bg-accent/50 transition-colors
  /* DE column */ font-bold + code badge below
  /* Unit column */ font-semibold
  /* Person column */ name + role badge
  /* Reason column */ text-sm italic, truncated with tooltip
  /* Date column */ text-xs text-muted-foreground
  /* Action column */
  Button(variant="outline", size="sm")
    Scale.h-4.w-4.mr-2  "Giải quyết"
    /* Click → open SCR-MAP-42 */

Empty State

/* When 0 DISPUTED cells */
flex flex-col items-center justify-center py-16 text-center
  CheckCircle.h-12.w-12.text-success/30
  p.text-lg.font-bold.text-muted-foreground.mt-4
    "Không còn ô tranh chấp"
  p.text-sm.text-muted-foreground.mt-2
    "Tất cả tranh chấp đã được giải quyết."

SCR-MAP-42: Popup Giải quyết DISPUTED

Trigger: Approver clicks "Giải quyết" on a row in SCR-MAP-41

Layout

+------------------------------------------+
| "Giải quyết tranh chấp"                 |
| [DE name] × [Unit name]                  |
+------------------------------------------+
| Thông tin tranh chấp:                     |
| Người đánh dấu: Chị Lan (Data Owner)     |
| Ngày: 24/03/2026                          |
| Lý do: "Đơn vị không lưu trữ trường     |
|         dữ liệu này trực tiếp..."        |
| ─────────────────────────────────────    |
| Quyết định của Approver:                  |
| (●) Xác nhận ánh xạ gốc → CONFIRMED    |
| (○) Bác bỏ hoàn toàn → REJECTED         |
| (○) Điều chỉnh sang DE khác              |
|     [Select DE — shown when selected]     |
|                                          |
| Lý do quyết định: *                      |
| [Textarea — required]                     |
+------------------------------------------+
|            [Hủy] [Xác nhận quyết định]   |
+------------------------------------------+

Components

/* Dialog — max-w-xl */

/* Dispute info card */
bg-destructive/5 border border-destructive/20 rounded-2xl p-4
  grid grid-cols-2 gap-3 text-sm
    /* Người đánh dấu, Ngày, Lý do (full width, italic) */

/* Decision radio group */
RadioGroup.space-y-3.mt-6
  /* Option A: Xác nhận ánh xạ gốc */
  label.flex.items-start.gap-3.p-4.rounded-2xl.border.border-border
  .hover:bg-green-50.dark:hover:bg-green-950.cursor-pointer.transition-all
  .has-[:checked]:bg-green-50.has-[:checked]:border-green-300
    RadioGroupItem
    div
      p.font-bold.text-success  "Xác nhận ánh xạ gốc"
      p.text-xs.text-muted-foreground  "Ô chuyển trạng thái CONFIRMED"

  /* Option B: Bác bỏ hoàn toàn */
  label...has-[:checked]:bg-red-50.has-[:checked]:border-red-300
    p.font-bold.text-destructive  "Bác bỏ hoàn toàn"
    p.text-xs.text-muted-foreground  "Ô chuyển trạng thái REJECTED"

  /* Option C: Điều chỉnh sang DE khác */
  label...has-[:checked]:bg-blue-50.has-[:checked]:border-blue-300
    p.font-bold.text-primary  "Điều chỉnh sang Data Element khác"
    p.text-xs.text-muted-foreground  "Chọn DE đúng, ô chuyển DATABASE"
    /* Conditional: shown when option C selected */
    Combobox.mt-3  /* Search & select DE */

/* Reason textarea — REQUIRED */
Label.mt-4  "Lý do quyết định *"
Textarea.rounded-2xl  placeholder="Nhập lý do quyết định..."

/* Footer */
Button(variant="outline")  "Hủy"
Button(variant="default")  "Xác nhận quyết định"

Business Rules

  • Only Approver can resolve DISPUTED
  • Reason is required
  • Option A → cell CONFIRMED (green)
  • Option B → cell REJECTED (strikethrough)
  • Option C → cell DATABASE with new DE, opens Combobox to search DE
  • Toast: "Tranh chấp đã được giải quyết"
  • Data Owner receives notification of result

SCR-MAP-43: Popup Phê duyệt Bảng C Tổng thể

Trigger: Approver clicks "Phê duyệt Bảng C" button on SCR-MAP-10

Layout

+------------------------------------------+
| "Phê duyệt Bảng C tổng thể"            |
+------------------------------------------+
| Tổng quan trạng thái:                     |
| ┌────────────────────────────────────┐   |
| │ ✅ Sở đã xác nhận: 18/24 (75%)    │   |
| │ ⏳ Sở chưa xác nhận: 6            │   |
| │ 🔴 Ô DISPUTED: 0                  │   |
| └────────────────────────────────────┘   |
|                                          |
| [Guard check: ✅ > 70% confirmed]        |
| [Guard check: ✅ 0 DISPUTED]             |
|                                          |
| ⚠️ Sở chưa xác nhận quá deadline:       |
| - Sở Xây dựng (quá 5 ngày)              |
| - Sở Giao thông (quá 3 ngày)            |
| [Chốt đơn phương cho các Sở trên?] ☐    |
+------------------------------------------+
|        [Hủy] [Phê duyệt Bảng C]         |
+------------------------------------------+

Components

/* Dialog — max-w-xl */

/* Status summary card */
bg-muted/50 rounded-2xl p-6 space-y-3
  /* Each stat line */
  flex items-center gap-3 text-sm
    /* Confirmed */ CheckCircle.h-5.w-5.text-success + span.font-bold
    /* Pending */   Clock.h-5.w-5.text-warning + span.font-bold
    /* DISPUTED */  AlertTriangle.h-5.w-5.text-destructive + span.font-bold

  /* Progress bar for % confirmed */
  div.h-3.bg-muted.rounded-full.overflow-hidden.mt-2
    div.h-full.bg-success.rounded-full  /* width = % */

/* Guard condition checks */
space-y-2.mt-4
  /* Each guard — pass or fail */
  flex items-center gap-2 text-sm
    /* Pass */ CheckCircle.h-4.w-4.text-success  span.text-success.font-semibold
    /* Fail */ XCircle.h-4.w-4.text-destructive  span.text-destructive.font-semibold

/* Overdue units list (if any) */
bg-warning/10 border border-warning/20 rounded-2xl p-4 mt-4
  h4.text-sm.font-bold.text-warning  "Sở chưa xác nhận quá deadline:"
  ul.mt-2.space-y-1.text-sm.text-muted-foreground
    /* Each: unit name + days overdue */
  /* Checkbox: "Chốt đơn phương" */
  label.flex.items-center.gap-2.mt-3.text-sm.font-semibold
    Checkbox
    "Chốt đơn phương cho các Sở trên (đánh dấu 'Chốt bởi Ban Quản trị')"

/* Footer */
Button(variant="outline")  "Hủy"
Button(variant="default", disabled={!guardsPass})
  CheckCircle.h-4.w-4.mr-2  "Phê duyệt Bảng C"
/* Button disabled state: opacity-50, tooltip "Chưa đạt điều kiện phê duyệt" */

Business Rules

  • Guard 1: > 70% units confirmed → green check
  • Guard 2: 0 DISPUTED remaining → green check
  • Both guards must pass for approval button to be enabled
  • Overdue units: Approver can check "Chốt đơn phương" checkbox
  • After approval: Bảng C → "Đã chốt", ready for EP-04 (Quy hoạch)
  • AlertDialog confirm before final approval (irreversible action)

Approval Confirmation (AlertDialog, after clicking "Phê duyệt")

AlertDialog
  title: "Xác nhận phê duyệt Bảng C?"
  description: "Sau khi phê duyệt, Bảng C sẽ được chốt chính thức.
               Bước tiếp theo là quy hoạch chủ quản (Bảng D).
               Hành động này không thể hoàn tác."
  cancel: "Quay lại"
  action: Button(variant="default")  "Phê duyệt chính thức"

Accessibility (all DISPUTED screens)

  • SCR-MAP-40: Character counter announced via aria-live="polite"
  • SCR-MAP-41: Table with aria-label="Danh sách ô tranh chấp"
  • SCR-MAP-42: Radio group aria-label="Quyết định giải quyết tranh chấp"
  • SCR-MAP-43: Guard conditions role="status", button disabled state aria-disabled="true" with tooltip
  • All dialogs: focus trap, Escape to close, auto-focus first interactive element

MASTER.md Overrides

What MASTER.md This Page Reason
SCR-MAP-40 header bg border-b border-border bg-destructive/5 Visual warning for destructive-adjacent action
SCR-MAP-42 dialog width max-w-lg max-w-xl Need room for 3 radio options with descriptions + conditional combobox