Skip to content

COMPONENT: ReportCard Component #53

@nayan458

Description

@nayan458

Task: ReportCard Component

Type: Component
Milestone: M0.5 — Shared Component Library
Estimate: M

Change Log

Updated: Now explicitly composes ListCard (not base Card directly). ListCard ticket must be completed before this one starts. Claimed state and deriveAvailableActions logic documented explicitly.

Component Type

  • Feature component (may use hooks)

Props Interface

interface ReportCardProps {
  report:          Report;
  isExpanded:      boolean;
  onToggleExpand:  () => void;
  onAction:        (reportId: string, action: ModerationAction) => void;
  isClaimed?:      boolean;
  claimedBy?:      string;
}

Internal Logic — deriveAvailableActions(report)

This function is the only place that decides which action buttons render. Maps directly to the Java backend state machine validateTransition().

Button Condition
Run AI screening status === 'PENDING' && aiConfidenceScore === 0
Remove content (status === 'PENDING' or 'ESCALATED') && targetType !== 'USER'
Ban author status === 'ESCALATED_TO_HUMAN'
Warn author status === 'PENDING' or 'ESCALATED_TO_HUMAN'
Dismiss status === 'PENDING' or 'ESCALATED_TO_HUMAN'
No buttons isClaimed === true — shows lock message instead

Variants / States

State Description
Collapsed Header row only — id, badges, title, AI score bar
Pending unscreened Expanded — "Run AI screening" button only
Pending screened Expanded — Remove + Warn + Dismiss
Escalated Expanded — all buttons including Ban author
Claimed Expanded — no buttons, shows "🔒 Being reviewed by {claimedBy}"
Resolved / Dismissed Expanded — read only, no action buttons

Acceptance Criteria

  • Composes ListCard — zero layout or expand logic duplicated here
  • deriveAvailableActions() is a pure function, unit tested independently
  • Correct buttons render for every status — verified via Storybook stories
  • onAction fires with correct (reportId, ModerationAction) — card does not execute the action itself
  • e.stopPropagation() on button clicks handled by ListCard footer — verify this works before closing
  • AI score bar uses ProgressBar shared component — not a raw div
  • Status badges use Badge shared component
  • Action buttons use Button shared component
  • Pipeline stepper uses StatusPipeline sub-component (private to this file unless reused)
  • Audit trail renders all entries with formatted timestamps
  • Zero hardcoded hex values
  • Storybook stories: one per state listed above + dark theme
  • Unit tested: deriveAvailableActions for all 6 statuses
  • No TypeScript errors

Notes

  • ListCard must be merged and signed off before this ticket starts
  • StatusPipeline and AuditTrail are sub-components private to this file — extract only if another feature needs them
  • deriveAvailableActions must be updated here if the backend state machine adds new valid transitions — single point of change

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requesttype: componentA reusable UI component (design system or feature-specific)

Type

No fields configured for Task.

Projects

Status

In progress

Relationships

None yet

Development

No branches or pull requests

Issue actions