Improve shipping locations table
This commit is contained in:
@@ -629,30 +629,107 @@ const ShippingDetails = ({ data }) => {
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-medium mb-4">Shipping Locations</h3>
|
<h3 className="text-lg font-medium mb-4">Shipping Locations</h3>
|
||||||
<div className="max-h-[400px] overflow-y-auto pr-2">
|
<div className="space-y-6">
|
||||||
<div className="space-y-2">
|
{/* Country summary cards */}
|
||||||
{locations.byState?.map((location) => (
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
<div
|
{locations.byCountry?.slice(0, 3).map((country) => (
|
||||||
key={location.state}
|
<Card key={country.country} className="p-4">
|
||||||
className="flex justify-between items-center p-3 bg-gray-50 dark:bg-gray-800 rounded-lg"
|
<div className="flex justify-between items-start mb-2">
|
||||||
>
|
|
||||||
<div>
|
<div>
|
||||||
|
<h4 className="font-semibold">{country.country}</h4>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
{country.states.length} states/regions
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="text-right">
|
||||||
|
<div className="font-semibold">{country.count.toLocaleString()}</div>
|
||||||
|
<div className="text-sm text-muted-foreground">
|
||||||
|
{country.percentage.toFixed(1)}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="h-2 bg-muted rounded-full overflow-hidden">
|
||||||
|
<div
|
||||||
|
className="h-full bg-teal-500"
|
||||||
|
style={{ width: `${country.percentage}%` }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* States grid */}
|
||||||
|
<div className="rounded-lg border bg-card">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 divide-y md:divide-y-0 md:divide-x divide-border">
|
||||||
|
{/* Left column */}
|
||||||
|
<div className="p-4 space-y-3">
|
||||||
|
<div className="flex justify-between items-center text-sm font-medium text-muted-foreground px-2">
|
||||||
|
<span>Top States</span>
|
||||||
|
<span>Orders</span>
|
||||||
|
</div>
|
||||||
|
{locations.byState?.slice(0, Math.ceil(locations.byState.length / 2)).map((location) => (
|
||||||
|
<div
|
||||||
|
key={`${location.state}-${location.country}`}
|
||||||
|
className="flex justify-between items-center p-2 hover:bg-accent rounded-lg transition-colors"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
<span className="font-medium">{location.state}</span>
|
<span className="font-medium">{location.state}</span>
|
||||||
<span className="text-sm text-muted-foreground ml-2">
|
<span className="text-xs text-muted-foreground">
|
||||||
{location.country}
|
{location.country}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm">
|
<div className="flex items-center gap-3">
|
||||||
<span className="font-medium">
|
<span className="font-medium">
|
||||||
{location.count.toLocaleString()}
|
{location.count.toLocaleString()}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-muted-foreground ml-2">
|
<span className="text-xs text-muted-foreground w-12 text-right">
|
||||||
({location.percentage.toFixed(1)}%)
|
{location.percentage.toFixed(1)}%
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Right column */}
|
||||||
|
<div className="p-4 space-y-3">
|
||||||
|
<div className="flex justify-between items-center text-sm font-medium text-muted-foreground px-2">
|
||||||
|
<span>Additional States</span>
|
||||||
|
<span>Orders</span>
|
||||||
|
</div>
|
||||||
|
{locations.byState?.slice(Math.ceil(locations.byState.length / 2)).map((location) => (
|
||||||
|
<div
|
||||||
|
key={`${location.state}-${location.country}`}
|
||||||
|
className="flex justify-between items-center p-2 hover:bg-accent rounded-lg transition-colors"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className="font-medium">{location.state}</span>
|
||||||
|
<span className="text-xs text-muted-foreground">
|
||||||
|
{location.country}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<span className="font-medium">
|
||||||
|
{location.count.toLocaleString()}
|
||||||
|
</span>
|
||||||
|
<span className="text-xs text-muted-foreground w-12 text-right">
|
||||||
|
{location.percentage.toFixed(1)}%
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Summary footer */}
|
||||||
|
<div className="flex justify-between items-center text-sm text-muted-foreground px-2">
|
||||||
|
<span>
|
||||||
|
Showing all {locations.byState?.length || 0} states across {locations.byCountry?.length || 0} countries
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
Total Orders: {shippedCount.toLocaleString()}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1299,7 +1376,7 @@ const StatCards = ({
|
|||||||
} finally {
|
} finally {
|
||||||
setDetailDataLoading(prev => ({ ...prev, [metric]: false }));
|
setDetailDataLoading(prev => ({ ...prev, [metric]: false }));
|
||||||
}
|
}
|
||||||
}, [timeRange, startDate, endDate, shouldUseLast30Days, setCacheData, getCacheData]);
|
}, [timeRange, startDate, endDate]);
|
||||||
// Corrected preloadDetailData function
|
// Corrected preloadDetailData function
|
||||||
const preloadDetailData = useCallback(() => {
|
const preloadDetailData = useCallback(() => {
|
||||||
const metrics = [
|
const metrics = [
|
||||||
|
|||||||
Reference in New Issue
Block a user