Skip to content

Commit

Permalink
feat: ux and ui improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
eman-bfloat committed Nov 20, 2024
1 parent 2bb0308 commit 8eae890
Show file tree
Hide file tree
Showing 11 changed files with 601 additions and 319 deletions.
60 changes: 57 additions & 3 deletions apps/agent/src/pages/orders/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,28 @@
import { useState } from 'react';
import { HiPlus } from "react-icons/hi2";
import { ListOrders } from "@sahil/features/Orders/ListOrders";
import { SectionHeader } from "ui";
import OrderHeader from "@sahil/features/Orders/OrderHeader";
import StatsPanel from "@sahil/features/Orders/StatsPanel";

type DateRange = 'today' | 'week' | 'month' | 'custom';
type SortOption = 'date_desc' | 'date_asc' | 'status' | 'customer';
type OrderStatus = 'CONFIRMED' | 'CANCELLED' | 'PENDING' | 'PROCESSING' | 'DELIVERED';

interface FilterState {
search: string;
status: OrderStatus | '';
dateRange: DateRange;
customDateRange?: { from: Date; to: Date };
sortBy: SortOption;
}

const initialFilters: FilterState = {
search: '',
status: '',
dateRange: 'week',
sortBy: 'date_desc'
};

const actions = [
{
Expand All @@ -12,9 +34,41 @@ const actions = [
];

export default function OrdersPage() {
const [filters, setFilters] = useState<FilterState>(initialFilters);
const [activeBusiness, setActiveBusiness] = useState<any>(null);

// Dummy data for demonstration
const businesses = [
{ id: '1', name: 'Business A', totalOrders: 450 },
{ id: '2', name: 'Business B', totalOrders: 280 },
{ id: '3', name: 'Business C', totalOrders: 150 },
];

const stats = {
totalOrders: 1234,
pendingOrders: 56,
completedOrders: 1178
};

return (
<SectionHeader title="Orders" actions={actions}>
<ListOrders />
</SectionHeader>
<div className="flex flex-col h-screen">
<OrderHeader
filters={filters}
onFilterChange={setFilters}
businesses={businesses}
activeBusiness={activeBusiness}
onBusinessSelect={setActiveBusiness}
/>

<div className="flex flex-1 overflow-hidden">

<div className="flex-1 overflow-auto">
<SectionHeader title="Orders" actions={actions}>
<ListOrders />
</SectionHeader>
</div>

</div>
</div>
);
}
114 changes: 114 additions & 0 deletions packages/features/Orders/OrderHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import React from 'react';
import { Card } from 'ui';
import { HiMagnifyingGlass } from 'react-icons/hi2';
import BusinessSwitcher from '../Shared/BusinessSwitcher';
import { CustomSelect, type SelectOption } from '../Shared/CustomSelect';
import { StatusBadge } from './StatusBadge';
import { HiOutlineCalendarDays } from 'react-icons/hi2';

type DateRange = 'today' | 'week' | 'month' | 'custom';
type SortOption = 'date_desc' | 'date_asc' | 'status' | 'customer';
type OrderStatus = 'CONFIRMED' | 'CANCELLED' | 'PENDING' | 'PROCESSING' | 'DELIVERED';

interface FilterState {
search: string;
status: OrderStatus | '';
dateRange: DateRange;
customDateRange?: { from: Date; to: Date };
sortBy: SortOption;
}

interface OrderHeaderProps {
filters: FilterState;
onFilterChange: (filters: FilterState) => void;
businesses: Array<{
id: string;
name: string;
totalOrders?: number;
}>;
activeBusiness?: { id: string; name: string; totalOrders?: number; } | null;
onBusinessSelect: (business: any) => void;
}

const OrderHeader = ({
filters,
onFilterChange,
businesses,
activeBusiness,
onBusinessSelect
}: OrderHeaderProps) => {
const statusOptions: SelectOption[] = [
{ value: '', label: 'All Status' },
...(['CONFIRMED', 'CANCELLED', 'PENDING', 'PROCESSING', 'DELIVERED'] as OrderStatus[]).map(status => ({
value: status,
label: status,
icon: <HiOutlineCalendarDays />
}))
];

const sortOptions: SelectOption[] = [
{ value: 'date_desc', label: 'Newest First' },
{ value: 'date_asc', label: 'Oldest First' },
{ value: 'status', label: 'By Status' },
{ value: 'customer', label: 'By Customer' },
];

const dateRangeOptions: SelectOption[] = [
{ value: 'today', label: 'Today' },
{ value: 'week', label: 'This Week' },
{ value: 'month', label: 'This Month' },
{ value: 'custom', label: 'Custom Range' },
];

return (
<Card className="rounded-none border-x-0 border-t-0">
<div className="p-6 space-y-4">
<BusinessSwitcher
businesses={businesses}
activeBusiness={activeBusiness}
onBusinessSelect={onBusinessSelect}
type="orders"
/>

<div className="flex items-center gap-3">
<div className="relative flex-1">
<HiMagnifyingGlass className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
<input
type="text"
placeholder="Search orders..."
value={filters.search}
onChange={(e) => onFilterChange({ ...filters, search: e.target.value })}
className="input input-bordered w-full pl-10"
/>
</div>

<CustomSelect
value={filters.status}
onChange={(value) => onFilterChange({ ...filters, status: value as OrderStatus })}
options={statusOptions}
placeholder="Filter by status"
width="180px"
/>

<CustomSelect
value={filters.dateRange}
onChange={(value) => onFilterChange({ ...filters, dateRange: value as DateRange })}
options={dateRangeOptions}
placeholder="Select date range"
width="180px"
/>

<CustomSelect
value={filters.sortBy}
onChange={(value) => onFilterChange({ ...filters, sortBy: value as SortOption })}
options={sortOptions}
placeholder="Sort by"
width="150px"
/>
</div>
</div>
</Card>
);
};

export default OrderHeader;
57 changes: 57 additions & 0 deletions packages/features/Orders/StatsPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React from 'react';

interface StatsPanelProps {
totalOrders: number;
pendingOrders: number;
completedOrders: number;
}

const StatsPanel = ({
totalOrders,
pendingOrders,
completedOrders
}: StatsPanelProps) => {
return (
<div className="w-64">
<div className="px-2 py-4 space-y-6">
<h3 className="font-medium text-sm text-gray-500">Overview</h3>

<div className="space-y-6">
<div className="space-y-2">

<div className="stats stats-vertical w-full">
<div className="stat">
<div className="stat-title">Total Orders</div>
<div className="stat-value text-primary">{totalOrders}</div>
<div className="stat-desc">All time orders</div>
</div>
</div>
</div>

<div className="space-y-2">

<div className="stats stats-vertical w-full">
<div className="stat">
<div className="stat-title">Pending</div>
<div className="stat-value text-warning">{pendingOrders}</div>
<div className="stat-desc">Awaiting processing</div>
</div>
</div>
</div>

<div className="space-y-2">
<div className="stats stats-vertical w-full">
<div className="stat">
<div className="stat-title">Delivered</div>
<div className="stat-value text-success">{completedOrders}</div>
<div className="stat-desc">Successfully delivered</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
};

export default StatsPanel;
85 changes: 85 additions & 0 deletions packages/features/Shared/BusinessSwitcher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from "react";
import { HiArrowsUpDown } from "react-icons/hi2";

interface Business {
id: string;
name: string;
totalOrders?: number;
totalProducts?: number;
}

interface BusinessSwitcherProps {
businesses: Business[];
activeBusiness?: Business | null;
onBusinessSelect: (business: Business) => void;
type?: 'orders' | 'inventory';
}

const BusinessSwitcher = ({
businesses,
activeBusiness,
onBusinessSelect,
type = 'orders'
}: BusinessSwitcherProps) => {
const [isOpen, setIsOpen] = React.useState(false);

return (
<div className="relative">
<button
onClick={() => setIsOpen(!isOpen)}
className="w-full bg-white px-4 py-2 text-left border rounded-md flex items-center justify-between hover:bg-gray-50"
>
<div className="flex items-center justify-between gap-2 w-full">
<div className="flex flex-col gap-1">
<div className="flex items-center gap-2">
<div className="h-2.5 w-2.5 rounded-full bg-green-500" />
<span className="text-sm text-gray-500">Active Business</span>
</div>
<p>
{activeBusiness && (
<span className="text-lg font-medium">
{activeBusiness.name}
</span>
)}
</p>
</div>
<HiArrowsUpDown />
</div>
</button>

{isOpen && (
<div className="absolute left-0 top-full mt-2 w-full bg-white rounded-md shadow-lg border p-1 z-10">
{businesses.map((business) => (
<button
key={business.id}
onClick={() => {
onBusinessSelect(business);
setIsOpen(false);
}}
className={`w-full px-3 py-2 text-left rounded-md flex items-center justify-between hover:bg-secondary/10 ${
activeBusiness?.id === business.id
? "bg-secondary/20 text-primary"
: ""
}`}
>
<div className="flex flex-col">
<span className="text-sm font-medium">{business.name}</span>
<span className="text-xs text-gray-500">
{type === 'orders'
? `${business.totalOrders || 0} orders`
: `${business.totalProducts || 0} products`
}
</span>
</div>
{activeBusiness?.id === business.id && (
<div className="w-1.5 h-1.5 rounded-full bg-primary"></div>
)}
</button>
))}
</div>
)}
</div>
);
};

export default BusinessSwitcher;
Loading

0 comments on commit 8eae890

Please sign in to comment.