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:
@@ -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>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user