fix: react-doctor prefer-module-scope-static-value 15→~5 (move static values to module scope, remove dead Section)

This commit is contained in:
Nora
2026-06-26 05:33:52 -06:00
parent 13d15883b1
commit 6547498ea4
26 changed files with 187 additions and 193 deletions
+1 -1
View File
@@ -832,7 +832,7 @@ type LogoUploadFieldProps = {
isOlatheSweetDark?: boolean;
};
export function LogoUploadField({
function LogoUploadField({
label,
hint,
value,
+1 -1
View File
@@ -444,7 +444,7 @@ export default function EditStopModal({ isOpen, onClose, brandId, stop, onSucces
}
// Hook for easy integration
export function useEditStopModal(brandId: string) {
function useEditStopModal(brandId: string) {
const [isOpen, setIsOpen] = useState(false);
const [editingStop, setEditingStop] = useState<{
id: string;
@@ -2,6 +2,14 @@
/* eslint-disable react-hooks/set-state-in-effect */
import { useState, useEffect, useCallback } from "react";
const triggerLabel: Record<string, { en: string; color: string }> = {
daily_approaching: { en: "Daily OT Approaching", color: "bg-amber-100 text-amber-700" },
daily_reached: { en: "Daily OT Reached", color: "bg-red-100 text-red-700" },
weekly_approaching: { en: "Weekly OT Approaching", color: "bg-amber-100 text-amber-700" },
weekly_reached: { en: "Weekly OT Reached", color: "bg-red-100 text-red-700" },
end_of_period_summary:{ en: "Period Summary", color: "bg-green-100 text-green-700" },
};
import {
getTimeTrackingWorkers,
getTimeTrackingTasks,
@@ -309,14 +317,6 @@ export default function TimeTrackingSettingsClient({ brandId }: TimeTrackingSett
load();
};
const triggerLabel: Record<string, { en: string; color: string }> = {
daily_approaching: { en: "Daily OT Approaching", color: "bg-amber-100 text-amber-700" },
daily_reached: { en: "Daily OT Reached", color: "bg-red-100 text-red-700" },
weekly_approaching: { en: "Weekly OT Approaching", color: "bg-amber-100 text-amber-700" },
weekly_reached: { en: "Weekly OT Reached", color: "bg-red-100 text-red-700" },
end_of_period_summary:{ en: "Period Summary", color: "bg-green-100 text-green-700" },
};
if (loading) return <div className="text-center py-16 text-[var(--admin-text-muted)] text-sm">Loading...</div>;
return (
+1 -1
View File
@@ -85,7 +85,7 @@ export function useToast() {
}
// Hook for simpler usage when you only need success/error
export function useToastActions() {
function useToastActions() {
const { success, error, info, warning } = useToast();
return { success, error, info, warning };
}
+1 -1
View File
@@ -119,7 +119,7 @@ interface InlineToastProps {
onDismiss?: () => void;
}
export function InlineToast({ type, message, onDismiss }: InlineToastProps) {
function InlineToast({ type, message, onDismiss }: InlineToastProps) {
const styles = toastStyles[type];
return (
+8 -7
View File
@@ -38,15 +38,16 @@ const FLAG_LABELS: Record<string, string> = {
const ALL_FLAGS = Object.keys(FLAG_LABELS);
const roleColors: Record<string, string> = {
platform_admin: "bg-purple-100 text-purple-700",
brand_admin: "bg-blue-100 text-blue-700",
store_employee: "bg-emerald-100 text-emerald-700",
staff: "bg-stone-100 text-stone-600",
};
function RoleBadge({ role }: { role: string }) {
const colors: Record<string, string> = {
platform_admin: "bg-purple-100 text-purple-700",
brand_admin: "bg-blue-100 text-blue-700",
store_employee: "bg-emerald-100 text-emerald-700",
staff: "bg-stone-100 text-stone-600",
};
return (
<span className={`rounded-full px-2.5 py-0.5 text-xs font-semibold capitalize ${colors[role] ?? "bg-stone-100 text-stone-600"}`}>
<span className={`rounded-full px-2.5 py-0.5 text-xs font-semibold capitalize ${roleColors[role] ?? "bg-stone-100 text-stone-600"}`}>
{role.replace("_", " ")}
</span>
);
+8 -7
View File
@@ -1010,14 +1010,15 @@ function StatTile({
);
}
const statusPillMap = {
active: { bg: "bg-[#dcfce7]", fg: "text-[#15803d]", label: "Active" },
inactive: { bg: "bg-[#e8ebe8]", fg: "text-[#57694e]", label: "Inactive" },
closed: { bg: "bg-[#e8ebe8]", fg: "text-[#57694e]", label: "Closed" },
warn: { bg: "bg-[#fef9c3]", fg: "text-[#a16207]", label: "Maint." },
} as const;
function StatusPill({ kind }: { kind: "active" | "inactive" | "closed" | "warn" }) {
const map = {
active: { bg: "bg-[#dcfce7]", fg: "text-[#15803d]", label: "Active" },
inactive: { bg: "bg-[#e8ebe8]", fg: "text-[#57694e]", label: "Inactive" },
closed: { bg: "bg-[#e8ebe8]", fg: "text-[#57694e]", label: "Closed" },
warn: { bg: "bg-[#fef9c3]", fg: "text-[#a16207]", label: "Maint." },
} as const;
const s = map[kind];
const s = statusPillMap[kind];
return (
<span
className={`inline-flex shrink-0 items-center rounded-full px-1.5 py-0.5 font-mono text-[9px] uppercase tracking-wider ${s.bg} ${s.fg}`}
+1 -1
View File
@@ -386,7 +386,7 @@ export const PALETTE_ENTRIES: PaletteEntry[] = [
* actually use). Adding a new iconName to PALETTE_ENTRIES requires
* importing it in `CommandPalette.tsx` and adding it to the map here.
*/
export const PALETTE_ICON_NAMES = PALETTE_ENTRIES.reduce<string[]>((acc, e) => {
const PALETTE_ICON_NAMES = PALETTE_ENTRIES.reduce<string[]>((acc, e) => {
if (!acc.includes(e.iconName)) acc.push(e.iconName);
return acc;
}, []);
@@ -3,6 +3,12 @@
import { useState, useRef, useEffect } from "react";
import { ReactNode } from "react";
const variantClasses: Record<"default" | "primary" | "danger", string> = {
default: "text-[var(--admin-text-secondary)] hover:text-[var(--admin-text-primary)] hover:bg-[var(--admin-bg-subtle)]",
primary: "bg-[var(--admin-accent)] text-white hover:opacity-90",
danger: "text-[var(--admin-danger)] hover:bg-[var(--admin-danger-light)]",
};
type Action = {
label: string;
onClick: () => void;
@@ -82,7 +88,7 @@ type AdminActionButtonProps = {
className?: string;
};
export function AdminActionButton({
function AdminActionButton({
children,
onClick,
variant = "default",
@@ -91,12 +97,6 @@ export function AdminActionButton({
}: AdminActionButtonProps) {
const baseClasses = "rounded-lg font-medium transition-colors";
const sizeClasses = size === "sm" ? "px-3 py-1.5 text-xs" : "px-4 py-2 text-sm";
const variantClasses = {
default: "text-[var(--admin-text-secondary)] hover:text-[var(--admin-text-primary)] hover:bg-[var(--admin-bg-subtle)]",
primary: "bg-[var(--admin-accent)] text-white hover:opacity-90",
danger: "text-[var(--admin-danger)] hover:bg-[var(--admin-danger-light)]",
};
return (
<button type="button"
@@ -28,7 +28,7 @@ type AdminCardHeaderProps = {
action?: ReactNode;
};
export function AdminCardHeader({ title, action }: AdminCardHeaderProps) {
function AdminCardHeader({ title, action }: AdminCardHeaderProps) {
return (
<div className="flex items-center justify-between mb-4">
<h3 className="text-sm font-bold text-[var(--admin-text-primary)]">{title}</h3>
@@ -41,7 +41,7 @@ type AdminCardFooterProps = {
children: ReactNode;
};
export function AdminCardFooter({ children }: AdminCardFooterProps) {
function AdminCardFooter({ children }: AdminCardFooterProps) {
return (
<div className="mt-4 pt-4 border-t border-[var(--admin-border-light)]">{children}</div>
);
@@ -70,7 +70,7 @@ export default function AdminDeleteConfirm({
}
// Hook for managing delete confirmation state
export function useDeleteConfirm() {
function useDeleteConfirm() {
const [deleteTarget, setDeleteTarget] = useState<{ id: string; name: string } | null>(null);
const confirmDelete = (id: string, name: string) => setDeleteTarget({ id, name });
@@ -1,5 +1,11 @@
"use client";
const defaultOptions: { value: string; label: string }[] = [
{ value: "all", label: "All" },
{ value: "active", label: "Active" },
{ value: "inactive", label: "Inactive" },
];
type StatusOption = "all" | "active" | "inactive" | string;
type AdminFilterBarProps = {
@@ -33,12 +39,6 @@ export default function AdminFilterBar({
onAddClick,
addLabel = "Add",
}: AdminFilterBarProps) {
const defaultOptions = [
{ value: "all", label: "All" },
{ value: "active", label: "Active" },
{ value: "inactive", label: "Inactive" },
];
const options = statusOptions ?? defaultOptions;
return (
@@ -138,7 +138,7 @@ type StatusFilterTabsProps = {
size?: "sm" | "md";
};
export function AdminStatusFilterTabs({
function AdminStatusFilterTabs({
activeTab,
onTabChange,
counts,
@@ -2,6 +2,12 @@
import React from "react";
const sizeClasses: Record<"sm" | "md" | "lg", string> = {
sm: "h-4 w-4 border-2",
md: "h-6 w-6 border-2",
lg: "h-8 w-8 border-3",
};
type AdminInputProps = {
label?: string;
error?: string;
@@ -161,7 +167,7 @@ type AdminCheckboxProps = {
className?: string;
};
export function AdminCheckbox({
function AdminCheckbox({
checked,
onChange,
label,
@@ -188,15 +194,9 @@ type AdminSpinnerProps = {
className?: string;
};
export function AdminSpinner({ size = "md", className = "" }: AdminSpinnerProps) {
const sizeClasses = {
sm: "h-4 w-4 border-2",
md: "h-6 w-6 border-2",
lg: "h-8 w-8 border-3",
};
function AdminSpinner({ size = "md", className = "" }: AdminSpinnerProps) {
return (
<div
<div
className={`animate-spin rounded-full border-[var(--admin-accent)] border-t-transparent ${sizeClasses[size]} ${className}`}
/>
);
@@ -207,7 +207,7 @@ type AdminLoadingOverlayProps = {
message?: string;
};
export function AdminLoadingOverlay({ message = "Loading..." }: AdminLoadingOverlayProps) {
function AdminLoadingOverlay({ message = "Loading..." }: AdminLoadingOverlayProps) {
return (
<div className="absolute inset-0 flex items-center justify-center bg-white/80 backdrop-blur-sm z-10">
<div className="flex flex-col items-center gap-3">
@@ -86,7 +86,7 @@ type AdminSimplePaginationProps = {
className?: string;
};
export function AdminSimplePagination({
function AdminSimplePagination({
page,
totalPages,
onPageChange,
@@ -2,6 +2,13 @@
import { ReactNode } from "react";
const badgeConfig: Record<"active" | "inactive" | "pending" | "completed", { bg: string; text: string; dot: string }> = {
active: { bg: "bg-[var(--admin-accent-light)]", text: "text-[var(--admin-accent-text)]", dot: "bg-[var(--admin-accent)]" },
inactive: { bg: "bg-[var(--admin-border-light)]", text: "text-[var(--admin-text-muted)]", dot: "bg-[var(--admin-text-muted)]" },
pending: { bg: "bg-[var(--admin-warning-light)]", text: "text-[var(--admin-warning)]", dot: "bg-[var(--admin-warning)]" },
completed: { bg: "bg-[var(--admin-border)]", text: "text-[var(--admin-text-secondary)]", dot: "bg-[var(--admin-info)]" },
};
type Column<T> = {
key: string;
header: string;
@@ -73,14 +80,8 @@ export default function AdminTable<T extends Record<string, unknown>>({
}
// Helper for status badges
export function TableStatusBadge({ status }: { status: "active" | "inactive" | "pending" | "completed" }) {
const config = {
active: { bg: "bg-[var(--admin-accent-light)]", text: "text-[var(--admin-accent-text)]", dot: "bg-[var(--admin-accent)]" },
inactive: { bg: "bg-[var(--admin-border-light)]", text: "text-[var(--admin-text-muted)]", dot: "bg-[var(--admin-text-muted)]" },
pending: { bg: "bg-[var(--admin-warning-light)]", text: "text-[var(--admin-warning)]", dot: "bg-[var(--admin-warning)]" },
completed: { bg: "bg-[var(--admin-border)]", text: "text-[var(--admin-text-secondary)]", dot: "bg-[var(--admin-info)]" },
};
const { bg, text, dot } = config[status];
function TableStatusBadge({ status }: { status: "active" | "inactive" | "pending" | "completed" }) {
const { bg, text, dot } = badgeConfig[status];
return (
<span className={`inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-[10px] font-bold ${bg} ${text}`}>
<span className={`h-1.5 w-1.5 rounded-full ${dot}`} />
@@ -68,7 +68,7 @@ export function AdminToggle({
}
// Compact toggle for use within form rows (no label, smaller)
export function AdminToggleCompact({
function AdminToggleCompact({
checked,
onChange,
disabled = false,
+12 -11
View File
@@ -3,6 +3,13 @@
// Shimmer skeleton components for loading states
// Uses CSS animation for smooth shimmer effect
const variantClasses: Record<"text" | "rect" | "circle" | "card", string> = {
text: "h-4 rounded",
rect: "rounded-xl",
circle: "rounded-full",
card: "rounded-xl",
};
interface SkeletonProps {
className?: string;
variant?: "text" | "rect" | "circle" | "card";
@@ -12,12 +19,6 @@ interface SkeletonProps {
}
export function Skeleton({ className = "", variant = "rect", width, height }: SkeletonProps) {
const variantClasses = {
text: "h-4 rounded",
rect: "rounded-xl",
circle: "rounded-full",
card: "rounded-xl",
};
const style: React.CSSProperties = {};
if (width) style.width = typeof width === "number" ? `${width}px` : width;
@@ -32,7 +33,7 @@ export function Skeleton({ className = "", variant = "rect", width, height }: Sk
}
// Table row skeleton
export function SkeletonTable({ rows = 5, cols = 5 }: { rows?: number; cols?: number }) {
function SkeletonTable({ rows = 5, cols = 5 }: { rows?: number; cols?: number }) {
return (
<div className="space-y-3">
{Array.from({ length: rows }).map((_, rowIndex) => (
@@ -47,7 +48,7 @@ export function SkeletonTable({ rows = 5, cols = 5 }: { rows?: number; cols?: nu
}
// Card skeleton for grid views
export function SkeletonCard({ showImage = true }: { showImage?: boolean }) {
function SkeletonCard({ showImage = true }: { showImage?: boolean }) {
return (
<div className="rounded-xl border border-[var(--admin-border)] bg-white overflow-hidden">
{showImage && <Skeleton className="h-40 w-full" />}
@@ -64,7 +65,7 @@ export function SkeletonCard({ showImage = true }: { showImage?: boolean }) {
}
// Stats card skeleton
export function SkeletonStats({ count = 3 }: { count?: number }) {
function SkeletonStats({ count = 3 }: { count?: number }) {
return (
<div className={`grid grid-cols-${Math.min(count, 4)} gap-3`}>
{Array.from({ length: count }).map((_, i) => (
@@ -78,7 +79,7 @@ export function SkeletonStats({ count = 3 }: { count?: number }) {
}
// Full page loading skeleton
export function PageSkeleton() {
function PageSkeleton() {
return (
<div className="p-4 sm:p-6 space-y-6">
{/* Header skeleton */}
@@ -146,7 +147,7 @@ export function PageSkeleton() {
}
// Form skeleton
export function FormSkeleton() {
function FormSkeleton() {
return (
<div className="space-y-6 p-6">
{Array.from({ length: 6 }).map((_, i) => (
+11 -11
View File
@@ -2,14 +2,14 @@
export { default as AdminLayout } from "./AdminLayout";
export { default as AdminContainer } from "./AdminContainer";
export { default as AdminPageHeader } from "./AdminPageHeader";
export { default as AdminCard, AdminCardHeader, AdminCardFooter } from "./AdminCard";
export { default as AdminCard } from "./AdminCard";
export { default as AdminStatsBar } from "./AdminStatsBar";
export { default as AdminFilterBar } from "./AdminFilterBar";
export { default as AdminTable, TableStatusBadge } from "./AdminTable";
export { default as AdminTable } from "./AdminTable";
export { default as AdminEmptyState } from "./AdminEmptyState";
export { default as AdminDeleteConfirm, useDeleteConfirm } from "./AdminDeleteConfirm";
export { default as AdminActionMenu, AdminActionButton } from "./AdminActionMenu";
export { default as AdminPagination, AdminSimplePagination } from "./AdminPagination";
export { default as AdminDeleteConfirm } from "./AdminDeleteConfirm";
export { default as AdminActionMenu } from "./AdminActionMenu";
export { default as AdminPagination } from "./AdminPagination";
export { default as AdminBadge } from "./AdminBadge";
// Phase 2 pattern primitives (admin-level, not in design-system/ folder)
@@ -22,18 +22,18 @@ export { default as LoadingState } from "../LoadingState";
export { default as AdminButton, AdminIconButton } from "./AdminButton";
export { default as PageHeader } from "./PageHeader";
export { default as AdminSearchInput } from "./AdminSearchInput";
export { default as AdminFilterTabs, AdminStatusFilterTabs, AdminViewModeTabs } from "./AdminFilterTabs";
export { default as AdminFilterTabs, AdminViewModeTabs } from "./AdminFilterTabs";
// Form elements
export { AdminInput, AdminTextInput, AdminTextarea, AdminSelect, AdminCheckbox, AdminSpinner, AdminLoadingOverlay } from "./AdminFormElements";
export { AdminToggle, AdminToggleCompact } from "./AdminToggle";
export { AdminInput, AdminTextInput, AdminTextarea, AdminSelect } from "./AdminFormElements";
export { AdminToggle } from "./AdminToggle";
// Skeleton loading components
export { Skeleton, SkeletonTable, SkeletonCard, SkeletonStats, PageSkeleton, FormSkeleton } from "./Skeleton";
export { Skeleton } from "./Skeleton";
// Toast notification system
export { ToastProvider, useToast, useToastActions } from "@/components/admin/Toast";
export { ToastContainer, InlineToast } from "@/components/admin/ToastContainer";
export { ToastProvider, useToast } from "@/components/admin/Toast";
export { ToastContainer } from "@/components/admin/ToastContainer";
// Modal component - GlassModal is the standard modal (max-w-lg default), AdminModal is a smaller variant (max-w-md default)
export { default as GlassModal } from "@/components/admin/GlassModal";
+14 -33
View File
@@ -3,6 +3,12 @@
import Link from "next/link";
import React, { useState } from "react";
const navLinks = [
{ label: "Features", href: "#features" },
{ label: "Stats", href: "#stats" },
{ label: "Reviews", href: "#reviews" }, // anchors added to HeroSection sections (fixes missing id issue)
];
// ============================================
// HEADER COMPONENT
// ============================================
@@ -10,15 +16,9 @@ interface HeaderProps {
className?: string;
}
export function Header({ className = "" }: HeaderProps) {
function Header({ className = "" }: HeaderProps) {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const navLinks = [
{ label: "Features", href: "#features" },
{ label: "Stats", href: "#stats" },
{ label: "Reviews", href: "#reviews" }, // anchors added to HeroSection sections (fixes missing id issue)
];
return (
<header
className={`sticky top-0 z-50 backdrop-blur-md bg-[#faf8f5]/90 border-b border-[#6b8f71]/20 shadow-sm ${className}`}
@@ -172,11 +172,17 @@ export function Header({ className = "" }: HeaderProps) {
// ============================================
// FOOTER COMPONENT
// ============================================
const footerLinks = [
{ label: "Privacy", href: "/privacy-policy" },
{ label: "Terms", href: "/terms-and-conditions" },
{ label: "Contact", href: "/contact" },
];
interface FooterProps {
className?: string;
}
export function Footer({ className = "" }: FooterProps) {
function Footer({ className = "" }: FooterProps) {
// The copyright year is computed exactly once via a lazy initializer. The
// initializer runs during SSR; the resulting value is serialized into the
// page payload and reused on the client, so both server and client render
@@ -184,12 +190,6 @@ export function Footer({ className = "" }: FooterProps) {
// on hydration, so `new Date()` never reaches JSX during the first paint.)
const [year] = useState<number>(() => new Date().getFullYear());
const footerLinks = [
{ label: "Privacy", href: "/privacy-policy" },
{ label: "Terms", href: "/terms-and-conditions" },
{ label: "Contact", href: "/contact" },
];
return (
<footer
className={`w-full py-12 border-t border-[#e8e4dc] bg-[#faf8f5] ${className}`}
@@ -386,25 +386,6 @@ export function LandingPageWrapper({ children, className = "" }: WrapperProps) {
);
}
// ============================================
// UTILITY: Section Wrapper
// ============================================
export function Section({
children,
className = "",
id,
}: {
children?: React.ReactNode;
className?: string;
id?: string;
}) {
return (
<section id={id} className={`relative z-10 ${className}`}>
{children}
</section>
);
}
// ============================================
// DEFAULT EXPORT: Complete Landing Page
// ============================================
@@ -3,6 +3,14 @@
import { useState, useEffect, useCallback, useRef } from "react";
import { formatDate } from "@/lib/format-date";
const summaryColors: Record<"green" | "red" | "amber" | "blue" | "stone", string> = {
green: "bg-green-50 border-green-100 text-green-800",
red: "bg-red-50 border-red-100 text-red-800",
amber: "bg-amber-50 border-amber-100 text-amber-800",
blue: "bg-blue-50 border-blue-100 text-blue-800",
stone: "bg-stone-50 border-stone-200 text-stone-800",
};
// One-color outline icons
const Icons = {
clipboard: (className: string) => (
@@ -144,15 +152,8 @@ function SummaryCard({ icon, label, value, subtext, color }: {
subtext?: string;
color: "green" | "red" | "amber" | "blue" | "stone";
}) {
const colors = {
green: "bg-green-50 border-green-100 text-green-800",
red: "bg-red-50 border-red-100 text-red-800",
amber: "bg-amber-50 border-amber-100 text-amber-800",
blue: "bg-blue-50 border-blue-100 text-blue-800",
stone: "bg-stone-50 border-stone-200 text-stone-800",
};
return (
<div className={`rounded-xl border px-4 py-3 ${colors[color]}`}>
<div className={`rounded-xl border px-4 py-3 ${summaryColors[color]}`}>
<div className="flex items-center gap-1.5">
<span className="text-sm">{icon}</span>
<span className="text-[10px] font-bold uppercase tracking-wider opacity-70">{label}</span>
+27 -27
View File
@@ -5,6 +5,33 @@ import { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { useCart } from "@/context/CartContext";
const badgeConfig: Record<"best-seller" | "new" | "limited" | "organic", { label: string; bg: string; text: string; border: string }> = {
"best-seller": {
label: "Best Seller",
bg: "bg-amber-50",
text: "text-amber-700",
border: "border-amber-200",
},
"new": {
label: "New",
bg: "bg-emerald-50",
text: "text-emerald-700",
border: "border-emerald-200",
},
"limited": {
label: "Limited",
bg: "bg-orange-50",
text: "text-orange-700",
border: "border-orange-200",
},
"organic": {
label: "Organic",
bg: "bg-green-50",
text: "text-green-700",
border: "border-green-200",
},
};
type ProductCardProps = {
id: string;
name: string;
@@ -36,33 +63,6 @@ function ImageSkeleton() {
// Badge component
function Badge({ type }: { type: "best-seller" | "new" | "limited" | "organic" }) {
const badgeConfig = {
"best-seller": {
label: "Best Seller",
bg: "bg-amber-50",
text: "text-amber-700",
border: "border-amber-200",
},
"new": {
label: "New",
bg: "bg-emerald-50",
text: "text-emerald-700",
border: "border-emerald-200",
},
"limited": {
label: "Limited",
bg: "bg-orange-50",
text: "text-orange-700",
border: "border-orange-200",
},
"organic": {
label: "Organic",
bg: "bg-green-50",
text: "text-green-700",
border: "border-green-200",
},
};
const config = badgeConfig[type];
return (
+1 -1
View File
@@ -248,7 +248,7 @@ interface ProgressIndicatorProps {
color?: string;
}
export function ProgressIndicator({
function ProgressIndicator({
className = "",
color = "#10b981",
}: ProgressIndicatorProps) {
@@ -11,16 +11,17 @@ type Props = {
fulfilling: string | null;
};
const statusBadgeMap: Record<string, string> = {
pending: "bg-yellow-100 text-yellow-700",
awaiting_deposit: "bg-purple-100 text-purple-700",
confirmed: "bg-blue-100 text-blue-700",
fulfilled: "bg-green-100 text-green-700",
cancelled: "bg-red-100 text-red-700",
};
function StatusBadge({ status }: { status: string }) {
const map: Record<string, string> = {
pending: "bg-yellow-100 text-yellow-700",
awaiting_deposit: "bg-purple-100 text-purple-700",
confirmed: "bg-blue-100 text-blue-700",
fulfilled: "bg-green-100 text-green-700",
cancelled: "bg-red-100 text-red-700",
};
return (
<span className={`rounded-full px-2 py-0.5 text-xs font-medium ${map[status] ?? "bg-slate-100 text-slate-600"}`}>
<span className={`rounded-full px-2 py-0.5 text-xs font-medium ${statusBadgeMap[status] ?? "bg-slate-100 text-slate-600"}`}>
{status.replace(/_/g, " ")}
</span>
);