fix(audit-wave-9): adopt StatusPill for berth + user status badges
- Extend StatusPill with berth (available/under_offer/sold) and user (enabled/disabled) variants so every "this thing is in state X" pill shares one primitive and palette. - Swap berth-card, berth-detail-header, berth-columns from ad-hoc bg-green-100 / bg-yellow-100 / bg-red-100 Tailwind tuples to <StatusPill status="...">. - Swap UserList Active/Disabled <Badge> and user-card Inactive pill to StatusPill; Super-Admin chip kept as a domain-specific accent (violet). Closes ui/ux M1+M2. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,23 +12,23 @@ import {
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { TagBadge } from '@/components/shared/tag-badge';
|
||||
import { ListCard, ListCardAvatar, ListCardMeta } from '@/components/shared/list-card';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { StatusPill, type StatusPillStatus } from '@/components/ui/status-pill';
|
||||
import { formatCurrency } from '@/lib/utils/currency';
|
||||
import type { BerthRow } from './berth-columns';
|
||||
import { mooringLetterDot } from './mooring-letter-tone';
|
||||
|
||||
const STATUS_VARIANTS: Record<string, string> = {
|
||||
available: 'bg-green-100 text-green-800 border-green-200',
|
||||
under_offer: 'bg-yellow-100 text-yellow-800 border-yellow-200',
|
||||
sold: 'bg-red-100 text-red-800 border-red-200',
|
||||
};
|
||||
|
||||
const STATUS_LABELS: Record<string, string> = {
|
||||
available: 'Available',
|
||||
under_offer: 'Under Offer',
|
||||
sold: 'Sold',
|
||||
};
|
||||
|
||||
const BERTH_STATUS_PILL: Record<string, StatusPillStatus> = {
|
||||
available: 'available',
|
||||
under_offer: 'under_offer',
|
||||
sold: 'sold',
|
||||
};
|
||||
|
||||
interface BerthCardProps {
|
||||
berth: BerthRow;
|
||||
}
|
||||
@@ -39,8 +39,7 @@ export function BerthCard({ berth }: BerthCardProps) {
|
||||
const portSlug = params?.portSlug ?? '';
|
||||
|
||||
const statusLabel = STATUS_LABELS[berth.status] ?? berth.status;
|
||||
const statusColor =
|
||||
STATUS_VARIANTS[berth.status] ?? 'bg-muted text-muted-foreground border-muted';
|
||||
const statusPill = BERTH_STATUS_PILL[berth.status] ?? 'pending';
|
||||
// Accent stripe groups visually by dock (A-row, B-row, ...). Status is
|
||||
// already conveyed by the pill below, so the stripe is dock-keyed.
|
||||
const accentClass = mooringLetterDot(berth.mooringNumber) ?? 'bg-slate-300';
|
||||
@@ -168,14 +167,7 @@ export function BerthCard({ berth }: BerthCardProps) {
|
||||
|
||||
{/* Status pill + tags */}
|
||||
<div className="mt-1.5 flex flex-wrap items-center gap-1.5">
|
||||
<span
|
||||
className={cn(
|
||||
'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-medium',
|
||||
statusColor,
|
||||
)}
|
||||
>
|
||||
{statusLabel}
|
||||
</span>
|
||||
<StatusPill status={statusPill}>{statusLabel}</StatusPill>
|
||||
{tags.slice(0, 2).map((tag) => (
|
||||
<TagBadge key={tag.id} name={tag.name} color={tag.color} />
|
||||
))}
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { TagBadge } from '@/components/shared/tag-badge';
|
||||
import { StatusPill, type StatusPillStatus } from '@/components/ui/status-pill';
|
||||
import { formatCurrency } from '@/lib/utils/currency';
|
||||
import { mooringLetterDot } from './mooring-letter-tone';
|
||||
import { stageBadgeClass, stageLabel } from '@/lib/constants';
|
||||
@@ -112,25 +113,23 @@ export const BERTH_DEFAULT_HIDDEN: string[] = [
|
||||
'pricingValidUntil',
|
||||
];
|
||||
|
||||
const BERTH_STATUS_PILL: Record<string, StatusPillStatus> = {
|
||||
available: 'available',
|
||||
under_offer: 'under_offer',
|
||||
sold: 'sold',
|
||||
};
|
||||
|
||||
const BERTH_STATUS_LABELS: Record<string, string> = {
|
||||
available: 'Available',
|
||||
under_offer: 'Under Offer',
|
||||
sold: 'Sold',
|
||||
};
|
||||
|
||||
function StatusBadge({ status }: { status: string }) {
|
||||
const variants: Record<string, string> = {
|
||||
available: 'bg-green-100 text-green-800 border-green-200',
|
||||
under_offer: 'bg-yellow-100 text-yellow-800 border-yellow-200',
|
||||
sold: 'bg-red-100 text-red-800 border-red-200',
|
||||
};
|
||||
|
||||
const labels: Record<string, string> = {
|
||||
available: 'Available',
|
||||
under_offer: 'Under Offer',
|
||||
sold: 'Sold',
|
||||
};
|
||||
|
||||
return (
|
||||
<span
|
||||
className={`inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-medium ${variants[status] ?? 'bg-muted text-muted-foreground'}`}
|
||||
>
|
||||
{labels[status] ?? status}
|
||||
</span>
|
||||
<StatusPill status={BERTH_STATUS_PILL[status] ?? 'pending'}>
|
||||
{BERTH_STATUS_LABELS[status] ?? status}
|
||||
</StatusPill>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { DetailHeaderStrip } from '@/components/shared/detail-header-strip';
|
||||
import { PermissionGate } from '@/components/shared/permission-gate';
|
||||
import { StatusPill, type StatusPillStatus } from '@/components/ui/status-pill';
|
||||
import { BerthForm } from './berth-form';
|
||||
import { mooringLetterDot } from './mooring-letter-tone';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -86,18 +87,18 @@ interface BerthDetailHeaderProps {
|
||||
berth: BerthDetailData;
|
||||
}
|
||||
|
||||
const STATUS_COLORS: Record<string, string> = {
|
||||
available: 'bg-green-100 text-green-800 border-green-300',
|
||||
under_offer: 'bg-yellow-100 text-yellow-800 border-yellow-300',
|
||||
sold: 'bg-red-100 text-red-800 border-red-300',
|
||||
};
|
||||
|
||||
const STATUS_LABELS: Record<string, string> = {
|
||||
available: 'Available',
|
||||
under_offer: 'Under Offer',
|
||||
sold: 'Sold',
|
||||
};
|
||||
|
||||
const BERTH_STATUS_PILL: Record<string, StatusPillStatus> = {
|
||||
available: 'available',
|
||||
under_offer: 'under_offer',
|
||||
sold: 'sold',
|
||||
};
|
||||
|
||||
interface InterestOption {
|
||||
id: string;
|
||||
clientName: string;
|
||||
@@ -276,11 +277,12 @@ export function BerthDetailHeader({ berth }: BerthDetailHeaderProps) {
|
||||
>
|
||||
{berth.mooringNumber}
|
||||
</div>
|
||||
<span
|
||||
className={`inline-flex items-center rounded-full border px-3 py-1 text-sm font-medium ${STATUS_COLORS[berth.status] ?? 'bg-muted text-muted-foreground border-muted'}`}
|
||||
<StatusPill
|
||||
status={BERTH_STATUS_PILL[berth.status] ?? 'pending'}
|
||||
className="px-3 py-1 text-sm"
|
||||
>
|
||||
{STATUS_LABELS[berth.status] ?? berth.status}
|
||||
</span>
|
||||
</StatusPill>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-2 sm:shrink-0">
|
||||
|
||||
Reference in New Issue
Block a user