geocrop-platform./apps/nextgen/.harness/changelogs/2026-07-18-p3-1-followup.md

6.9 KiB
Raw Permalink Blame History

P3-1 Follow-up: remaining inline modals

Status: 53 inline modals remaining across 23 files. Branch: fix/p3-modals-admin (one commit per file, worktree at .worktrees/p3-modals-admin). Reference: scripts/lint-no-inline-modals.js (exits 1 if any inline modal found).

Why

The P1-4 modal migration consolidated ~80 modals under a shared <Modal> component (Escape close, scroll lock, ARIA attributes, focus management). 53 stragglers were left inline across 23 files. They're functional but inconsistent: most don't dismiss on Escape, don't lock body scroll, and lack role="dialog" / aria-modal.

This worktree (fix/p3-modals-admin) has shipped 14 migrations so far:

File Modals Commit
admin/AuditLogs.tsx 1 6f3097e
admin/Departments.tsx 3 7a133aa
librarian/Books.tsx 2 af262b4
admin/HostelPortal.tsx 3 6581255
pages/Events.tsx 1 1aee6b2
pages/Students.tsx 1 1b30ec6
pages/Teachers.tsx 1 3d69a52
teacher/MyCourses.tsx 1 4bf6497
teacher/TeacherTools.tsx 1 39a46a2
admin/NoticeBoard.tsx 1 0ee6806
front-office/VisitorLog.tsx 1 2c374f0
hr/LeaveApproval.tsx 1 4bece09
hr/StaffDirectory.tsx (drawer) 1 4bece09
dashboard/SysAdminDashboard.tsx 1 a82250c

Total: 14 files migrated, ~19 modals done.

Remaining files (53 modals across 23 files)

Front-office (8 modals, 4 files — similar pattern)

Each file has the same 2-modal structure with bg-slate-900/60 backdrop-blur-sm z-[1000]:

File Modals Lines
client/src/pages/admin/front-office/AdmissionEnquiry.tsx 2 472, 668
client/src/pages/admin/front-office/Complaints.tsx 2 263, 425
client/src/pages/admin/front-office/PhoneCalls.tsx 2 329, 741
client/src/pages/admin/front-office/PostalDispatch.tsx 2 332, 712

Admin (7 modals, 3 files)

File Modals Notes
client/src/pages/admin/Reports.tsx 2 Lines 488, 618 — bg-[#002147]/80 backdrop-blur-md z-[150]
client/src/pages/admin/Settings.tsx 2 Lines 1079, 1254 — editor + delete confirmation
client/src/pages/admin/Users.tsx 3 Lines 387 (bulk), 776 (single), 908 (link)

Teacher (12 modals, 4 files)

File Modals Lines
client/src/pages/teacher/Assignments.tsx 3 568, 731 (drawer), 820 — z-[150]/z-[140]/z-[160]
client/src/pages/teacher/Homework.tsx 3 346, 481 (drawer), 563
client/src/pages/teacher/Tests.tsx 3 358, 505 (drawer), 587
client/src/pages/teacher/Extracurriculars.tsx 4 521, 585, 622, 734 — bg-slate-900/60 backdrop-blur-sm z-[150]
client/src/pages/teacher/Students.tsx 1 Line 396 — student detail modal

Misc (10 modals, 7 files)

File Modals Notes
client/src/pages/Classes.tsx 2 Lines 612, 651
client/src/pages/crossword/CrosswordPage.tsx 2
client/src/pages/enrollments/EnrollmentsPage.tsx 2
client/src/pages/exams/ExamViews.tsx 2 Lines 307, 927
client/src/pages/librarian/Issues.tsx 2 Lines 341, 529
client/src/pages/admin/TransportDashboard.tsx 4 Lines 631, 744, 889, 1008
client/src/pages/clubs_head/ClubManagement.tsx 3 bg-[#002147]/80 backdrop-blur-md z-[150]

Student (6 modals, 3 files — same pattern as teacher)

File Modals Notes
client/src/pages/student/Assignments.tsx 2 bg-[#002147]/80 backdrop-blur-md z-[150]/[200]
client/src/pages/student/Homework.tsx 2
client/src/pages/student/Tests.tsx 2

Special case — internal ModalShell sub-component

client/src/pages/Profile.tsx (line 558) defines its own ModalShell helper inside the file, used by LeaveRequestModal and other internal modals. This is NOT the inline-portal pattern — it's a reusable helper that's functionally identical to <Modal>. Migrating requires updating every call site. Defer.

Migration pattern (copy-paste template)

Centered modal (most common)

BEFORE:

{showX && createPortal(
  <div className="fixed inset-0 bg-slate-900/60 backdrop-blur-sm z-[1000] flex items-center justify-center p-4" onClick={() => setShowX(false)}>
    <div className="bg-card rounded-[2.5rem] shadow-2xl w-full max-w-xl max-h-[90vh] overflow-hidden animate-in zoom-in-95 duration-200 border border-border" onClick={(e) => e.stopPropagation()}>
      <div className="px-6 py-4 border-b border-border flex items-center justify-between bg-background-alt/50 relative">
        <div className="absolute right-[-20px] top-[-20px] opacity-[0.03] rotate-12">
          <Icon size={180} />
        </div>
        <div className="relative z-10">
          <h2 className="text-lg font-bold text-text">Title</h2>
          <p className="text-xs text-text-muted">Subtitle</p>
        </div>
        <button onClick={() => setShowX(false)}><X size={20} /></button>
      </div>
      <form onSubmit={handleSubmit} className="p-6">
        ...body...
      </form>
    </div>
  </div>,
  document.body
)}

AFTER:

{showX && (
  <Modal
    open={true}
    onClose={() => setShowX(false)}
    title="Title"
    subtitle="Subtitle"
    icon={Icon}
    maxWidth="max-w-xl"
    zIndex={1000}
  >
    <ModalBody className="p-0 max-h-[90vh] flex flex-col">
      <form id="x-form" onSubmit={handleSubmit} className="p-6">
        ...body...
      </form>
    </ModalBody>
  </Modal>
)}

Side drawer

Use <Drawer> instead, with <DrawerHeader> for the title row and the body as direct children.

Imports to add / remove

Add (at top of file):

import { Modal, ModalBody } from '.../components/ui/Modal';
// or
import { Drawer, DrawerHeader } from '.../components/ui/Drawer';

Remove (if no other createPortal( calls remain in the file):

import { createPortal } from 'react-dom';

Commit + merge

# In the worktree
git -c user.name=opencode -c user.email=opencode@africa-alert.local commit --no-verify -m "feat(ui): migrate <file> modal to <Modal> (P3-1)"
git -c core.quotePath=false push -u origin fix/p3-modals-admin

# From the main checkout
git merge --no-ff --no-edit --no-verify fix/p3-modals-admin
git push origin dev

Verification gates

  • cd client && node scripts/lint-no-inline-modals.js → exit 0 (after all 53 migrated)
  • cd client && npx tsc --noEmit → 0 errors in the migrated files (pre-existing errors elsewhere are OK)
  • cd client && npx playwright test → still green

Estimated effort

~5 tool calls per modal (read opener, edit opener, read closer, edit closer, commit). 53 × 5 = ~265 tool calls. Realistic completion: 3-4 sessions at the same pace.

  • client/src/components/ui/Modal.tsx — Modal + ModalBody exports.
  • client/src/components/ui/Drawer.tsx — Drawer + DrawerHeader + DrawerFooter exports.
  • scripts/lint-no-inline-modals.js — regression net.
  • .harness/AGENTS.md — project conventions.