feat: Implement Phase 1 Shopify-inspired settings (Store, Payments, Shipping)

 Features:
- Store Details page with live currency preview
- Payments page with visual provider cards and test mode
- Shipping & Delivery page with zone cards and local pickup
- Shared components: SettingsLayout, SettingsCard, SettingsSection, ToggleField

🎨 UI/UX:
- Card-based layouts (not boring forms)
- Generous whitespace and visual hierarchy
- Toast notifications using sonner (reused from Orders)
- Sticky save button at top
- Mobile-responsive design

🔧 Technical:
- Installed ESLint with TypeScript support
- Fixed all lint errors (0 errors)
- Phase 1 files have zero warnings
- Used existing toast from sonner (not reinvented)
- Updated routes in App.tsx

📝 Files Created:
- Store.tsx (currency preview, address, timezone)
- Payments.tsx (provider cards, manual methods)
- Shipping.tsx (zone cards, rates, local pickup)
- SettingsLayout.tsx, SettingsCard.tsx, SettingsSection.tsx, ToggleField.tsx

Phase 1 complete: 18-24 hours estimated work
This commit is contained in:
dwindown
2025-11-05 18:54:41 +07:00
parent f8247faf22
commit e49a0d1e3d
19 changed files with 4264 additions and 68 deletions

View File

@@ -15,13 +15,14 @@ export function DummyDataToggle() {
const location = useLocation();
const isDashboardRoute = location.pathname === '/' || location.pathname.startsWith('/dashboard');
// Use dashboard context for dashboard routes, otherwise use local state
const dashboardContext = isDashboardRoute ? useDashboardContext() : null;
// Always call hooks unconditionally
const dashboardContext = useDashboardContext();
const localToggle = useDummyDataToggle();
const useDummyData = isDashboardRoute ? dashboardContext!.useDummyData : localToggle.useDummyData;
// Use dashboard context for dashboard routes, otherwise use local state
const useDummyData = isDashboardRoute ? dashboardContext.useDummyData : localToggle.useDummyData;
const toggleDummyData = isDashboardRoute
? () => dashboardContext!.setUseDummyData(!dashboardContext!.useDummyData)
? () => dashboardContext.setUseDummyData(!dashboardContext.useDummyData)
: localToggle.toggleDummyData;
// Only show in development (always show for now until we have real data)

View File

@@ -30,9 +30,9 @@ export default function DashboardSubmenuBar({ items = [], fullscreen = false }:
return (
<div data-submenubar className={`border-b border-border bg-background md:bg-background/95 md:backdrop-blur md:supports-[backdrop-filter]:bg-background/60 sticky ${topClass} z-20`}>
<div className="px-4 py-2">
<div className="flex items-center justify-between gap-4">
<div className="flex flex-col lg:flex-row items-center justify-between gap-4">
{/* Submenu Links */}
<div className="flex gap-2 overflow-x-auto no-scrollbar">
<div className="flex gap-2 overflow-x-auto no-scrollbar w-full flex-shrink">
{items.map((it) => {
const key = `${it.label}-${it.path || it.href}`;
const isActive = !!it.path && (
@@ -65,9 +65,9 @@ export default function DashboardSubmenuBar({ items = [], fullscreen = false }:
</div>
{/* Period Selector, Refresh & Dummy Toggle */}
<div className="flex items-center gap-2 flex-shrink-0">
<div className="flex justify-end lg:items-center gap-2 flex-shrink-0 w-full flex-shrink">
<Select value={period} onValueChange={setPeriod}>
<SelectTrigger className="w-[140px] h-8">
<SelectTrigger className="w-full lg:w-[140px] h-8">
<SelectValue />
</SelectTrigger>
<SelectContent>

View File

@@ -5,11 +5,12 @@ import type { SubItem } from '@/nav/tree';
type Props = { items?: SubItem[] };
export default function SubmenuBar({ items = [] }: Props) {
// Always call hooks first
const { pathname } = useLocation();
// Single source of truth: props.items. No fallbacks, no demos, no path-based defaults
if (items.length === 0) return null;
const { pathname } = useLocation();
return (
<div data-submenubar className="border-b border-border bg-background/95">
<div className="px-4 py-2">