Files
trackgo-fe/packages/ui/src/components/status-badge/status-badge.tsx
T
shancheas a5a42cf87e feat: add privileges management module with CRUD functionality
- Introduced a new Privileges module, including routes for creating, editing, and viewing privileges.
- Implemented a detailed permissions matrix for managing actions (view, create, update, delete, import) associated with each privilege.
- Added validation schema for privilege creation and editing.
- Developed UI components for displaying and managing privilege details and permissions.
- Integrated language support for English and Indonesian in the privileges module.
- Created unit tests for the privileges remote data service and transformer to ensure functionality.

This commit enhances the application by providing a comprehensive privileges management system, improving user role management and permissions handling.
2026-08-25 19:06:50 +07:00

287 lines
10 KiB
TypeScript

import React from 'react';
import { Badge, BadgeProps } from '@mantine/core';
import {
CheckCircle2,
XCircle,
Clock,
Edit2,
Loader2,
Package,
AlertCircle,
RotateCcw,
Check,
CreditCard,
Send,
Users,
} from 'lucide-react';
export enum STATUS_DATA {
DRAFT = 'draft',
ACTIVE = 'active',
ACTIVATED = 'activated',
INACTIVE = 'inactive',
DEACTIVATED = 'deactivated',
ARCHIVED = 'archived',
REQUEST = 'request',
REQUESTING = 'requesting',
REQUESTED = 'requested',
APPROVAL = 'approval',
APPROVED = 'approved',
OPEN = 'open',
OPENED = 'opened',
PENDING = 'pending',
WAIT = 'wait',
WAITING = 'waiting',
WAITING_LIST = 'waiting-list',
PROCESS = 'process',
PROCESSING = 'processing',
IN_PROCESS = 'in-process',
PROCESSED = 'processed',
CLOSE = 'close',
CLOSED = 'closed',
CANCEL = 'cancel',
CANCELLED = 'cancelled',
COMPLETE = 'complete',
COMPLETED = 'completed',
TODO = 'todo',
DONE = 'done',
PARTIAL_DONE = 'partial-done',
ON_HOLD = 'on-hold',
SHIPMENT = 'shipment',
SHIPPING = 'shipping',
SHIPPED = 'shipped',
EXPIRED = 'expired',
REFUND = 'refund',
REFUNDED = 'refunded',
PARTIAL_REFUND = 'partial-refund',
PARTIALLY_REFUNDED = 'partially-refunded',
REFUND_PROCESSING = 'refund-processing',
REFUND_PROCESS = 'refund-process',
CANCEL_REFUNDED = 'cancel-refunded',
TRANSFERRED = 'transferred',
SETTLEMENT = 'settlement',
SETTLED = 'settled',
SETTLED_FREE = 'settled-free',
REJECTION = 'rejection',
REJECTED = 'rejected',
PAYMENT = 'payment',
PAID = 'paid',
ISSUE = 'issue',
PROBLEM = 'problem',
RESOLVED = 'resolved',
CHECKOUT = 'checkout',
INVOICE = 'invoice',
INVOICED = 'invoiced',
JOINED = 'joined',
INVITED = 'invited',
PRESENT = 'present',
}
export enum STATUS_COLOR {
// DRAFT = '#6A6725',
DRAFT = '#B6B6B6',
TODO = '#CCCF77',
// INACTIVE = '#6A252A',
// DEACTIVATED = '#792A2C',
INACTIVE = '#BC1913',
DEACTIVATED = '#BC1913',
CLOSE = '#883230',
CLOSED = '#973C35',
// ACTIVE = '#518F00',
// ACTIVATED = '#539B01',
ACTIVE = '#54B304',
ACTIVATED = '#54B304',
APPROVED = '#54A702',
PROCESSED = '#54B304',
COMPLETED = '#54BE05',
COMPLETE = '#53CA07',
DONE = '#51D509',
SHIPPED = '#4EE00B',
REFUNDED = '#4BEB0D',
SETTLED = '#4BF114',
PAID = '#4DF022',
INVOICED = '#51EF30',
RESOLVED = '#56EF3D',
JOINED = '#5CEF4B',
PRESENT = '#62EE58',
REQUEST = '#00758F',
REQUESTING = '#017A9D',
REQUESTED = '#037FAB',
OPEN = '#0482B8',
OPENED = '#0685C6',
PROCESS = '#0886D3',
PROCESSING = '#0B86E0',
IN_PROCESS = '#0D86ED',
SHIPMENT = '#1985F0',
SHIPPING = '#2985F0',
TRANSFERRED = '#3986EF',
PAYMENT = '#4988EF',
INVOICE = '#588BEE',
APPROVAL = '#8F4500',
PENDING = '#9D5301',
WAIT = '#AB6103',
WAITING = '#B87104',
WAITING_LIST = '#C68106',
PARTIAL_DONE = '#D39308',
ON_HOLD = '#E0A50B',
REFUND = '#EDB70D',
REFUND_PROCESSING = '#F0C519',
REFUND_PROCESS = '#F0C519',
PARTIAL_REFUND = '#F0D029',
PARTIALLY_REFUNDED = '#EFD939',
SETTLEMENT = '#EFE149',
INVITED = '#EEE858',
CANCEL = '#7C1217',
CANCELLED = '#991B1A',
REJECTION = '#B52B24',
REJECTED = '#CF3D2E',
ISSUE = '#D3614F',
PROBLEM = '#D78270',
EXPIRED = '#8F0005',
CANCEL_REFUNDED = '#BC1913',
CHECKOUT = '#FF7B00',
SETTLED_FREE = '#3D6E93',
}
export type StatusBadgeConfigCallback = (status: string) => Partial<BadgeProps>;
export interface StatusBadgeProps extends Omit<BadgeProps, 'color' | 'leftSection'> {
/** The status string or STATUS_DATA enum value */
status: STATUS_DATA | string;
/** Optional custom label, overrides default status string */
label?: string;
/** Callback to provide custom badge props (color, icon) for a specific status */
getCustomConfig?: StatusBadgeConfigCallback;
/** Overrides default and custom color */
color?: string;
/** Overrides default and custom leftSection icon */
leftSection?: React.ReactNode;
}
const ICON_SIZE = 12;
const STROKE_WIDTH = 2.5;
const getIcon = (IconCmp: any) => <IconCmp size={ICON_SIZE} strokeWidth={STROKE_WIDTH} />;
export const DEFAULT_STATUS_MAP: Record<string, BadgeProps> = {
[STATUS_DATA.DRAFT]: { color: STATUS_COLOR.DRAFT, leftSection: getIcon(Edit2) },
[STATUS_DATA.TODO]: { color: STATUS_COLOR.TODO, leftSection: getIcon(Clock) },
[STATUS_DATA.INACTIVE]: { color: STATUS_COLOR.INACTIVE, leftSection: getIcon(XCircle) },
[STATUS_DATA.ARCHIVED]: { color: STATUS_COLOR.INACTIVE, leftSection: getIcon(XCircle) },
[STATUS_DATA.DEACTIVATED]: { color: STATUS_COLOR.DEACTIVATED, leftSection: getIcon(XCircle) },
[STATUS_DATA.CLOSE]: { color: STATUS_COLOR.CLOSE, leftSection: getIcon(XCircle) },
[STATUS_DATA.CLOSED]: { color: STATUS_COLOR.CLOSED, leftSection: getIcon(XCircle) },
[STATUS_DATA.ACTIVE]: { color: STATUS_COLOR.ACTIVE, leftSection: getIcon(CheckCircle2) },
[STATUS_DATA.ACTIVATED]: { color: STATUS_COLOR.ACTIVATED, leftSection: getIcon(CheckCircle2) },
[STATUS_DATA.APPROVED]: { color: STATUS_COLOR.APPROVED, leftSection: getIcon(CheckCircle2) },
[STATUS_DATA.PROCESSED]: { color: STATUS_COLOR.PROCESSED, leftSection: getIcon(Check) },
[STATUS_DATA.COMPLETED]: { color: STATUS_COLOR.COMPLETED, leftSection: getIcon(CheckCircle2) },
[STATUS_DATA.COMPLETE]: { color: STATUS_COLOR.COMPLETE, leftSection: getIcon(CheckCircle2) },
[STATUS_DATA.DONE]: { color: STATUS_COLOR.DONE, leftSection: getIcon(CheckCircle2) },
[STATUS_DATA.SHIPPED]: { color: STATUS_COLOR.SHIPPED, leftSection: getIcon(Check) },
[STATUS_DATA.REFUNDED]: { color: STATUS_COLOR.REFUNDED, leftSection: getIcon(RotateCcw) },
[STATUS_DATA.SETTLED]: { color: STATUS_COLOR.SETTLED, leftSection: getIcon(CheckCircle2) },
[STATUS_DATA.PAID]: { color: STATUS_COLOR.PAID, leftSection: getIcon(CreditCard) },
[STATUS_DATA.INVOICED]: { color: STATUS_COLOR.INVOICED, leftSection: getIcon(CreditCard) },
[STATUS_DATA.RESOLVED]: { color: STATUS_COLOR.RESOLVED, leftSection: getIcon(CheckCircle2) },
[STATUS_DATA.JOINED]: { color: STATUS_COLOR.JOINED, leftSection: getIcon(Users) },
[STATUS_DATA.PRESENT]: { color: STATUS_COLOR.PRESENT, leftSection: getIcon(Users) },
[STATUS_DATA.REQUEST]: { color: STATUS_COLOR.REQUEST, leftSection: getIcon(Send) },
[STATUS_DATA.REQUESTING]: { color: STATUS_COLOR.REQUESTING, leftSection: getIcon(Send) },
[STATUS_DATA.REQUESTED]: { color: STATUS_COLOR.REQUESTED, leftSection: getIcon(Send) },
[STATUS_DATA.OPEN]: { color: STATUS_COLOR.OPEN, leftSection: getIcon(CheckCircle2) },
[STATUS_DATA.OPENED]: { color: STATUS_COLOR.OPENED, leftSection: getIcon(CheckCircle2) },
[STATUS_DATA.PROCESS]: { color: STATUS_COLOR.PROCESS, leftSection: getIcon(Loader2) },
[STATUS_DATA.PROCESSING]: { color: STATUS_COLOR.PROCESSING, leftSection: getIcon(Loader2) },
[STATUS_DATA.IN_PROCESS]: { color: STATUS_COLOR.IN_PROCESS, leftSection: getIcon(Loader2) },
[STATUS_DATA.SHIPMENT]: { color: STATUS_COLOR.SHIPMENT, leftSection: getIcon(Package) },
[STATUS_DATA.SHIPPING]: { color: STATUS_COLOR.SHIPPING, leftSection: getIcon(Package) },
[STATUS_DATA.TRANSFERRED]: { color: STATUS_COLOR.TRANSFERRED, leftSection: getIcon(Send) },
[STATUS_DATA.PAYMENT]: { color: STATUS_COLOR.PAYMENT, leftSection: getIcon(CreditCard) },
[STATUS_DATA.INVOICE]: { color: STATUS_COLOR.INVOICE, leftSection: getIcon(CreditCard) },
[STATUS_DATA.APPROVAL]: { color: STATUS_COLOR.APPROVAL, leftSection: getIcon(CheckCircle2) },
[STATUS_DATA.PENDING]: { color: STATUS_COLOR.PENDING, leftSection: getIcon(Clock) },
[STATUS_DATA.WAIT]: { color: STATUS_COLOR.WAIT, leftSection: getIcon(Clock) },
[STATUS_DATA.WAITING]: { color: STATUS_COLOR.WAITING, leftSection: getIcon(Clock) },
[STATUS_DATA.WAITING_LIST]: { color: STATUS_COLOR.WAITING_LIST, leftSection: getIcon(Clock) },
[STATUS_DATA.PARTIAL_DONE]: { color: STATUS_COLOR.PARTIAL_DONE, leftSection: getIcon(Clock) },
[STATUS_DATA.ON_HOLD]: { color: STATUS_COLOR.ON_HOLD, leftSection: getIcon(Clock) },
[STATUS_DATA.REFUND]: { color: STATUS_COLOR.REFUND, leftSection: getIcon(RotateCcw) },
[STATUS_DATA.REFUND_PROCESSING]: { color: STATUS_COLOR.REFUND_PROCESSING, leftSection: getIcon(Loader2) },
[STATUS_DATA.REFUND_PROCESS]: { color: STATUS_COLOR.REFUND_PROCESS, leftSection: getIcon(Loader2) },
[STATUS_DATA.PARTIAL_REFUND]: { color: STATUS_COLOR.PARTIAL_REFUND, leftSection: getIcon(RotateCcw) },
[STATUS_DATA.PARTIALLY_REFUNDED]: { color: STATUS_COLOR.PARTIALLY_REFUNDED, leftSection: getIcon(RotateCcw) },
[STATUS_DATA.SETTLEMENT]: { color: STATUS_COLOR.SETTLEMENT, leftSection: getIcon(CheckCircle2) },
[STATUS_DATA.INVITED]: { color: STATUS_COLOR.INVITED, leftSection: getIcon(Users) },
[STATUS_DATA.CANCEL]: { color: STATUS_COLOR.CANCEL, leftSection: getIcon(XCircle) },
[STATUS_DATA.CANCELLED]: { color: STATUS_COLOR.CANCELLED, leftSection: getIcon(XCircle) },
[STATUS_DATA.REJECTION]: { color: STATUS_COLOR.REJECTION, leftSection: getIcon(XCircle) },
[STATUS_DATA.REJECTED]: { color: STATUS_COLOR.REJECTED, leftSection: getIcon(XCircle) },
[STATUS_DATA.ISSUE]: { color: STATUS_COLOR.ISSUE, leftSection: getIcon(AlertCircle) },
[STATUS_DATA.PROBLEM]: { color: STATUS_COLOR.PROBLEM, leftSection: getIcon(AlertCircle) },
[STATUS_DATA.EXPIRED]: { color: STATUS_COLOR.EXPIRED, leftSection: getIcon(AlertCircle) },
[STATUS_DATA.CANCEL_REFUNDED]: { color: STATUS_COLOR.CANCEL_REFUNDED, leftSection: getIcon(XCircle) },
[STATUS_DATA.CHECKOUT]: { color: STATUS_COLOR.CHECKOUT, leftSection: getIcon(CreditCard) },
[STATUS_DATA.SETTLED_FREE]: { color: STATUS_COLOR.SETTLED_FREE, leftSection: getIcon(CheckCircle2) },
};
export function StatusBadge({ status, label, getCustomConfig, color, ...rest }: StatusBadgeProps) {
if (!status) return null;
const normalizedStatus = status?.toLowerCase() || '';
const defaultConfig = DEFAULT_STATUS_MAP[normalizedStatus] || { color: 'gray' };
const customConfig = getCustomConfig ? getCustomConfig(normalizedStatus) : {};
return (
<Badge
size="sm"
radius="sm"
fw={600}
style={{ textTransform: 'capitalize' }}
variant={customConfig.variant ? customConfig.variant : 'light'}
color={color || customConfig.color || defaultConfig.color}
{...rest}
>
{label || (status ? status.replace(/-/g, ' ') : 'Unknown')}
</Badge>
);
}