232 lines
8.5 KiB
TypeScript
232 lines
8.5 KiB
TypeScript
/**
|
|
* Unified status & progress colors across the app.
|
|
* Uses CSS classes from globals.css (amber) — NOT Tailwind bg-amber-* (remapped to re-red globally).
|
|
*
|
|
* - In progress / active: amber via .bg-status-progress / .bg-status-workflow-*
|
|
* - Completed / success: green
|
|
* - Rejected / revoked: re-red
|
|
*
|
|
* Primary buttons / brand UI: use bg-re-red (never amber).
|
|
*/
|
|
|
|
const TERMINAL_NEGATIVE = ['Rejected', 'Revoked', 'Withdrawn'] as const;
|
|
|
|
export type StatusProgressVariant = 'inProgress' | 'success' | 'negative' | 'neutral';
|
|
|
|
export function isStatusTerminalNegative(
|
|
status: string | null | undefined,
|
|
currentStage?: string | null | undefined
|
|
): boolean {
|
|
const s = String(status || '');
|
|
const stage = String(currentStage || '');
|
|
return TERMINAL_NEGATIVE.some((label) => s.includes(label) || stage === label);
|
|
}
|
|
|
|
export function isStatusTerminalSuccess(
|
|
status: string | null | undefined,
|
|
currentStage?: string | null | undefined
|
|
): boolean {
|
|
const s = String(status || '');
|
|
const stage = String(currentStage || '');
|
|
return (
|
|
s === 'Completed' ||
|
|
stage === 'Completed' ||
|
|
s === 'Settled' ||
|
|
s === 'Onboarded' ||
|
|
s === 'Verified' ||
|
|
s === 'Closed'
|
|
);
|
|
}
|
|
|
|
export function resolveStatusProgressVariant(
|
|
status: string | null | undefined,
|
|
currentStage?: string | null | undefined
|
|
): StatusProgressVariant {
|
|
if (isStatusTerminalSuccess(status, currentStage)) return 'success';
|
|
if (isStatusTerminalNegative(status, currentStage)) return 'negative';
|
|
return 'inProgress';
|
|
}
|
|
|
|
/** Semantic class sets — status/progress uses globals.css amber tokens */
|
|
export const STATUS_PROGRESS_THEME = {
|
|
inProgress: {
|
|
bar: 'bg-status-progress',
|
|
barBadge: 'bg-status-progress hover:bg-status-progress-hover text-white border-transparent',
|
|
badge: 'bg-status-progress-soft text-status-progress-strong border-status-progress',
|
|
badgeSolid: 'bg-status-progress hover:bg-status-progress-hover text-white border-transparent',
|
|
text: 'text-status-progress-muted',
|
|
textStrong: 'text-status-progress-strong',
|
|
icon: 'text-status-progress',
|
|
workflowIcon: 'bg-status-workflow-icon',
|
|
workflowPanel: 'bg-status-workflow-panel -ml-4 pl-4 pr-4 py-3 rounded-lg border border-status-workflow-panel',
|
|
workflowTitle: 'text-status-progress-strong',
|
|
workflowSubtitle: 'text-status-progress-muted',
|
|
workflowStageBadge: 'bg-status-workflow-badge border',
|
|
panel: 'bg-status-workflow-panel -ml-4 pl-4 pr-4 py-3 rounded-lg border border-status-workflow-panel',
|
|
title: 'text-status-progress-strong',
|
|
subtitle: 'text-status-progress-muted',
|
|
stageBadge: 'bg-status-workflow-badge border',
|
|
progress: 'bg-status-progress',
|
|
workflowActive: 'bg-status-workflow-active',
|
|
},
|
|
success: {
|
|
bar: 'bg-green-600',
|
|
barBadge: 'bg-green-600 hover:bg-green-700 text-white border-transparent',
|
|
badge: 'bg-green-100 text-green-800 border-green-200',
|
|
badgeSolid: 'bg-green-600 hover:bg-green-700 text-white border-transparent',
|
|
text: 'text-green-700',
|
|
textStrong: 'text-green-900',
|
|
icon: 'text-green-600',
|
|
workflowIcon: 'bg-green-100 text-green-600',
|
|
workflowPanel: 'bg-green-50 border border-green-200',
|
|
workflowTitle: 'text-green-900',
|
|
workflowSubtitle: 'text-green-700',
|
|
workflowStageBadge: 'bg-green-100 text-green-700 border-green-300',
|
|
panel: 'bg-green-50 border border-green-200',
|
|
title: 'text-green-900',
|
|
subtitle: 'text-green-700',
|
|
stageBadge: 'bg-green-100 text-green-700 border-green-300',
|
|
progress: 'bg-green-600',
|
|
workflowActive: 'bg-green-600 border-green-600',
|
|
},
|
|
negative: {
|
|
bar: 'bg-re-red',
|
|
barBadge: 'bg-re-red hover:bg-re-red-hover text-white border-transparent',
|
|
badge: 'bg-red-50 text-re-red border-red-200',
|
|
badgeSolid: 'bg-re-red hover:bg-re-red-hover text-white border-transparent',
|
|
text: 'text-re-red-hover',
|
|
textStrong: 'text-red-900',
|
|
icon: 'text-re-red',
|
|
workflowIcon: 'bg-red-100 text-re-red',
|
|
workflowPanel: 'bg-red-50 border border-red-200',
|
|
workflowTitle: 'text-red-900',
|
|
workflowSubtitle: 'text-re-red-hover',
|
|
workflowStageBadge: 'bg-red-50 text-re-red border-red-200',
|
|
panel: 'bg-red-50 border border-red-200',
|
|
title: 'text-red-900',
|
|
subtitle: 'text-re-red-hover',
|
|
stageBadge: 'bg-red-50 text-re-red border-red-200',
|
|
progress: 'bg-re-red',
|
|
workflowActive: 'bg-re-red border-re-red',
|
|
},
|
|
neutral: {
|
|
bar: 'bg-slate-300',
|
|
barBadge: 'bg-slate-500 text-white border-transparent',
|
|
badge: 'bg-slate-100 text-slate-700 border-slate-200',
|
|
badgeSolid: 'bg-slate-600 hover:bg-slate-700 text-white border-transparent',
|
|
text: 'text-slate-600',
|
|
textStrong: 'text-slate-900',
|
|
icon: 'text-slate-500',
|
|
workflowIcon: 'bg-slate-100 text-slate-400',
|
|
workflowPanel: '',
|
|
workflowTitle: 'text-slate-900',
|
|
workflowSubtitle: 'text-slate-600',
|
|
workflowStageBadge: 'bg-slate-100 text-slate-500 border-slate-300',
|
|
panel: '',
|
|
title: 'text-slate-900',
|
|
subtitle: 'text-slate-600',
|
|
stageBadge: 'bg-slate-100 text-slate-500 border-slate-300',
|
|
progress: 'bg-slate-300',
|
|
workflowActive: 'bg-slate-400 border-slate-400',
|
|
},
|
|
} as const;
|
|
|
|
function themeFor(status: string | null | undefined, currentStage?: string | null | undefined) {
|
|
return STATUS_PROGRESS_THEME[resolveStatusProgressVariant(status, currentStage)];
|
|
}
|
|
|
|
export function getStatusProgressBarClass(
|
|
status: string | null | undefined,
|
|
currentStage?: string | null | undefined
|
|
): string {
|
|
return themeFor(status, currentStage).bar;
|
|
}
|
|
|
|
export function getStatusProgressBadgeSolidClass(
|
|
status: string | null | undefined,
|
|
currentStage?: string | null | undefined
|
|
): string {
|
|
return themeFor(status, currentStage).barBadge;
|
|
}
|
|
|
|
export function getStatusProgressBadgeClass(
|
|
status: string | null | undefined,
|
|
currentStage?: string | null | undefined
|
|
): string {
|
|
return themeFor(status, currentStage).badge;
|
|
}
|
|
|
|
export function getWorkflowActiveStageTheme() {
|
|
return STATUS_PROGRESS_THEME.inProgress;
|
|
}
|
|
|
|
/** Progress bar / badge from completion % (EOR checklist, sub-trackers, etc.) */
|
|
export function getPercentProgressBarClass(percent: number): string {
|
|
if (percent >= 100) return STATUS_PROGRESS_THEME.success.bar;
|
|
return STATUS_PROGRESS_THEME.inProgress.bar;
|
|
}
|
|
|
|
export function getPercentProgressBadgeSolidClass(percent: number): string {
|
|
if (percent >= 100) return STATUS_PROGRESS_THEME.success.barBadge;
|
|
return STATUS_PROGRESS_THEME.inProgress.barBadge;
|
|
}
|
|
|
|
export function getStatusLabelBadgeClass(status: string | null | undefined): string {
|
|
const s = String(status || '');
|
|
const upper = s.toUpperCase();
|
|
if (s.includes('Rejected') || upper.includes('DOCUMENT_REJECTED')) {
|
|
return STATUS_PROGRESS_THEME.negative.badge;
|
|
}
|
|
if (s === 'Verified' || s === 'Completed' || upper.includes('DOCUMENT_VERIFIED')) {
|
|
return STATUS_PROGRESS_THEME.success.badge;
|
|
}
|
|
if (s.includes('Pending') || s.includes('Review') || s === 'In Progress') {
|
|
return STATUS_PROGRESS_THEME.inProgress.badge;
|
|
}
|
|
return STATUS_PROGRESS_THEME.neutral.badge;
|
|
}
|
|
|
|
/** Request status on listing/detail header — re-red while active (not amber). */
|
|
export function getRequestStatusBadgeClass(
|
|
status: string | null | undefined,
|
|
currentStage?: string | null | undefined
|
|
): string {
|
|
if (isStatusTerminalSuccess(status, currentStage)) {
|
|
return STATUS_PROGRESS_THEME.success.badge;
|
|
}
|
|
if (isStatusTerminalNegative(status, currentStage)) {
|
|
return STATUS_PROGRESS_THEME.negative.badge;
|
|
}
|
|
return STATUS_PROGRESS_THEME.negative.badge;
|
|
}
|
|
|
|
/** Solid request status pill (detail header). */
|
|
export function getRequestStatusBadgeSolidClass(
|
|
status: string | null | undefined,
|
|
currentStage?: string | null | undefined
|
|
): string {
|
|
if (isStatusTerminalSuccess(status, currentStage)) {
|
|
return STATUS_PROGRESS_THEME.success.badgeSolid;
|
|
}
|
|
if (isStatusTerminalNegative(status, currentStage)) {
|
|
return STATUS_PROGRESS_THEME.negative.badgeSolid;
|
|
}
|
|
return STATUS_PROGRESS_THEME.negative.badgeSolid;
|
|
}
|
|
|
|
/** Current stage chip (e.g. ASM Review) — brand re-red, not amber/yellow. */
|
|
export function getCurrentStageBadgeClass(
|
|
stage: string | null | undefined,
|
|
requestStatus?: string | null | undefined
|
|
): string {
|
|
const s = String(stage || '');
|
|
const status = String(requestStatus || '');
|
|
if (isStatusTerminalNegative(status, s) || /rejected|revoked/i.test(s)) {
|
|
return STATUS_PROGRESS_THEME.negative.badge;
|
|
}
|
|
if (s === 'Completed' || status === 'Completed' || s === 'Closed') {
|
|
return STATUS_PROGRESS_THEME.success.badge;
|
|
}
|
|
return STATUS_PROGRESS_THEME.negative.badge;
|
|
}
|