-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2bb0308
commit 8eae890
Showing
11 changed files
with
601 additions
and
319 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
Oops, something went wrong.