/* Me2You - Shared UI components: Icon, StatusTag, Field, etc. */
/* global React */
const { useState, useRef, useEffect, useCallback } = React;
/* --- Lucide-style inline SVG icons --- */
const ICON_PATHS = {
'home': 'M3 9l9-7 9 7v11a2 2 0 0 1-2 2h-4v-7h-6v7H5a2 2 0 0 1-2-2z',
'layout-grid': 'M3 3h7v7H3zM14 3h7v7h-7zM3 14h7v7H3zM14 14h7v7h-7z',
'search': 'M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16zM21 21l-4.3-4.3',
'shopping-bag': 'M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4zM3 6h18M16 10a4 4 0 0 1-8 0',
'user-round': 'M18 20a6 6 0 0 0-12 0M12 14a4 4 0 1 0 0-8 4 4 0 0 0 0 8z',
'receipt': 'M4 2v20l2-2 2 2 2-2 2 2 2-2 2 2 2-2 2 2V2l-2 2-2-2-2 2-2-2-2 2-2-2-2 2-2-2zM16 8H8M16 12H8M13 16H8',
'package': 'M16.5 9.4 7.55 4.24M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16zM3.27 6.96 12 12.01l8.73-5.05M12 22.08V12',
'shield-check': 'M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10zM9 12l2 2 4-4',
'truck': 'M14 17V5h6v8M3 5h11v12M7 17a2 2 0 1 0 0 4 2 2 0 0 0 0-4M17 17a2 2 0 1 0 0 4 2 2 0 0 0 0-4',
'map-pin': 'M20 10c0 7-8 12-8 12s-8-5-8-12a8 8 0 0 1 16 0zM12 13a3 3 0 1 0 0-6 3 3 0 0 0 0 6z',
'share-2': 'M18 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM18 22a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM8.6 13.5l6.8 3M15.4 7.5l-6.8 3',
'check': 'M20 6 9 17l-5-5',
'x': 'M18 6 6 18M6 6l12 12',
'plus': 'M12 5v14M5 12h14',
'minus': 'M5 12h14',
'star': 'M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01z',
'heart': 'M19 14c1.5-1.5 3-3.5 3-6a4.5 4.5 0 0 0-9-1 4.5 4.5 0 0 0-9 1c0 2.5 1.5 4.5 3 6l6 6z',
'arrow-left': 'M19 12H5M12 19l-7-7 7-7',
'arrow-right': 'M5 12h14M12 5l7 7-7 7',
'chevron-right': 'M9 18l6-6-6-6',
'chevron-down': 'M6 9l6 6 6-6',
'chevron-up': 'M18 15l-6-6-6 6',
'monitor': 'M2 3h20v14H2zM8 21h8M12 17v4',
'shirt': 'M20.4 5.6L16 4h-1.5a2.5 2.5 0 0 1-5 0H8L3.6 5.6 6 8l-2 2v10h16V10l-2-2z',
'sofa': 'M20 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v3M2 11v5a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-5a2 2 0 0 0-4 0v2H6v-2a2 2 0 0 0-4 0zM4 18v2M20 18v2',
'book-open': 'M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2zM22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z',
'apple': 'M12 3a5 5 0 0 1 5 5c0 4-5 9-5 9s-5-5-5-9a5 5 0 0 1 5-5z',
'wrench': 'M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z',
'baby': 'M12 12a5 5 0 1 0 0-10 5 5 0 0 0 0 10zM20 21a8 8 0 0 0-16 0',
'dumbbell': 'M6.5 6.5h11M6 12H4a2 2 0 0 1 0-4h2v8H4a2 2 0 0 0 0 4h2M18 12h2a2 2 0 0 0 0-4h-2v8h2a2 2 0 0 1 0 4h-2',
'users': 'M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75',
'bar-chart': 'M12 20V10M18 20V4M6 20v-4',
'settings': 'M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8zM19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z',
'gavel': 'M14 13l5 5-2 2-5-5M3 21l9-9M9 7l4-4 6 6-4 4z',
'triangle-alert': 'M10.3 2.9L1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 2.9a2 2 0 0 0-3.4 0zM12 9v4M12 17h.01',
'circle-check': 'M22 11.08V12a10 10 0 1 1-5.93-9.14M22 4 12 14.01l-3-3',
'eye': 'M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8zM12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z',
'edit': 'M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7M18.5 2.5a2.12 2.12 0 0 1 3 3L12 15l-4 1 1-4z',
'trash': 'M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6M10 11v6M14 11v6',
'ban': 'M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20zM4.9 4.9l14.2 14.2',
'log-out': 'M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4M16 17l5-5-5-5M21 12H9',
'filter': 'M22 3H2l8 9.46V19l4 2v-8.54z',
'camera': 'M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2zM12 17a4 4 0 1 0 0-8 4 4 0 0 0 0 8z',
'image': 'M21 3H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h18a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zM8.5 10a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zM21 15l-5-5L5 21',
'tag': 'M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82zM7 7h.01',
'clock': 'M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20zM12 6v6l4 2',
'phone': 'M22 16.9v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.9z',
'message-circle': 'M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z',
'scan-line': 'M3 7V5a2 2 0 0 1 2-2h2M17 3h2a2 2 0 0 1 2 2v2M21 17v2a2 2 0 0 1-2 2h-2M7 21H5a2 2 0 0 1-2-2v-2M7 12h10',
'navigation': 'M3 11l19-9-9 19-2-8z',
'check-circle': 'M22 11.08V12a10 10 0 1 1-5.93-9.14M22 4 12 14.01l-3-3',
'wallet': 'M20 12V8H6a2 2 0 0 1-2-2c0-1.1.9-2 2-2h12v4M4 6v12a2 2 0 0 0 2 2h14v-4M18 12a2 2 0 0 0 0 4h4v-4z',
'bell': 'M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9M13.73 21a2 2 0 0 1-3.46 0',
'play': 'M6 4l14 8-14 8z',
'volume-x': 'M11 5L6 9H2v6h4l5 4zM22 9l-6 6M16 9l6 6',
'calendar': 'M8 2v4M16 2v4M3 10h18M5 4h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z',
'megaphone': 'M3 11l18-5v12L3 13v-2zM3 11v6a1 1 0 0 0 1 1h2v-7M11.6 16.8a3 3 0 1 1-5.8-1.6',
'user-plus': 'M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM19 8v6M22 11h-6',
'send': 'M22 2L11 13M22 2l-7 20-4-9-9-4z',
'arrow-left-right': 'M8 3 4 7l4 4M4 7h16M16 21l4-4-4-4M20 17H4',
'umbrella': 'M12 12v7a2 2 0 0 0 4 0M12 2v1M2 12a10 10 0 0 1 20 0z',
'lock': 'M5 11h14a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2zM7 11V7a5 5 0 0 1 10 0v4',
};
function Icon({ name, size = 20, stroke = 1.75, fill = 'none', className = '' }) {
const d = ICON_PATHS[name] || '';
return (
);
}
/* --- Status Tag --- */
function StatusTag({ status }) {
const s = status.toLowerCase();
const map = {
placed: { bg:'var(--status-placed-bg)', fg:'var(--status-placed-fg)' },
paid: { bg:'var(--status-paid-bg)', fg:'var(--status-paid-fg)' },
dispatched: { bg:'var(--status-dispatched-bg)', fg:'var(--status-dispatched-fg)' },
received: { bg:'var(--status-received-bg)', fg:'var(--status-received-fg)' },
completed: { bg:'var(--status-completed-bg)', fg:'var(--status-completed-fg)' },
cancelled: { bg:'var(--status-cancelled-bg)', fg:'var(--status-cancelled-fg)' },
disputed: { bg:'var(--status-disputed-bg)', fg:'var(--status-disputed-fg)' },
active: { bg:'var(--success-100)', fg:'var(--success)' },
suspended: { bg:'var(--danger-100)', fg:'var(--danger)' },
available: { bg:'var(--success-100)', fg:'var(--success)' },
in_progress:{ bg:'var(--info-100)', fg:'var(--info)' },
};
const c = map[s] || map.placed;
return (
{status}
);
}
/* --- Role Tag --- */
function RoleTag({ role }) {
const map = { admin:'var(--role-admin)', seller:'var(--role-seller)', buyer:'var(--role-buyer)' };
const color = map[role] || 'var(--ink-500)';
return (
{role}
);
}
/* --- Form Field --- */
function Field({ label, value, placeholder, type='text', full, icon, error, onChange }) {
return (
{error &&
{error}
}
);
}
/* --- Order Status Stepper --- */
function OrderStepper({ current = 'Dispatched' }) {
const steps = ['Placed','Paid','Dispatched','Received','Completed'];
const idx = steps.findIndex(s => s.toLowerCase() === current.toLowerCase());
return (
{steps.map((s,i) => (
{i < idx ? '' : i + 1}
{s}
{i < steps.length - 1 && (
)}
))}
);
}
/* --- Price display --- */
function Price({ amount, size='md' }) {
const s = size === 'lg' ? 32 : size === 'sm' ? 16 : 20;
const cs = size === 'lg' ? 20 : size === 'sm' ? 11 : 13;
const formatted = typeof amount === 'number' ? amount.toLocaleString('en-ZA') : amount;
return (
R {formatted}
);
}
/* --- Condition Tag --- */
function CondTag({ condition }) {
const map = {
'New': { bg:'var(--success-100)', fg:'var(--success)' },
'Like new': { bg:'var(--brand-orange-100)', fg:'var(--brand-orange-700)' },
'Good': { bg:'var(--info-100)', fg:'var(--info)' },
'Fair': { bg:'var(--ink-100)', fg:'var(--ink-700)' },
};
const c = map[condition] || map['Good'];
return (
{condition}
);
}
/* --- Animated page wrapper --- */
function PageTransition({ children, routeKey }) {
const [visible, setVisible] = useState(false);
useEffect(() => {
setVisible(false);
const t = requestAnimationFrame(() => setVisible(true));
return () => cancelAnimationFrame(t);
}, [routeKey]);
return (
{children}
);
}
/* --- Empty State --- */
function EmptyState({ icon, title, subtitle, action, onAction }) {
return (
{title}
{subtitle &&
{subtitle}
}
{action &&
}
);
}
/* --- Shared button styles --- */
const btnPrimary = {
background:'var(--brand-orange)',color:'white',border:'none',
padding:'12px 22px',borderRadius:'var(--radius-md)',
fontFamily:'var(--font-body)',fontWeight:700,fontSize:15,
cursor:'pointer',boxShadow:'var(--shadow-pop)',
transition:'all .15s ease',display:'inline-flex',alignItems:'center',gap:8,
};
const btnGhost = {
background:'transparent',color:'var(--ink-900)',border:'1.5px solid var(--ink-300)',
padding:'12px 20px',borderRadius:'var(--radius-md)',
fontFamily:'var(--font-body)',fontWeight:700,fontSize:15,cursor:'pointer',
display:'inline-flex',alignItems:'center',gap:8,transition:'all .15s ease',
};
const btnDanger = {
background:'var(--danger)',color:'white',border:'none',
padding:'10px 18px',borderRadius:'var(--radius-md)',
fontFamily:'var(--font-body)',fontWeight:700,fontSize:14,cursor:'pointer',
display:'inline-flex',alignItems:'center',gap:8,
};
const btnSmall = {
...btnGhost,padding:'8px 14px',fontSize:13,
};
const panelStyle = {
background:'var(--paper)',padding:20,borderRadius:'var(--radius-lg)',
border:'1px solid var(--ink-200)',marginBottom:16,
};
Object.assign(window, {
Icon, StatusTag, RoleTag, Field, OrderStepper, Price, CondTag,
PageTransition, EmptyState,
btnPrimary, btnGhost, btnDanger, btnSmall, panelStyle,
ICON_PATHS,
});