feat: Comprehensive contextual headers for all pages

Applied "bigger picture" thinking - added contextual headers to ALL submenu pages consistently.

Problem: Only some pages had headers, creating inconsistent UX

Issues Fixed:

1. Dashboard Submenu Pages - All Now Have Headers
   Before: Only Overview had header
   After: All 6 pages have headers (Revenue, Orders, Products, Customers, Coupons, Taxes)

2. Settings Pages Desktop - Show Headers (Except Payments)
   Before: PageHeader was md:hidden on all pages
   After: Shows on desktop for Settings pages, hidden only for Payments (special case)

Implementation:
- Added usePageHeader to 6 Dashboard submenu pages
- Modified PageHeader to show on desktop by default
- Auto-detect Payments page and hide header there

Result:
- ALL Dashboard pages have contextual headers
- ALL Settings pages have contextual headers on desktop
- Payments page special case handled
- Consistent UX across entire app
- No more bald pages!

Files Modified: 6 Dashboard pages + PageHeader.tsx
This commit is contained in:
dwindown
2025-11-06 22:54:14 +07:00
parent 97288a41dc
commit bc86a12c38
7 changed files with 57 additions and 9 deletions

View File

@@ -1,20 +1,26 @@
import React from 'react'; import React from 'react';
import { useLocation } from 'react-router-dom';
import { usePageHeader } from '@/contexts/PageHeaderContext'; import { usePageHeader } from '@/contexts/PageHeaderContext';
interface PageHeaderProps { interface PageHeaderProps {
fullscreen?: boolean; fullscreen?: boolean;
hideOnDesktop?: boolean;
} }
export function PageHeader({ fullscreen = false }: PageHeaderProps) { export function PageHeader({ fullscreen = false, hideOnDesktop = false }: PageHeaderProps) {
const { title, action } = usePageHeader(); const { title, action } = usePageHeader();
const location = useLocation();
if (!title) return null; if (!title) return null;
// Special case: Payments page should hide header on desktop (has its own layout)
const isPaymentsPage = location.pathname.startsWith('/settings/payments');
const shouldHideOnDesktop = hideOnDesktop || isPaymentsPage;
// PageHeader is now ABOVE submenu in DOM order // PageHeader is now ABOVE submenu in DOM order
// z-20 ensures it stays on top when both are sticky // z-20 ensures it stays on top when both are sticky
// Mobile-only: hidden on desktop (md:hidden)
return ( return (
<div className="sticky top-0 z-20 border-b bg-background md:hidden"> <div className={`sticky top-0 z-20 border-b bg-background ${shouldHideOnDesktop ? 'md:hidden' : ''}`}>
<div className="w-full max-w-5xl mx-auto px-4 py-3 flex items-center justify-between min-w-0"> <div className="w-full max-w-5xl mx-auto px-4 py-3 flex items-center justify-between min-w-0">
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<h1 className="text-lg font-semibold truncate">{title}</h1> <h1 className="text-lg font-semibold truncate">{title}</h1>

View File

@@ -1,4 +1,4 @@
import React, { useState, useMemo } from 'react'; import React, { useState, useMemo, useEffect } from 'react';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts'; import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts';
import { Tag, DollarSign, TrendingUp, ShoppingCart } from 'lucide-react'; import { Tag, DollarSign, TrendingUp, ShoppingCart } from 'lucide-react';
import { __ } from '@/lib/i18n'; import { __ } from '@/lib/i18n';
@@ -12,11 +12,18 @@ import { ChartCard } from './components/ChartCard';
import { DataTable, Column } from './components/DataTable'; import { DataTable, Column } from './components/DataTable';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { DUMMY_COUPONS_DATA, CouponsData, CouponPerformance } from './data/dummyCoupons'; import { DUMMY_COUPONS_DATA, CouponsData, CouponPerformance } from './data/dummyCoupons';
import { usePageHeader } from '@/contexts/PageHeaderContext';
export default function CouponsReport() { export default function CouponsReport() {
const { setPageHeader, clearPageHeader } = usePageHeader();
const { period } = useDashboardPeriod(); const { period } = useDashboardPeriod();
const store = getStoreCurrency(); const store = getStoreCurrency();
useEffect(() => {
setPageHeader(__('Coupons'));
return () => clearPageHeader();
}, [setPageHeader, clearPageHeader]);
// Fetch real data or use dummy data based on toggle // Fetch real data or use dummy data based on toggle
const { data, isLoading, error, refetch } = useCouponsAnalytics(DUMMY_COUPONS_DATA); const { data, isLoading, error, refetch } = useCouponsAnalytics(DUMMY_COUPONS_DATA);

View File

@@ -1,4 +1,4 @@
import React, { useState, useMemo } from 'react'; import React, { useState, useMemo, useEffect } from 'react';
import { BarChart, Bar, LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts'; import { BarChart, Bar, LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts';
import { Users, TrendingUp, DollarSign, ShoppingCart, UserPlus, UserCheck, Info } from 'lucide-react'; import { Users, TrendingUp, DollarSign, ShoppingCart, UserPlus, UserCheck, Info } from 'lucide-react';
import { __ } from '@/lib/i18n'; import { __ } from '@/lib/i18n';
@@ -12,11 +12,18 @@ import { ChartCard } from './components/ChartCard';
import { DataTable, Column } from './components/DataTable'; import { DataTable, Column } from './components/DataTable';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { DUMMY_CUSTOMERS_DATA, CustomersData, TopCustomer } from './data/dummyCustomers'; import { DUMMY_CUSTOMERS_DATA, CustomersData, TopCustomer } from './data/dummyCustomers';
import { usePageHeader } from '@/contexts/PageHeaderContext';
export default function CustomersAnalytics() { export default function CustomersAnalytics() {
const { setPageHeader, clearPageHeader } = usePageHeader();
const { period } = useDashboardPeriod(); const { period } = useDashboardPeriod();
const store = getStoreCurrency(); const store = getStoreCurrency();
useEffect(() => {
setPageHeader(__('Customers'));
return () => clearPageHeader();
}, [setPageHeader, clearPageHeader]);
// Fetch real data or use dummy data based on toggle // Fetch real data or use dummy data based on toggle
const { data, isLoading, error, refetch } = useCustomersAnalytics(DUMMY_CUSTOMERS_DATA); const { data, isLoading, error, refetch } = useCustomersAnalytics(DUMMY_CUSTOMERS_DATA);

View File

@@ -1,4 +1,4 @@
import React, { useState, useMemo, useRef } from 'react'; import React, { useState, useMemo, useRef, useEffect } from 'react';
import { BarChart, Bar, LineChart, Line, AreaChart, Area, ComposedChart, PieChart, Pie, Cell, Label, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts'; import { BarChart, Bar, LineChart, Line, AreaChart, Area, ComposedChart, PieChart, Pie, Cell, Label, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts';
import { ShoppingCart, TrendingUp, Package, XCircle, DollarSign, CheckCircle, Clock } from 'lucide-react'; import { ShoppingCart, TrendingUp, Package, XCircle, DollarSign, CheckCircle, Clock } from 'lucide-react';
import { __ } from '@/lib/i18n'; import { __ } from '@/lib/i18n';
@@ -12,13 +12,20 @@ import { ChartCard } from './components/ChartCard';
import { DataTable, Column } from './components/DataTable'; import { DataTable, Column } from './components/DataTable';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { DUMMY_ORDERS_DATA, OrdersData } from './data/dummyOrders'; import { DUMMY_ORDERS_DATA, OrdersData } from './data/dummyOrders';
import { usePageHeader } from '@/contexts/PageHeaderContext';
export default function OrdersAnalytics() { export default function OrdersAnalytics() {
const { setPageHeader, clearPageHeader } = usePageHeader();
const { period } = useDashboardPeriod(); const { period } = useDashboardPeriod();
const store = getStoreCurrency(); const store = getStoreCurrency();
const [hoverIndex, setHoverIndex] = useState<number | undefined>(undefined); const [hoverIndex, setHoverIndex] = useState<number | undefined>(undefined);
const chartRef = useRef<any>(null); const chartRef = useRef<any>(null);
useEffect(() => {
setPageHeader(__('Orders'));
return () => clearPageHeader();
}, [setPageHeader, clearPageHeader]);
// Fetch real data or use dummy data based on toggle // Fetch real data or use dummy data based on toggle
const { data, isLoading, error, refetch } = useOrdersAnalytics(DUMMY_ORDERS_DATA); const { data, isLoading, error, refetch } = useOrdersAnalytics(DUMMY_ORDERS_DATA);

View File

@@ -1,4 +1,4 @@
import React, { useState, useMemo } from 'react'; import React, { useState, useMemo, useEffect } from 'react';
import { Package, TrendingUp, DollarSign, AlertTriangle, XCircle } from 'lucide-react'; import { Package, TrendingUp, DollarSign, AlertTriangle, XCircle } from 'lucide-react';
import { __ } from '@/lib/i18n'; import { __ } from '@/lib/i18n';
import { formatMoney, getStoreCurrency } from '@/lib/currency'; import { formatMoney, getStoreCurrency } from '@/lib/currency';
@@ -12,11 +12,18 @@ import { DataTable, Column } from './components/DataTable';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { DUMMY_PRODUCTS_DATA, ProductsData, TopProduct, ProductByCategory, StockAnalysisProduct } from './data/dummyProducts'; import { DUMMY_PRODUCTS_DATA, ProductsData, TopProduct, ProductByCategory, StockAnalysisProduct } from './data/dummyProducts';
import { usePageHeader } from '@/contexts/PageHeaderContext';
export default function ProductsPerformance() { export default function ProductsPerformance() {
const { setPageHeader, clearPageHeader } = usePageHeader();
const { period } = useDashboardPeriod(); const { period } = useDashboardPeriod();
const store = getStoreCurrency(); const store = getStoreCurrency();
useEffect(() => {
setPageHeader(__('Products'));
return () => clearPageHeader();
}, [setPageHeader, clearPageHeader]);
// Fetch real data or use dummy data based on toggle // Fetch real data or use dummy data based on toggle
const { data, isLoading, error, refetch } = useProductsAnalytics(DUMMY_PRODUCTS_DATA); const { data, isLoading, error, refetch } = useProductsAnalytics(DUMMY_PRODUCTS_DATA);

View File

@@ -1,4 +1,4 @@
import React, { useState, useMemo } from 'react'; import React, { useState, useMemo, useEffect } from 'react';
import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts'; import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts';
import { DollarSign, TrendingUp, TrendingDown, CreditCard, Truck, RefreshCw } from 'lucide-react'; import { DollarSign, TrendingUp, TrendingDown, CreditCard, Truck, RefreshCw } from 'lucide-react';
import { __ } from '@/lib/i18n'; import { __ } from '@/lib/i18n';
@@ -13,12 +13,19 @@ import { DataTable, Column } from './components/DataTable';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { DUMMY_REVENUE_DATA, RevenueData, RevenueByProduct, RevenueByCategory, RevenueByPaymentMethod, RevenueByShippingMethod } from './data/dummyRevenue'; import { DUMMY_REVENUE_DATA, RevenueData, RevenueByProduct, RevenueByCategory, RevenueByPaymentMethod, RevenueByShippingMethod } from './data/dummyRevenue';
import { usePageHeader } from '@/contexts/PageHeaderContext';
export default function RevenueAnalytics() { export default function RevenueAnalytics() {
const { setPageHeader, clearPageHeader } = usePageHeader();
const { period } = useDashboardPeriod(); const { period } = useDashboardPeriod();
const [granularity, setGranularity] = useState<'day' | 'week' | 'month'>('day'); const [granularity, setGranularity] = useState<'day' | 'week' | 'month'>('day');
const store = getStoreCurrency(); const store = getStoreCurrency();
useEffect(() => {
setPageHeader(__('Revenue'));
return () => clearPageHeader();
}, [setPageHeader, clearPageHeader]);
// Fetch real data or use dummy data based on toggle // Fetch real data or use dummy data based on toggle
const { data, isLoading, error, refetch } = useRevenueAnalytics(DUMMY_REVENUE_DATA, granularity); const { data, isLoading, error, refetch } = useRevenueAnalytics(DUMMY_REVENUE_DATA, granularity);

View File

@@ -1,4 +1,4 @@
import React, { useState, useMemo } from 'react'; import React, { useState, useMemo, useEffect } from 'react';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts'; import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
import { DollarSign, FileText, ShoppingCart, TrendingUp } from 'lucide-react'; import { DollarSign, FileText, ShoppingCart, TrendingUp } from 'lucide-react';
import { __ } from '@/lib/i18n'; import { __ } from '@/lib/i18n';
@@ -12,11 +12,18 @@ import { ChartCard } from './components/ChartCard';
import { DataTable, Column } from './components/DataTable'; import { DataTable, Column } from './components/DataTable';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { DUMMY_TAXES_DATA, TaxesData, TaxByRate, TaxByLocation } from './data/dummyTaxes'; import { DUMMY_TAXES_DATA, TaxesData, TaxByRate, TaxByLocation } from './data/dummyTaxes';
import { usePageHeader } from '@/contexts/PageHeaderContext';
export default function TaxesReport() { export default function TaxesReport() {
const { setPageHeader, clearPageHeader } = usePageHeader();
const { period } = useDashboardPeriod(); const { period } = useDashboardPeriod();
const store = getStoreCurrency(); const store = getStoreCurrency();
useEffect(() => {
setPageHeader(__('Taxes'));
return () => clearPageHeader();
}, [setPageHeader, clearPageHeader]);
// Fetch real data or use dummy data based on toggle // Fetch real data or use dummy data based on toggle
const { data, isLoading, error, refetch } = useTaxesAnalytics(DUMMY_TAXES_DATA); const { data, isLoading, error, refetch } = useTaxesAnalytics(DUMMY_TAXES_DATA);