feat: comprehensive mobile optimization, role-based AI chatbot, and multi-role dashboard enhancements
- Rewrote AI chatbot context system with deep role-aware data injection for all 7 roles (Owner, Admin, Field Agent, Contractor, Subcontractor, Vendor, Customer) plus guest fallback - Added mobile-responsive bottom-sheet modals across all roles (ChangeOrderDrawer, InvoiceDetailModal, FinancialSummaryModal, VendorFinancialSummaryModal, FinancialDetailsModal) - Converted Owner Project List and Vendor Orders tables to mobile card views with touch-friendly layouts - Optimized Vendor Management and People Directory with mobile list/detail toggle and back navigation - Fixed Document Control mobile view: horizontally scrollable filter tabs, proper overflow chain for document visibility - Added responsive padding, text scaling, and flex-wrap across StatCard, TaskDetailsModal, OwnerSnapshot, OwnerProjectDetail, VendorDashboard, and DocumentManagement - Expanded mock data store with richer vendor invoices, orders, documents, and compliance records - Enhanced Owner Snapshot with financial KPI cards, urgent items panel, and Action Center modal - Built Contractor Dashboard with task management, financial summary, and performance metrics - Built Subcontractor Dashboard with clock-in tracking, task assignments, and invoice management - Enhanced Vendor Dashboard with earnings summary, active orders, compliance status, and performance rating - Added icon-only tab navigation on mobile for OwnerProjectDetail - Extended attribution signatures across all platform pages
This commit is contained in:
Vendored
+45
-2
@@ -71,7 +71,49 @@ const VendorOrders = () => {
|
||||
</div>
|
||||
|
||||
<SpotlightCard className="overflow-hidden">
|
||||
<div className="overflow-x-auto">
|
||||
{/* Mobile Card View */}
|
||||
<div className="md:hidden divide-y divide-zinc-100 dark:divide-white/5">
|
||||
{filteredOrders.length > 0 ? filteredOrders.map(order => (
|
||||
<div
|
||||
key={order.id}
|
||||
onClick={() => handleOrderClick(order)}
|
||||
className="p-4 active:bg-zinc-50 dark:active:bg-white/5 transition-colors cursor-pointer"
|
||||
>
|
||||
<div className="flex justify-between items-start mb-2">
|
||||
<div className="flex-1 min-w-0 mr-3">
|
||||
<h4 className="font-medium text-sm text-zinc-900 dark:text-white truncate">
|
||||
{order.projectAddress || order.project}
|
||||
</h4>
|
||||
<p className="text-xs text-zinc-500 font-mono mt-0.5">{order.id}</p>
|
||||
</div>
|
||||
<ChevronRight size={16} className="text-zinc-400 shrink-0 mt-1" />
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2 mb-2">
|
||||
<span className={`inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[10px] font-bold uppercase tracking-wide ${getStatusColor(order.status)}`}>
|
||||
{order.status === 'delivered' && <CheckCircle size={10} />}
|
||||
{order.status === 'shipped' && <Truck size={10} />}
|
||||
{(order.status === 'pending' || order.status === 'confirmed') && <Clock size={10} />}
|
||||
{order.status}
|
||||
</span>
|
||||
<span className="text-xs text-zinc-500 flex items-center gap-1">
|
||||
<Package size={12} /> {order.items ? `${order.items.length} items` : order.item}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center text-xs">
|
||||
<span className="text-zinc-500">Due: {order.dueDate || 'N/A'}</span>
|
||||
<span className="font-mono font-semibold text-zinc-900 dark:text-white">${(order.total || order.amount).toLocaleString()}</span>
|
||||
</div>
|
||||
</div>
|
||||
)) : (
|
||||
<div className="p-12 text-center text-zinc-500">
|
||||
<Package size={40} className="mx-auto mb-3 opacity-20" />
|
||||
<p>No orders found matching this filter.</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Desktop Table View */}
|
||||
<div className="hidden md:block overflow-x-auto">
|
||||
<table className="w-full text-left border-collapse">
|
||||
<thead>
|
||||
<tr className="border-b border-zinc-200 dark:border-white/10 text-xs font-bold uppercase tracking-wider text-zinc-500 bg-zinc-50/50 dark:bg-white/5">
|
||||
@@ -128,7 +170,7 @@ const VendorOrders = () => {
|
||||
</table>
|
||||
</div>
|
||||
{filteredOrders.length === 0 && (
|
||||
<div className="p-12 text-center text-zinc-500">
|
||||
<div className="hidden md:block p-12 text-center text-zinc-500">
|
||||
<Package size={48} className="mx-auto mb-4 opacity-20" />
|
||||
<p>No orders found matching this filter.</p>
|
||||
</div>
|
||||
@@ -141,6 +183,7 @@ const VendorOrders = () => {
|
||||
onClose={() => setIsOrderModalOpen(false)}
|
||||
order={selectedOrder}
|
||||
/>
|
||||
<span className="attribution-ghost">igotsar.matyas | LynkedUpPro - Turns out roofing CRMs don't build themselves. Who knew?</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user