diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index cae85eb..e93756d 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,6 +1,10 @@ import { BrowserRouter, Routes, Route } from 'react-router-dom'; import RootLayout from './layouts/RootLayout'; -import { BuyerSidebar, SellerSidebar, AdminSidebar } from './components/RoleBasedSidebar'; +import { + BuyerSidebar, + SellerSidebar, + AdminSidebar, +} from './components/RoleBasedSidebar'; import WorkspaceView from './components/WorkspaceView'; import { CartProvider } from './context/CartContext'; @@ -18,27 +22,50 @@ import Orders from './pages/buyer/Orders'; // Seller Pages import Dashboard from './pages/seller/dashboard'; import Catalog from './pages/seller/catalog'; +import Inventory from './pages/seller/inventory'; +import SellerOrders from './pages/seller/orders'; +import Earnings from './pages/seller/earnings'; + +// Admin Pages +import Overview from './pages/admin/overview'; +import Verify from './pages/admin/verify'; +import Moderate from './pages/admin/moderate'; +import Users from './pages/admin/users'; +import Logs from './pages/admin/logs'; +import Disputes from './pages/admin/disputes'; const App = () => ( + {/* Admin Routes */} } />} > + } /> + } /> + } /> + } /> + } /> + } /> } /> + {/* Seller Routes */} } />} > } /> } /> + } /> + } /> + } /> } /> + {/* Buyer Routes */} } />} diff --git a/frontend/src/components/RoleBasedSidebar.jsx b/frontend/src/components/RoleBasedSidebar.jsx index 540b620..7fa1f17 100644 --- a/frontend/src/components/RoleBasedSidebar.jsx +++ b/frontend/src/components/RoleBasedSidebar.jsx @@ -114,7 +114,7 @@ export const SellerSidebar = () => ( icon={Store} /> @@ -133,7 +133,7 @@ export const AdminSidebar = () => (
    { + return ( + + {reason} + + ); +}; + +const ActiveDisputeQueue = ({ data, onRowClick, onFilterClick, onSortClick }) => { + return ( +
    + {/* Header */} +
    +

    Active Dispute Queue

    +
    + + +
    + + 1-4 of 24 + +
    +
    + + {/* Table Content */} +
    + + + + + + + + + + + + {data.map((row, i) => ( + onRowClick(row.id)} + className={`border-b border-neutral-dark/5 hover:bg-neutral-dark/5 transition-colors cursor-pointer group/row ${i === data.length - 1 ? 'border-b-0' : ''}`} + > + + + + + + + ))} + +
    Dispute IDArtisan / ShopCustomerReasonAmount
    + + {row.id} + + +
    + {row.shopName} +
    + + {row.shopName} + +
    + + {row.customerName} + + + + + + {row.amount} + +
    +
    + + {/* Footer / Pagination */} +
    +
    + Showing 1-4 of 24 open disputes +
    +
    + +
    +
    +
    + ); +}; + +export default ActiveDisputeQueue; diff --git a/frontend/src/components/admin/AdminActionModal.jsx b/frontend/src/components/admin/AdminActionModal.jsx new file mode 100644 index 0000000..90f832a --- /dev/null +++ b/frontend/src/components/admin/AdminActionModal.jsx @@ -0,0 +1,63 @@ +import React, { useEffect } from 'react'; +import { X, Info } from 'lucide-react'; + +const AdminActionModal = ({ isOpen, onClose, title, message }) => { + useEffect(() => { + if (isOpen) { + document.body.style.overflow = 'hidden'; + } else { + document.body.style.overflow = 'unset'; + } + return () => { + document.body.style.overflow = 'unset'; + }; + }, [isOpen]); + + if (!isOpen) return null; + + return ( +
    + {/* Backdrop */} +
    + + {/* Modal Dialog */} +
    + {/* Header */} +
    +

    + + {title} +

    + +
    + + {/* Content */} +
    +

    + {message || "This feature is currently under development for the Admin Portal. Check back later!"} +

    +
    + + {/* Footer */} +
    + +
    +
    +
    + ); +}; + +export default AdminActionModal; diff --git a/frontend/src/components/admin/AdminHeader.jsx b/frontend/src/components/admin/AdminHeader.jsx new file mode 100644 index 0000000..6185d77 --- /dev/null +++ b/frontend/src/components/admin/AdminHeader.jsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { Search, Bell, HelpCircle } from 'lucide-react'; + +const AdminHeader = ({ + searchPlaceholder = "Search for shops, orders, or reports...", + primaryActionText = "Export Report", + onPrimaryActionClick, + secondaryActionText, + secondaryActionIcon: SecondaryActionIcon, + onSecondaryActionClick +}) => { + return ( +
    + {/* Search Bar */} +
    + + +
    + + {/* Right Controls */} +
    +
    + {secondaryActionText && ( + + )} + +
    + + +
    +
    + ); +}; + +export default AdminHeader; diff --git a/frontend/src/components/admin/AdminStatCard.jsx b/frontend/src/components/admin/AdminStatCard.jsx new file mode 100644 index 0000000..1ff34ad --- /dev/null +++ b/frontend/src/components/admin/AdminStatCard.jsx @@ -0,0 +1,28 @@ +import React from 'react'; + +const AdminStatCard = ({ title, value, subtext, subtextColor = 'text-neutral-dark/60', icon: Icon, iconBgClass = 'bg-[#F5EDE8]', iconColorClass = 'text-primary', accentClass = '' }) => { + return ( +
    +
    +

    + {title} +

    + {Icon && ( +
    + +
    + )} +
    + +
    +
    + {value} +
    +
    + {subtext} +
    +
    +
    + ); +}; +export default AdminStatCard; \ No newline at end of file diff --git a/frontend/src/components/admin/ApplicationsTable.jsx b/frontend/src/components/admin/ApplicationsTable.jsx new file mode 100644 index 0000000..b13a895 --- /dev/null +++ b/frontend/src/components/admin/ApplicationsTable.jsx @@ -0,0 +1,122 @@ +import React from 'react'; +import { Filter, Download, ChevronRight } from 'lucide-react'; +import Pagination from '../seller/Pagination'; + +const StatusBadge = ({ status }) => { + const isFlagged = status === 'FLAGGED'; + return ( + + {status} + + ); +}; + +const ScoreBar = ({ score }) => { + const isLow = score < 50; + const colorClass = isLow ? 'bg-destructive' : 'bg-[#8C5233]'; + + return ( +
    +
    + {score} +
    +
    +
    +
    +
    + ); +}; + +const ApplicationsTable = ({ data, onFilterClick, onDownloadClick, onRowClick }) => { + return ( +
    + {/* Header */} +
    +

    Applications Overview

    +
    + + +
    +
    + + {/* Table Content */} +
    + + + + + + + + + + + + + {data.map((row, i) => ( + onRowClick(row.name)} + className={`border-b border-neutral-dark/5 hover:bg-neutral-dark/5 transition-colors group/row cursor-pointer ${i === data.length - 1 ? 'border-b-0' : ''}`} + > + + + + + + + + ))} + +
    Shop NameCategoryApplied OnScoreStatus
    +
    + +
    +
    +
    + {row.name} +
    +
    + {row.id} +
    +
    +
    + {row.category} + + {row.appliedOn} + + + + + + +
    +
    + + {/* Footer / Pagination */} +
    +
    + Showing 4 of 42 pending shops +
    +
    + +
    +
    +
    + ); +}; + +export default ApplicationsTable; diff --git a/frontend/src/components/admin/AuditSummaryCard.jsx b/frontend/src/components/admin/AuditSummaryCard.jsx new file mode 100644 index 0000000..e320b85 --- /dev/null +++ b/frontend/src/components/admin/AuditSummaryCard.jsx @@ -0,0 +1,36 @@ +import React from 'react'; + +const AuditSummaryCard = ({ onReviewClick, onDownloadClick }) => { + return ( +
    + {/* Background Graphic Suggestion */} +
    + +
    +

    + Automated Audit Summary +

    +

    + The platform AI has analyzed the last 500 transactions. No systemic anomalies detected, but 2 shops are flagged for manual review based on volume spikes. +

    +
    + +
    + + +
    +
    + ); +}; + +export default AuditSummaryCard; diff --git a/frontend/src/components/admin/BatchVerifyFAB.jsx b/frontend/src/components/admin/BatchVerifyFAB.jsx new file mode 100644 index 0000000..b1776c1 --- /dev/null +++ b/frontend/src/components/admin/BatchVerifyFAB.jsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { BadgeCheck } from 'lucide-react'; + +const BatchVerifyFAB = ({ count = 5, onClick }) => { + return ( + + ); +}; + +export default BatchVerifyFAB; diff --git a/frontend/src/components/admin/BulkActionOverlay.jsx b/frontend/src/components/admin/BulkActionOverlay.jsx new file mode 100644 index 0000000..8bb2a4e --- /dev/null +++ b/frontend/src/components/admin/BulkActionOverlay.jsx @@ -0,0 +1,61 @@ +import React from 'react'; +import { Check, XCircle, CornerRightUp } from 'lucide-react'; + +const BulkActionOverlay = ({ selectedCount = 4, onActionClick }) => { + if (selectedCount === 0) return null; + + return ( +
    +
    + + {/* Selection Count */} +
    +
    + {selectedCount} +
    + + SELECTED + +
    + + {/* Divider */} +
    + + {/* Quick Actions */} +
    + + + +
    + + {/* Primary Action */} + +
    +
    + ); +}; + +export default BulkActionOverlay; diff --git a/frontend/src/components/admin/CategoryPerformanceTable.jsx b/frontend/src/components/admin/CategoryPerformanceTable.jsx new file mode 100644 index 0000000..1e639fe --- /dev/null +++ b/frontend/src/components/admin/CategoryPerformanceTable.jsx @@ -0,0 +1,93 @@ +import React from 'react'; +import { Filter, ChevronDown, ChevronRight } from 'lucide-react'; + +const StatusBadge = ({ status }) => { + const isTrending = status === 'TRENDING'; + return ( + + {status} + + ); +}; + +const CategoryPerformanceTable = ({ data, onViewDetailedAnalyticsClick, onAllRegionsClick }) => { + return ( +
    + {/* Header */} +
    +

    Shop Performance by Category

    +
    + + +
    +
    + + {/* Table Content */} +
    + + + + + + + + + + + + + {data.map((row, i) => ( + + + + + + + + + ))} + +
    CategoryActive ShopsAvg. SalesGrowthStatus
    +
    + +
    + + {row.category.name} + +
    + {row.activeShops} + + {row.avgSales} + + + {row.growth} + + + + + +
    +
    + + {/* Footer Link */} +
    + + View Detailed Analytics + +
    +
    + ); +}; + +export default CategoryPerformanceTable; diff --git a/frontend/src/components/admin/DisputeReasonsCard.jsx b/frontend/src/components/admin/DisputeReasonsCard.jsx new file mode 100644 index 0000000..18e5473 --- /dev/null +++ b/frontend/src/components/admin/DisputeReasonsCard.jsx @@ -0,0 +1,49 @@ +import React from 'react'; + +const ReasonBar = ({ label, percentage }) => { + return ( +
    +
    + + {label} + + + {percentage}% + +
    +
    +
    +
    +
    + ); +}; + +const DisputeReasonsCard = ({ data, trend }) => { + return ( +
    +

    + Dispute Reasons +

    + +
    + {data.map((item, i) => ( + + ))} +
    + +
    +

    + Trend Analysis +

    +

    + {trend} +

    +
    +
    + ); +}; + +export default DisputeReasonsCard; diff --git a/frontend/src/components/admin/ModerationTable.jsx b/frontend/src/components/admin/ModerationTable.jsx new file mode 100644 index 0000000..a8a6be1 --- /dev/null +++ b/frontend/src/components/admin/ModerationTable.jsx @@ -0,0 +1,175 @@ +import React from 'react'; +import { ChevronDown, Download } from 'lucide-react'; +import Pagination from '../seller/Pagination'; + +const ViolationBadge = ({ type }) => { + let styleClass = "bg-neutral-dark/10 text-neutral-dark/60"; // Default + if (type === 'COPYRIGHT') { + styleClass = "bg-[#F8E2DF] text-destructive"; // Pink/Red + } else if (type === 'QUALITY') { + styleClass = "bg-[#FDF3E1] text-[#B7791F]"; // Yellow/Orange + } else if (type === 'PROHIBITED') { + styleClass = "bg-[#E2E8F0] text-[#4A5568]"; // Gray + } + + return ( + + {type} + + ); +}; + +const SeverityBar = ({ score }) => { + let colorClass = "bg-[#CBD5E1] text-[#64748B]"; // Default gray (<30) + if (score >= 80) { + colorClass = "bg-destructive text-destructive"; // High (red) + } else if (score >= 40) { + colorClass = "bg-[#ED8936] text-[#DD6B20]"; // Medium (orange) + } + + return ( +
    +
    + {score} +
    +
    +
    +
    +
    + ); +}; + +const StatusDisplay = ({ status }) => { + if (status === 'ESCALATED') { + return ( +
    +
    + + ESCALATED + +
    + ); + } + return ( + + {status} + + ); +}; + +const ModerationTable = ({ data, onFilterClick, onDownloadClick, onReviewClick }) => { + return ( +
    + {/* Header */} +
    +

    Moderation Queue

    +
    + + +
    + +
    +
    + + {/* Table Content */} +
    {/* Extra padding bottom for the floating bar */} + + + + + + + + + + + + + {data.map((row, i) => ( + + + + + + + + + ))} + +
    Product & IDShop NameViolationFlagged OnSeverityStatus
    +
    + {row.productName} +
    +
    +
    + {row.productName} +
    +
    + {row.id} +
    +
    +
    + + {row.shopName} + + + + +
    + {row.flaggedDate} +
    +
    + {row.flaggedTime} +
    +
    + + +
    + + +
    +
    +
    + + {/* Footer / Pagination */} +
    +
    + Showing 1 to 10 of 124 tickets +
    +
    + +
    +
    +
    + ); +}; + +export default ModerationTable; diff --git a/frontend/src/components/admin/PayoutHealthCard.jsx b/frontend/src/components/admin/PayoutHealthCard.jsx new file mode 100644 index 0000000..b923174 --- /dev/null +++ b/frontend/src/components/admin/PayoutHealthCard.jsx @@ -0,0 +1,49 @@ +import React from 'react'; + +const HealthBar = ({ label, percentage }) => { + const isHealthy = percentage >= 95; + const colorClass = isHealthy ? "bg-[#16A34A] text-[#16A34A]" : "bg-destructive text-destructive"; + + return ( +
    +
    + + {label} + + + {percentage}% + +
    +
    +
    +
    +
    + ); +}; + +const PayoutHealthCard = ({ data, lastUpdated }) => { + return ( +
    +

    + Payout Method Health +

    + +
    + {data.map((item, i) => ( + + ))} +
    + +
    + + Last updated: {lastUpdated} + +
    +
    + ); +}; + +export default PayoutHealthCard; diff --git a/frontend/src/components/admin/PlatformGrowthChart.jsx b/frontend/src/components/admin/PlatformGrowthChart.jsx new file mode 100644 index 0000000..1f5930c --- /dev/null +++ b/frontend/src/components/admin/PlatformGrowthChart.jsx @@ -0,0 +1,76 @@ +import React from 'react'; + +const PlatformGrowthChart = ({ data }) => { + // data is expected to be an array of objects: { label: 'OCT 01', value: 40, isHighlighted: false, tooltip: null } + const maxVal = Math.max(...data.map(d => d.value), 1); + + return ( +
    +
    +
    +

    + PLATFORM GROWTH +

    +

    + Merchant acquisition vs Transaction volume +

    +
    +
    + + + +
    +
    + + {/* Bar Chart Area */} +
    +
    + {data.map((item, i) => { + const heightPercent = (item.value / maxVal) * 100; + return ( +
    + {/* Tooltip for highlighted bar */} + {item.isHighlighted && item.tooltip && ( +
    +
    + PEAK PERFORMANCE +
    +
    + {item.tooltip.value} +
    +
    + {item.tooltip.date} +
    + {/* Arrow down */} +
    +
    + )} +
    + ); + })} +
    + + {/* X-Axis Labels */} +
    + {data.map((item, i) => ( + + {item.showLabel ? item.label : ''} + + ))} +
    +
    +
    + ); +}; + +export default PlatformGrowthChart; diff --git a/frontend/src/components/admin/RecentActivityCard.jsx b/frontend/src/components/admin/RecentActivityCard.jsx new file mode 100644 index 0000000..48fa3fa --- /dev/null +++ b/frontend/src/components/admin/RecentActivityCard.jsx @@ -0,0 +1,57 @@ +import React from 'react'; +import { CheckCircle, MessageSquare } from 'lucide-react'; + +const ActivityItem = ({ type, text, timeAgo }) => { + const Icon = type === 'resolution' ? CheckCircle : MessageSquare; + const iconColor = type === 'resolution' ? 'text-[#8C5233]' : 'text-destructive'; + const iconBg = type === 'resolution' ? 'bg-[#8C5233]/10' : 'bg-destructive/10'; + + return ( +
    +
    + +
    +
    +

    +

    + {timeAgo} +

    +
    +
    + ); +}; + +const RecentActivityCard = ({ activities, onViewAllClick }) => { + return ( +
    +

    + Recent Activity +

    + +
    + {activities.map((activity, i) => ( + + ))} +
    + +
    + +
    +
    + ); +}; + +export default RecentActivityCard; diff --git a/frontend/src/components/admin/SystemAlerts.jsx b/frontend/src/components/admin/SystemAlerts.jsx new file mode 100644 index 0000000..e08955f --- /dev/null +++ b/frontend/src/components/admin/SystemAlerts.jsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { MoreVertical, ArrowRight } from 'lucide-react'; + +const SystemAlerts = ({ alerts, onViewAllClick }) => { + return ( +
    +
    +

    + SYSTEM ALERTS +

    + +
    + +
    + {alerts.map((alert, index) => ( +
    + {/* Indicator Dot */} +
    +
    +
    + {/* Content */} +
    +

    + {alert.title} +

    +

    + {alert.message} +

    +
    + {alert.timeAgo} +
    +
    +
    + ))} +
    + + {/* Footer Link */} +
    + +
    +
    + ); +}; + +export default SystemAlerts; diff --git a/frontend/src/components/admin/TransactionLogsTable.jsx b/frontend/src/components/admin/TransactionLogsTable.jsx new file mode 100644 index 0000000..2d697d4 --- /dev/null +++ b/frontend/src/components/admin/TransactionLogsTable.jsx @@ -0,0 +1,144 @@ +import React from 'react'; +import { ChevronDown, Eye } from 'lucide-react'; +import Pagination from '../seller/Pagination'; + +const TypeBadge = ({ type }) => { + return ( + + {type} + + ); +}; + +const AmountDisplay = ({ amount, type }) => { + let colorClass = "text-neutral-dark"; + if (type === 'SALE') colorClass = "text-[#16A34A]"; // Green + if (type === 'REFUND') colorClass = "text-destructive"; // Red + + return ( + + {amount} + + ); +}; + +const StatusDisplay = ({ status }) => { + let colorClass = "bg-[#16A34A] text-[#16A34A]"; // COMPLETED (Green) + if (status === 'PENDING') colorClass = "bg-[#D97706] text-[#D97706]"; + if (status === 'DISPUTED') colorClass = "bg-destructive text-destructive"; + + return ( +
    +
    + + {status} + +
    + ); +}; + +const TransactionLogsTable = ({ data, onFilterClick, onActionClick }) => { + return ( +
    + {/* Header */} +
    +

    Recent Financial Activities

    +
    + + +
    + + 1-5 of 1,284 + +
    +
    + + {/* Table Content */} +
    + + + + + + + + + + + + + + {data.map((row, i) => ( + + + + + + + + + + ))} + +
    DateTransaction IDShop NameTypeAmountStatusActions
    +
    + {row.date.split(',')[0]}, +
    +
    + {row.date.split(',')[1]} +
    +
    + + {row.id} + + + + {row.shopName} + + + + + + + + +
    + +
    +
    +
    + + {/* Footer / Pagination */} +
    +
    + Showing 1 to 5 of 1,284 transactions +
    +
    + +
    +
    +
    + ); +}; + +export default TransactionLogsTable; diff --git a/frontend/src/components/admin/UserDirectoryTable.jsx b/frontend/src/components/admin/UserDirectoryTable.jsx new file mode 100644 index 0000000..2780e01 --- /dev/null +++ b/frontend/src/components/admin/UserDirectoryTable.jsx @@ -0,0 +1,162 @@ +import React from 'react'; +import { ChevronDown, Pencil, Store, Ban, CheckCircle, RefreshCw } from 'lucide-react'; +import Pagination from '../seller/Pagination'; + +const RoleBadge = ({ role }) => { + return ( + + {role} + + ); +}; + +const StatusDisplay = ({ status }) => { + let colorClass = "bg-primary text-primary"; + if (status === 'PENDING') colorClass = "bg-[#D97706] text-[#D97706]"; + if (status === 'SUSPENDED') colorClass = "bg-destructive text-destructive"; + + return ( +
    +
    + + {status} + +
    + ); +}; + +const UserDirectoryTable = ({ data, onFilterClick, onActionClick }) => { + return ( +
    + {/* Header */} +
    +

    Directory

    +
    + + +
    + + 1-10 of 24,892 + +
    +
    + + {/* Table Content */} +
    + + + + + + + + + + + + {data.map((row, i) => ( + + + + + + + + ))} + +
    Name / ShopRoleStatusJoin DateActions
    +
    + {row.name} +
    +
    +
    + {row.name} +
    +
    + {row.subtext} +
    +
    +
    + + + + + {row.joinDate} + +
    + {/* Common Edit Action */} + + + {/* Role-specific Action */} + {row.role === 'SELLER' ? ( + + ) : row.status === 'PENDING' ? ( + + ) : ( +
    /* Spacer if no action */ + )} + + {/* Status-specific Action (Suspend / Restore) */} + {row.status === 'SUSPENDED' ? ( + + ) : ( + + )} +
    +
    +
    + + {/* Footer / Pagination */} +
    +
    + Showing 1 to 10 of 24,892 users +
    +
    + +
    +
    +
    + ); +}; + +export default UserDirectoryTable; diff --git a/frontend/src/components/seller/ActionModal.jsx b/frontend/src/components/seller/ActionModal.jsx new file mode 100644 index 0000000..898f6f6 --- /dev/null +++ b/frontend/src/components/seller/ActionModal.jsx @@ -0,0 +1,64 @@ +import React, { useEffect } from 'react'; +import { X, Info } from 'lucide-react'; + +const ActionModal = ({ isOpen, onClose, title, message }) => { + // Prevent scrolling when modal is open + useEffect(() => { + if (isOpen) { + document.body.style.overflow = 'hidden'; + } else { + document.body.style.overflow = 'unset'; + } + return () => { + document.body.style.overflow = 'unset'; + }; + }, [isOpen]); + + if (!isOpen) return null; + + return ( +
    + {/* Backdrop */} +
    + + {/* Modal Dialog */} +
    + {/* Header */} +
    +

    + + {title} +

    + +
    + + {/* Content */} +
    +

    + {message || "This feature is currently under development. Check back later!"} +

    +
    + + {/* Footer */} +
    + +
    +
    +
    + ); +}; + +export default ActionModal; diff --git a/frontend/src/components/seller/AlertBanner.jsx b/frontend/src/components/seller/AlertBanner.jsx new file mode 100644 index 0000000..68a61fe --- /dev/null +++ b/frontend/src/components/seller/AlertBanner.jsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { TriangleAlert } from 'lucide-react'; + +const AlertBanner = ({ title, message, buttonText, onClick, variant = 'danger', icon: Icon = TriangleAlert }) => { + // Danger variant (Red/Pink) + let containerClass = "bg-[#FCF1F0] border border-[#EAC2BE]"; + let iconContainerClass = "bg-[#F8E2DF]"; + let iconColor = "text-destructive"; + let buttonClass = "bg-[#C85746] hover:bg-destructive text-white"; + + // Warning variant (Beige/Brown) + if (variant === 'warning') { + containerClass = "bg-[#F3EBE3] border border-[#E3D4C4]"; + iconContainerClass = "bg-[#EBDDD0]"; + iconColor = "text-[#8C5233]"; + buttonClass = "bg-[#8C5233] hover:bg-[#7E4A2E] text-white"; + } + + return ( +
    +
    +
    + +
    +
    +

    + {title} +

    +

    + {message} +

    +
    +
    + +
    + ); +}; + +export default AlertBanner; diff --git a/frontend/src/components/seller/DailyShipmentsChart.jsx b/frontend/src/components/seller/DailyShipmentsChart.jsx new file mode 100644 index 0000000..147fe8e --- /dev/null +++ b/frontend/src/components/seller/DailyShipmentsChart.jsx @@ -0,0 +1,44 @@ +import React from 'react'; + +const DailyShipmentsChart = ({ data }) => { + // data is expected to be an array of objects: { label: 'MON', value: 40, isHighlighted: false } + const maxVal = Math.max(...data.map(d => d.value), 1); + + return ( +
    +
    +

    + DAILY SHIPMENTS +

    +

    + Last 7 Days +

    +
    + + {/* Bar Chart Area */} +
    +
    + {data.map((item, i) => { + const heightPercent = (item.value / maxVal) * 100; + return ( +
    + ); + })} +
    + + {/* X-Axis Labels */} +
    + {data.map((item, i) => ( + {item.label} + ))} +
    +
    +
    + ); +}; + +export default DailyShipmentsChart; diff --git a/frontend/src/components/seller/DashboardFAB.jsx b/frontend/src/components/seller/DashboardFAB.jsx index 3901fa4..4edf162 100644 --- a/frontend/src/components/seller/DashboardFAB.jsx +++ b/frontend/src/components/seller/DashboardFAB.jsx @@ -1,9 +1,12 @@ import React from 'react'; import { Plus } from 'lucide-react'; -const DashboardFAB = () => { +const DashboardFAB = ({ onClick }) => { return ( - ); diff --git a/frontend/src/components/seller/DashboardHeader.jsx b/frontend/src/components/seller/DashboardHeader.jsx index a287e19..ad49e0d 100644 --- a/frontend/src/components/seller/DashboardHeader.jsx +++ b/frontend/src/components/seller/DashboardHeader.jsx @@ -1,7 +1,15 @@ import React from 'react'; -import { Search, Bell, MessageSquare } from 'lucide-react'; +import { Search, Bell, MessageSquare, Settings } from 'lucide-react'; -const DashboardHeader = () => { +const DashboardHeader = ({ + user = { + name: 'Habib Mangoranda', + role: 'Master Potter', + initials: 'HM' + }, + searchPlaceholder = 'Search orders, products...', + showSettings = false +}) => { return (
    {/* Search Bar */} @@ -12,7 +20,7 @@ const DashboardHeader = () => {
    @@ -21,20 +29,26 @@ const DashboardHeader = () => { - + {showSettings ? ( + + ) : ( + + )} {/* User Profile */}
    -
    Habib Mangoranda
    -
    Master Potter
    +
    {user.name}
    +
    {user.role}
    Elena Rodriguez
    diff --git a/frontend/src/components/seller/DeliveryPerformance.jsx b/frontend/src/components/seller/DeliveryPerformance.jsx new file mode 100644 index 0000000..e93af73 --- /dev/null +++ b/frontend/src/components/seller/DeliveryPerformance.jsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { Clock } from 'lucide-react'; + +const DeliveryPerformance = ({ onTimeRate, avgFulfillmentTime, performanceMessage }) => { + return ( +
    +

    + DELIVERY PERFORMANCE +

    + + {/* On-Time Rate */} +
    +
    + On-Time Delivery Rate + {onTimeRate}% +
    +
    +
    +
    +
    + + {/* Avg Fulfillment Time */} +
    +
    +
    Avg. Fulfillment Time
    +
    {avgFulfillmentTime} Days
    +
    +
    + +
    +
    + + {/* Message */} +
    +

    + "{performanceMessage}" +

    +
    +
    + ); +}; + +export default DeliveryPerformance; diff --git a/frontend/src/components/seller/InventoryOptimizer.jsx b/frontend/src/components/seller/InventoryOptimizer.jsx new file mode 100644 index 0000000..d2714e6 --- /dev/null +++ b/frontend/src/components/seller/InventoryOptimizer.jsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { Sparkles } from 'lucide-react'; + +const InventoryOptimizer = ({ title, description, buttonText, onOptimize }) => { + return ( +
    +

    + {title} +

    +

    + {description} +

    + + +
    + ); +}; + +export default InventoryOptimizer; diff --git a/frontend/src/components/seller/InventoryStatCard.jsx b/frontend/src/components/seller/InventoryStatCard.jsx new file mode 100644 index 0000000..8921039 --- /dev/null +++ b/frontend/src/components/seller/InventoryStatCard.jsx @@ -0,0 +1,29 @@ +import React from 'react'; + +const InventoryStatCard = ({ title, value, subtext, subtextColor = 'text-neutral-dark/60', icon: Icon, iconBgClass = 'bg-[#F5EDE8]' }) => { + return ( +
    +
    +

    + {title} +

    + {Icon && ( +
    + +
    + )} +
    + +
    +
    + {value} +
    +
    + {subtext} +
    +
    +
    + ); +}; + +export default InventoryStatCard; diff --git a/frontend/src/components/seller/InventoryTable.jsx b/frontend/src/components/seller/InventoryTable.jsx new file mode 100644 index 0000000..ce36093 --- /dev/null +++ b/frontend/src/components/seller/InventoryTable.jsx @@ -0,0 +1,103 @@ +import React from 'react'; +import { Filter, Download } from 'lucide-react'; +import Pagination from './Pagination'; // Reuse the Pagination component + +const StatusBadge = ({ status }) => { + let badgeStyle = "bg-[#EBE5D9] text-neutral-dark/70"; // IN STOCK + if (status === 'LOW STOCK') { + badgeStyle = "bg-[#F8E2DF] text-[#C85746]"; + } else if (status === 'OUT OF STOCK') { + badgeStyle = "bg-[#F8E2DF] text-destructive"; + } + + return ( + + {status.replace(' ', '\n')} + + ); +}; + +const InventoryTable = ({ items, totalItems, currentlyShowing }) => { + return ( +
    + {/* Header */} +
    +

    Stock Inventory List

    +
    + + +
    +
    + + {/* Table Content */} +
    + + + + + + + + + + + + + {items.map((item, i) => ( + + + + + + + + + ))} + +
    Item DetailsSKUCategoryCurrent StockReorder PointStatus
    +
    +
    + {item.name} +
    +
    +

    {item.name}

    +

    {item.description}

    +
    +
    +
    +
    + {item.sku.split('-').map((part, index) => ( + + {part}{index < item.sku.split('-').length - 1 ? '-' : ''}
    +
    + ))} +
    +
    + + {item.category} + + + + {item.currentStock} pcs + + + {item.reorderPoint ? `${item.reorderPoint} pcs` : ''} + + +
    +
    + + {/* Footer / Pagination */} +
    +
    + Showing {currentlyShowing} of {totalItems} items +
    +
    + +
    +
    +
    + ); +}; + +export default InventoryTable; diff --git a/frontend/src/components/seller/OrderQueueTable.jsx b/frontend/src/components/seller/OrderQueueTable.jsx new file mode 100644 index 0000000..52ddff3 --- /dev/null +++ b/frontend/src/components/seller/OrderQueueTable.jsx @@ -0,0 +1,87 @@ +import React from 'react'; +import { Filter, MoreVertical } from 'lucide-react'; +import Pagination from './Pagination'; + +const StatusBadge = ({ status }) => { + let badgeStyle = "bg-[#EBE5D9] text-[#8C5233]"; // default PENDING / READY FOR PICKUP + if (status === 'PROCESSING') { + badgeStyle = "bg-[#D9E2EB] text-[#4A6478]"; + } + + return ( + + {status} + + ); +}; + +const OrderQueueTable = ({ orders, totalOrders, currentlyShowing }) => { + return ( +
    + {/* Header */} +
    +

    Recent Orders Queue

    +
    + + +
    +
    + + {/* Table Content */} +
    + + + + + + + + + + + + {orders.map((order, i) => ( + + + + + + + + ))} + +
    Order IDDateCustomerProductStatus
    + + {order.id.split('-').map((part, index) => ( + + {part}{index < order.id.split('-').length - 1 ? '-' : ''}
    +
    + ))} +
    +
    + {order.date.replace(', ', ',\n')} + + + {order.customer.replace(' ', '\n')} + + + {order.product} + + +
    +
    + + {/* Footer / Pagination */} +
    +
    + Showing {currentlyShowing} of {totalOrders} pending orders +
    +
    + +
    +
    +
    + ); +}; + +export default OrderQueueTable; diff --git a/frontend/src/components/seller/PayoutDetails.jsx b/frontend/src/components/seller/PayoutDetails.jsx new file mode 100644 index 0000000..a4a8f70 --- /dev/null +++ b/frontend/src/components/seller/PayoutDetails.jsx @@ -0,0 +1,60 @@ +import React from 'react'; +import { Building2, ArrowRight } from 'lucide-react'; + +const PayoutDetails = ({ nextPayoutDate, scheduleType, bankName, accountEnding, onManageClick }) => { + return ( +
    +

    + PAYOUT DETAILS +

    + + {/* Next Scheduled Payout */} +
    +

    + NEXT SCHEDULED PAYOUT +

    +
    +
    + {nextPayoutDate} +
    +
    + {scheduleType} +
    +
    +
    + + {/* Linked Bank Account */} +
    +

    + LINKED BANK ACCOUNT +

    +
    +
    + +
    +
    +
    + {bankName} +
    +
    + Checking **** {accountEnding} +
    +
    +
    +
    + + {/* Manage Link */} +
    + +
    +
    + ); +}; + +export default PayoutDetails; diff --git a/frontend/src/components/seller/RestockForecast.jsx b/frontend/src/components/seller/RestockForecast.jsx new file mode 100644 index 0000000..9f3b4a0 --- /dev/null +++ b/frontend/src/components/seller/RestockForecast.jsx @@ -0,0 +1,46 @@ +import React from 'react'; + +const RestockForecast = ({ data }) => { + // data is expected to be an array of objects: { label: 'MON', value: 40 } + const maxVal = Math.max(...data.map(d => d.value), 1); + + return ( +
    +
    +
    +

    Restock Forecast

    +

    Next 30 Days

    +
    + +
    + ANALYTIC
    S +
    +
    + + {/* Bar Chart Area */} +
    +
    + {data.map((item, i) => { + const heightPercent = (item.value / maxVal) * 100; + return ( +
    + ); + })} +
    + + {/* X-Axis Labels */} +
    + {data.map((item, i) => ( + {item.label} + ))} +
    +
    +
    + ); +}; + +export default RestockForecast; diff --git a/frontend/src/components/seller/RevenueTrendChart.jsx b/frontend/src/components/seller/RevenueTrendChart.jsx new file mode 100644 index 0000000..b3c052b --- /dev/null +++ b/frontend/src/components/seller/RevenueTrendChart.jsx @@ -0,0 +1,51 @@ +import React from 'react'; + +const RevenueTrendChart = ({ data }) => { + // data expected to be an array of objects representing weeks: + // { label: 'W1', bars: [40, 60, 50] } // values 0-100 representing height % + // One bar can have isHighlighted: true: { value: 90, isHighlighted: true } + + return ( +
    +
    +
    +

    + REVENUE TREND +

    +

    + Last 30 Days +

    +
    + +
    + + {/* Bar Chart Area */} +
    +
    + {data.map((week, i) => ( +
    + {week.bars.map((bar, j) => ( +
    + ))} +
    + ))} +
    + + {/* X-Axis Labels */} +
    + {data.map((week, i) => ( + {week.label} + ))} +
    +
    +
    + ); +}; + +export default RevenueTrendChart; diff --git a/frontend/src/components/seller/TransactionsTable.jsx b/frontend/src/components/seller/TransactionsTable.jsx new file mode 100644 index 0000000..b26f8ea --- /dev/null +++ b/frontend/src/components/seller/TransactionsTable.jsx @@ -0,0 +1,92 @@ +import React from 'react'; +import { Filter } from 'lucide-react'; + +const StatusBadge = ({ status, type }) => { + let badgeStyle = "bg-[#D9E2EB] text-[#4A6478]"; // Default COMPLETED + + if (status === 'PROCESSING') { + badgeStyle = "bg-[#EBE5D9] text-[#8C5233]"; + } else if (status === 'COMPLETED' && type === 'Refund') { + badgeStyle = "bg-[#F8E2DF] text-[#C85746]"; + } + + return ( + + {status} + + ); +}; + +const TransactionsTable = ({ transactions }) => { + return ( +
    + {/* Header */} +
    +

    Recent Transactions

    +
    + + +
    +
    + + {/* Table Content */} +
    + + + + + + + + + + + + + {transactions.map((txn, i) => ( + + + + + + + + + ))} + +
    DateTransaction IDTypeOrder IDStatusAmount
    + {txn.date.replace(', ', ',\n')} + + + {txn.id} + + + {txn.type} + + + {txn.orderId || '—'} + + + + + + {txn.amount} + +
    +
    + + {/* Footer */} +
    + + View All Transactions + +
    +
    + ); +}; + +export default TransactionsTable; diff --git a/frontend/src/pages/admin/disputes.jsx b/frontend/src/pages/admin/disputes.jsx new file mode 100644 index 0000000..eaba21a --- /dev/null +++ b/frontend/src/pages/admin/disputes.jsx @@ -0,0 +1,192 @@ +import React, { useState } from 'react'; +import { Scale, Clock, BadgeCheck, AlertCircle, TrendingUp, Filter } from 'lucide-react'; +import AdminHeader from '../../components/admin/AdminHeader'; +import AdminStatCard from '../../components/admin/AdminStatCard'; +import ActiveDisputeQueue from '../../components/admin/ActiveDisputeQueue'; +import DisputeReasonsCard from '../../components/admin/DisputeReasonsCard'; +import RecentActivityCard from '../../components/admin/RecentActivityCard'; +import AdminActionModal from '../../components/admin/AdminActionModal'; + +// --- Dummy Data (Data Contract for Backend) --- +const pageData = { + stats: { + open: { value: '24', subtext: '12% VS LAST WEEK' }, + avgResolution: { value: '3.2 Days', subtext: '-0.4 DAYS IMPROVEMENT' }, + resolutionRate: { value: '94%', subtext: 'TARGET: 90%' }, + appeals: { value: '8', subtext: 'REQUIRES SENIOR ADMIN' } + }, + queue: [ + { + id: '#DISP-9021', + shopName: 'Terra Ceramics', + shopImg: 'https://images.unsplash.com/photo-1610701596007-11502861dcfa?w=100&q=80', + customerName: 'Elena Rodriguez', + reason: 'DAMAGED', + amount: '$145.00' + }, + { + id: '#DISP-8942', + shopName: 'Loom & Leaf', + shopImg: 'https://images.unsplash.com/photo-1590736969955-71cc94801759?w=100&q=80', + customerName: 'Jameson Blake', + reason: 'DELIVERY', + amount: '$89.20' + }, + { + id: '#DISP-8710', + shopName: 'Silver Lining', + shopImg: 'https://images.unsplash.com/photo-1611085583191-a3b181a88401?w=100&q=80', + customerName: 'Sarah Jenkins', + reason: 'QUALITY', + amount: '$320.00' + }, + { + id: '#DISP-8604', + shopName: 'Kiln & Kin', + shopImg: 'https://images.unsplash.com/photo-1578749556568-bc2c40e68b61?w=100&q=80', + customerName: 'David Miller', + reason: 'DAMAGED', + amount: '$64.00' + } + ], + reasons: [ + { reason: 'DAMAGED ITEM', percentage: 42 }, + { reason: 'ITEM NOT RECEIVED', percentage: 28 }, + { reason: 'QUALITY ISSUE', percentage: 20 } + ], + trendAnalysis: "Damaged item reports are up by 8%. Recommend updating 'Packaging Guidelines'.", + activities: [ + { + type: 'resolution', + text: '#DISP-8590 was resolved in favor of the customer.', + timeAgo: '2 hours ago' + }, + { + type: 'message', + text: 'Elena R. added a photo to dispute #DISP-9021.', + timeAgo: '4 hours ago' + } + ] +}; + +const DisputesPage = () => { + const [modalState, setModalState] = useState({ isOpen: false, title: '', message: '' }); + + const openModal = (title, message) => { + setModalState({ isOpen: true, title, message }); + }; + + const closeModal = () => { + setModalState(prev => ({ ...prev, isOpen: false })); + }; + + return ( +
    + openModal('Export Report', 'Download comprehensive dispute records.')} + secondaryActionText="Filters" + secondaryActionIcon={Filter} + onSecondaryActionClick={() => openModal('Advanced Filters', 'Select date ranges and status filters.')} + /> + + {/* Header Section */} +
    +
    +

    + Disputes & Complaints +

    +

    + Review and resolve customer conflicts within the artisan marketplace. +

    +
    +
    + + {/* Stats Grid */} +
    + + + {pageData.stats.open.subtext} + + } + icon={Scale} + /> + + {pageData.stats.avgResolution.subtext} + + } + icon={Clock} + /> + + {pageData.stats.resolutionRate.subtext} + + } + icon={BadgeCheck} + /> + + {pageData.stats.appeals.subtext} + + } + icon={AlertCircle} + iconBgClass="bg-[#F8E2DF]" + iconColorClass="text-destructive" + accentClass="border-l-4 border-l-destructive" + /> +
    + + {/* Main Content Area (2-column layout) */} +
    + + {/* Left Column: Active Dispute Queue */} +
    + openModal('Filter Queue', 'Filter table by dispute reason or amount.')} + onSortClick={() => openModal('Sort Queue', 'Sort table by newest or oldest.')} + onRowClick={(id) => openModal('Review Dispute', `Opening full workspace for dispute ${id}.`)} + /> +
    + + {/* Right Column: Sidebar Cards */} +
    + + openModal('Activity Log', 'Viewing complete timeline of dispute events.')} + /> +
    + +
    + + {/* Action Modal */} + +
    + ); +}; + +export default DisputesPage; \ No newline at end of file diff --git a/frontend/src/pages/admin/logs.jsx b/frontend/src/pages/admin/logs.jsx new file mode 100644 index 0000000..9eca169 --- /dev/null +++ b/frontend/src/pages/admin/logs.jsx @@ -0,0 +1,168 @@ +import React, { useState } from 'react'; +import { Banknote, CheckCircle, Hourglass, AlertCircle, TrendingUp, Calendar } from 'lucide-react'; +import AdminHeader from '../../components/admin/AdminHeader'; +import AdminStatCard from '../../components/admin/AdminStatCard'; +import TransactionLogsTable from '../../components/admin/TransactionLogsTable'; +import AuditSummaryCard from '../../components/admin/AuditSummaryCard'; +import PayoutHealthCard from '../../components/admin/PayoutHealthCard'; +import AdminActionModal from '../../components/admin/AdminActionModal'; + +// --- Dummy Data (Data Contract for Backend) --- +const pageData = { + stats: { + volume: { value: 'P142,850.00', subtext: '12% increase' }, + successRate: { value: '99.4%', subtext: 'STABLE GROWTH' }, + pending: { value: 'P12,400.00', subtext: '86 PROCESSING' }, + disputes: { value: '14', subtext: 'IMMEDIATE ACTION' } + }, + transactions: [ + { + date: 'Oct 24, 2023', + id: 'TXN-9021834', + shopName: 'Ancient Earth Crafts', + type: 'SALE', + amount: '+P245.00', + status: 'COMPLETED' + }, + { + date: 'Oct 23, 2023', + id: 'TXN-9021835', + shopName: 'Indigo Loom Textiles', + type: 'PAYOUT', + amount: '-P1,200.00', + status: 'PENDING' + }, + { + date: 'Oct 23, 2023', + id: 'TXN-9021836', + shopName: 'Obsidian Fire Glass', + type: 'SALE', + amount: '+P68.00', + status: 'DISPUTED' + }, + { + date: 'Oct 22, 2023', + id: 'TXN-9021837', + shopName: 'The Iron Forge', + type: 'REFUND', + amount: '-P142.50', + status: 'COMPLETED' + } + ], + payoutHealth: [ + { name: 'BANK TRANSFER (ACH)', health: 99.8 }, + { name: 'STRIPE CONNECT', health: 98.9 }, + { name: 'PAYPAL GLOBAL', health: 94.2 } + ] +}; + +const LogsPage = () => { + const [modalState, setModalState] = useState({ isOpen: false, title: '', message: '' }); + const openModal = (title, message) => { + setModalState({ isOpen: true, title, message }); + }; + const closeModal = () => { + setModalState(prev => ({ ...prev, isOpen: false })); + }; + return ( +
    + openModal('Export CSV', 'Download comprehensive financial records.')} + secondaryActionText="Filters" + secondaryActionIcon={Calendar} + onSecondaryActionClick={() => openModal('Advanced Filters', 'Select date ranges and transaction types.')} + /> + {/* Header Section */} +
    +
    +

    + Transaction Logs +

    +

    + Monitor and audit all platform financial activity from artisanal crafts to raw material sales. +

    +
    +
    + {/* Stats Grid */} +
    + + + {pageData.stats.volume.subtext} + + } + icon={Banknote} + /> + + {pageData.stats.successRate.subtext} + + } + icon={CheckCircle} + /> + + {pageData.stats.pending.subtext} + + } + icon={Hourglass} + /> + + {pageData.stats.disputes.subtext} + + } + icon={AlertCircle} + iconBgClass="bg-[#F8E2DF]" + iconColorClass="text-destructive" + accentClass="border-l-4 border-l-destructive" + /> +
    + {/* Main Table Content */} +
    + openModal(`${filterName} Filter`, `Select options to filter the logs by ${filterName}.`)} + onActionClick={(actionName, txnId) => openModal(`Action: ${actionName}`, `Viewing full details for transaction ${txnId}.`)} + /> +
    + {/* Bottom Widgets */} +
    +
    + openModal('Review Flags', 'Opening the AI audit flags queue for manual review.')} + onDownloadClick={() => openModal('Download Audit', 'Generating the full automated audit PDF report.')} + /> +
    +
    + +
    +
    + {/* Action Modal */} + +
    + ); +}; +export default LogsPage; \ No newline at end of file diff --git a/frontend/src/pages/admin/moderate.jsx b/frontend/src/pages/admin/moderate.jsx new file mode 100644 index 0000000..7602dfb --- /dev/null +++ b/frontend/src/pages/admin/moderate.jsx @@ -0,0 +1,161 @@ +import React, { useState } from 'react'; +import { + Hourglass, + Flag, + Clock, + CheckCircle, + TrendingDown +} from 'lucide-react'; +import AdminHeader from '../../components/admin/AdminHeader'; +import AdminStatCard from '../../components/admin/AdminStatCard'; +import ModerationTable from '../../components/admin/ModerationTable'; +// import BulkActionOverlay from '../../components/admin/BulkActionOverlay'; +import AdminActionModal from '../../components/admin/AdminActionModal'; + +// --- Dummy Data (Data Contract for Backend) --- +const pageData = { + stats: { + pending: { value: '124', subtext: '12% less', isPositive: false }, + flagged: { value: '42', subtext: '8 urgent escalations' }, + avgTime: { value: '4.2h', subtext: 'Within SLA (6h)' }, + resolved: { value: '89', subtext: 'TARGET MET' } + }, + tickets: [ + { + productName: 'Hand-Carved Earthen Vase', + id: '#PRD-9842', + image: 'https://images.unsplash.com/photo-1610701596007-11502861dcfa?w=400&q=80', + shopName: 'Ancient Earth Crafts', + violation: 'COPYRIGHT', + flaggedDate: 'Oct 24, 2023', + flaggedTime: '10:42 AM', + severity: 88, + status: 'ESCALATED' + }, + { + productName: 'Indigo Weave Runner', + id: '#PRD-7210', + image: 'https://images.unsplash.com/photo-1596526131083-e8c633c948d2?w=400&q=80', + shopName: 'Studio Indigo', + violation: 'QUALITY', + flaggedDate: 'Oct 24, 2023', + flaggedTime: '09:15 AM', + severity: 45, + status: 'UNDER REVIEW' + }, + { + productName: 'Botanical Soap Set', + id: '#PRD-3301', + image: 'https://images.unsplash.com/photo-1600857062241-98e5dba7f214?w=400&q=80', + shopName: "Nature's Lather", + violation: 'PROHIBITED', + flaggedDate: 'Oct 23, 2023', + flaggedTime: '04:30 PM', + severity: 12, + status: 'PENDING' + } + ] +}; + +const Moderate = () => { + const [modalState, setModalState] = useState({ isOpen: false, title: '', message: '' }); + + const openModal = (title, message) => { + setModalState({ isOpen: true, title, message }); + }; + + const closeModal = () => { + setModalState(prev => ({ ...prev, isOpen: false })); + }; + + return ( +
    + openModal('Bulk Resolve', 'The bulk resolution wizard will open here.')} + /> + + {/* Header Section */} +
    +
    +

    + Product Moderation +

    +

    + Review and manage reported items from the Artisan community. +

    +
    +
    + + {/* Stats Grid */} +
    + + + {pageData.stats.pending.subtext} + + } + icon={Hourglass} + /> + + {pageData.stats.flagged.subtext} + + } + icon={Flag} + iconBgClass="bg-[#F8E2DF]" + iconColorClass="text-destructive" + /> + + + {pageData.stats.resolved.subtext} + + } + icon={CheckCircle} + /> +
    + + {/* Main Table Content */} +
    + openModal(`${filterName} Filter`, `Select options to filter the moderation queue by ${filterName}.`)} + onDownloadClick={() => openModal('Download Report', 'Download the current moderation queue data.')} + onReviewClick={(productName) => openModal('Review Ticket', `Review full moderation details for ${productName}.`)} + /> +
    + + {/* Floating Bulk Action Overlay (Mockup State) */} + {/* openModal(`Bulk Action: ${actionName}`, `Applying ${actionName} to 4 selected tickets.`)} + /> */} + + {/* Action Modal */} + +
    + ); +}; + +export default Moderate; diff --git a/frontend/src/pages/admin/overview.jsx b/frontend/src/pages/admin/overview.jsx new file mode 100644 index 0000000..5d52134 --- /dev/null +++ b/frontend/src/pages/admin/overview.jsx @@ -0,0 +1,201 @@ +import React, { useState } from 'react'; +import { + Store, + Banknote, + BadgeCheck, + AlertTriangle, + TrendingUp, + TrendingDown, + Armchair, + Gem, + Palette +} from 'lucide-react'; +import AdminHeader from '../../components/admin/AdminHeader'; +import AdminStatCard from '../../components/admin/AdminStatCard'; +import PlatformGrowthChart from '../../components/admin/PlatformGrowthChart'; +import SystemAlerts from '../../components/admin/SystemAlerts'; +import CategoryPerformanceTable from '../../components/admin/CategoryPerformanceTable'; +import AdminActionModal from '../../components/admin/AdminActionModal'; + +// --- Dummy Data (Data Contract for Backend) --- +const pageData = { + stats: { + shops: { value: '4,281', subtext: '+12%', isPositive: true }, + gmv: { value: 'P1.2M', subtext: '+8.4%', isPositive: true }, + verifications: { value: '84', subtext: 'REVIEW QUEUE' }, + disputes: { value: '12', subtext: '-2.1%', isPositive: false } + }, + growthData: [ + { label: 'OCT 01', showLabel: true, value: 30 }, + { label: '', showLabel: false, value: 40 }, + { label: '', showLabel: false, value: 35 }, + { label: 'OCT 10', showLabel: true, value: 50 }, + { label: '', showLabel: false, value: 65 }, + { + label: '', showLabel: false, value: 100, + isHighlighted: true, + tooltip: { value: 'P42,800.00', date: 'Oct 12, 2023' } + }, + { label: 'OCT 20', showLabel: true, value: 55 }, + { label: '', showLabel: false, value: 45 }, + { label: '', showLabel: false, value: 75 }, + { label: 'OCT 30', showLabel: true, value: 60 } + ], + systemAlerts: [ + { + title: 'New verification request', + message: 'The "Highland Loom" shop has submitted premium papers.', + timeAgo: '2 MINUTES AGO', + isUrgent: false + }, + { + title: 'Dispute Escalation', + message: 'Order #8821 from "Ceramic Echoes" marked as undelivered.', + timeAgo: '45 MINUTES AGO', + isUrgent: true + }, + { + title: 'Server maintenance', + message: 'Database optimization scheduled for 02:00 UTC.', + timeAgo: '2 HOURS AGO', + isUrgent: false + } + ], + categoryPerformance: [ + { + category: { name: 'Handcrafted Furniture', icon: Armchair }, + activeShops: '1,120', + avgSales: 'P4,250', + growth: '+14.2%', + status: 'TRENDING' + }, + { + category: { name: 'Artisanal Jewelry', icon: Gem }, + activeShops: '845', + avgSales: 'P1,980', + growth: '+5.8%', + status: 'STABLE' + }, + { + category: { name: 'Ceramics & Pottery', icon: Palette }, + activeShops: '562', + avgSales: 'P2,110', + growth: '-1.2%', + status: 'STABLE' + } + ] +}; + +const Overview = () => { + const [modalState, setModalState] = useState({ isOpen: false, title: '', message: '' }); + + const openModal = (title, message) => { + setModalState({ isOpen: true, title, message }); + }; + + const closeModal = () => { + setModalState(prev => ({ ...prev, isOpen: false })); + }; + + return ( +
    + openModal('Export Report', 'The report generation and export feature is coming soon.')} /> + + {/* Header Section */} +
    +
    +

    + System Overview +

    +

    + Real-time health and performance metrics for the Artisan Hub ecosystem. +

    +
    +
    + + {/* Stats Grid */} +
    + + + {pageData.stats.shops.subtext} + + } + icon={Store} + /> + + + {pageData.stats.gmv.subtext} + + } + icon={Banknote} + /> + + {pageData.stats.verifications.subtext} + + } + icon={BadgeCheck} + /> + + + {pageData.stats.disputes.subtext} + + } + icon={AlertTriangle} + iconBgClass="bg-[#F8E2DF]" + iconColorClass="text-destructive" + /> +
    + + {/* Main Content Layout */} +
    + {/* Left Column (Chart) */} +
    + +
    + + {/* Right Column (Alerts) */} +
    + openModal('System Activity Log', 'Full system activity log and filters will be displayed here.')} + /> +
    +
    + + {/* Bottom Layout (Table) */} +
    + openModal('Region Filter', 'Geographic filtering options will be available soon.')} + onViewDetailedAnalyticsClick={() => openModal('Detailed Analytics', 'Comprehensive category analytics dashboard is under construction.')} + /> +
    + + {/* Action Modal */} + +
    + ); +}; + +export default Overview; \ No newline at end of file diff --git a/frontend/src/pages/admin/users.jsx b/frontend/src/pages/admin/users.jsx new file mode 100644 index 0000000..885d1a8 --- /dev/null +++ b/frontend/src/pages/admin/users.jsx @@ -0,0 +1,147 @@ +import React, { useState } from 'react'; +import { + Users, + Store, + Ban, + UserPlus, + TrendingUp +} from 'lucide-react'; +import AdminHeader from '../../components/admin/AdminHeader'; +import AdminStatCard from '../../components/admin/AdminStatCard'; +import UserDirectoryTable from '../../components/admin/UserDirectoryTable'; +import AdminActionModal from '../../components/admin/AdminActionModal'; + +// --- Dummy Data (Data Contract for Backend) --- +const pageData = { + stats: { + totalUsers: { value: '24,892', subtext: '12% increase' }, + activeShops: { value: '1,402', subtext: 'Active Now' }, + suspended: { value: '43', subtext: 'Immediate Action' }, + newReg: { value: '128', subtext: 'LAST 24H' } + }, + directory: [ + { + name: 'Aurelia James', + subtext: 'EARTH & FIRE STUDIO', + avatar: 'https://images.unsplash.com/photo-1544005313-94ddf0286df2?w=400&q=80', + role: 'SELLER', + status: 'VERIFIED', + joinDate: 'Oct 12, 2023' + }, + { + name: 'Marcus Smith', + subtext: 'MARCUS.VIBE@EMAIL.COM', + avatar: 'https://images.unsplash.com/photo-1506794778202-cad84cf45f1d?w=400&q=80', + role: 'CUSTOMER', + status: 'PENDING', + joinDate: 'Jan 05, 2024' + }, + { + name: 'Liam Weaver', + subtext: 'THE LOOM & HIDE', + avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=400&q=80', + role: 'SELLER', + status: 'SUSPENDED', + joinDate: 'Nov 22, 2023' + } + ] +}; + +const UsersPage = () => { + const [modalState, setModalState] = useState({ isOpen: false, title: '', message: '' }); + + const openModal = (title, message) => { + setModalState({ isOpen: true, title, message }); + }; + + const closeModal = () => { + setModalState(prev => ({ ...prev, isOpen: false })); + }; + + return ( +
    + openModal('Export Data', 'Download comprehensive user and store reports.')} + secondaryActionText="Add New User" + secondaryActionIcon={UserPlus} + onSecondaryActionClick={() => openModal('Add New User', 'The user creation wizard will open here.')} + /> + + {/* Header Section */} +
    +
    +

    + User & Store Management +

    +

    + Oversee Artisan Hub's ecosystem of creators and customers. +

    +
    +
    + + {/* Stats Grid */} +
    + + + {pageData.stats.totalUsers.subtext} + + } + icon={Users} + /> + + + {pageData.stats.suspended.subtext} + + } + icon={Ban} + iconBgClass="bg-[#F8E2DF]" + iconColorClass="text-destructive" + /> + + {pageData.stats.newReg.subtext} + + } + icon={UserPlus} + /> +
    + + {/* Main Table Content */} +
    + openModal(`${filterName} Filter`, `Select options to filter the user directory by ${filterName}.`)} + onActionClick={(actionName, userName) => openModal(`Action: ${actionName}`, `Applying ${actionName} to user ${userName}.`)} + /> +
    + + {/* Action Modal */} + +
    + ); +}; + +export default UsersPage; \ No newline at end of file diff --git a/frontend/src/pages/admin/verify.jsx b/frontend/src/pages/admin/verify.jsx new file mode 100644 index 0000000..425526d --- /dev/null +++ b/frontend/src/pages/admin/verify.jsx @@ -0,0 +1,158 @@ +import React, { useState } from 'react'; +import { + ClipboardList, + Clock, + Percent, + BadgeCheck, + TrendingUp, + Palette, + Gem, + Hammer, + Scissors +} from 'lucide-react'; +import AdminHeader from '../../components/admin/AdminHeader'; +import AdminStatCard from '../../components/admin/AdminStatCard'; +import ApplicationsTable from '../../components/admin/ApplicationsTable'; +import BatchVerifyFAB from '../../components/admin/BatchVerifyFAB'; +import AdminActionModal from '../../components/admin/AdminActionModal'; + +// --- Dummy Data (Data Contract for Backend) --- +const pageData = { + stats: { + pending: { value: '42', subtext: '+5', isPositive: true }, + avgReviewTime: { value: '18 hrs', subtext: 'Goal: 12h' }, + approvalRate: { value: '76%', subtext: 'Target: 80%' }, + verifiedToday: { value: '12', subtext: 'DAILY STATS' } + }, + applications: [ + { + name: 'Earthbound Arts', + id: '#SHOP-9041', + icon: Palette, + category: 'Ceramics & Clay', + appliedOn: 'Oct 24, 2023', + score: 92, + status: 'UNDER REVIEW' + }, + { + name: 'Silver Lining Studio', + id: '#SHOP-8822', + icon: Gem, + category: 'Jewelry Design', + appliedOn: 'Oct 25, 2023', + score: 48, + status: 'FLAGGED' + }, + { + name: 'Wildwood Craft', + id: '#SHOP-9128', + icon: Hammer, + category: 'Woodworking', + appliedOn: 'Oct 26, 2023', + score: 85, + status: 'NEW' + }, + { + name: 'Northern Fabrics', + id: '#SHOP-9233', + icon: Scissors, + category: 'Textiles', + appliedOn: 'Oct 26, 2023', + score: 78, + status: 'NEW' + } + ] +}; + +const Verify = () => { + const [modalState, setModalState] = useState({ isOpen: false, title: '', message: '' }); + + const openModal = (title, message) => { + setModalState({ isOpen: true, title, message }); + }; + + const closeModal = () => { + setModalState(prev => ({ ...prev, isOpen: false })); + }; + + return ( +
    + openModal('Export Report', 'Verification queue reports can be exported here.')} /> + + {/* Header Section */} +
    +
    +

    + Verified Shops Queue +

    +

    + Review and verify pending shop applications to maintain marketplace quality. +

    +
    +
    + + {/* Stats Grid */} +
    + + + {pageData.stats.pending.subtext} + + } + icon={ClipboardList} + /> + + + + {pageData.stats.verifiedToday.subtext} + + } + icon={BadgeCheck} + /> +
    + + {/* Main Table Content */} +
    + openModal('Filter Applications', 'Filter by status, category, or application date.')} + onDownloadClick={() => openModal('Download Queue', 'Download the current verification queue data.')} + onRowClick={(shopName) => openModal('Review Application', `Review full application details for ${shopName}.`)} + /> +
    + + {/* Action Modal */} + + + {/* Floating Action Button */} + openModal('Batch Verify', 'Select multiple shops to verify them simultaneously.')} + /> +
    + ); +}; + +export default Verify; diff --git a/frontend/src/pages/seller/catalog.jsx b/frontend/src/pages/seller/catalog.jsx index be4ff7c..9910df7 100644 --- a/frontend/src/pages/seller/catalog.jsx +++ b/frontend/src/pages/seller/catalog.jsx @@ -5,6 +5,8 @@ import CatalogFilterBar from '../../components/seller/CatalogFilterBar'; import ProductCard from '../../components/seller/ProductCard'; import Pagination from '../../components/seller/Pagination'; import DashboardFAB from '../../components/seller/DashboardFAB'; +import ActionModal from '../../components/seller/ActionModal'; +import { useState } from 'react'; const dummyProducts = [ { @@ -82,6 +84,16 @@ const dummyProducts = [ ]; const Catalog = () => { + const [modalState, setModalState] = useState({ isOpen: false, title: '', message: '' }); + + const openModal = (title, message) => { + setModalState({ isOpen: true, title, message }); + }; + + const closeModal = () => { + setModalState(prev => ({ ...prev, isOpen: false })); + }; + return (
    @@ -98,7 +110,10 @@ const Catalog = () => {
    {/* Add Product Button */} - @@ -115,7 +130,15 @@ const Catalog = () => { - + openModal('Quick Actions', 'Quick action shortcuts will be available in a future update.')} /> + + {/* Action Modal */} +
    ); }; diff --git a/frontend/src/pages/seller/dashboard.jsx b/frontend/src/pages/seller/dashboard.jsx index fd15b5c..eee1cc6 100644 --- a/frontend/src/pages/seller/dashboard.jsx +++ b/frontend/src/pages/seller/dashboard.jsx @@ -6,8 +6,20 @@ import SalesPerformance from '../../components/seller/SalesPerformance'; import TopProducts from '../../components/seller/TopProducts'; import RecentOrders from '../../components/seller/RecentOrders'; import DashboardFAB from '../../components/seller/DashboardFAB'; +import ActionModal from '../../components/seller/ActionModal'; +import { useState } from 'react'; const Dashboard = () => { + const [modalState, setModalState] = useState({ isOpen: false, title: '', message: '' }); + + const openModal = (title, message) => { + setModalState({ isOpen: true, title, message }); + }; + + const closeModal = () => { + setModalState(prev => ({ ...prev, isOpen: false })); + }; + return (
    @@ -24,7 +36,10 @@ const Dashboard = () => {
    {/* Date Picker Button */} -
    {/* Floating Action Button */} - + openModal('Quick Actions', 'Quick action shortcuts will be available in a future update.')} /> + + {/* Action Modal */} +
    ); }; diff --git a/frontend/src/pages/seller/earnings.jsx b/frontend/src/pages/seller/earnings.jsx new file mode 100644 index 0000000..ab6d9cd --- /dev/null +++ b/frontend/src/pages/seller/earnings.jsx @@ -0,0 +1,189 @@ +import React from 'react'; +import { Wallet, Banknote, Landmark, Clock, CheckCircle, TrendingUp } from 'lucide-react'; +import DashboardHeader from '../../components/seller/DashboardHeader'; +import InventoryStatCard from '../../components/seller/InventoryStatCard'; +import TransactionsTable from '../../components/seller/TransactionsTable'; +import RevenueTrendChart from '../../components/seller/RevenueTrendChart'; +import PayoutDetails from '../../components/seller/PayoutDetails'; +import ActionModal from '../../components/seller/ActionModal'; +import { useState } from 'react'; + +// --- Dummy Data (Data Contract for Backend) --- +const pageData = { + userProfile: { + name: 'Julian Marks', + role: 'Master Weaver', + initials: 'JM' + }, + stats: { + revenue: { value: 'P24,850.40' }, + available: { value: 'P4,120.00' }, + pending: { value: 'P1,840.50', subtext: '3-5 days arrival' }, + lastPayout: { value: 'P3,200.00', subtext: 'Oct 12, 2023' } + }, + recentTransactions: [ + { + id: 'TXN-9021834', + date: 'Oct 24, 2023', + type: 'Sale', + orderId: '#AH-22941', + status: 'COMPLETED', + amount: '+P120.00' + }, + { + id: 'TXN-9021822', + date: 'Oct 23, 2023', + type: 'Payout', + orderId: null, + status: 'PROCESSING', + amount: '-P3,200.00' + }, + { + id: 'TXN-9021810', + date: 'Oct 22, 2023', + type: 'Sale', + orderId: '#AH-22938', + status: 'COMPLETED', + amount: '+P45.50' + }, + { + id: 'TXN-9021795', + date: 'Oct 21, 2023', + type: 'Refund', + orderId: '#AH-22912', + status: 'COMPLETED', + amount: '-P24.00' + } + ], + revenueTrend: [ + { label: 'W1', bars: [45, 65, 55] }, + { label: 'W2', bars: [85, 75, 95] }, + { label: 'W3', bars: [60, 70, { value: 100, isHighlighted: true }] }, + { label: 'W4', bars: [80] } + ], + payoutInfo: { + nextPayoutDate: 'October 28, 2023', + scheduleType: 'Weekly Schedule', + bankName: 'Artisans National Bank', + accountEnding: '5821' + } +}; + +const Earnings = () => { + const [modalState, setModalState] = useState({ isOpen: false, title: '', message: '' }); + + const openModal = (title, message) => { + setModalState({ isOpen: true, title, message }); + }; + + const closeModal = () => { + setModalState(prev => ({ ...prev, isOpen: false })); + }; + + return ( +
    + + + {/* Header Section */} +
    +
    +

    + Earnings & Payouts +

    +

    + Monitor your business growth, manage withdrawals, and track transactions. +

    +
    + + {/* Action Buttons */} +
    + +
    +
    + + {/* Stats Grid */} +
    + + + +12.5% + + } + icon={Banknote} + /> + openModal('Withdraw Funds', 'Withdrawal processing will be available soon.')} + className="text-[#8C5233] hover:text-[#7E4A2E] hover:underline cursor-pointer transition-all" + > + WITHDRAW NOW + + } + icon={Landmark} + iconBgClass="bg-[#F8E2DF]" + /> + + +
    + + {/* Main Content Layout */} +
    + {/* Left Column (Table) */} +
    + +
    + + {/* Right Column (Sidebar Cards) */} +
    + + openModal('Manage Payout Methods', 'Bank account management settings will be added in a future update.')} + /> +
    +
    + + {/* Action Modal */} + +
    + ); +}; + +export default Earnings; \ No newline at end of file diff --git a/frontend/src/pages/seller/inventory.jsx b/frontend/src/pages/seller/inventory.jsx new file mode 100644 index 0000000..283e362 --- /dev/null +++ b/frontend/src/pages/seller/inventory.jsx @@ -0,0 +1,216 @@ +import React from 'react'; +import { Users, RotateCcw, Box, TrendingDown, AlertCircle, MapPin } from 'lucide-react'; +import DashboardHeader from '../../components/seller/DashboardHeader'; +import AlertBanner from '../../components/seller/AlertBanner'; +import InventoryStatCard from '../../components/seller/InventoryStatCard'; +import InventoryTable from '../../components/seller/InventoryTable'; +import RestockForecast from '../../components/seller/RestockForecast'; +import InventoryOptimizer from '../../components/seller/InventoryOptimizer'; +import ActionModal from '../../components/seller/ActionModal'; +import { useState } from 'react'; + +// --- Dummy Data (Data Contract for Backend) --- +const pageData = { + userProfile: { + name: 'Julian Marks', + role: 'Master Weaver', + initials: 'JM' + }, + alert: { + title: 'Critical Action Required: Low Stock Alert', + message: '4 items have fallen below their reorder points. Restock recommended immediately.', + buttonText: 'Review Items' + }, + stats: { + totalSkus: { value: '1,284', subtext: '+12 this month', subtextColor: 'text-neutral-dark/50' }, + lowStock: { value: '04', subtext: 'Alerting now', subtextColor: 'text-[#C85746]' }, + outOfStock: { value: '01', subtext: 'Needs removal', subtextColor: 'text-destructive' }, + warehouses: { value: '03', subtext: 'Global hubs', subtextColor: 'text-neutral-dark/50' } + }, + inventoryItems: [ + { + sku: 'DY-IND-001', + name: 'Organic Indigo Dye', + description: 'Natural Fermentation Base', + category: 'TEXTILE', + currentStock: 120, + reorderPoint: 50, + status: 'IN STOCK', + image: 'https://placehold.co/100x100/1E3A8A/FFFFFF?text=Indigo' + }, + { + sku: 'TX-SIL-202', + name: 'Hand-Spun Raw Silk', + description: 'Natural Ivory, Grade A', + category: 'TEXTILE', + currentStock: 12, + reorderPoint: 20, + status: 'LOW STOCK', + image: 'https://placehold.co/100x100/FDE68A/78350F?text=Silk' + }, + { + sku: 'CL-TER-509', + name: 'Terracotta Clay', + description: 'Fine Grit, Red Earth', + category: 'CLAY', + currentStock: 150, + reorderPoint: 50, + status: 'IN STOCK', + image: 'https://placehold.co/100x100/9A3412/FFFFFF?text=Clay' + }, + { + sku: 'WD-TEA-991', + name: 'Reclaimed Teak Planks', + description: 'Aged 20yrs, 2" thickness', + category: 'WOOD', + currentStock: 0, + reorderPoint: 10, + status: 'OUT OF STOCK', + image: 'https://placehold.co/100x100/A8A29E/44403C?text=Teak' + } + ], + forecast: [ + { label: 'MON', value: 30 }, + { label: 'TUE', value: 25 }, + { label: 'WED', value: 45 }, + { label: 'THU', value: 15 }, + { label: 'FRI', value: 35 }, + { label: 'SAT', value: 25 }, + { label: 'SUN', value: 50 } + ], + optimizer: { + title: 'Inventory Optimizer', + description: 'You can save up to 12% on shipping by consolidating your next 3 supplier orders.', + buttonText: 'Optimize Orders' + } +}; + +const Inventory = () => { + const [modalState, setModalState] = useState({ isOpen: false, title: '', message: '' }); + + const openModal = (title, message) => { + setModalState({ isOpen: true, title, message }); + }; + + const closeModal = () => { + setModalState(prev => ({ ...prev, isOpen: false })); + }; + + return ( +
    + + + {/* Header Section */} +
    +
    +

    + Inventory Management +

    +

    + Monitor, restock, and manage your artisan craft supplies. +

    +
    + + {/* Action Buttons */} +
    + + +
    +
    + + {/* Alert Banner */} +
    + openModal('Review Items', 'Low stock items review panel will open here.')} + /> +
    + + {/* Stats Grid */} +
    + + + + +
    + + {/* Table Section */} +
    + +
    + + {/* Bottom Grid */} +
    +
    + +
    +
    + openModal('Optimize Orders', 'The inventory optimizer tool is currently under construction.')} + /> +
    +
    + + {/* Action Modal */} + +
    + ); +}; + +export default Inventory; \ No newline at end of file diff --git a/frontend/src/pages/seller/orders.jsx b/frontend/src/pages/seller/orders.jsx new file mode 100644 index 0000000..18b2f1f --- /dev/null +++ b/frontend/src/pages/seller/orders.jsx @@ -0,0 +1,203 @@ +import React from 'react'; +import { Settings, Printer, CircleAlert, ClipboardList, Package, Truck, CheckCircle } from 'lucide-react'; +import DashboardHeader from '../../components/seller/DashboardHeader'; +import AlertBanner from '../../components/seller/AlertBanner'; +import InventoryStatCard from '../../components/seller/InventoryStatCard'; +import OrderQueueTable from '../../components/seller/OrderQueueTable'; +import DailyShipmentsChart from '../../components/seller/DailyShipmentsChart'; +import DeliveryPerformance from '../../components/seller/DeliveryPerformance'; +import ActionModal from '../../components/seller/ActionModal'; +import { useState } from 'react'; + +// --- Dummy Data (Data Contract for Backend) --- +const pageData = { + userProfile: { + name: 'Julian Marks', + role: 'Master Weaver', + initials: 'JM' + }, + alert: { + title: '3 Priority Orders', + message: 'Ship today to meet your 2-day delivery guarantee. Late shipments may impact seller ratings.', + buttonText: 'View Priority Queue', + variant: 'warning' + }, + stats: { + pending: { value: '14', subtext: '-2%', subtextColor: 'text-destructive' }, + awaiting: { value: '5', subtext: '+12%', subtextColor: 'text-[#8C5233]' }, + transit: { value: '42', subtext: '+5%', subtextColor: 'text-[#8C5233]' }, + delivered: { value: '128', subtext: '+18%', subtextColor: 'text-[#8C5233]' } + }, + recentOrders: [ + { + id: '#ORD-9821', + date: 'Oct 24, 2023', + customer: 'Sarah Jenkins', + product: '2x Organic Indigo Dye', + status: 'PENDING' + }, + { + id: '#ORD-9819', + date: 'Oct 23, 2023', + customer: 'Michael Chen', + product: '1x Hand-Spun Raw Silk', + status: 'PROCESSING' + }, + { + id: '#ORD-9815', + date: 'Oct 22, 2023', + customer: 'Emma Watson', + product: '4x Hand-Carved Spools', + status: 'READY FOR PICKUP' + }, + { + id: '#ORD-9812', + date: 'Oct 22, 2023', + customer: 'Robert Downey', + product: '1x Linen Weaving Kit', + status: 'PENDING' + } + ], + shipmentsData: [ + { label: 'MON', value: 20, isHighlighted: false }, + { label: 'TUE', value: 30, isHighlighted: false }, + { label: 'WED', value: 25, isHighlighted: false }, + { label: 'THU', value: 40, isHighlighted: false }, + { label: 'FRI', value: 35, isHighlighted: false }, + { label: 'SAT', value: 45, isHighlighted: false }, + { label: 'SUN', value: 15, isHighlighted: true } + ], + performance: { + onTimeRate: 98.5, + avgFulfillmentTime: '1.2', + message: 'Excellent performance this week.' + } +}; + +const Orders = () => { + const [modalState, setModalState] = useState({ isOpen: false, title: '', message: '' }); + + const openModal = (title, message) => { + setModalState({ isOpen: true, title, message }); + }; + + const closeModal = () => { + setModalState(prev => ({ ...prev, isOpen: false })); + }; + + return ( +
    + + + {/* Header Section */} +
    +
    +

    + Order Fulfilment +

    +

    + Process, ship, and track your artisan orders. +

    +
    + + {/* Action Buttons */} +
    + + +
    +
    + + {/* Alert Banner */} +
    + openModal('Priority Queue', 'The priority queue view is being prepared.')} + /> +
    + + {/* Stats Grid */} +
    + + + + +
    + + {/* Main Content Layout */} +
    + {/* Left Column (Table) */} +
    + +
    + + {/* Right Column (Sidebar Cards) */} +
    + + +
    +
    + + {/* Action Modal */} + +
    + ); +}; + +export default Orders; \ No newline at end of file