Declaration Detail Page¶
Overview¶
The Declaration Detail page (/declarations/:id) provides a comprehensive view of a single Form 3A/3B/3C declaration, its workflow approval chain, full form data, and historical activity timeline. The page is implemented in client/src/pages/DeclarationDetailPage.tsx.
Page context: The page wraps its content in <PageEntityProvider entity={{ kind: 'declaration', id: asDeclarationId(declaration.id) }}>, providing the declaration ID to the chatbot.
Page Layout¶
Header¶
The PageHeader component displays:
- Title: "Declaration #N" (numeric ID)
- Subtitle: form type label + representative name
- Breadcrumbs: Dashboard > Declarations > Declaration #N
- Right side: StatusBadge for current declaration status + days-pending badge (color-coded: green 0-3 days, amber 4-5, red 6+)
Metadata Card (2-Column Grid)¶
Left column:
- Representative Name (from declaration.rep_name or form_data.personal_info.full_name)
- Rep ID (declaration.rep_id)
- Form Type (via formTypeLabel() util: "Form 3A", "Form 3B", or "Form 3C")
- Status (via StatusBadge component)
- Days Pending (computed from submitted_at; color-coded green/amber/red)
Right column:
- Created (SG-locale datetime)
- Submitted (SG-locale datetime; "--" if not yet submitted)
- Last Updated (SG-locale datetime)
- Organisation (from form_data.general_info.principal_company_name)
Action Buttons Card (Conditional)¶
Shown when the current user can act on the declaration. Three possible states:
- Current Approver (
isCurrentApprover: user's ID matches the pending step'sapprover_user_id): - Blue left border with "Awaiting Your Decision" heading
- Buttons: Approve (green), Send Back (orange outline), Reject (red danger)
-
Subtitle: "Review the declaration and take action."
-
Draft Owner (
isDraft: declaration status is DRAFT and user owns it): - Buttons: Edit (outline), Submit (primary blue)
-
Subtitle: "Continue editing or submit this declaration."
-
Revision Required (
isRepWithRevision: declaration is REVISION_REQUESTED and user owns it): - Buttons: Edit (outline), Resubmit (primary with refresh icon)
- Subtitle: "This declaration was sent back for revision."
All approval actions (Approve, Reject, Send Back) require a mandatory comment and trigger a confirmation modal before executing the mutation.
Send-Back Detail Card¶
Shown when declaration status is REVISION_REQUESTED and a sent_back step exists in the workflow. Orange left border with:
- Heading: "Changes Requested" with warning icon
- Sent back by: step approver name + step number
- On: action date
- Reason: the approver's comment in a white bordered box (with whitespace-pre-wrap for multi-line comments)
Currently Waiting Card¶
Shown when declaration status is PENDING_REVIEW and the current step is pending. Blue left border with:
- Heading: "Currently waiting for: [Approver Name] at Step N of M"
- "Assigned since:" timestamp (previous step's acted_at or declaration's submitted_at)
- Idle days badge: green (0-3 days), amber (4-7), red (8+)
Workflow Stepper¶
Shown when a workflow instance exists with steps. Rendered via <WorkflowStepper> component in a card with blue top border:
- Sequential step circles connected by colored connector lines
- Each step shows: approver initial (or check/X icon for terminal states), approver name, status label, acted-at date
- Current step pulses with blue ring animation and shows "Waiting for: [Approver]" with idle-day indicator
- Completed steps show green checkmark; rejected show red X; sent-back show orange
- Connector lines: green for completed, red for rejected, orange for sent-back, gray for pending
Two-Column Content Area¶
Left Column (2/3 width):
- Approval Timeline (
Card): chronological list ofTimelineEntrycomponents from workflow events - Each entry: colored dot with action icon + vertical connector line + content
- Shows actor initials avatar, action label, actor name, timestamp (date + time)
- Comment displayed in colored background box (e.g., green for approved, red for rejected, orange for sent-back)
- Action types mapped:
approved/step_approved/approve(green check),rejected/step_rejected/reject(red X),sent_back/send_back/step_sent_back(orange rotate),submitted(amber send),resubmitted(amber refresh),sent_to_mas(indigo send),mas_approved(green check),mas_rejected(red X),created(blue file-plus),pending(gray clock) -
Empty state when no events: dashed border box with clock icon
-
Form Data Summary (
Card): toggle-able collapsible panel - Collapse/expand button: "Form Data Summary" heading with FileText icon + chevron
- When expanded, shows collapsible
FormSectioncomponents for each data category:- General Information (default open):
principal_company_name,rep_type,license_type,business_activity,product_type - Personal Information (default open):
full_name,email,nric,phone,date_of_birth,nationality,address - Education & Qualifications:
highest_qualification,institution,graduation_year,cmfas_modules - Employment History:
current_employer,position,years_experience,previous_employers - Regulatory Information:
has_criminal_record,has_regulatory_action,has_civil_proceedings,has_bankruptcy,declaration_remarks
- General Information (default open):
- Each section shows only non-empty fields
- "View full declaration form" link at bottom navigates to the Form 3A view-only page
Right Column (1/3 width):
-
Export Card: PDF and DOCX export buttons, each calling the FastAPI export endpoint via
exportDeclarationPdf()/exportDeclarationDocx()helpers fromclient/src/services/api.ts -
Quick Info Card: compact summary with key-value rows: Rep Name, Status (with StatusBadge), Submitted, Last Updated, Created
Modals¶
Approve/Reject Modal: triggered by the action buttons. Shows: - Declaration summary (ID, rep, form type, status) - Mandatory comment textarea with role-specific placeholder - Cancel and Confirm buttons
Send Back Modal: triggered by "Send Back" or "Request Changes". Shows: - Declaration summary (ID, rep) - "What changes are needed?" textarea (mandatory) - Cancel and Send Back buttons (orange-themed)
On confirmation, the modal calls the corresponding mutation (approveWorkflowStep, rejectWorkflowStep, or sendBackWorkflowStep) and refetches all data on success.
GraphQL Data Sources¶
| Query | Purpose | Key Fields |
|---|---|---|
declaration(id) |
Fetch declaration metadata | id, rep_id, rep_name, user_id, form_type, status, form_data, created_at, submitted_at, updated_at |
workflowInstances(declarationId) |
Fetch linked workflow | id, declaration_id, rep_id, status, current_step_index, steps { step_index, approver_user_id, approver_name, status, comment, acted_at } |
workflowEvents(declarationId) |
Fetch activity history | id, event_type, actor_name, created_at, comment |
| Mutation | Purpose | Parameters |
|---|---|---|
approveWorkflowStep |
Approve current step | instanceId, stepIndex, comment |
rejectWorkflowStep |
Reject current step | instanceId, stepIndex, comment |
sendBackWorkflowStep |
Send back for revision | instanceId, stepIndex, comment |
Role-Based Actions¶
| User Condition | Available Actions | Effect |
|---|---|---|
| Current approver (pending step matches user) | Approve, Send Back, Reject | Advances/reverts/sends back the workflow |
| Rep owner + DRAFT status | Edit, Submit | Navigates to the Form 3A single-page form |
| Rep owner + REVISION_REQUESTED status | Edit, Resubmit | Navigates to the Form 3A single-page form in edit mode |
| Other users / terminal states | None | View-only + export buttons |
Page Context Details¶
The DeclarationDetailPage publishes { kind: 'declaration', id: DeclarationId } to the chatbot. When responding to page-context queries about a declaration, the chatbot should:
- Examine the declaration status, form type, and rep name from the page context
- Read the workflow state (current step, pending approver, idle days) to diagnose stalls
- Check whether the current user is the active approver, the rep owner, or a viewer
- Report specific numbers: days pending, step position, approver names
- Not fabricate data — the chatbot must call GraphQL queries via the page context if page data is stale