From fe01f31538855add4c57b9d069c9b47973de978c Mon Sep 17 00:00:00 2001 From: g Date: Tue, 13 Jan 2026 05:02:13 +0000 Subject: [PATCH] Refactor UI imports and update component paths Replaces imports from 'components/ui' with 'components/common' across the app and dashboard pages, and updates model and API imports to use new paths under 'lib'. Removes redundant authentication checks from several dashboard pages. Adds new dashboard components and utility files, and reorganizes hooks and services into the 'lib' directory for improved structure. --- app/auth/login/components/LoginForm.tsx | 8 +- app/auth/register/page.tsx | 10 +- app/auth/reset-password/page.tsx | 10 +- app/dashboard/admin/ban/page.tsx | 25 +- app/dashboard/admin/invite/page.tsx | 15 +- app/dashboard/admin/orders/page.tsx | 6 +- app/dashboard/admin/page.tsx | 11 +- app/dashboard/admin/status/page.tsx | 8 +- app/dashboard/admin/users/page.tsx | 18 +- app/dashboard/admin/vendors/page.tsx | 22 +- app/dashboard/analytics/loading.tsx | 6 +- app/dashboard/analytics/page.tsx | 20 +- app/dashboard/balance/page.tsx | 5 +- app/dashboard/categories/page.tsx | 15 +- app/dashboard/chats/[id]/loading.tsx | 4 +- app/dashboard/chats/[id]/page.tsx | 2 +- app/dashboard/chats/new/page.tsx | 4 +- app/dashboard/chats/page.tsx | 39 +-- app/dashboard/dashboard-content-wrapper.tsx | 9 +- app/dashboard/loading.tsx | 6 +- app/dashboard/orders/[id]/loading.tsx | 4 +- app/dashboard/orders/[id]/page.tsx | 16 +- app/dashboard/orders/page.tsx | 37 +-- app/dashboard/page.tsx | 7 +- app/dashboard/products/page.tsx | 26 +- app/dashboard/shipping/page.tsx | 13 +- app/dashboard/stock/page.tsx | 37 ++- app/dashboard/storefront/customers/page.tsx | 33 +-- app/dashboard/storefront/page.tsx | 30 +-- app/not-found.tsx | 3 +- app/page.tsx | 11 +- components/KeepOnline.ts | 4 +- components/admin/AdminAnalytics.tsx | 44 ++-- components/admin/BanUserCard.tsx | 3 +- components/admin/InvitationsListCard.tsx | 3 +- components/admin/InviteVendorCard.tsx | 10 +- components/admin/OrderDetailsModal.tsx | 16 +- components/admin/OrdersTable.tsx | 11 +- components/admin/RecentOrdersCard.tsx | 3 +- components/admin/SystemStatusCard.tsx | 8 +- components/admin/VendorsCard.tsx | 3 +- components/analytics/AnalyticsDashboard.tsx | 28 ++- .../analytics/AnalyticsDashboardSkeleton.tsx | 8 +- .../analytics/CustomerInsightsChart.tsx | 17 +- components/analytics/GrowthAnalyticsChart.tsx | 47 ++-- components/analytics/MetricsCard.tsx | 4 +- components/analytics/OrderAnalyticsChart.tsx | 13 +- components/analytics/PredictionsChart.tsx | 24 +- .../analytics/ProductPerformanceChart.tsx | 23 +- components/analytics/ProfitAnalyticsChart.tsx | 14 +- components/analytics/RevenueChart.tsx | 11 +- components/analytics/SkeletonLoaders.tsx | 6 +- components/analytics/StoreSelector.tsx | 13 +- components/animated-stats-section.tsx | 2 +- components/{ui => common}/alert-dialog.tsx | 3 +- components/{ui => common}/alert.tsx | 0 components/{ui => common}/avatar.tsx | 0 components/{ui => common}/badge.tsx | 0 components/{ui => common}/breadcrumb.tsx | 0 components/{ui => common}/button.tsx | 0 components/{ui => common}/calendar.tsx | 3 +- components/{ui => common}/card.tsx | 0 components/{ui => common}/carousel.tsx | 3 +- components/{ui => common}/chart.tsx | 0 components/{ui => common}/checkbox.tsx | 0 components/{ui => common}/collapsible.tsx | 0 components/{ui => common}/command.tsx | 19 +- components/{ui => common}/context-menu.tsx | 0 components/{ui => common}/date-picker.tsx | 16 +- components/{ui => common}/dialog.tsx | 0 components/{ui => common}/drawer.tsx | 0 components/{ui => common}/dropdown-menu.tsx | 0 components/{ui => common}/empty-state.tsx | 3 +- components/{ui => common}/form.tsx | 3 +- components/{ui => common}/input.tsx | 0 components/{ui => common}/label.tsx | 0 components/{ui => common}/menubar.tsx | 0 components/{ui => common}/motion-wrapper.tsx | 0 components/{ui => common}/navigation-menu.tsx | 0 components/{ui => common}/pagination.tsx | 3 +- components/{ui => common}/popover.tsx | 0 components/{ui => common}/progress.tsx | 0 components/{ui => common}/radio-group.tsx | 0 components/{ui => common}/relative-time.tsx | 3 +- components/{ui => common}/resizable.tsx | 0 components/{ui => common}/scroll-area.tsx | 0 components/{ui => common}/select.tsx | 0 components/{ui => common}/separator.tsx | 0 components/{ui => common}/sheet.tsx | 0 components/{ui => common}/sidebar.tsx | 16 +- components/{ui => common}/skeleton.tsx | 0 components/{ui => common}/slider.tsx | 0 components/{ui => common}/switch.tsx | 0 components/{ui => common}/table.tsx | 0 components/{ui => common}/tabs.tsx | 0 components/{ui => common}/textarea.tsx | 0 components/{ui => common}/toast.tsx | 0 components/{ui => common}/toggle-group.tsx | 3 +- components/{ui => common}/toggle.tsx | 0 components/{ui => common}/tooltip.tsx | 0 {hooks => components/common}/use-toast.ts | 3 +- components/dashboard/BuyerOrderInfo.tsx | 11 +- components/dashboard/ChatDetail.tsx | 17 +- components/dashboard/ChatTable.tsx | 14 +- components/dashboard/NewChatForm.tsx | 12 +- components/dashboard/command-palette.tsx | 139 +++++++++++ components/dashboard/content.tsx | 136 +++++++---- components/dashboard/dashboard-editor.tsx | 6 +- components/dashboard/draggable-widget.tsx | 7 +- components/dashboard/low-stock-widget.tsx | 8 +- components/dashboard/order-peek.tsx | 226 ++++++++++++++++++ components/dashboard/order-stats.tsx | 34 ++- components/dashboard/page-loading.tsx | 6 +- components/dashboard/pending-chats-widget.tsx | 12 +- components/dashboard/product-peek.tsx | 191 +++++++++++++++ .../promotions/EditPromotionForm.tsx | 17 +- .../dashboard/promotions/NewPromotionForm.tsx | 19 +- .../dashboard/promotions/ProductSelector.tsx | 15 +- .../promotions/PromotionDetailsModal.tsx | 15 +- .../dashboard/promotions/PromotionsList.tsx | 15 +- .../promotions/PromotionsPageSkeleton.tsx | 8 +- components/dashboard/quick-actions.tsx | 8 +- components/dashboard/recent-activity.tsx | 32 ++- .../dashboard/recent-customers-widget.tsx | 10 +- components/dashboard/revenue-widget.tsx | 40 ++-- .../dashboard/widget-settings-modal.tsx | 18 +- components/dashboard/widget-settings.tsx | 8 +- components/forms/image-upload.tsx | 4 +- components/forms/pricing-tiers.tsx | 5 +- components/{ => layout}/home-navbar.tsx | 4 +- components/layout/sidebar.tsx | 6 +- components/{ => layout}/theme-switcher.tsx | 4 +- components/{ => layout}/theme-toggle.tsx | 0 components/modals/broadcast-dialog.tsx | 11 +- components/modals/image-viewer-modal.tsx | 6 +- components/modals/import-products-modal.tsx | 8 +- components/modals/product-modal.tsx | 17 +- components/modals/product-selector.tsx | 11 +- components/modals/profit-analysis-modal.tsx | 10 +- components/modals/shipping-modal.tsx | 7 +- .../notifications/OrderNotifications.tsx | 9 +- .../notifications/UnifiedNotifications.tsx | 10 +- components/tables/order-table.tsx | 19 +- components/tables/product-table.tsx | 14 +- components/tables/shipping-table.tsx | 9 +- components/ui/accordion.tsx | 58 ----- lib/{ => api}/api-client.ts | 4 +- lib/{api.ts => api/index.ts} | 16 +- lib/{ => api}/server-api.ts | 38 +-- .../hooks}/use-chromebook-keyboard.tsx | 0 .../hooks}/use-chromebook-scroll.tsx | 0 {hooks => lib/hooks}/use-mobile.tsx | 0 {components/ui => lib/hooks}/use-toast.ts | 2 +- {hooks => lib/hooks}/useFilterState.ts | 0 {hooks => lib/hooks}/useKeepOnline.ts | 0 {hooks => lib/hooks}/useUser.ts | 2 +- {hooks => lib/hooks}/useWidgetLayout.ts | 52 +--- {models => lib/models}/categories.ts | 0 {models => lib/models}/products.ts | 0 lib/notification-context.tsx | 4 +- lib/services/analytics-service.ts | 12 +- {services => lib/services}/customerService.ts | 0 lib/services/index.ts | 8 +- lib/services/product-service.ts | 2 +- lib/services/shipping-service.ts | 2 +- lib/services/stats-service.ts | 2 +- lib/types/dashboard.ts | 61 +++++ lib/utils/format.ts | 28 +++ middleware.ts | 25 ++ public/git-info.json | 4 +- services/index.ts | 3 - tailwind.config.ts | 10 +- utils/format.ts | 15 -- 173 files changed, 1512 insertions(+), 867 deletions(-) rename components/{ui => common}/alert-dialog.tsx (98%) rename components/{ui => common}/alert.tsx (100%) rename components/{ui => common}/avatar.tsx (100%) rename components/{ui => common}/badge.tsx (100%) rename components/{ui => common}/breadcrumb.tsx (100%) rename components/{ui => common}/button.tsx (100%) rename components/{ui => common}/calendar.tsx (97%) rename components/{ui => common}/card.tsx (100%) rename components/{ui => common}/carousel.tsx (99%) rename components/{ui => common}/chart.tsx (100%) rename components/{ui => common}/checkbox.tsx (100%) rename components/{ui => common}/collapsible.tsx (100%) rename components/{ui => common}/command.tsx (69%) rename components/{ui => common}/context-menu.tsx (100%) rename components/{ui => common}/date-picker.tsx (97%) rename components/{ui => common}/dialog.tsx (100%) rename components/{ui => common}/drawer.tsx (100%) rename components/{ui => common}/dropdown-menu.tsx (100%) rename components/{ui => common}/empty-state.tsx (98%) rename components/{ui => common}/form.tsx (98%) rename components/{ui => common}/input.tsx (100%) rename components/{ui => common}/label.tsx (100%) rename components/{ui => common}/menubar.tsx (100%) rename components/{ui => common}/motion-wrapper.tsx (100%) rename components/{ui => common}/navigation-menu.tsx (100%) rename components/{ui => common}/pagination.tsx (97%) rename components/{ui => common}/popover.tsx (100%) rename components/{ui => common}/progress.tsx (100%) rename components/{ui => common}/radio-group.tsx (100%) rename components/{ui => common}/relative-time.tsx (98%) rename components/{ui => common}/resizable.tsx (100%) rename components/{ui => common}/scroll-area.tsx (100%) rename components/{ui => common}/select.tsx (100%) rename components/{ui => common}/separator.tsx (100%) rename components/{ui => common}/sheet.tsx (100%) rename components/{ui => common}/sidebar.tsx (98%) rename components/{ui => common}/skeleton.tsx (100%) rename components/{ui => common}/slider.tsx (100%) rename components/{ui => common}/switch.tsx (100%) rename components/{ui => common}/table.tsx (100%) rename components/{ui => common}/tabs.tsx (100%) rename components/{ui => common}/textarea.tsx (100%) rename components/{ui => common}/toast.tsx (100%) rename components/{ui => common}/toggle-group.tsx (96%) rename components/{ui => common}/toggle.tsx (100%) rename components/{ui => common}/tooltip.tsx (100%) rename {hooks => components/common}/use-toast.ts (99%) create mode 100644 components/dashboard/command-palette.tsx create mode 100644 components/dashboard/order-peek.tsx create mode 100644 components/dashboard/product-peek.tsx rename components/{ => layout}/home-navbar.tsx (98%) rename components/{ => layout}/theme-switcher.tsx (95%) rename components/{ => layout}/theme-toggle.tsx (100%) delete mode 100644 components/ui/accordion.tsx rename lib/{ => api}/api-client.ts (99%) rename lib/{api.ts => api/index.ts} (91%) rename lib/{ => api}/server-api.ts (97%) rename {hooks => lib/hooks}/use-chromebook-keyboard.tsx (100%) rename {hooks => lib/hooks}/use-chromebook-scroll.tsx (100%) rename {hooks => lib/hooks}/use-mobile.tsx (100%) rename {components/ui => lib/hooks}/use-toast.ts (99%) rename {hooks => lib/hooks}/useFilterState.ts (100%) rename {hooks => lib/hooks}/useKeepOnline.ts (100%) rename {hooks => lib/hooks}/useUser.ts (94%) rename {hooks => lib/hooks}/useWidgetLayout.ts (79%) rename {models => lib/models}/categories.ts (100%) rename {models => lib/models}/products.ts (100%) rename {services => lib/services}/customerService.ts (100%) create mode 100644 lib/types/dashboard.ts create mode 100644 lib/utils/format.ts create mode 100644 middleware.ts delete mode 100644 services/index.ts delete mode 100644 utils/format.ts diff --git a/app/auth/login/components/LoginForm.tsx b/app/auth/login/components/LoginForm.tsx index 034068d..8512d8c 100644 --- a/app/auth/login/components/LoginForm.tsx +++ b/app/auth/login/components/LoginForm.tsx @@ -4,9 +4,9 @@ import { useState, useEffect, useRef } from "react"; import { useRouter, useSearchParams } from "next/navigation"; import Link from "next/link"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; +import { Button } from "@/components/common/button"; +import { Input } from "@/components/common/input"; +import { Label } from "@/components/common/label"; import { toast } from "sonner"; import { Loader2, ArrowRight } from "lucide-react"; import { motion } from "framer-motion"; @@ -186,4 +186,4 @@ export default function LoginForm() { ); -} \ No newline at end of file +} diff --git a/app/auth/register/page.tsx b/app/auth/register/page.tsx index b275b97..a98aaca 100644 --- a/app/auth/register/page.tsx +++ b/app/auth/register/page.tsx @@ -4,12 +4,12 @@ import { useState } from "react"; import { useRouter } from "next/navigation"; import Image from "next/image"; import Link from "next/link"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; +import { Button } from "@/components/common/button"; +import { Input } from "@/components/common/input"; +import { Label } from "@/components/common/label"; import { Loader2, ArrowRight } from "lucide-react"; import { motion } from "framer-motion"; -import { toast } from "@/hooks/use-toast"; +import { toast } from "@/lib/hooks/use-toast"; // Matches LoginPage background const AuthBackground = () => ( @@ -164,3 +164,5 @@ export default function RegisterPage() { ); } + + diff --git a/app/auth/reset-password/page.tsx b/app/auth/reset-password/page.tsx index 1fb5dd4..92c4b60 100644 --- a/app/auth/reset-password/page.tsx +++ b/app/auth/reset-password/page.tsx @@ -2,11 +2,11 @@ import { useState, useEffect, Suspense } from "react"; import { useRouter, useSearchParams } from "next/navigation"; import Link from "next/link"; -import { fetchClient } from "@/lib/api-client"; +import { fetchClient } from "@/lib/api/api-client"; import { toast } from "sonner"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; +import { Button } from "@/components/common/button"; +import { Input } from "@/components/common/input"; +import { Label } from "@/components/common/label"; import { Loader2 } from "lucide-react"; interface Vendor { @@ -193,3 +193,5 @@ export default function ResetPasswordPage() { ); } + + diff --git a/app/dashboard/admin/ban/page.tsx b/app/dashboard/admin/ban/page.tsx index 9f3f37e..098cc46 100644 --- a/app/dashboard/admin/ban/page.tsx +++ b/app/dashboard/admin/ban/page.tsx @@ -1,18 +1,18 @@ "use client"; import React, { useState, useEffect } from "react"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { Textarea } from "@/components/ui/textarea"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { Badge } from "@/components/ui/badge"; -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; -import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card"; +import { Button } from "@/components/common/button"; +import { Input } from "@/components/common/input"; +import { Label } from "@/components/common/label"; +import { Textarea } from "@/components/common/textarea"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/common/select"; +import { Badge } from "@/components/common/badge"; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/common/table"; +import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/common/alert-dialog"; import { UserX, Shield, Search, Ban, Unlock, Loader2 } from "lucide-react"; -import { fetchClient } from "@/lib/api-client"; -import { useToast } from "@/hooks/use-toast"; +import { fetchClient } from "@/lib/api/api-client"; +import { useToast } from "@/lib/hooks/use-toast"; interface BlockedUser { _id: string; @@ -445,4 +445,5 @@ export default function AdminBanPage() { ); -} \ No newline at end of file +} + diff --git a/app/dashboard/admin/invite/page.tsx b/app/dashboard/admin/invite/page.tsx index 9a1693a..d593d6e 100644 --- a/app/dashboard/admin/invite/page.tsx +++ b/app/dashboard/admin/invite/page.tsx @@ -1,13 +1,13 @@ "use client"; import React from "react"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { Textarea } from "@/components/ui/textarea"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { Badge } from "@/components/ui/badge"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card"; +import { Button } from "@/components/common/button"; +import { Input } from "@/components/common/input"; +import { Label } from "@/components/common/label"; +import { Textarea } from "@/components/common/textarea"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/common/select"; +import { Badge } from "@/components/common/badge"; import { UserPlus, Mail, Copy, Check } from "lucide-react"; import { useState } from "react"; import Link from "next/link"; @@ -206,3 +206,4 @@ export default function AdminInvitePage() { ); } + diff --git a/app/dashboard/admin/orders/page.tsx b/app/dashboard/admin/orders/page.tsx index 8da0c31..aa13fd2 100644 --- a/app/dashboard/admin/orders/page.tsx +++ b/app/dashboard/admin/orders/page.tsx @@ -1,9 +1,9 @@ import React from "react"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card"; import { Package, AlertTriangle, CheckCircle2, XCircle, DollarSign } from "lucide-react"; import { fetchServer } from "@/lib/api"; import OrdersTable from "@/components/admin/OrdersTable"; -import { MotionWrapper } from "@/components/ui/motion-wrapper"; +import { MotionWrapper } from "@/components/common/motion-wrapper"; export const dynamic = 'force-dynamic'; @@ -241,3 +241,5 @@ export default async function AdminOrdersPage() { ); } + + diff --git a/app/dashboard/admin/page.tsx b/app/dashboard/admin/page.tsx index def9a4e..0198514 100644 --- a/app/dashboard/admin/page.tsx +++ b/app/dashboard/admin/page.tsx @@ -2,12 +2,12 @@ export const dynamic = "force-dynamic"; import React, { Suspense, lazy, useState, useEffect, Component, ReactNode } from "react"; -import { Button } from "@/components/ui/button"; +import { Button } from "@/components/common/button"; import Link from "next/link"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { Skeleton } from "@/components/ui/skeleton"; -import { Card, CardContent, CardHeader } from "@/components/ui/card"; -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/common/tabs"; +import { Skeleton } from "@/components/common/skeleton"; +import { Card, CardContent, CardHeader } from "@/components/common/card"; +import { Alert, AlertDescription, AlertTitle } from "@/components/common/alert"; import { AlertCircle, RefreshCw } from "lucide-react"; // Error Boundary Component @@ -466,3 +466,4 @@ export default function AdminPage() { } + diff --git a/app/dashboard/admin/status/page.tsx b/app/dashboard/admin/status/page.tsx index c9b73bf..383b6b4 100644 --- a/app/dashboard/admin/status/page.tsx +++ b/app/dashboard/admin/status/page.tsx @@ -1,10 +1,10 @@ import React from "react"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/common/card"; +import { Badge } from "@/components/common/badge"; import { Server, Database, Cpu, HardDrive, Activity, Zap } from "lucide-react"; import { fetchServer } from "@/lib/api"; import SystemStatusCard from "@/components/admin/SystemStatusCard"; -import { MotionWrapper } from "@/components/ui/motion-wrapper"; +import { MotionWrapper } from "@/components/common/motion-wrapper"; export const dynamic = 'force-dynamic'; @@ -243,3 +243,5 @@ export default async function AdminStatusPage() { ); } + + diff --git a/app/dashboard/admin/users/page.tsx b/app/dashboard/admin/users/page.tsx index 30446ba..ed80df3 100644 --- a/app/dashboard/admin/users/page.tsx +++ b/app/dashboard/admin/users/page.tsx @@ -1,15 +1,15 @@ "use client"; import React, { useState, useEffect } from "react"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card"; +import { Badge } from "@/components/common/badge"; +import { Button } from "@/components/common/button"; +import { Input } from "@/components/common/input"; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/common/table"; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/common/tooltip"; import { Search, Ban, UserCheck, Package, DollarSign, Loader2, Repeat, Users, ShoppingBag, CreditCard, UserX } from "lucide-react"; -import { fetchClient } from "@/lib/api-client"; -import { useToast } from "@/hooks/use-toast"; +import { fetchClient } from "@/lib/api/api-client"; +import { useToast } from "@/lib/hooks/use-toast"; import { motion, AnimatePresence } from "framer-motion"; interface TelegramUser { @@ -328,3 +328,5 @@ export default function AdminUsersPage() { ); } + + diff --git a/app/dashboard/admin/vendors/page.tsx b/app/dashboard/admin/vendors/page.tsx index e57d400..5a4a65b 100644 --- a/app/dashboard/admin/vendors/page.tsx +++ b/app/dashboard/admin/vendors/page.tsx @@ -1,16 +1,16 @@ "use client"; import React, { useState, useEffect, useCallback } from "react"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card"; +import { Badge } from "@/components/common/badge"; +import { Button } from "@/components/common/button"; +import { Input } from "@/components/common/input"; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/common/table"; import { Search, MoreHorizontal, UserCheck, UserX, Mail, Loader2, Store, Shield, ShieldAlert, Clock, Calendar, Pencil, Plus } from "lucide-react"; -import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; -import { Label } from "@/components/ui/label"; -import { fetchClient } from "@/lib/api-client"; -import { useToast } from "@/hooks/use-toast"; +import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/common/dialog"; +import { Label } from "@/components/common/label"; +import { fetchClient } from "@/lib/api/api-client"; +import { useToast } from "@/lib/hooks/use-toast"; import { motion, AnimatePresence } from "framer-motion"; import { DropdownMenu, @@ -19,7 +19,7 @@ import { DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; +} from "@/components/common/dropdown-menu"; interface Vendor { _id: string; @@ -571,3 +571,5 @@ export default function AdminVendorsPage() { ); } + + diff --git a/app/dashboard/analytics/loading.tsx b/app/dashboard/analytics/loading.tsx index c3a1483..7ba8343 100644 --- a/app/dashboard/analytics/loading.tsx +++ b/app/dashboard/analytics/loading.tsx @@ -1,5 +1,5 @@ -import { Skeleton } from "@/components/ui/skeleton"; -import { Card, CardContent, CardHeader } from "@/components/ui/card"; +import { Skeleton } from "@/components/common/skeleton"; +import { Card, CardContent, CardHeader } from "@/components/common/card"; import Layout from "@/components/layout/layout"; import { SnowLoader } from "@/components/snow-loader"; @@ -61,4 +61,4 @@ export default function AnalyticsLoading() { ); -} \ No newline at end of file +} diff --git a/app/dashboard/analytics/page.tsx b/app/dashboard/analytics/page.tsx index 45e5161..a28100f 100644 --- a/app/dashboard/analytics/page.tsx +++ b/app/dashboard/analytics/page.tsx @@ -5,7 +5,7 @@ import Dashboard from "@/components/dashboard/dashboard"; import AnalyticsDashboard from '@/components/analytics/AnalyticsDashboard'; import AnalyticsDashboardSkeleton from '@/components/analytics/AnalyticsDashboardSkeleton'; import StoreSelector from '@/components/analytics/StoreSelector'; -import { getAnalyticsOverviewServer } from '@/lib/server-api'; +import { getAnalyticsOverviewServer } from '@/lib/api/server-api'; import { fetchServer } from '@/lib/api'; import { performance } from 'perf_hooks'; import { Info, GitCommit, User, Zap, BarChart3 } from 'lucide-react'; @@ -34,14 +34,14 @@ export default async function AnalyticsPage({ // Await searchParams as required by Next.js 15+ const resolvedSearchParams = await searchParams; - + // Check for storeId in query parameters (for staff users) const storeId = resolvedSearchParams?.storeId; - + // Check for storeId in cookies (alternative method for staff users) const cookieStore = await cookies(); const cookieStoreId = cookieStore.get('storeId')?.value; - + // Use query parameter first, then cookie, then undefined (for vendors) const finalStoreId = storeId || cookieStoreId; @@ -73,7 +73,7 @@ export default async function AnalyticsPage({
- + v{panelVersion}
@@ -100,12 +100,12 @@ export default async function AnalyticsPage({ ); } catch (error) { console.error('Error fetching analytics data:', error); - + // If it's a 401/403 error, redirect to login if (error instanceof Error && error.message.includes('401')) { - redirect('/login'); + redirect('/auth/login'); } - + // If it's a 400 error (missing storeId for staff), show store selector if (error instanceof Error && error.message.includes('400')) { return ( @@ -122,7 +122,7 @@ export default async function AnalyticsPage({ ); } - + // For other errors, show a fallback return ( @@ -142,4 +142,4 @@ export default async function AnalyticsPage({ ); } -} \ No newline at end of file +} diff --git a/app/dashboard/balance/page.tsx b/app/dashboard/balance/page.tsx index 7e9faf3..6b10598 100644 --- a/app/dashboard/balance/page.tsx +++ b/app/dashboard/balance/page.tsx @@ -2,8 +2,8 @@ import { useState } from "react"; import Dashboard from "@/components/dashboard/dashboard"; -import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; -import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/common/card"; +import { Button } from "@/components/common/button"; import { Wallet, Bitcoin, Coins, DollarSign, ArrowUpRight } from "lucide-react"; import { toast } from "sonner"; @@ -166,3 +166,4 @@ export default function BalancePage() { ); } + diff --git a/app/dashboard/categories/page.tsx b/app/dashboard/categories/page.tsx index f466c3d..3f54bd4 100644 --- a/app/dashboard/categories/page.tsx +++ b/app/dashboard/categories/page.tsx @@ -2,8 +2,8 @@ import { useState, useEffect, useRef } from "react"; import Layout from "@/components/layout/layout"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; +import { Button } from "@/components/common/button"; +import { Input } from "@/components/common/input"; import { Plus, Pencil, Trash2, ChevronRight, ChevronDown, MoveVertical, FolderTree } from "lucide-react"; import { toast } from "sonner"; import { @@ -12,7 +12,7 @@ import { SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; +} from "@/components/common/select"; import { AlertDialog, AlertDialogAction, @@ -22,10 +22,10 @@ import { AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, -} from "@/components/ui/alert-dialog"; +} from "@/components/common/alert-dialog"; import { apiRequest } from "@/lib/api"; -import type { Category } from "@/models/categories"; -import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; +import type { Category } from "@/lib/models/categories"; +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/common/card"; import { motion, AnimatePresence } from "framer-motion"; // Drag and Drop imports @@ -494,4 +494,5 @@ export default function CategoriesPage() {
); -} \ No newline at end of file +} + diff --git a/app/dashboard/chats/[id]/loading.tsx b/app/dashboard/chats/[id]/loading.tsx index 06a3133..8b5294d 100644 --- a/app/dashboard/chats/[id]/loading.tsx +++ b/app/dashboard/chats/[id]/loading.tsx @@ -1,6 +1,6 @@ import Layout from "@/components/layout/layout"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/common/card"; +import { Skeleton } from "@/components/common/skeleton"; import { Loader2 } from "lucide-react"; import { SnowLoader } from "@/components/snow-loader"; diff --git a/app/dashboard/chats/[id]/page.tsx b/app/dashboard/chats/[id]/page.tsx index 9e5bee1..00e1911 100644 --- a/app/dashboard/chats/[id]/page.tsx +++ b/app/dashboard/chats/[id]/page.tsx @@ -1,7 +1,7 @@ import React from "react"; import { Metadata } from "next"; import dynamic from "next/dynamic"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Skeleton } from "@/components/common/skeleton"; import Dashboard from "@/components/dashboard/dashboard"; export const metadata: Metadata = { diff --git a/app/dashboard/chats/new/page.tsx b/app/dashboard/chats/new/page.tsx index 03c5723..e56fca2 100644 --- a/app/dashboard/chats/new/page.tsx +++ b/app/dashboard/chats/new/page.tsx @@ -1,7 +1,7 @@ import React from "react"; import { Metadata, Viewport } from "next"; import dynamic from "next/dynamic"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Skeleton } from "@/components/common/skeleton"; import Dashboard from "@/components/dashboard/dashboard"; export const metadata: Metadata = { @@ -42,4 +42,4 @@ export default function NewChatPage() { ); -} \ No newline at end of file +} diff --git a/app/dashboard/chats/page.tsx b/app/dashboard/chats/page.tsx index f338905..0992960 100644 --- a/app/dashboard/chats/page.tsx +++ b/app/dashboard/chats/page.tsx @@ -5,10 +5,10 @@ import { useRouter } from "next/navigation"; import Dashboard from "@/components/dashboard/dashboard"; import { MessageCircle, AlertCircle, RefreshCw } from "lucide-react"; import dynamic from "next/dynamic"; -import { Skeleton } from "@/components/ui/skeleton"; -import { Card, CardContent, CardHeader } from "@/components/ui/card"; -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; -import { Button } from "@/components/ui/button"; +import { Skeleton } from "@/components/common/skeleton"; +import { Card, CardContent, CardHeader } from "@/components/common/card"; +import { Alert, AlertDescription, AlertTitle } from "@/components/common/alert"; +import { Button } from "@/components/common/button"; // Error Boundary Component interface ErrorBoundaryState { @@ -95,7 +95,7 @@ function ChatTableSkeleton() { {/* Subtle loading indicator */}
-
- +
@@ -115,8 +115,8 @@ function ChatTableSkeleton() {
{['Customer', 'Last Message', 'Date', 'Status', 'Actions'].map((header, i) => ( -
- + {[...Array(6)].map((_, i) => ( -
{ - const authToken = document.cookie - .split("; ") - .find((row) => row.startsWith("Authorization=")) - ?.split("=")[1]; - - if (!authToken) { - router.push("/login"); - } - }, [router]); - return (
@@ -185,7 +172,7 @@ export default function ChatsPage() { Customer Chats
- + }> @@ -194,4 +181,4 @@ export default function ChatsPage() {
); -} \ No newline at end of file +} diff --git a/app/dashboard/dashboard-content-wrapper.tsx b/app/dashboard/dashboard-content-wrapper.tsx index bf0d4df..7726d3e 100644 --- a/app/dashboard/dashboard-content-wrapper.tsx +++ b/app/dashboard/dashboard-content-wrapper.tsx @@ -1,11 +1,11 @@ "use client"; import { Component, ReactNode, useState, useEffect, Suspense } from "react"; -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; -import { Button } from "@/components/ui/button"; +import { Alert, AlertDescription, AlertTitle } from "@/components/common/alert"; +import { Button } from "@/components/common/button"; import { AlertCircle, RefreshCw } from "lucide-react"; -import { Skeleton } from "@/components/ui/skeleton"; -import { Card, CardContent, CardHeader } from "@/components/ui/card"; +import { Skeleton } from "@/components/common/skeleton"; +import { Card, CardContent, CardHeader } from "@/components/common/card"; // Error Boundary Component interface ErrorBoundaryState { @@ -260,3 +260,4 @@ export default function DashboardContentWrapper({ children }: { children: ReactN ); } + diff --git a/app/dashboard/loading.tsx b/app/dashboard/loading.tsx index 6a55e5c..b1db624 100644 --- a/app/dashboard/loading.tsx +++ b/app/dashboard/loading.tsx @@ -1,7 +1,7 @@ "use client" -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card"; +import { Skeleton } from "@/components/common/skeleton"; import Layout from "@/components/layout/layout"; import { Loader2 } from "lucide-react"; import { SnowLoader } from "@/components/snow-loader"; @@ -77,4 +77,4 @@ export default function DashboardLoading() {
); -} \ No newline at end of file +} diff --git a/app/dashboard/orders/[id]/loading.tsx b/app/dashboard/orders/[id]/loading.tsx index 8fd214e..7d16b93 100644 --- a/app/dashboard/orders/[id]/loading.tsx +++ b/app/dashboard/orders/[id]/loading.tsx @@ -1,7 +1,7 @@ "use client" -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/common/card"; +import { Skeleton } from "@/components/common/skeleton"; import Layout from "@/components/layout/layout"; import { Loader2 } from "lucide-react"; import { SnowLoader } from "@/components/snow-loader"; diff --git a/app/dashboard/orders/[id]/page.tsx b/app/dashboard/orders/[id]/page.tsx index 2ebd044..4913e6d 100644 --- a/app/dashboard/orders/[id]/page.tsx +++ b/app/dashboard/orders/[id]/page.tsx @@ -4,10 +4,10 @@ import { fetchData } from '@/lib/api'; import { clientFetch } from '@/lib/api'; import { useEffect, useState } from "react"; import { useParams } from "next/navigation"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { Textarea } from "@/components/ui/textarea"; +import { Button } from "@/components/common/button"; +import { Input } from "@/components/common/input"; +import { Label } from "@/components/common/label"; +import { Textarea } from "@/components/common/textarea"; import { Table, TableBody, @@ -15,13 +15,13 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; +} from "@/components/common/table"; import { Card, CardContent, CardHeader, CardTitle, -} from "@/components/ui/card"; +} from "@/components/common/card"; import { Clipboard, Truck, Package, ArrowRight, ChevronDown, AlertTriangle, Copy, Loader2, RefreshCw, MessageCircle } from "lucide-react"; import Link from "next/link"; import { useRouter } from "next/navigation"; @@ -36,9 +36,9 @@ import { AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, -} from "@/components/ui/alert-dialog"; +} from "@/components/common/alert-dialog"; import Layout from "@/components/layout/layout"; -import { cacheUtils } from '@/lib/api-client'; +import { cacheUtils } from '@/lib/api/api-client'; import OrderTimeline from "@/components/orders/order-timeline"; import { motion, AnimatePresence } from "framer-motion"; diff --git a/app/dashboard/orders/page.tsx b/app/dashboard/orders/page.tsx index e6428a3..9e5b36e 100644 --- a/app/dashboard/orders/page.tsx +++ b/app/dashboard/orders/page.tsx @@ -5,10 +5,10 @@ import { useRouter } from "next/navigation"; import Dashboard from "@/components/dashboard/dashboard"; import { Package, AlertCircle, RefreshCw } from "lucide-react"; import dynamic from "next/dynamic"; -import { Skeleton } from "@/components/ui/skeleton"; -import { Card, CardContent, CardHeader } from "@/components/ui/card"; -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; -import { Button } from "@/components/ui/button"; +import { Skeleton } from "@/components/common/skeleton"; +import { Card, CardContent, CardHeader } from "@/components/common/card"; +import { Alert, AlertDescription, AlertTitle } from "@/components/common/alert"; +import { Button } from "@/components/common/button"; // Error Boundary Component interface ErrorBoundaryState { @@ -95,7 +95,7 @@ function OrderTableSkeleton() { {/* Subtle loading indicator */}
-
- +
@@ -119,8 +119,8 @@ function OrderTableSkeleton() {
{['Order ID', 'Customer', 'Status', 'Total', 'Date', 'Actions'].map((header, i) => ( -
- + {/* Table rows skeleton */} {[...Array(8)].map((_, i) => ( -
{ - const authToken = document.cookie - .split("; ") - .find((row) => row.startsWith("Authorization=")) - ?.split("=")[1]; - - if (!authToken) { - router.push("/login"); - } - }, [router]); - return (
@@ -194,4 +181,4 @@ export default function OrdersPage() {
); -} \ No newline at end of file +} diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx index c71afc7..318b772 100644 --- a/app/dashboard/page.tsx +++ b/app/dashboard/page.tsx @@ -6,8 +6,8 @@ import packageJson from '../../package.json'; import { getGitInfo, getShortGitHash } from '@/lib/utils/git'; import { Suspense } from 'react'; import dynamic from 'next/dynamic'; -import { Skeleton } from '@/components/ui/skeleton'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; +import { Skeleton } from '@/components/common/skeleton'; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/common/card'; import DashboardContentWrapper from './dashboard-content-wrapper'; // Loading skeleton for the dashboard content @@ -182,4 +182,5 @@ export default async function DashboardPage() {
); -} \ No newline at end of file +} + diff --git a/app/dashboard/products/page.tsx b/app/dashboard/products/page.tsx index f6aa4a7..5547692 100644 --- a/app/dashboard/products/page.tsx +++ b/app/dashboard/products/page.tsx @@ -3,16 +3,16 @@ import { useState, useEffect, ChangeEvent, Suspense } from "react"; import { useRouter } from "next/navigation"; import Layout from "@/components/layout/layout"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Product } from "@/models/products"; +import { Button } from "@/components/common/button"; +import { Input } from "@/components/common/input"; +import { Product } from "@/lib/models/products"; import { Plus, Upload, Search, RefreshCw, Package2 } from "lucide-react"; import { clientFetch } from "@/lib/api"; -import { Category } from "@/models/categories"; +import { Category } from "@/lib/models/categories"; import { toast } from "sonner"; import dynamic from "next/dynamic"; -import { Skeleton } from "@/components/ui/skeleton"; -import { Card, CardContent, CardHeader } from "@/components/ui/card"; +import { Skeleton } from "@/components/common/skeleton"; +import { Card, CardContent, CardHeader } from "@/components/common/card"; // Lazy load heavy components with error handling const ProductTable = dynamic(() => import("@/components/tables/product-table").catch((err) => { @@ -156,16 +156,6 @@ export default function ProductsPage() { // Fetch products and categories useEffect(() => { - const authToken = document.cookie - .split("; ") - .find((row) => row.startsWith("Authorization=")) - ?.split("=")[1]; - - if (!authToken) { - router.push("/login"); - return; - } - const fetchDataAsync = async () => { try { setLoading(true); @@ -194,7 +184,7 @@ export default function ProductsPage() { }; fetchDataAsync(); - }, [router]); + }, []); const handleAddTier = () => { setProductData((prev) => ({ @@ -552,3 +542,5 @@ export default function ProductsPage() { ); } + + diff --git a/app/dashboard/shipping/page.tsx b/app/dashboard/shipping/page.tsx index 6b58cf4..f494e0a 100644 --- a/app/dashboard/shipping/page.tsx +++ b/app/dashboard/shipping/page.tsx @@ -4,8 +4,8 @@ import { useState, useEffect, ChangeEvent, Suspense } from "react"; import { useRouter } from "next/navigation"; import Layout from "@/components/layout/layout"; import { Edit, Plus, Trash, Truck } from "lucide-react"; -import { Button } from "@/components/ui/button"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Button } from "@/components/common/button"; +import { Skeleton } from "@/components/common/skeleton"; import { fetchShippingMethods, addShippingMethod, @@ -15,7 +15,7 @@ import { ShippingData } from "@/lib/services/shipping-service"; import dynamic from "next/dynamic"; -import { Card, CardContent, CardHeader } from "@/components/ui/card"; +import { Card, CardContent, CardHeader } from "@/components/common/card"; // Lazy load components with error handling const ShippingModal = dynamic(() => import("@/components/modals/shipping-modal").then(mod => ({ default: mod.ShippingModal })).catch((err) => { @@ -142,11 +142,6 @@ export default function ShippingPage() { .find((row) => row.startsWith("Authorization=")) ?.split("=")[1]; - if (!authToken) { - router.push("/login"); - return; - } - const fetchedMethods: ShippingMethod[] = await fetchShippingMethods( authToken ); @@ -317,4 +312,4 @@ export default function ShippingPage() { /> ); -} \ No newline at end of file +} diff --git a/app/dashboard/stock/page.tsx b/app/dashboard/stock/page.tsx index 1abeb46..43cd6d3 100644 --- a/app/dashboard/stock/page.tsx +++ b/app/dashboard/stock/page.tsx @@ -3,12 +3,12 @@ import { useState, useEffect } from "react"; import { useRouter } from "next/navigation"; import Layout from "@/components/layout/layout"; -import { Button } from "@/components/ui/button"; -import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from "@/components/ui/table"; -import { Input } from "@/components/ui/input"; -import { Switch } from "@/components/ui/switch"; -import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/common/button"; +import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from "@/components/common/table"; +import { Input } from "@/components/common/input"; +import { Switch } from "@/components/common/switch"; +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/common/card"; +import { Badge } from "@/components/common/badge"; import { DropdownMenu, DropdownMenuContent, @@ -16,12 +16,12 @@ import { DropdownMenuTrigger, DropdownMenuLabel, DropdownMenuSeparator -} from "@/components/ui/dropdown-menu"; +} from "@/components/common/dropdown-menu"; import { Popover, PopoverContent, PopoverTrigger, -} from "@/components/ui/popover"; +} from "@/components/common/popover"; import { AlertDialog, AlertDialogAction, @@ -32,12 +32,12 @@ import { AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, -} from "@/components/ui/alert-dialog"; -import { Product } from "@/models/products"; +} from "@/components/common/alert-dialog"; +import { Product } from "@/lib/models/products"; import { Package, RefreshCw, ChevronDown, CheckSquare, XSquare, Boxes, Download, Calendar, Search, Filter, Save, X, Edit2 } from "lucide-react"; import { clientFetch } from "@/lib/api"; import { toast } from "sonner"; -import { DatePicker, DateRangePicker, DateRangeDisplay, MonthPicker } from "@/components/ui/date-picker"; +import { DatePicker, DateRangePicker, DateRangeDisplay, MonthPicker } from "@/components/common/date-picker"; import { DateRange } from "react-day-picker"; import { addDays, startOfDay, endOfDay, format, isSameDay } from "date-fns"; import { motion, AnimatePresence } from "framer-motion"; @@ -72,16 +72,6 @@ export default function StockManagementPage() { const [isExporting, setIsExporting] = useState(false); useEffect(() => { - const authToken = document.cookie - .split("; ") - .find((row) => row.startsWith("Authorization=")) - ?.split("=")[1]; - - if (!authToken) { - router.push("/login"); - return; - } - const fetchDataAsync = async () => { try { const response = await clientFetch('api/products'); @@ -105,7 +95,7 @@ export default function StockManagementPage() { }; fetchDataAsync(); - }, [router]); + }, []); const handleEditStock = (productId: string) => { setEditingStock({ @@ -687,4 +677,5 @@ export default function StockManagementPage() { ); -} \ No newline at end of file +} + diff --git a/app/dashboard/storefront/customers/page.tsx b/app/dashboard/storefront/customers/page.tsx index 360fed3..a37bb5c 100644 --- a/app/dashboard/storefront/customers/page.tsx +++ b/app/dashboard/storefront/customers/page.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useState, useCallback } from "react"; import { getCustomers, type CustomerStats } from "@/lib/api"; -import { formatCurrency } from "@/utils/format"; +import { formatCurrency } from "@/lib/utils/format"; import { useRouter } from "next/navigation"; import { toast } from "sonner"; import Layout from "@/components/layout/layout"; @@ -13,14 +13,14 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; +} from "@/components/common/table"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; +} from "@/components/common/select"; import { Dialog, DialogContent, @@ -28,8 +28,8 @@ import { DialogTitle, DialogDescription, DialogFooter, -} from "@/components/ui/dialog"; -import { Button } from "@/components/ui/button"; +} from "@/components/common/dialog"; +import { Button } from "@/components/common/button"; import { ChevronLeft, ChevronRight, @@ -47,17 +47,17 @@ import { Truck, CheckCircle, } from "lucide-react"; -import { Badge } from "@/components/ui/badge"; -import { Input } from "@/components/ui/input"; -import { Skeleton } from "@/components/ui/skeleton"; -import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; +import { Badge } from "@/components/common/badge"; +import { Input } from "@/components/common/input"; +import { Skeleton } from "@/components/common/skeleton"; +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/common/card"; import { motion, AnimatePresence } from "framer-motion"; import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, -} from "@/components/ui/dropdown-menu"; +} from "@/components/common/dropdown-menu"; export default function CustomerManagementPage() { const router = useRouter(); @@ -126,16 +126,6 @@ export default function CustomerManagementPage() { fetchCustomers(); }, [fetchCustomers]); - useEffect(() => { - const authToken = document.cookie - .split("; ") - .find((row) => row.startsWith("Authorization=")) - ?.split("=")[1]; - - if (!authToken) { - router.push("/login"); - } - }, [router]); // Add filter function to filter customers when search query changes useEffect(() => { @@ -716,4 +706,5 @@ export default function CustomerManagementPage() {
); -} \ No newline at end of file +} + diff --git a/app/dashboard/storefront/page.tsx b/app/dashboard/storefront/page.tsx index 471769d..16de8bc 100644 --- a/app/dashboard/storefront/page.tsx +++ b/app/dashboard/storefront/page.tsx @@ -3,17 +3,17 @@ import { useState, useEffect, ChangeEvent } from "react"; import { useRouter } from "next/navigation"; import Layout from "@/components/layout/layout"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Textarea } from "@/components/ui/textarea"; +import { Button } from "@/components/common/button"; +import { Input } from "@/components/common/input"; +import { Textarea } from "@/components/common/textarea"; import { Save, Send, Key, MessageSquare, Shield, Globe, Wallet, RefreshCw } from "lucide-react"; import { apiRequest } from "@/lib/api"; import { toast } from "sonner"; import BroadcastDialog from "@/components/modals/broadcast-dialog"; import Dashboard from "@/components/dashboard/dashboard"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle, CardFooter } from "@/components/ui/card"; -import { Label } from "@/components/ui/label"; -import { Badge } from "@/components/ui/badge"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle, CardFooter } from "@/components/common/card"; +import { Label } from "@/components/common/label"; +import { Badge } from "@/components/common/badge"; import { motion, AnimatePresence } from "framer-motion"; import { Select, @@ -21,9 +21,9 @@ import { SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import { Switch } from "@/components/ui/switch"; -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; +} from "@/components/common/select"; +import { Switch } from "@/components/common/switch"; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/common/tooltip"; const SHIPPING_REGIONS = [ { value: "UK", label: "United Kingdom", emoji: "🇬🇧" }, @@ -106,16 +106,6 @@ export default function StorefrontPage() { const [saving, setSaving] = useState(false); useEffect(() => { - const authToken = document.cookie - .split("; ") - .find((row) => row.startsWith("Authorization=")) - ?.split("=")[1]; - - if (!authToken) { - router.push("/login"); - return; - } - const fetchStorefront = async () => { try { setLoading(true); @@ -465,3 +455,5 @@ export default function StorefrontPage() { ); } + + diff --git a/app/not-found.tsx b/app/not-found.tsx index 457f036..eb2d17d 100644 --- a/app/not-found.tsx +++ b/app/not-found.tsx @@ -1,6 +1,6 @@ import { Metadata, Viewport } from "next"; import Link from "next/link"; -import { buttonVariants } from "@/components/ui/button"; +import { buttonVariants } from "@/components/common/button"; import { ArrowLeft } from "lucide-react"; export const metadata: Metadata = { @@ -38,3 +38,4 @@ export default function NotFound() {
); } + diff --git a/app/page.tsx b/app/page.tsx index 733e6d8..094156f 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,10 +1,10 @@ -import { getPlatformStatsServer } from "@/lib/server-api"; -import { HomeNavbar } from "@/components/home-navbar"; +import { getPlatformStatsServer } from "@/lib/api/server-api"; +import { HomeNavbar } from "@/components/layout/home-navbar"; import { Shield, LineChart, Zap, ArrowRight, Sparkles } from "lucide-react"; -import { Button } from "@/components/ui/button"; +import { Button } from "@/components/common/button"; import Link from "next/link"; import { AnimatedStatsSection } from "@/components/animated-stats-section"; -import { MotionWrapper } from "@/components/ui/motion-wrapper"; +import { MotionWrapper } from "@/components/common/motion-wrapper"; export const dynamic = 'force-dynamic'; @@ -109,3 +109,6 @@ export default async function Home() { return
Error loading page
; } } + + + diff --git a/components/KeepOnline.ts b/components/KeepOnline.ts index fe53598..0e7bc7b 100644 --- a/components/KeepOnline.ts +++ b/components/KeepOnline.ts @@ -1,6 +1,6 @@ "use client"; -import { useKeepOnline } from "@/hooks/useKeepOnline"; +import { useKeepOnline } from "@/lib/hooks/useKeepOnline"; const KeepOnline = () => { useKeepOnline({ @@ -14,4 +14,4 @@ const KeepOnline = () => { return null; } -export default KeepOnline; \ No newline at end of file +export default KeepOnline; diff --git a/components/admin/AdminAnalytics.tsx b/components/admin/AdminAnalytics.tsx index 36c946e..e48ba7e 100644 --- a/components/admin/AdminAnalytics.tsx +++ b/components/admin/AdminAnalytics.tsx @@ -7,16 +7,16 @@ import { CardDescription, CardHeader, CardTitle, -} from "@/components/ui/card"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +} from "@/components/common/card"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/common/tabs"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import { Button } from "@/components/ui/button"; +} from "@/components/common/select"; +import { Button } from "@/components/common/button"; import { AlertCircle, BarChart, @@ -29,8 +29,8 @@ import { Package, Trophy, } from "lucide-react"; -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; -import { fetchClient } from "@/lib/api-client"; +import { Alert, AlertDescription, AlertTitle } from "@/components/common/alert"; +import { fetchClient } from "@/lib/api/api-client"; import { BarChart as RechartsBarChart, Bar, @@ -43,7 +43,7 @@ import { Line, ComposedChart, } from "recharts"; -import { formatGBP } from "@/utils/format"; +import { formatGBP, formatNumber } from "@/lib/utils/format"; import { PieChart, Pie, Cell, Legend } from "recharts"; interface GrowthData { @@ -691,7 +691,7 @@ export default function AdminAnalytics() { {formatCurrency(bestMonth.revenue)}
- {bestMonth.orders.toLocaleString()} orders + {formatNumber(bestMonth.orders)} orders
@@ -714,7 +714,7 @@ export default function AdminAnalytics() {
- {analyticsData?.orders?.total?.toLocaleString() || "0"} + {formatNumber(analyticsData?.orders?.total)}
Today: {analyticsData?.orders?.totalToday || 0} @@ -876,7 +876,7 @@ export default function AdminAnalytics() {
- {analyticsData?.products?.total?.toLocaleString() || "0"} + {formatNumber(analyticsData?.products?.total)}
New This Week: {analyticsData?.products?.recent || 0} @@ -1096,27 +1096,25 @@ export default function AdminAnalytics() {
Total Vendors
- {analyticsData?.vendors?.total?.toLocaleString() || "0"} + {formatNumber(analyticsData?.vendors?.total)}
Active Vendors
- {analyticsData?.vendors?.active?.toLocaleString() || "0"} + {formatNumber(analyticsData?.vendors?.active)}
Active Stores
- {analyticsData?.vendors?.activeStores?.toLocaleString() || - "0"} + {formatNumber(analyticsData?.vendors?.activeStores)}
New This Week
- {analyticsData?.vendors?.newThisWeek?.toLocaleString() || - "0"} + {formatNumber(analyticsData?.vendors?.newThisWeek)}
@@ -1202,7 +1200,7 @@ export default function AdminAnalytics() {
Total Orders
-
{growthData.cumulative.orders.toLocaleString()}
+
{formatNumber(growthData.cumulative.orders)}
@@ -1214,19 +1212,19 @@ export default function AdminAnalytics() {
Customers
-
{growthData.cumulative.customers.toLocaleString()}
+
{formatNumber(growthData.cumulative.customers)}
Vendors
-
{growthData.cumulative.vendors.toLocaleString()}
+
{formatNumber(growthData.cumulative.vendors)}
Products
-
{growthData.cumulative.products.toLocaleString()}
+
{formatNumber(growthData.cumulative.products)}
@@ -1292,7 +1290,7 @@ export default function AdminAnalytics() {
Orders - {data.orders.toLocaleString()} + {formatNumber(data.orders)}
@@ -1304,7 +1302,7 @@ export default function AdminAnalytics() {
Customers - {data.customers.toLocaleString()} + {formatNumber(data.customers)}
@@ -1554,3 +1552,5 @@ export default function AdminAnalytics() {
); } + + diff --git a/components/admin/BanUserCard.tsx b/components/admin/BanUserCard.tsx index 7ff4cf4..0cf44f4 100644 --- a/components/admin/BanUserCard.tsx +++ b/components/admin/BanUserCard.tsx @@ -1,6 +1,6 @@ "use client"; import { useState } from "react"; -import { fetchClient } from "@/lib/api-client"; +import { fetchClient } from "@/lib/api/api-client"; export default function BanUserCard() { const [telegramUserId, setTelegramUserId] = useState(""); @@ -70,3 +70,4 @@ export default function BanUserCard() { } + diff --git a/components/admin/InvitationsListCard.tsx b/components/admin/InvitationsListCard.tsx index 18172d3..b609d2b 100644 --- a/components/admin/InvitationsListCard.tsx +++ b/components/admin/InvitationsListCard.tsx @@ -1,6 +1,6 @@ "use client"; import { useEffect, useState } from "react"; -import { fetchClient } from "@/lib/api-client"; +import { fetchClient } from "@/lib/api/api-client"; interface Invitation { _id: string; @@ -88,3 +88,4 @@ export default function InvitationsListCard() { } + diff --git a/components/admin/InviteVendorCard.tsx b/components/admin/InviteVendorCard.tsx index 0732f58..50204bc 100644 --- a/components/admin/InviteVendorCard.tsx +++ b/components/admin/InviteVendorCard.tsx @@ -1,9 +1,9 @@ import { useState } from "react"; -import { fetchClient } from "@/lib/api-client"; -import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; -import { Button } from "@/components/ui/button"; +import { fetchClient } from "@/lib/api/api-client"; +import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/common/card"; +import { Button } from "@/components/common/button"; import { Copy, Check, Ticket, Loader2, RefreshCw } from "lucide-react"; -import { useToast } from "@/hooks/use-toast"; +import { useToast } from "@/lib/hooks/use-toast"; export default function InviteVendorCard() { const [loading, setLoading] = useState(false); @@ -103,3 +103,5 @@ export default function InviteVendorCard() { } + + diff --git a/components/admin/OrderDetailsModal.tsx b/components/admin/OrderDetailsModal.tsx index cda7277..a6d2184 100644 --- a/components/admin/OrderDetailsModal.tsx +++ b/components/admin/OrderDetailsModal.tsx @@ -7,13 +7,13 @@ import { DialogDescription, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; -import { Skeleton } from "@/components/ui/skeleton"; -import { Button } from "@/components/ui/button"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { fetchClient } from "@/lib/api-client"; +} from "@/components/common/dialog"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card"; +import { Badge } from "@/components/common/badge"; +import { Skeleton } from "@/components/common/skeleton"; +import { Button } from "@/components/common/button"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/common/select"; +import { fetchClient } from "@/lib/api/api-client"; import { toast } from "sonner"; import { Package, User, Calendar, DollarSign, MapPin, Truck, CheckCircle, XCircle, Clock, Wallet, Copy, ExternalLink } from "lucide-react"; @@ -562,3 +562,5 @@ export default function OrderDetailsModal({ orderId, open, onOpenChange }: Order ); } + + diff --git a/components/admin/OrdersTable.tsx b/components/admin/OrdersTable.tsx index 9cceb19..fc35ac1 100644 --- a/components/admin/OrdersTable.tsx +++ b/components/admin/OrdersTable.tsx @@ -1,11 +1,11 @@ "use client"; import { useState, useMemo } from "react"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card"; +import { Button } from "@/components/common/button"; +import { Input } from "@/components/common/input"; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/common/table"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/common/select"; import { Search, Filter, Eye, ChevronLeft, ChevronRight } from "lucide-react"; import { List } from 'react-window'; import OrderDetailsModal from "./OrderDetailsModal"; @@ -366,3 +366,4 @@ export default function OrdersTable({ orders, enableModal = true }: OrdersTableP ); } + diff --git a/components/admin/RecentOrdersCard.tsx b/components/admin/RecentOrdersCard.tsx index 6f4c5f6..18503b1 100644 --- a/components/admin/RecentOrdersCard.tsx +++ b/components/admin/RecentOrdersCard.tsx @@ -1,6 +1,6 @@ "use client"; import { useEffect, useState } from "react"; -import { fetchClient } from "@/lib/api-client"; +import { fetchClient } from "@/lib/api/api-client"; interface OrderItem { name: string; @@ -99,3 +99,4 @@ export default function RecentOrdersCard() { } + diff --git a/components/admin/SystemStatusCard.tsx b/components/admin/SystemStatusCard.tsx index f035127..b0badd5 100644 --- a/components/admin/SystemStatusCard.tsx +++ b/components/admin/SystemStatusCard.tsx @@ -1,8 +1,8 @@ "use client"; import { useEffect, useState } from "react"; -import { fetchClient } from "@/lib/api-client"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { fetchClient } from "@/lib/api/api-client"; +import { Button } from "@/components/common/button"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card"; interface Status { uptimeSeconds: number; @@ -151,3 +151,5 @@ export default function SystemStatusCard() { } + + diff --git a/components/admin/VendorsCard.tsx b/components/admin/VendorsCard.tsx index 1034254..832f1d0 100644 --- a/components/admin/VendorsCard.tsx +++ b/components/admin/VendorsCard.tsx @@ -1,6 +1,6 @@ "use client"; import { useEffect, useState } from "react"; -import { fetchClient } from "@/lib/api-client"; +import { fetchClient } from "@/lib/api/api-client"; interface Vendor { _id: string; @@ -137,3 +137,4 @@ export default function VendorsCard() {
); } + diff --git a/components/analytics/AnalyticsDashboard.tsx b/components/analytics/AnalyticsDashboard.tsx index 9450aa8..6b56cf5 100644 --- a/components/analytics/AnalyticsDashboard.tsx +++ b/components/analytics/AnalyticsDashboard.tsx @@ -7,17 +7,17 @@ import { CardDescription, CardHeader, CardTitle, -} from "@/components/ui/card"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; +} from "@/components/common/card"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/common/tabs"; +import { Badge } from "@/components/common/badge"; +import { Button } from "@/components/common/button"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; +} from "@/components/common/select"; import { TrendingUp, ShoppingCart, @@ -32,21 +32,21 @@ import { EyeOff, Calculator, } from "lucide-react"; -import { useToast } from "@/hooks/use-toast"; +import { useToast } from "@/lib/hooks/use-toast"; import MetricsCard from "./MetricsCard"; import { getAnalyticsOverviewWithStore, type AnalyticsOverview, } from "@/lib/services/analytics-service"; -import { formatGBP } from "@/utils/format"; +import { formatGBP, formatNumber } from "@/lib/utils/format"; import { MetricsCardSkeleton } from "./SkeletonLoaders"; import dynamic from "next/dynamic"; -import { Skeleton } from "@/components/ui/skeleton"; -import { DateRangePicker } from "@/components/ui/date-picker"; +import { Skeleton } from "@/components/common/skeleton"; +import { DateRangePicker } from "@/components/common/date-picker"; import { DateRange } from "react-day-picker"; import { addDays, startOfDay, endOfDay } from "date-fns"; import type { DateRange as ProfitDateRange } from "@/lib/services/profit-analytics-service"; -import { MotionWrapper } from "@/components/ui/motion-wrapper"; +import { MotionWrapper } from "@/components/common/motion-wrapper"; import { motion } from "framer-motion"; const RevenueChart = dynamic(() => import("./RevenueChart"), { @@ -170,7 +170,7 @@ export default function AnalyticsDashboard({ }, { title: "Total Orders", - value: maskValue(data.orders.total.toLocaleString()), + value: maskValue(formatNumber(data.orders.total)), description: "All-time orders", icon: ShoppingCart, trend: data.orders.completed > 0 ? ("up" as const) : ("neutral" as const), @@ -178,7 +178,7 @@ export default function AnalyticsDashboard({ }, { title: "Unique Customers", - value: maskValue(data.customers.unique.toLocaleString()), + value: maskValue(formatNumber(data.customers.unique)), description: "Total customers", icon: Users, trend: "neutral" as const, @@ -186,7 +186,7 @@ export default function AnalyticsDashboard({ }, { title: "Products", - value: maskValue(data.products.total.toLocaleString()), + value: maskValue(formatNumber(data.products.total)), description: "Active products", icon: Package, trend: "neutral" as const, @@ -451,3 +451,5 @@ export default function AnalyticsDashboard({
); } + + diff --git a/components/analytics/AnalyticsDashboardSkeleton.tsx b/components/analytics/AnalyticsDashboardSkeleton.tsx index ea4e8ad..9892af3 100644 --- a/components/analytics/AnalyticsDashboardSkeleton.tsx +++ b/components/analytics/AnalyticsDashboardSkeleton.tsx @@ -1,6 +1,6 @@ -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { Skeleton } from "@/components/ui/skeleton"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card"; +import { Skeleton } from "@/components/common/skeleton"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/common/tabs"; import { MetricsCardSkeleton } from './SkeletonLoaders'; import { TrendingUp, @@ -201,4 +201,4 @@ export default function AnalyticsDashboardSkeleton() { ); -} \ No newline at end of file +} diff --git a/components/analytics/CustomerInsightsChart.tsx b/components/analytics/CustomerInsightsChart.tsx index 04830b4..85d7f96 100644 --- a/components/analytics/CustomerInsightsChart.tsx +++ b/components/analytics/CustomerInsightsChart.tsx @@ -1,15 +1,15 @@ "use client" import { useState, useEffect } from 'react'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { useToast } from "@/hooks/use-toast"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card"; +import { Badge } from "@/components/common/badge"; +import { Button } from "@/components/common/button"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/common/select"; +import { useToast } from "@/lib/hooks/use-toast"; +import { Skeleton } from "@/components/common/skeleton"; import { Users, Crown, UserPlus, UserCheck, Star, ChevronLeft, ChevronRight } from "lucide-react"; import { getCustomerInsightsWithStore, type CustomerInsights } from "@/lib/services/analytics-service"; -import { formatGBP } from "@/utils/format"; +import { formatGBP } from "@/lib/utils/format"; import { CustomerInsightsSkeleton } from './SkeletonLoaders'; export default function CustomerInsightsChart() { @@ -305,4 +305,5 @@ export default function CustomerInsightsChart() {
); -} \ No newline at end of file +} + diff --git a/components/analytics/GrowthAnalyticsChart.tsx b/components/analytics/GrowthAnalyticsChart.tsx index 52289de..251c5f4 100644 --- a/components/analytics/GrowthAnalyticsChart.tsx +++ b/components/analytics/GrowthAnalyticsChart.tsx @@ -7,9 +7,9 @@ import { CardDescription, CardHeader, CardTitle, -} from "@/components/ui/card"; -import { Button } from "@/components/ui/button"; -import { useToast } from "@/hooks/use-toast"; +} from "@/components/common/card"; +import { Button } from "@/components/common/button"; +import { useToast } from "@/lib/hooks/use-toast"; import { RefreshCw } from "lucide-react"; import { getGrowthAnalyticsWithStore, @@ -26,6 +26,7 @@ import { ResponsiveContainer, Area, } from "recharts"; +import { formatGBP, formatNumber } from "@/lib/utils/format"; interface GrowthAnalyticsChartProps { hideNumbers?: boolean; @@ -63,14 +64,6 @@ export default function GrowthAnalyticsChart({ fetchGrowthData(); }; - const formatCurrency = (value: number) => { - if (hideNumbers) return "£***"; - return new Intl.NumberFormat("en-GB", { - style: "currency", - currency: "GBP", - maximumFractionDigits: 0, - }).format(value); - }; return (
@@ -115,9 +108,7 @@ export default function GrowthAnalyticsChart({ Total Orders
- {hideNumbers - ? "***" - : growthData.cumulative.orders.toLocaleString()} + {hideNumbers ? "***" : formatNumber(growthData.cumulative.orders)}
@@ -127,7 +118,7 @@ export default function GrowthAnalyticsChart({ Total Revenue
- {formatCurrency(growthData.cumulative.revenue)} + {hideNumbers ? "£***" : formatGBP(growthData.cumulative.revenue)}
@@ -137,9 +128,7 @@ export default function GrowthAnalyticsChart({ Customers
- {hideNumbers - ? "***" - : growthData.cumulative.customers.toLocaleString()} + {hideNumbers ? "***" : formatNumber(growthData.cumulative.customers)}
@@ -149,9 +138,7 @@ export default function GrowthAnalyticsChart({ Products
- {hideNumbers - ? "***" - : growthData.cumulative.products.toLocaleString()} + {hideNumbers ? "***" : formatNumber(growthData.cumulative.products)}
@@ -161,7 +148,7 @@ export default function GrowthAnalyticsChart({ Avg Order Value
- {formatCurrency(growthData.cumulative.avgOrderValue)} + {hideNumbers ? "£***" : formatGBP(growthData.cumulative.avgOrderValue)}
@@ -236,16 +223,16 @@ export default function GrowthAnalyticsChart({ Orders:{" "} {hideNumbers ? "***" - : data.orders.toLocaleString()} + : formatNumber(data.orders)}

- Revenue: {formatCurrency(data.revenue)} + Revenue: {hideNumbers ? "£***" : formatGBP(data.revenue)}

Customers:{" "} {hideNumbers ? "***" - : data.customers.toLocaleString()} + : formatNumber(data.customers)}

{data.newCustomers !== undefined && (

@@ -327,16 +314,16 @@ export default function GrowthAnalyticsChart({ )} - {hideNumbers ? "***" : month.orders.toLocaleString()} + {hideNumbers ? "***" : formatNumber(month.orders)} - {formatCurrency(month.revenue)} + {hideNumbers ? "£***" : formatGBP(month.revenue)} - {hideNumbers ? "***" : month.customers.toLocaleString()} + {hideNumbers ? "***" : formatNumber(month.customers)} - {formatCurrency(month.avgOrderValue)} + {hideNumbers ? "£***" : formatGBP(month.avgOrderValue)} {hideNumbers ? "***" : (month.newCustomers ?? 0)} @@ -352,3 +339,5 @@ export default function GrowthAnalyticsChart({ ); } + + diff --git a/components/analytics/MetricsCard.tsx b/components/analytics/MetricsCard.tsx index 450870c..4374c22 100644 --- a/components/analytics/MetricsCard.tsx +++ b/components/analytics/MetricsCard.tsx @@ -1,6 +1,6 @@ "use client" -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card"; import { TrendingUp, TrendingDown, Minus } from "lucide-react"; import { LucideIcon } from "lucide-react"; import { motion } from "framer-motion"; @@ -112,4 +112,4 @@ export default function MetricsCard({ ); -} \ No newline at end of file +} diff --git a/components/analytics/OrderAnalyticsChart.tsx b/components/analytics/OrderAnalyticsChart.tsx index fa01263..140cccb 100644 --- a/components/analytics/OrderAnalyticsChart.tsx +++ b/components/analytics/OrderAnalyticsChart.tsx @@ -1,13 +1,13 @@ "use client" import { useState, useEffect } from 'react'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; -import { useToast } from "@/hooks/use-toast"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card"; +import { Badge } from "@/components/common/badge"; +import { useToast } from "@/lib/hooks/use-toast"; +import { Skeleton } from "@/components/common/skeleton"; import { BarChart3, Clock, CheckCircle, XCircle, AlertCircle, AlertTriangle } from "lucide-react"; import { getOrderAnalyticsWithStore, type OrderAnalytics } from "@/lib/services/analytics-service"; -import { formatGBP } from "@/utils/format"; +import { formatGBP } from "@/lib/utils/format"; import { ChartSkeleton } from './SkeletonLoaders'; interface OrderAnalyticsChartProps { @@ -201,4 +201,5 @@ export default function OrderAnalyticsChart({ timeRange }: OrderAnalyticsChartPr ); -} \ No newline at end of file +} + diff --git a/components/analytics/PredictionsChart.tsx b/components/analytics/PredictionsChart.tsx index 96e8954..7aa5522 100644 --- a/components/analytics/PredictionsChart.tsx +++ b/components/analytics/PredictionsChart.tsx @@ -7,16 +7,16 @@ import { CardDescription, CardHeader, CardTitle, -} from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; +} from "@/components/common/card"; +import { Badge } from "@/components/common/badge"; +import { Button } from "@/components/common/button"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; +} from "@/components/common/select"; import { TrendingUp, TrendingDown, @@ -32,8 +32,8 @@ import { Info, Download, } from "lucide-react"; -import { useToast } from "@/hooks/use-toast"; -import { Skeleton } from "@/components/ui/skeleton"; +import { useToast } from "@/lib/hooks/use-toast"; +import { Skeleton } from "@/components/common/skeleton"; import CountUp from "react-countup"; import { getPredictionsOverviewWithStore, @@ -41,7 +41,7 @@ import { type PredictionsOverview, type StockPredictionsResponse, } from "@/lib/services/analytics-service"; -import { formatGBP } from "@/utils/format"; +import { formatGBP } from "@/lib/utils/format"; import { Table, TableBody, @@ -49,7 +49,7 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; +} from "@/components/common/table"; import { format } from "date-fns"; import { AreaChart, @@ -65,9 +65,9 @@ import { TooltipContent, TooltipProvider, TooltipTrigger, -} from "@/components/ui/tooltip"; -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; -import { Slider } from "@/components/ui/slider"; +} from "@/components/common/tooltip"; +import { Alert, AlertDescription, AlertTitle } from "@/components/common/alert"; +import { Slider } from "@/components/common/slider"; interface PredictionsChartProps { timeRange?: number; @@ -933,3 +933,5 @@ export default function PredictionsChart({ ); } + + diff --git a/components/analytics/ProductPerformanceChart.tsx b/components/analytics/ProductPerformanceChart.tsx index f7858c8..9b21adc 100644 --- a/components/analytics/ProductPerformanceChart.tsx +++ b/components/analytics/ProductPerformanceChart.tsx @@ -1,14 +1,14 @@ "use client" import { useState, useEffect } from 'react'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; -import { Badge } from "@/components/ui/badge"; -import { useToast } from "@/hooks/use-toast"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card"; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/common/table"; +import { Badge } from "@/components/common/badge"; +import { useToast } from "@/lib/hooks/use-toast"; +import { Skeleton } from "@/components/common/skeleton"; import { Package } from "lucide-react"; import { getProductPerformanceWithStore, type ProductPerformance } from "@/lib/services/analytics-service"; -import { formatGBP } from "@/utils/format"; +import { formatGBP, formatNumber } from "@/lib/utils/format"; import { TableSkeleton } from './SkeletonLoaders'; export default function ProductPerformanceChart() { @@ -123,10 +123,10 @@ export default function ProductPerformanceChart() {

-
- {parseInt(product.totalSold.toFixed(0)).toLocaleString()} {product.unitType} + {formatNumber(parseInt(product.totalSold.toFixed(0)))} {product.unitType} {formatGBP(product.totalRevenue)} @@ -155,4 +155,5 @@ export default function ProductPerformanceChart() { ); -} \ No newline at end of file +} + diff --git a/components/analytics/ProfitAnalyticsChart.tsx b/components/analytics/ProfitAnalyticsChart.tsx index e2f3978..c4d237e 100644 --- a/components/analytics/ProfitAnalyticsChart.tsx +++ b/components/analytics/ProfitAnalyticsChart.tsx @@ -1,9 +1,9 @@ "use client" import { useState, useEffect } from 'react'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; -import { Alert, AlertDescription } from "@/components/ui/alert"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card"; +import { Badge } from "@/components/common/badge"; +import { Alert, AlertDescription } from "@/components/common/alert"; import { TrendingUp, TrendingDown, @@ -14,10 +14,10 @@ import { AlertTriangle, Package } from "lucide-react"; -import { useToast } from "@/hooks/use-toast"; -import { formatGBP } from "@/utils/format"; +import { useToast } from "@/lib/hooks/use-toast"; +import { formatGBP } from "@/lib/utils/format"; import { getProfitOverview, type ProfitOverview, type DateRange } from "@/lib/services/profit-analytics-service"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Skeleton } from "@/components/common/skeleton"; interface ProfitAnalyticsChartProps { timeRange?: string; @@ -379,3 +379,5 @@ export default function ProfitAnalyticsChart({ timeRange, dateRange, hideNumbers
); } + + diff --git a/components/analytics/RevenueChart.tsx b/components/analytics/RevenueChart.tsx index 7c27504..7879525 100644 --- a/components/analytics/RevenueChart.tsx +++ b/components/analytics/RevenueChart.tsx @@ -1,12 +1,12 @@ "use client" import { useState, useEffect } from 'react'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { useToast } from "@/hooks/use-toast"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card"; +import { useToast } from "@/lib/hooks/use-toast"; +import { Skeleton } from "@/components/common/skeleton"; import { TrendingUp, DollarSign } from "lucide-react"; import { getRevenueTrendsWithStore, type RevenueData } from "@/lib/services/analytics-service"; -import { formatGBP } from "@/utils/format"; +import { formatGBP } from "@/lib/utils/format"; import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, AreaChart, Area } from 'recharts'; import { ChartSkeleton } from './SkeletonLoaders'; @@ -239,4 +239,5 @@ export default function RevenueChart({ timeRange, hideNumbers = false }: Revenue ); -} \ No newline at end of file +} + diff --git a/components/analytics/SkeletonLoaders.tsx b/components/analytics/SkeletonLoaders.tsx index 8415177..3ff81ff 100644 --- a/components/analytics/SkeletonLoaders.tsx +++ b/components/analytics/SkeletonLoaders.tsx @@ -1,5 +1,5 @@ -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card"; +import { Skeleton } from "@/components/common/skeleton"; // Chart skeleton for revenue trends and order analytics export function ChartSkeleton({ @@ -167,4 +167,4 @@ export function MetricsCardSkeleton() { ); -} \ No newline at end of file +} diff --git a/components/analytics/StoreSelector.tsx b/components/analytics/StoreSelector.tsx index ebc9b5c..6a69926 100644 --- a/components/analytics/StoreSelector.tsx +++ b/components/analytics/StoreSelector.tsx @@ -2,12 +2,12 @@ import { useState, useEffect } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/common/button"; +import { Input } from "@/components/common/input"; +import { Label } from "@/components/common/label"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card"; import { Store, Search } from "lucide-react"; -import { useToast } from "@/hooks/use-toast"; +import { useToast } from "@/lib/hooks/use-toast"; export default function StoreSelector() { const [storeId, setStoreId] = useState(''); @@ -111,4 +111,5 @@ export default function StoreSelector() { ); -} \ No newline at end of file +} + diff --git a/components/animated-stats-section.tsx b/components/animated-stats-section.tsx index d84616d..8b71940 100644 --- a/components/animated-stats-section.tsx +++ b/components/animated-stats-section.tsx @@ -80,4 +80,4 @@ export function AnimatedStatsSection({ stats }: AnimatedStatsProps) {
); -} \ No newline at end of file +} diff --git a/components/ui/alert-dialog.tsx b/components/common/alert-dialog.tsx similarity index 98% rename from components/ui/alert-dialog.tsx rename to components/common/alert-dialog.tsx index 81f54b8..d472a6c 100644 --- a/components/ui/alert-dialog.tsx +++ b/components/common/alert-dialog.tsx @@ -4,7 +4,7 @@ import * as React from "react" import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog" import { cn } from "@/lib/utils/styles"; -import { buttonVariants } from "@/components/ui/button" +import { buttonVariants } from "@/components/common/button" const AlertDialog = AlertDialogPrimitive.Root @@ -139,3 +139,4 @@ export { AlertDialogAction, AlertDialogCancel, } + diff --git a/components/ui/alert.tsx b/components/common/alert.tsx similarity index 100% rename from components/ui/alert.tsx rename to components/common/alert.tsx diff --git a/components/ui/avatar.tsx b/components/common/avatar.tsx similarity index 100% rename from components/ui/avatar.tsx rename to components/common/avatar.tsx diff --git a/components/ui/badge.tsx b/components/common/badge.tsx similarity index 100% rename from components/ui/badge.tsx rename to components/common/badge.tsx diff --git a/components/ui/breadcrumb.tsx b/components/common/breadcrumb.tsx similarity index 100% rename from components/ui/breadcrumb.tsx rename to components/common/breadcrumb.tsx diff --git a/components/ui/button.tsx b/components/common/button.tsx similarity index 100% rename from components/ui/button.tsx rename to components/common/button.tsx diff --git a/components/ui/calendar.tsx b/components/common/calendar.tsx similarity index 97% rename from components/ui/calendar.tsx rename to components/common/calendar.tsx index 990feca..822b369 100644 --- a/components/ui/calendar.tsx +++ b/components/common/calendar.tsx @@ -5,7 +5,7 @@ import { ChevronLeft, ChevronRight } from "lucide-react" import { DayPicker } from "react-day-picker" import { cn } from "@/lib/utils/styles"; -import { buttonVariants } from "@/components/ui/button" +import { buttonVariants } from "@/components/common/button" export type CalendarProps = React.ComponentProps @@ -64,3 +64,4 @@ function Calendar({ Calendar.displayName = "Calendar" export { Calendar } + diff --git a/components/ui/card.tsx b/components/common/card.tsx similarity index 100% rename from components/ui/card.tsx rename to components/common/card.tsx diff --git a/components/ui/carousel.tsx b/components/common/carousel.tsx similarity index 99% rename from components/ui/carousel.tsx rename to components/common/carousel.tsx index 3bb8c21..165fade 100644 --- a/components/ui/carousel.tsx +++ b/components/common/carousel.tsx @@ -7,7 +7,7 @@ import useEmblaCarousel, { import { ArrowLeft, ArrowRight } from "lucide-react" import { cn } from "@/lib/utils/styles"; -import { Button } from "@/components/ui/button" +import { Button } from "@/components/common/button" type CarouselApi = UseEmblaCarouselType[1] type UseCarouselParameters = Parameters @@ -260,3 +260,4 @@ export { CarouselPrevious, CarouselNext, } + diff --git a/components/ui/chart.tsx b/components/common/chart.tsx similarity index 100% rename from components/ui/chart.tsx rename to components/common/chart.tsx diff --git a/components/ui/checkbox.tsx b/components/common/checkbox.tsx similarity index 100% rename from components/ui/checkbox.tsx rename to components/common/checkbox.tsx diff --git a/components/ui/collapsible.tsx b/components/common/collapsible.tsx similarity index 100% rename from components/ui/collapsible.tsx rename to components/common/collapsible.tsx diff --git a/components/ui/command.tsx b/components/common/command.tsx similarity index 69% rename from components/ui/command.tsx rename to components/common/command.tsx index 73d036c..3f6d92d 100644 --- a/components/ui/command.tsx +++ b/components/common/command.tsx @@ -6,7 +6,7 @@ import { Command as CommandPrimitive } from "cmdk" import { Search } from "lucide-react" import { cn } from "@/lib/utils/styles"; -import { Dialog, DialogContent } from "@/components/ui/dialog" +import { Dialog, DialogContent } from "@/components/common/dialog" const Command = React.forwardRef< React.ElementRef, @@ -15,7 +15,7 @@ const Command = React.forwardRef< { return ( - - + + {children} @@ -39,12 +39,12 @@ const CommandInput = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( -
- +
+ (({ className, ...props }, ref) => ( )) @@ -115,7 +115,7 @@ const CommandItem = React.forwardRef<
) -} \ No newline at end of file +} diff --git a/components/ui/dialog.tsx b/components/common/dialog.tsx similarity index 100% rename from components/ui/dialog.tsx rename to components/common/dialog.tsx diff --git a/components/ui/drawer.tsx b/components/common/drawer.tsx similarity index 100% rename from components/ui/drawer.tsx rename to components/common/drawer.tsx diff --git a/components/ui/dropdown-menu.tsx b/components/common/dropdown-menu.tsx similarity index 100% rename from components/ui/dropdown-menu.tsx rename to components/common/dropdown-menu.tsx diff --git a/components/ui/empty-state.tsx b/components/common/empty-state.tsx similarity index 98% rename from components/ui/empty-state.tsx rename to components/common/empty-state.tsx index 81695d5..10785ae 100644 --- a/components/ui/empty-state.tsx +++ b/components/common/empty-state.tsx @@ -1,7 +1,7 @@ "use client" import * as React from "react" -import { Button } from "@/components/ui/button" +import { Button } from "@/components/common/button" import { Package, ShoppingBag, @@ -136,3 +136,4 @@ export function ChatsEmptyState() { /> ) } + diff --git a/components/ui/form.tsx b/components/common/form.tsx similarity index 98% rename from components/ui/form.tsx rename to components/common/form.tsx index 7b8d7e7..db3d21f 100644 --- a/components/ui/form.tsx +++ b/components/common/form.tsx @@ -13,7 +13,7 @@ import { } from "react-hook-form" import { cn } from "@/lib/utils/styles"; -import { Label } from "@/components/ui/label" +import { Label } from "@/components/common/label" const Form = FormProvider @@ -176,3 +176,4 @@ export { FormMessage, FormField, } + diff --git a/components/ui/input.tsx b/components/common/input.tsx similarity index 100% rename from components/ui/input.tsx rename to components/common/input.tsx diff --git a/components/ui/label.tsx b/components/common/label.tsx similarity index 100% rename from components/ui/label.tsx rename to components/common/label.tsx diff --git a/components/ui/menubar.tsx b/components/common/menubar.tsx similarity index 100% rename from components/ui/menubar.tsx rename to components/common/menubar.tsx diff --git a/components/ui/motion-wrapper.tsx b/components/common/motion-wrapper.tsx similarity index 100% rename from components/ui/motion-wrapper.tsx rename to components/common/motion-wrapper.tsx diff --git a/components/ui/navigation-menu.tsx b/components/common/navigation-menu.tsx similarity index 100% rename from components/ui/navigation-menu.tsx rename to components/common/navigation-menu.tsx diff --git a/components/ui/pagination.tsx b/components/common/pagination.tsx similarity index 97% rename from components/ui/pagination.tsx rename to components/common/pagination.tsx index 9ad1c59..d0691f8 100644 --- a/components/ui/pagination.tsx +++ b/components/common/pagination.tsx @@ -2,7 +2,7 @@ import * as React from "react" import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react" import { cn } from "@/lib/utils/styles"; -import { ButtonProps, buttonVariants } from "@/components/ui/button" +import { ButtonProps, buttonVariants } from "@/components/common/button" const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
); -} \ No newline at end of file +} + diff --git a/components/dashboard/ChatTable.tsx b/components/dashboard/ChatTable.tsx index 80d7c08..162edf8 100644 --- a/components/dashboard/ChatTable.tsx +++ b/components/dashboard/ChatTable.tsx @@ -10,11 +10,11 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { Avatar, AvatarFallback } from "@/components/ui/avatar"; +} from "@/components/common/table"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/common/card"; +import { Badge } from "@/components/common/badge"; +import { Button } from "@/components/common/button"; +import { Avatar, AvatarFallback } from "@/components/common/avatar"; import { formatDistanceToNow } from "date-fns"; import { Plus, @@ -41,7 +41,7 @@ import { SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; +} from "@/components/common/select"; import { toast } from "sonner"; import { clientFetch, getCookie } from "@/lib/api"; import { formatDistance } from 'date-fns'; @@ -474,3 +474,5 @@ export default function ChatTable() { ); } + + diff --git a/components/dashboard/NewChatForm.tsx b/components/dashboard/NewChatForm.tsx index eb5f019..cc6c2d6 100644 --- a/components/dashboard/NewChatForm.tsx +++ b/components/dashboard/NewChatForm.tsx @@ -8,11 +8,11 @@ import { CardHeader, CardTitle, CardDescription, -} from "@/components/ui/card"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { Textarea } from "@/components/ui/textarea"; +} from "@/components/common/card"; +import { Button } from "@/components/common/button"; +import { Input } from "@/components/common/input"; +import { Label } from "@/components/common/label"; +import { Textarea } from "@/components/common/textarea"; import { ArrowLeft, Send, RefreshCw, Search, User } from "lucide-react"; import axios from "axios"; import { toast } from "sonner"; @@ -376,3 +376,5 @@ export default function NewChatForm() { ); } + + diff --git a/components/dashboard/command-palette.tsx b/components/dashboard/command-palette.tsx new file mode 100644 index 0000000..15874bf --- /dev/null +++ b/components/dashboard/command-palette.tsx @@ -0,0 +1,139 @@ +"use client" + +import * as React from "react" +import { + Calculator, + Calendar, + CreditCard, + Settings, + Smile, + User, + LayoutDashboard, + Package, + ShoppingCart, + Users, + BarChart3, + RefreshCcw, + RotateCcw, + Search, + MessageSquare, + Truck +} from "lucide-react" + +import { + CommandDialog, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, + CommandSeparator, + CommandShortcut, +} from "@/components/common/command" +import { useRouter } from "next/navigation" + +interface CommandPaletteProps { + onResetLayout?: () => void + onToggleWidget?: (id: string) => void + availableWidgets?: Array<{ id: string; title: string; visible: boolean }> +} + +export function CommandPalette({ onResetLayout, onToggleWidget, availableWidgets }: CommandPaletteProps) { + const [open, setOpen] = React.useState(false) + const router = useRouter() + + React.useEffect(() => { + const down = (e: KeyboardEvent) => { + if (e.key === "k" && (e.metaKey || e.ctrlKey)) { + e.preventDefault() + setOpen((open) => !open) + } + } + + document.addEventListener("keydown", down) + return () => document.removeEventListener("keydown", down) + }, []) + + const runCommand = React.useCallback((command: () => void) => { + setOpen(false) + command() + }, []) + + return ( + + + + No results found. + + runCommand(() => router.push("/dashboard"))}> + + Dashboard + + runCommand(() => router.push("/dashboard/orders"))}> + + Manage Orders + + runCommand(() => router.push("/dashboard/stock"))}> + + Inventory & Stock + + runCommand(() => router.push("/dashboard/customers"))}> + + Customers + + runCommand(() => router.push("/dashboard/analytics"))}> + + Advanced Analytics + + runCommand(() => router.push("/dashboard/shipping"))}> + + Shipping Options + + + + + + + runCommand(() => window.location.reload())}> + + Reload Data + + {onResetLayout && ( + runCommand(onResetLayout)}> + + Reset Widget Layout + + )} + + + {availableWidgets && availableWidgets.length > 0 && ( + <> + + + {availableWidgets.map((widget) => ( + runCommand(() => onToggleWidget?.(widget.id))} + > +
+ {widget.visible ? "Hide" : "Show"} {widget.title} + + ))} + + + )} + + + + + runCommand(() => router.push("/dashboard/settings"))}> + + General Settings + ⌘S + + + + + ) +} + diff --git a/components/dashboard/content.tsx b/components/dashboard/content.tsx index 9f4d906..b24dc9d 100644 --- a/components/dashboard/content.tsx +++ b/components/dashboard/content.tsx @@ -8,43 +8,47 @@ import { WidgetSettings } from "./widget-settings" import { WidgetSettingsModal } from "./widget-settings-modal" import { DashboardEditor } from "./dashboard-editor" import { DraggableWidget } from "./draggable-widget" +import { CommandPalette } from "./command-palette" import RevenueWidget from "./revenue-widget" import LowStockWidget from "./low-stock-widget" import RecentCustomersWidget from "./recent-customers-widget" +import { ProductPeek } from "./product-peek" import PendingChatsWidget from "./pending-chats-widget" import { getGreeting } from "@/lib/utils/general" import { statsConfig } from "@/config/dashboard" import { getRandomQuote } from "@/config/quotes" import type { OrderStatsData } from "@/lib/types" -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card" import { ShoppingCart, RefreshCcw, ArrowRight } from "lucide-react" -import { Button } from "@/components/ui/button" -import { useToast } from "@/components/ui/use-toast" -import { Skeleton } from "@/components/ui/skeleton" +import { Button } from "@/components/common/button" +import { useToast } from "@/components/common/use-toast" +import { Skeleton } from "@/components/common/skeleton" import { clientFetch } from "@/lib/api" import { motion } from "framer-motion" import Link from "next/link" -import { useWidgetLayout, WidgetConfig } from "@/hooks/useWidgetLayout" +import { useWidgetLayout } from "@/lib/hooks/useWidgetLayout" +import type { TopProduct, WidgetConfig } from "@/lib/types/dashboard" interface ContentProps { username: string orderStats: OrderStatsData } -interface TopProduct { - id: string; - name: string; - price: number | number[]; - image: string; - count: number; - revenue: number; -} +// TopProduct interface moved to @/lib/types/dashboard export default function Content({ username, orderStats }: ContentProps) { const [greeting, setGreeting] = useState(""); const [topProducts, setTopProducts] = useState([]); - const [isLoading, setIsLoading] = useState(true); - const [error, setError] = useState(null); + const [loading, setLoading] = useState(true); + const [errorQuery, setErrorQuery] = useState(false); + const [selectedProductId, setSelectedProductId] = useState(null); + const [isProductPeekOpen, setIsProductPeekOpen] = useState(false); + const [trends, setTrends] = useState([]); + + const handleProductPeek = (id: string) => { + setSelectedProductId(id); + setIsProductPeekOpen(true); + }; const { toast } = useToast(); const { widgets, toggleWidget, moveWidget, reorderWidgets, resetLayout, isWidgetVisible, updateWidgetSettings } = useWidgetLayout(); const [configuredWidget, setConfiguredWidget] = useState(null); @@ -59,14 +63,25 @@ export default function Content({ username, orderStats }: ContentProps) { const fetchTopProducts = async () => { try { - setIsLoading(true); + setLoading(true); const data = await clientFetch('/orders/top-products'); setTopProducts(data); } catch (err) { console.error("Error fetching top products:", err); - setError(err instanceof Error ? err.message : "Failed to fetch top products"); + setErrorQuery(true); } finally { - setIsLoading(false); + setLoading(false); + } + }; + + const fetchTrends = async () => { + try { + const data = await clientFetch('/analytics/revenue-trends?period=30'); + if (Array.isArray(data)) { + setTrends(data); + } + } catch (err) { + console.error("Error fetching trends:", err); } }; @@ -88,16 +103,35 @@ export default function Content({ username, orderStats }: ContentProps) {

Overview

- {statsConfig.map((stat, index) => ( - - ))} + {statsConfig.map((stat, index) => { + const colors = ["#8884d8", "#10b981", "#3b82f6", "#f59e0b"]; + const val = Number(orderStats[stat.key as keyof OrderStatsData]) || 0; + + // Map real trend data if available, otherwise fallback to empty (or subtle random if just started) + let trendData = trends.map(t => ({ + value: stat.key === "revenue" ? t.revenue : t.orders + })).slice(-12); // Last 12 points + + // Fallback for demo/new stores if no trends yet + if (trendData.length === 0) { + trendData = Array.from({ length: 12 }, (_, i) => ({ + value: Math.max(0, val * (0.8 + Math.random() * 0.4 + (i / 20))) + })); + } + + return ( + + ); + })}
); @@ -118,7 +152,7 @@ export default function Content({ username, orderStats }: ContentProps) { Top Performing Listings Your products with the highest sales volume
- {error && ( + {errorQuery && ( + + )} + + +
+ {loading ? : order ? `Order #${order.orderId}` : "Loading..."} +
+
+ + + + {loading ? ( +
+
+ + +
+ +
+ {[1, 2, 3].map(i => )} +
+
+ ) : order ? ( +
+ {/* Summary Stats */} +
+
+ Status +
+ + {order.status} + +
+
+
+ Total Value +
+ {formatGBP(order.totalPrice)} +
+
+
+ + {/* Customer Info */} +
+

+ Customer Information +

+
+
+ Customer +
+ + {order.telegramUsername ? `@${order.telegramUsername}` : "Anonymous"} + + + ID: {order.telegramBuyerId?.slice(0, 16) || "N/A"} + +
+
+
+ Order Date + + {order.orderDate ? : "N/A"} + +
+
+
+ + {/* Order Items */} +
+

+ Order Items +

+
+ {order.products?.map((item: any, idx: number) => ( +
+
+ + {item.name || `Item ${idx + 1}`} + + Qty: {item.quantity} +
+ {formatGBP(item.totalItemPrice)} +
+ ))} + {order.shippingMethod && ( +
+
+ Shipping: {order.shippingMethod.type} + Standard Delivery +
+ {formatGBP(order.shippingMethod.price)} +
+ )} +
+
+ + {/* Shipping Address Peek */} +
+

+ Delivery Address +

+
+

+ {order.pgpAddress || "No address provided or encrypted."} +

+
+
+ + {/* Timeline Indicator */} +
+

+ Next Milestone +

+
+
+
+ +
+
+

Pending Shipment

+

Awaiting vendor processing and label creation.

+
+
+
+
+
+ ) : ( +
+ Failed to load order data. +
+ )} +
+ + {order && ( +
+ onOpenChange(false)}> + + +
+ )} + + + ) +} + + diff --git a/components/dashboard/order-stats.tsx b/components/dashboard/order-stats.tsx index abe454b..43b3c6f 100644 --- a/components/dashboard/order-stats.tsx +++ b/components/dashboard/order-stats.tsx @@ -1,7 +1,8 @@ import type { LucideIcon } from "lucide-react" -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/common/card" import { motion } from "framer-motion" import Link from "next/link" +import { ResponsiveContainer, LineChart, Line } from "recharts" interface OrderStatsProps { title: string @@ -12,6 +13,10 @@ interface OrderStatsProps { filterStatus?: string /** Custom href if not using filterStatus */ href?: string + /** Data for sparkline [ { value: number }, ... ] */ + trendData?: { value: number }[] + /** Color for the sparkline */ + trendColor?: string } export default function OrderStats({ @@ -20,7 +25,9 @@ export default function OrderStats({ icon: Icon, index = 0, filterStatus, - href + href, + trendData, + trendColor = "#8884d8" }: OrderStatsProps) { const linkHref = href || (filterStatus ? `/dashboard/orders?status=${filterStatus}` : undefined) @@ -45,8 +52,26 @@ export default function OrderStats({ -
{value}
-
+
+
{value}
+ {trendData && trendData.length > 0 && ( +
+ + + + + +
+ )} +
+
{linkHref && (
Click to view → @@ -59,3 +84,4 @@ export default function OrderStats({ ) } + diff --git a/components/dashboard/page-loading.tsx b/components/dashboard/page-loading.tsx index 5574836..2ec88f6 100644 --- a/components/dashboard/page-loading.tsx +++ b/components/dashboard/page-loading.tsx @@ -1,7 +1,7 @@ "use client" -import { Skeleton } from "@/components/ui/skeleton"; -import { Card } from "@/components/ui/card"; +import { Skeleton } from "@/components/common/skeleton"; +import { Card } from "@/components/common/card"; import { Loader2 } from "lucide-react"; import { SnowLoader } from "@/components/snow-loader"; @@ -113,4 +113,4 @@ export default function PageLoading({
); -} \ No newline at end of file +} diff --git a/components/dashboard/pending-chats-widget.tsx b/components/dashboard/pending-chats-widget.tsx index e56567d..48eb7fe 100644 --- a/components/dashboard/pending-chats-widget.tsx +++ b/components/dashboard/pending-chats-widget.tsx @@ -1,14 +1,14 @@ "use client" import { useState, useEffect } from "react" -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" -import { Button } from "@/components/ui/button" -import { Skeleton } from "@/components/ui/skeleton" +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card" +import { Button } from "@/components/common/button" +import { Skeleton } from "@/components/common/skeleton" import { MessageSquare, MessageCircle, ArrowRight, Clock } from "lucide-react" import { clientFetch, getCookie } from "@/lib/api" -import { Avatar, AvatarFallback } from "@/components/ui/avatar" +import { Avatar, AvatarFallback } from "@/components/common/avatar" import Link from "next/link" -import { RelativeTime } from "@/components/ui/relative-time" +import { RelativeTime } from "@/components/common/relative-time" interface PendingChatsWidgetProps { settings?: { @@ -170,3 +170,5 @@ export default function PendingChatsWidget({ settings }: PendingChatsWidgetProps ) } + + diff --git a/components/dashboard/product-peek.tsx b/components/dashboard/product-peek.tsx new file mode 100644 index 0000000..88eab03 --- /dev/null +++ b/components/dashboard/product-peek.tsx @@ -0,0 +1,191 @@ +"use client" + +import { useState, useEffect } from "react" +import { + Sheet, + SheetContent, + SheetHeader, + SheetTitle, + SheetDescription +} from "@/components/common/sheet" +import { clientFetch } from "@/lib/api" +import { Badge } from "@/components/common/badge" +import { Separator } from "@/components/common/separator" +import { ScrollArea } from "@/components/common/scroll-area" +import { ShoppingCart, TrendingUp, BarChart3, Package, History, ExternalLink, AlertCircle } from "lucide-react" +import { formatGBP } from "@/lib/utils/format" +import Link from "next/link" +import { Button } from "@/components/common/button" +import { Skeleton } from "@/components/common/skeleton" + +interface ProductPeekProps { + productId: string | null + open: boolean + onOpenChange: (open: boolean) => void +} + +export function ProductPeek({ productId, open, onOpenChange }: ProductPeekProps) { + const [product, setProduct] = useState(null) + const [loading, setLoading] = useState(false) + + useEffect(() => { + if (open && productId) { + fetchProductDetails() + } + }, [open, productId]) + + const fetchProductDetails = async () => { + setLoading(true) + try { + // In this app, productId might be the ID used in the list, + // which corresponds to the mongo _id or a semantic ID. + const data = await clientFetch(`/products/${productId}`) + setProduct(data) + } catch (error) { + console.error("Failed to fetch product details for peek:", error) + } finally { + setLoading(false) + } + } + + return ( + + + +
+ + + Product Insight + + {product && ( + onOpenChange(false)}> + + + )} +
+ +
+ {loading ? : product ? product.name : "Loading..."} +
+
+
+ + + {loading ? ( +
+
+ +
+ + +
+
+ +
+ + +
+
+ ) : product ? ( +
+ {/* Product Visual & Basic Info */} +
+
+
+ + {product.type || "Physical"} + +

{product.name}

+
+
+ + {/* Inventory Stats */} +
+
+ Current Stock +
+ + {product.currentStock || 0} + + {(product.currentStock || 0) <= 5 && } +
+
+
+ Unit Type +
+ {product.unitType || "Units"} +
+
+
+ + {/* Analytics Section */} +
+

+ Performance Metrics +

+
+
+ Type + {product.type || "Physical"} +
+
+ Rating +
+
+ {"★".repeat(Math.round(product.rating || 5))} +
+ ({product.rating || "5.0"}) +
+
+
+
+ + {/* Status & Settings */} +
+

+ Market Visibility +

+
+
+
+ +
+
+

Active Listing

+

This product is currently visible to all buyers.

+
+
+
+
+ + {/* Quick Actions */} +
+ onOpenChange(false)} className="w-full"> + + +
+
+ ) : ( +
+ Failed to load product details. +
+ )} + + + + ) +} + + diff --git a/components/dashboard/promotions/EditPromotionForm.tsx b/components/dashboard/promotions/EditPromotionForm.tsx index 473b117..d21b40b 100644 --- a/components/dashboard/promotions/EditPromotionForm.tsx +++ b/components/dashboard/promotions/EditPromotionForm.tsx @@ -5,7 +5,7 @@ import { z } from 'zod'; import { zodResolver } from '@hookform/resolvers/zod'; import { useForm } from 'react-hook-form'; import { Save, X, Loader2 } from 'lucide-react'; -import { Button } from '@/components/ui/button'; +import { Button } from '@/components/common/button'; import { Form, FormControl, @@ -14,12 +14,12 @@ import { FormItem, FormLabel, FormMessage, -} from '@/components/ui/form'; -import { Input } from '@/components/ui/input'; -import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; -import { Switch } from '@/components/ui/switch'; -import { Textarea } from '@/components/ui/textarea'; -import { toast } from '@/components/ui/use-toast'; +} from '@/components/common/form'; +import { Input } from '@/components/common/input'; +import { RadioGroup, RadioGroupItem } from "@/components/common/radio-group"; +import { Switch } from '@/components/common/switch'; +import { Textarea } from '@/components/common/textarea'; +import { toast } from '@/components/common/use-toast'; import { Promotion, PromotionFormData } from '@/lib/types/promotion'; import { fetchClient } from '@/lib/api'; import dynamic from 'next/dynamic'; @@ -464,4 +464,5 @@ export default function EditPromotionForm({ promotion, onSuccess, onCancel }: Ed ); -} \ No newline at end of file +} + diff --git a/components/dashboard/promotions/NewPromotionForm.tsx b/components/dashboard/promotions/NewPromotionForm.tsx index 715799c..e569b37 100644 --- a/components/dashboard/promotions/NewPromotionForm.tsx +++ b/components/dashboard/promotions/NewPromotionForm.tsx @@ -5,7 +5,7 @@ import { z } from 'zod'; import { zodResolver } from '@hookform/resolvers/zod'; import { useForm } from 'react-hook-form'; import { Plus, Save, X, Loader2 } from 'lucide-react'; -import { Button } from '@/components/ui/button'; +import { Button } from '@/components/common/button'; import { Form, FormControl, @@ -14,15 +14,15 @@ import { FormItem, FormLabel, FormMessage, -} from '@/components/ui/form'; -import { Input } from '@/components/ui/input'; -import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; -import { Switch } from '@/components/ui/switch'; -import { Textarea } from '@/components/ui/textarea'; -import { toast } from '@/components/ui/use-toast'; +} from '@/components/common/form'; +import { Input } from '@/components/common/input'; +import { RadioGroup, RadioGroupItem } from "@/components/common/radio-group"; +import { Switch } from '@/components/common/switch'; +import { Textarea } from '@/components/common/textarea'; +import { toast } from '@/components/common/use-toast'; import { PromotionFormData } from '@/lib/types/promotion'; import { fetchClient } from '@/lib/api'; -import { DatePicker } from '@/components/ui/date-picker'; +import { DatePicker } from '@/components/common/date-picker'; import dynamic from 'next/dynamic'; const ProductSelector = dynamic(() => import('./ProductSelector')); @@ -459,4 +459,5 @@ export default function NewPromotionForm({ onSuccess, onCancel }: NewPromotionFo ); -} \ No newline at end of file +} + diff --git a/components/dashboard/promotions/ProductSelector.tsx b/components/dashboard/promotions/ProductSelector.tsx index 27bc2b2..4d930d2 100644 --- a/components/dashboard/promotions/ProductSelector.tsx +++ b/components/dashboard/promotions/ProductSelector.tsx @@ -2,12 +2,12 @@ import { useState, useEffect, useRef } from 'react'; import { Check, ChevronDown, X, Search } from 'lucide-react'; -import { Button } from '@/components/ui/button'; -import { Input } from '@/components/ui/input'; -import { Badge } from '@/components/ui/badge'; -import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; -import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem } from '@/components/ui/command'; -import { ScrollArea } from '@/components/ui/scroll-area'; +import { Button } from '@/components/common/button'; +import { Input } from '@/components/common/input'; +import { Badge } from '@/components/common/badge'; +import { Popover, PopoverContent, PopoverTrigger } from '@/components/common/popover'; +import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem } from '@/components/common/command'; +import { ScrollArea } from '@/components/common/scroll-area'; import { Product } from '@/lib/types/promotion'; import { fetchClient } from '@/lib/api'; @@ -248,4 +248,5 @@ export default function ProductSelector({ )}
); -} \ No newline at end of file +} + diff --git a/components/dashboard/promotions/PromotionDetailsModal.tsx b/components/dashboard/promotions/PromotionDetailsModal.tsx index 8ed342c..005d238 100644 --- a/components/dashboard/promotions/PromotionDetailsModal.tsx +++ b/components/dashboard/promotions/PromotionDetailsModal.tsx @@ -7,11 +7,11 @@ import { DialogHeader, DialogTitle, DialogDescription -} from '@/components/ui/dialog'; -import { Badge } from '@/components/ui/badge'; -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; -import { Separator } from '@/components/ui/separator'; -import { ScrollArea } from '@/components/ui/scroll-area'; +} from '@/components/common/dialog'; +import { Badge } from '@/components/common/badge'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/common/card'; +import { Separator } from '@/components/common/separator'; +import { ScrollArea } from '@/components/common/scroll-area'; import { Calendar, Target, @@ -28,7 +28,7 @@ import { } from 'lucide-react'; import { Promotion, Product } from '@/lib/types/promotion'; import { fetchClient } from '@/lib/api'; -import { toast } from '@/components/ui/use-toast'; +import { toast } from '@/components/common/use-toast'; interface PromotionDetailsModalProps { promotion: Promotion | null; @@ -382,4 +382,5 @@ export default function PromotionDetailsModal({
); -} \ No newline at end of file +} + diff --git a/components/dashboard/promotions/PromotionsList.tsx b/components/dashboard/promotions/PromotionsList.tsx index 0e4daa2..e29e314 100644 --- a/components/dashboard/promotions/PromotionsList.tsx +++ b/components/dashboard/promotions/PromotionsList.tsx @@ -3,7 +3,7 @@ import { useState, useEffect } from 'react'; import { Plus, Tag, RefreshCw, Trash, Edit, Check, X, Eye } from 'lucide-react'; import { useRouter } from 'next/navigation'; -import { Button } from '@/components/ui/button'; +import { Button } from '@/components/common/button'; import { Table, TableBody, @@ -11,14 +11,14 @@ import { TableHead, TableHeader, TableRow, -} from '@/components/ui/table'; +} from '@/components/common/table'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, -} from '@/components/ui/card'; +} from '@/components/common/card'; import { Dialog, DialogContent, @@ -27,9 +27,9 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from '@/components/ui/dialog'; -import { toast } from '@/components/ui/use-toast'; -import { Badge } from '@/components/ui/badge'; +} from '@/components/common/dialog'; +import { toast } from '@/components/common/use-toast'; +import { Badge } from '@/components/common/badge'; import { Promotion } from '@/lib/types/promotion'; import { fetchClient } from '@/lib/api'; import dynamic from 'next/dynamic'; @@ -306,4 +306,5 @@ export default function PromotionsList() { /> ); -} \ No newline at end of file +} + diff --git a/components/dashboard/promotions/PromotionsPageSkeleton.tsx b/components/dashboard/promotions/PromotionsPageSkeleton.tsx index af97572..cee6e93 100644 --- a/components/dashboard/promotions/PromotionsPageSkeleton.tsx +++ b/components/dashboard/promotions/PromotionsPageSkeleton.tsx @@ -5,9 +5,9 @@ import { TableHead, TableHeader, TableRow, -} from '@/components/ui/table'; -import { Card, CardContent } from '@/components/ui/card'; -import { Skeleton } from '@/components/ui/skeleton'; +} from '@/components/common/table'; +import { Card, CardContent } from '@/components/common/card'; +import { Skeleton } from '@/components/common/skeleton'; export default function PromotionsPageSkeleton() { return ( @@ -59,4 +59,4 @@ export default function PromotionsPageSkeleton() { ); -} \ No newline at end of file +} diff --git a/components/dashboard/quick-actions.tsx b/components/dashboard/quick-actions.tsx index 5a02f90..ecb5379 100644 --- a/components/dashboard/quick-actions.tsx +++ b/components/dashboard/quick-actions.tsx @@ -9,10 +9,10 @@ import { BarChart3, MessageSquare, } from "lucide-react" -import { Card, CardContent } from "@/components/ui/card" +import { Card, CardContent } from "@/components/common/card" import dynamic from "next/dynamic" -import { Product } from "@/models/products" -import { Category } from "@/models/categories" +import { Product } from "@/lib/models/products" +import { Category } from "@/lib/models/categories" import { clientFetch } from "@/lib/api" import { toast } from "sonner" @@ -217,3 +217,5 @@ export default function QuickActions() { ) } + + diff --git a/components/dashboard/recent-activity.tsx b/components/dashboard/recent-activity.tsx index 8c9cfc8..68ac642 100644 --- a/components/dashboard/recent-activity.tsx +++ b/components/dashboard/recent-activity.tsx @@ -3,11 +3,12 @@ import { useState, useEffect } from "react" import { motion } from "framer-motion" import { ShoppingBag, CreditCard, Truck, MessageSquare, AlertCircle } from "lucide-react" -import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card" +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/common/card" import { clientFetch } from "@/lib/api" -import { Skeleton } from "@/components/ui/skeleton" -import { RelativeTime } from "@/components/ui/relative-time" +import { Skeleton } from "@/components/common/skeleton" +import { RelativeTime } from "@/components/common/relative-time" import Link from "next/link" +import { OrderPeek } from "./order-peek" interface ActivityItem { _id: string; @@ -21,6 +22,13 @@ interface ActivityItem { export default function RecentActivity() { const [activities, setActivities] = useState([]); const [loading, setLoading] = useState(true); + const [selectedOrderId, setSelectedOrderId] = useState(null); + const [isPeekOpen, setIsPeekOpen] = useState(false); + + const handlePeek = (id: string) => { + setSelectedOrderId(id); + setIsPeekOpen(true); + }; useEffect(() => { async function fetchRecentOrders() { @@ -89,16 +97,19 @@ export default function RecentActivity() { className="flex items-start gap-4 relative" > {index !== activities.length - 1 && ( -
+
)}
{getStatusIcon(item.status)}
- + @@ -106,14 +117,21 @@ export default function RecentActivity() {

{item.status === "paid" ? "Payment received" : item.status === "shipped" ? "Order marked as shipped" : - `Order status: ${item.status}`} for £{item.totalPrice.toFixed(2)} + `Order status: ${item.status}`}

))}
)} + ) } + + diff --git a/components/dashboard/recent-customers-widget.tsx b/components/dashboard/recent-customers-widget.tsx index 19f9612..63c8982 100644 --- a/components/dashboard/recent-customers-widget.tsx +++ b/components/dashboard/recent-customers-widget.tsx @@ -1,12 +1,12 @@ "use client" import { useState, useEffect } from "react" -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" -import { Button } from "@/components/ui/button" -import { Skeleton } from "@/components/ui/skeleton" +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card" +import { Button } from "@/components/common/button" +import { Skeleton } from "@/components/common/skeleton" import { Users, User, ArrowRight, DollarSign } from "lucide-react" import { getCustomerInsightsWithStore, formatGBP } from "@/lib/api" -import { Avatar, AvatarFallback } from "@/components/ui/avatar" +import { Avatar, AvatarFallback } from "@/components/common/avatar" import Link from "next/link" interface RecentCustomersWidgetProps { @@ -152,3 +152,5 @@ export default function RecentCustomersWidget({ settings }: RecentCustomersWidge ) } + + diff --git a/components/dashboard/revenue-widget.tsx b/components/dashboard/revenue-widget.tsx index a55a330..2e9691f 100644 --- a/components/dashboard/revenue-widget.tsx +++ b/components/dashboard/revenue-widget.tsx @@ -1,13 +1,13 @@ "use client" import { useState, useEffect } from "react" -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" -import { Button } from "@/components/ui/button" -import { Skeleton } from "@/components/ui/skeleton" +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/common/card" +import { Button } from "@/components/common/button" +import { Skeleton } from "@/components/common/skeleton" import { TrendingUp, DollarSign, RefreshCcw } from "lucide-react" import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from "recharts" import { getRevenueTrendsWithStore, type RevenueData, formatGBP } from "@/lib/api" -import { useToast } from "@/components/ui/use-toast" +import { useToast } from "@/components/common/use-toast" interface RevenueWidgetProps { settings?: { @@ -63,7 +63,6 @@ export default function RevenueWidget({ settings }: RevenueWidgetProps) { }) // Summary stats - const totalRevenue = data.reduce((sum, item) => sum + (item.revenue || 0), 0) const totalOrders = data.reduce((sum, item) => sum + (item.orders || 0), 0) const CustomTooltip = ({ active, payload }: any) => { @@ -74,9 +73,6 @@ export default function RevenueWidget({ settings }: RevenueWidgetProps) {

{data.formattedDate}

- Revenue: {formatGBP(data.revenue)} -

-

Orders: {data.orders}

@@ -106,7 +102,7 @@ export default function RevenueWidget({ settings }: RevenueWidgetProps) {
- Revenue Insights + Order Insights Performance over the last {days} days @@ -122,15 +118,15 @@ export default function RevenueWidget({ settings }: RevenueWidgetProps) { {error ? (
-

Could not load revenue trends

+

Could not load order trends

) : chartData.length === 0 ? (
-

No revenue data

+

No order data

- Start making sales to see your revenue trends here. + Start making sales to see your order trends here.

) : ( @@ -139,7 +135,7 @@ export default function RevenueWidget({ settings }: RevenueWidgetProps) { - + @@ -156,15 +152,15 @@ export default function RevenueWidget({ settings }: RevenueWidgetProps) { tick={{ fontSize: 11, fill: "hsl(var(--muted-foreground))" }} axisLine={false} tickLine={false} - tickFormatter={(value) => `£${value >= 1000 ? (value / 1000).toFixed(1) + 'k' : value}`} + tickFormatter={(value) => `${value}`} /> } /> @@ -172,14 +168,10 @@ export default function RevenueWidget({ settings }: RevenueWidgetProps) {
-
-
-
Total Revenue
-
{formatGBP(totalRevenue)}
-
-
+
+
Total Orders
-
{totalOrders}
+
{totalOrders}
@@ -188,3 +180,5 @@ export default function RevenueWidget({ settings }: RevenueWidgetProps) { ) } + + diff --git a/components/dashboard/widget-settings-modal.tsx b/components/dashboard/widget-settings-modal.tsx index 37b645e..3f161a0 100644 --- a/components/dashboard/widget-settings-modal.tsx +++ b/components/dashboard/widget-settings-modal.tsx @@ -1,7 +1,7 @@ "use client" import { useState } from "react" -import { Button } from "@/components/ui/button" +import { Button } from "@/components/common/button" import { Dialog, DialogContent, @@ -9,20 +9,20 @@ import { DialogTitle, DialogDescription, DialogFooter, -} from "@/components/ui/dialog" -import { Label } from "@/components/ui/label" -import { Input } from "@/components/ui/input" -import { Switch } from "@/components/ui/switch" +} from "@/components/common/dialog" +import { Label } from "@/components/common/label" +import { Input } from "@/components/common/input" +import { Switch } from "@/components/common/switch" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select" -import { WidgetConfig } from "@/hooks/useWidgetLayout" +} from "@/components/common/select" +import { WidgetConfig } from "@/lib/types/dashboard" import { Settings2 } from "lucide-react" -import { ScrollArea } from "@/components/ui/scroll-area" +import { ScrollArea } from "@/components/common/scroll-area" interface WidgetSettingsModalProps { widget: WidgetConfig | null @@ -269,3 +269,5 @@ export function WidgetSettingsModal({ widget, open, onOpenChange, onSave }: Widg ) } + + diff --git a/components/dashboard/widget-settings.tsx b/components/dashboard/widget-settings.tsx index d21ffd4..46b83d9 100644 --- a/components/dashboard/widget-settings.tsx +++ b/components/dashboard/widget-settings.tsx @@ -1,6 +1,6 @@ "use client" -import { Button } from "@/components/ui/button" +import { Button } from "@/components/common/button" import { DropdownMenu, DropdownMenuContent, @@ -9,9 +9,9 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, DropdownMenuCheckboxItem, -} from "@/components/ui/dropdown-menu" +} from "@/components/common/dropdown-menu" import { Settings2, ChevronUp, ChevronDown, RotateCcw, Eye, EyeOff, Cog } from "lucide-react" -import { WidgetConfig } from "@/hooks/useWidgetLayout" +import { WidgetConfig } from "@/lib/types/dashboard" interface WidgetSettingsProps { widgets: WidgetConfig[] @@ -99,3 +99,5 @@ export function WidgetSettings({ widgets, onToggle, onMove, onReset, onConfigure ) } + + diff --git a/components/forms/image-upload.tsx b/components/forms/image-upload.tsx index 6e4cfab..5cb89f8 100644 --- a/components/forms/image-upload.tsx +++ b/components/forms/image-upload.tsx @@ -1,7 +1,7 @@ "use client"; import { ChangeEvent } from "react"; -import { Input } from "@/components/ui/input"; +import { Input } from "@/components/common/input"; import Image from "next/image"; interface ImageUploadProps { @@ -44,4 +44,4 @@ export const ImageUpload = ({ className="mt-2 h-9 text-sm" />
-); \ No newline at end of file +); diff --git a/components/forms/pricing-tiers.tsx b/components/forms/pricing-tiers.tsx index a1d3228..20fee20 100644 --- a/components/forms/pricing-tiers.tsx +++ b/components/forms/pricing-tiers.tsx @@ -1,7 +1,7 @@ "use client"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; +import { Button } from "@/components/common/button"; +import { Input } from "@/components/common/input"; import { Trash, PlusCircle } from "lucide-react"; interface PricingTiersProps { @@ -137,3 +137,4 @@ export const PricingTiers = ({
); }; + diff --git a/components/home-navbar.tsx b/components/layout/home-navbar.tsx similarity index 98% rename from components/home-navbar.tsx rename to components/layout/home-navbar.tsx index 1cd145c..e783b22 100644 --- a/components/home-navbar.tsx +++ b/components/layout/home-navbar.tsx @@ -1,7 +1,7 @@ "use client"; import Link from "next/link"; -import { Button } from "@/components/ui/button"; +import { Button } from "@/components/common/button"; import { LogIn } from "lucide-react"; import { useState } from "react"; @@ -88,4 +88,4 @@ export function HomeNavbar() { )} ); -} \ No newline at end of file +} diff --git a/components/layout/sidebar.tsx b/components/layout/sidebar.tsx index f45ec00..408f6dc 100644 --- a/components/layout/sidebar.tsx +++ b/components/layout/sidebar.tsx @@ -5,12 +5,12 @@ import Link from "next/link" import { useRouter, usePathname } from "next/navigation" import { ShoppingCart, LogOut, Shield } from "lucide-react" import { NavItem } from "./nav-item" -import { Button } from "@/components/ui/button" +import { Button } from "@/components/common/button" import { sidebarConfig } from "@/config/sidebar" import { adminSidebarConfig } from "@/config/admin-sidebar" import { logoutUser } from "@/lib/utils/auth" import { toast } from "sonner" -import { useUser } from "@/hooks/useUser" +import { useUser } from "@/lib/hooks/useUser" const Sidebar: React.FC = () => { const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false) @@ -119,3 +119,5 @@ const Sidebar: React.FC = () => { export default Sidebar + + diff --git a/components/theme-switcher.tsx b/components/layout/theme-switcher.tsx similarity index 95% rename from components/theme-switcher.tsx rename to components/layout/theme-switcher.tsx index 9500b86..3272b69 100644 --- a/components/theme-switcher.tsx +++ b/components/layout/theme-switcher.tsx @@ -2,7 +2,7 @@ import { useTheme } from "next-themes"; import { useEffect, useState } from "react"; -import { Button } from "@/components/ui/button"; +import { Button } from "@/components/common/button"; export function ThemeSwitcher() { const { theme, setTheme } = useTheme(); @@ -27,4 +27,4 @@ export function ThemeSwitcher() { )} ); -} \ No newline at end of file +} diff --git a/components/theme-toggle.tsx b/components/layout/theme-toggle.tsx similarity index 100% rename from components/theme-toggle.tsx rename to components/layout/theme-toggle.tsx diff --git a/components/modals/broadcast-dialog.tsx b/components/modals/broadcast-dialog.tsx index b1a9e7e..3698741 100644 --- a/components/modals/broadcast-dialog.tsx +++ b/components/modals/broadcast-dialog.tsx @@ -1,12 +1,12 @@ "use client"; import { useState, useRef, lazy, Suspense } from "react"; -import { Button } from "@/components/ui/button"; -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; +import { Button } from "@/components/common/button"; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/common/dialog"; import { Send, Bold, Italic, Code, Link as LinkIcon, Image as ImageIcon, X, Eye, EyeOff, Package } from "lucide-react"; import { toast } from "sonner"; import { clientFetch } from "@/lib/api"; -import { Textarea } from "@/components/ui/textarea"; +import { Textarea } from "@/components/common/textarea"; import Image from "next/image"; import ProductSelector from "./product-selector"; @@ -108,7 +108,7 @@ export default function BroadcastDialog({ open, setOpen }: BroadcastDialogProps) ?.split("=")[1]; if (!authToken) { - document.location.href = "/login"; + document.location.href = "/auth/login"; throw new Error("No authentication token found"); } @@ -365,4 +365,5 @@ __italic text__ ); -} \ No newline at end of file +} + diff --git a/components/modals/image-viewer-modal.tsx b/components/modals/image-viewer-modal.tsx index 269a56d..8e59c93 100644 --- a/components/modals/image-viewer-modal.tsx +++ b/components/modals/image-viewer-modal.tsx @@ -1,6 +1,6 @@ -import { Dialog, DialogContent } from "@/components/ui/dialog"; +import { Dialog, DialogContent } from "@/components/common/dialog"; import { ChevronLeft, ChevronRight, X } from "lucide-react"; -import { Button } from "@/components/ui/button"; +import { Button } from "@/components/common/button"; import { useEffect } from "react"; interface ImageViewerModalProps { @@ -96,4 +96,4 @@ export function ImageViewerModal({ isOpen, onClose, imageUrl, onNavigate }: Imag ); -} \ No newline at end of file +} diff --git a/components/modals/import-products-modal.tsx b/components/modals/import-products-modal.tsx index d45408e..ceb997c 100644 --- a/components/modals/import-products-modal.tsx +++ b/components/modals/import-products-modal.tsx @@ -1,11 +1,11 @@ "use client"; import { useState } from "react"; -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; -import { Button } from "@/components/ui/button"; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/common/dialog"; +import { Button } from "@/components/common/button"; import { Upload, AlertCircle } from "lucide-react"; import { toast } from "sonner"; -import { Alert, AlertDescription } from "@/components/ui/alert"; +import { Alert, AlertDescription } from "@/components/common/alert"; interface ImportProductsModalProps { open: boolean; @@ -193,4 +193,4 @@ export default function ImportProductsModal({ open, setOpen, onImportComplete }: ); -} \ No newline at end of file +} diff --git a/components/modals/product-modal.tsx b/components/modals/product-modal.tsx index 18b79b8..a8f4098 100644 --- a/components/modals/product-modal.tsx +++ b/components/modals/product-modal.tsx @@ -1,10 +1,10 @@ "use client"; import { useState, useEffect } from "react"; -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Textarea } from "@/components/ui/textarea"; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/common/dialog"; +import { Button } from "@/components/common/button"; +import { Input } from "@/components/common/input"; +import { Textarea } from "@/components/common/textarea"; import { Select, SelectContent, @@ -13,7 +13,7 @@ import { SelectLabel, SelectTrigger, SelectValue, -} from "@/components/ui/select"; +} from "@/components/common/select"; import { ImageUpload } from "@/components/forms/image-upload"; import { PricingTiers } from "@/components/forms/pricing-tiers"; import type { ProductModalProps, ProductData } from "@/lib/types"; @@ -21,8 +21,8 @@ import { toast } from "sonner"; import type React from "react"; import { Plus } from "lucide-react"; import { apiRequest } from "@/lib/api"; -import { Switch } from "@/components/ui/switch"; -import { Badge } from "@/components/ui/badge"; +import { Switch } from "@/components/common/switch"; +import { Badge } from "@/components/common/badge"; type CategorySelectProps = { categories: { _id: string; name: string; parentId?: string }[]; @@ -485,4 +485,5 @@ const UnitTypeSelect: React.FC<{
-); \ No newline at end of file +); + diff --git a/components/modals/product-selector.tsx b/components/modals/product-selector.tsx index b32a282..c8e7d75 100644 --- a/components/modals/product-selector.tsx +++ b/components/modals/product-selector.tsx @@ -1,10 +1,10 @@ "use client"; import { useState, useEffect } from "react"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Checkbox } from "@/components/ui/checkbox"; -import { ScrollArea } from "@/components/ui/scroll-area"; +import { Button } from "@/components/common/button"; +import { Input } from "@/components/common/input"; +import { Checkbox } from "@/components/common/checkbox"; +import { ScrollArea } from "@/components/common/scroll-area"; import { Search, Package } from "lucide-react"; import { apiRequest } from "@/lib/api"; @@ -127,4 +127,5 @@ export default function ProductSelector({ selectedProducts, onSelectionChange }: )} ); -} \ No newline at end of file +} + diff --git a/components/modals/profit-analysis-modal.tsx b/components/modals/profit-analysis-modal.tsx index d82e1fd..d322b1c 100644 --- a/components/modals/profit-analysis-modal.tsx +++ b/components/modals/profit-analysis-modal.tsx @@ -1,10 +1,10 @@ "use client"; import { useState, useEffect } from "react"; -import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; +import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/common/dialog"; +import { Button } from "@/components/common/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/common/card"; +import { Badge } from "@/components/common/badge"; import { TrendingUp, TrendingDown, Calculator, DollarSign, Loader2, Info } from "lucide-react"; import { toast } from "sonner"; import { apiRequest } from "@/lib/api"; @@ -336,3 +336,5 @@ export const ProfitAnalysisModal: React.FC = ({ ); }; + + diff --git a/components/modals/shipping-modal.tsx b/components/modals/shipping-modal.tsx index c8af667..220753c 100644 --- a/components/modals/shipping-modal.tsx +++ b/components/modals/shipping-modal.tsx @@ -1,9 +1,9 @@ "use client"; import { ChangeEvent, FormEvent } from "react"; -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/common/dialog"; +import { Button } from "@/components/common/button"; +import { Input } from "@/components/common/input"; import { ShippingData } from "@/lib/types"; interface ShippingModalProps { @@ -80,3 +80,4 @@ export const ShippingModal = ({ ); }; + diff --git a/components/notifications/OrderNotifications.tsx b/components/notifications/OrderNotifications.tsx index 1fff6e8..d500fa6 100644 --- a/components/notifications/OrderNotifications.tsx +++ b/components/notifications/OrderNotifications.tsx @@ -5,14 +5,14 @@ import { clientFetch } from "@/lib/api"; import { toast } from "sonner"; import { Package, Bell } from "lucide-react"; import { useRouter } from "next/navigation"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/common/badge"; +import { Button } from "@/components/common/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; +} from "@/components/common/dropdown-menu"; interface Order { _id: string; @@ -234,4 +234,5 @@ export default function OrderNotifications() { ); -} \ No newline at end of file +} + diff --git a/components/notifications/UnifiedNotifications.tsx b/components/notifications/UnifiedNotifications.tsx index c19eb6d..66c28f1 100644 --- a/components/notifications/UnifiedNotifications.tsx +++ b/components/notifications/UnifiedNotifications.tsx @@ -2,8 +2,8 @@ import React, { useState } from "react"; import { useRouter } from "next/navigation"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/common/badge"; +import { Button } from "@/components/common/button"; import { BellRing, Package, MessageCircle } from "lucide-react"; import { DropdownMenu, @@ -11,8 +11,8 @@ import { DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +} from "@/components/common/dropdown-menu"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/common/tabs"; import { useNotifications } from "@/lib/notification-context"; export default function UnifiedNotifications() { @@ -283,4 +283,4 @@ export default function UnifiedNotifications() { ); -} \ No newline at end of file +} diff --git a/components/tables/order-table.tsx b/components/tables/order-table.tsx index c5bde0f..baf7a42 100644 --- a/components/tables/order-table.tsx +++ b/components/tables/order-table.tsx @@ -11,16 +11,16 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; +} from "@/components/common/table"; +import { Button } from "@/components/common/button"; +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/common/card"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; +} from "@/components/common/select"; import { Eye, Loader2, @@ -37,10 +37,10 @@ import { } from "lucide-react"; import Link from "next/link"; import { clientFetch } from '@/lib/api'; -import { exportOrdersToCSV } from '@/lib/api-client'; +import { exportOrdersToCSV } from '@/lib/api/api-client'; import { toast } from "sonner"; import { Download } from "lucide-react"; -import { Checkbox } from "@/components/ui/checkbox"; +import { Checkbox } from "@/components/common/checkbox"; import { AlertDialog, AlertDialogAction, @@ -51,8 +51,8 @@ import { AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, -} from "@/components/ui/alert-dialog"; -import { cacheUtils } from '@/lib/api-client'; +} from "@/components/common/alert-dialog"; +import { cacheUtils } from '@/lib/api/api-client'; interface Order { _id: string; @@ -815,4 +815,5 @@ export default function OrderTable() { ); -} \ No newline at end of file +} + diff --git a/components/tables/product-table.tsx b/components/tables/product-table.tsx index 442e665..adcaebb 100644 --- a/components/tables/product-table.tsx +++ b/components/tables/product-table.tsx @@ -5,7 +5,7 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; +} from "@/components/common/table"; import Image from "next/image"; import { Edit, @@ -18,12 +18,12 @@ import { PackageX, Archive } from "lucide-react"; -import { Button } from "@/components/ui/button"; +import { Button } from "@/components/common/button"; import React, { useState, useEffect } from "react"; -import { Product } from "@/models/products"; -import { Badge } from "@/components/ui/badge"; -import { Switch } from "@/components/ui/switch"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Product } from "@/lib/models/products"; +import { Badge } from "@/components/common/badge"; +import { Switch } from "@/components/common/switch"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/common/card"; import { motion, AnimatePresence } from "framer-motion"; const getProductImageUrl = (product: Product) => { @@ -329,3 +329,5 @@ const ProductTable = ({ }; export default ProductTable; + + diff --git a/components/tables/shipping-table.tsx b/components/tables/shipping-table.tsx index 6f40071..19510b0 100644 --- a/components/tables/shipping-table.tsx +++ b/components/tables/shipping-table.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from "react"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Skeleton } from "@/components/common/skeleton"; import { Table, TableBody, @@ -7,10 +7,10 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; -import { Button } from "@/components/ui/button"; +} from "@/components/common/table"; +import { Button } from "@/components/common/button"; import { Edit, Trash, Truck, PackageX } from "lucide-react"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/common/card"; import { motion, AnimatePresence } from "framer-motion"; import { ShippingMethod } from "@/lib/types"; @@ -185,3 +185,4 @@ export const ShippingTable: React.FC = ({ ); }; + diff --git a/components/ui/accordion.tsx b/components/ui/accordion.tsx deleted file mode 100644 index 070c70f..0000000 --- a/components/ui/accordion.tsx +++ /dev/null @@ -1,58 +0,0 @@ -"use client" - -import * as React from "react" -import * as AccordionPrimitive from "@radix-ui/react-accordion" -import { ChevronDown } from "lucide-react" - -import { cn } from "@/lib/utils/styles"; - -const Accordion = AccordionPrimitive.Root - -const AccordionItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AccordionItem.displayName = "AccordionItem" - -const AccordionTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - svg]:rotate-180", - className - )} - {...props} - > - {children} - - - -)) -AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName - -const AccordionContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - -
{children}
-
-)) - -AccordionContent.displayName = AccordionPrimitive.Content.displayName - -export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/lib/api-client.ts b/lib/api/api-client.ts similarity index 99% rename from lib/api-client.ts rename to lib/api/api-client.ts index c7e7781..a8e2b69 100644 --- a/lib/api-client.ts +++ b/lib/api/api-client.ts @@ -4,7 +4,7 @@ let toast: any; try { // Try to import from the UI components - toast = require("@/components/ui/use-toast").toast; + toast = require("@/components/common/use-toast").toast; } catch (error) { // Fallback toast function if not available toast = { @@ -512,4 +512,4 @@ export async function clientFetchWithCache( } return result; -} \ No newline at end of file +} diff --git a/lib/api.ts b/lib/api/index.ts similarity index 91% rename from lib/api.ts rename to lib/api/index.ts index 5ab537e..accdbab 100644 --- a/lib/api.ts +++ b/lib/api/index.ts @@ -33,7 +33,7 @@ export { type Product, type ProductsResponse, type StockData, -} from './services/product-service'; +} from '../services/product-service'; // Re-export shipping services export { @@ -46,7 +46,7 @@ export { // Types type ShippingOption, type ShippingOptionsResponse, -} from './services/shipping-service'; +} from '../services/shipping-service'; // Re-export analytics services export { @@ -61,15 +61,15 @@ export { getCustomerInsightsWithStore, getOrderAnalyticsWithStore, getStoreIdForUser, - formatGBP, - // Types type AnalyticsOverview, type RevenueData, type ProductPerformance, type CustomerInsights, type OrderAnalytics, -} from './services/analytics-service'; +} from '../services/analytics-service'; + +export { formatGBP, formatNumber } from '../utils/format'; // Define the PlatformStats interface to match the expected format export interface PlatformStats { @@ -89,7 +89,7 @@ export interface PlatformStats { export { getPlatformStats, getVendorStats, -} from './services/stats-service'; +} from '../services/stats-service'; // Re-export server API functions export { @@ -111,8 +111,8 @@ export { // Get clientFetch first so we can use it in the compatibility functions import { clientFetch } from './api-client'; -import { getProductDetails, updateProduct } from './services/product-service'; -import { getPlatformStats } from './services/stats-service'; +import { getProductDetails, updateProduct } from '../services/product-service'; +import { getPlatformStats } from '../services/stats-service'; // Add missing functions for backward compatibility // These are functions from the old style that we need to maintain compatibility diff --git a/lib/server-api.ts b/lib/api/server-api.ts similarity index 97% rename from lib/server-api.ts rename to lib/api/server-api.ts index fcbd0d0..f466d5b 100644 --- a/lib/server-api.ts +++ b/lib/api/server-api.ts @@ -22,20 +22,20 @@ try { */ function getServerApiUrl(endpoint: string): string { const apiUrl = process.env.SERVER_API_URL || 'http://localhost:3001/api'; - + // Validate API URL to prevent 500 errors if (!apiUrl || apiUrl === 'undefined' || apiUrl === 'null') { console.warn('SERVER_API_URL not properly set, using localhost fallback'); const fallbackUrl = 'http://localhost:3001/api'; const cleanEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint; - return fallbackUrl.endsWith('/') + return fallbackUrl.endsWith('/') ? `${fallbackUrl}${cleanEndpoint}` : `${fallbackUrl}/${cleanEndpoint}`; } - + const cleanEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint; - - return apiUrl.endsWith('/') + + return apiUrl.endsWith('/') ? `${apiUrl}${cleanEndpoint}` : `${apiUrl}/${cleanEndpoint}`; } @@ -58,18 +58,18 @@ export async function fetchServer( "For client components, use clientFetch or fetchClient instead." ); } - + // Get auth token from cookies const cookieStore = await cookiesModule.cookies(); const authToken = cookieStore.get('Authorization')?.value; // Redirect to login if not authenticated - if (!authToken) redirect('/login'); - + if (!authToken) redirect('/auth/login'); + try { // Get the complete backend URL using the utility function const url = getServerApiUrl(endpoint); - + // Make the request with proper auth headers const res = await fetch(url, { ...options, @@ -82,8 +82,8 @@ export async function fetchServer( }); // Handle auth failures - if (res.status === 401) redirect('/login'); - + if (res.status === 401) redirect('/auth/login'); + // Handle other errors if (!res.ok) { let errorData; @@ -92,7 +92,7 @@ export async function fetchServer( } catch { errorData = {}; } - + // Handle new error format: { success: false, error: { message: "...", code: "..." } } // or old format: { error: "...", message: "..." } let errorMessage: string; @@ -105,7 +105,7 @@ export async function fetchServer( } else { errorMessage = `Request failed: ${res.status} ${res.statusText}`; } - + throw new Error(errorMessage); } @@ -158,22 +158,22 @@ export const getCustomerDetailsServer = async (userId: string): Promise 0) { return data; } - + console.info('Using sample stats data for demo'); return { orders: { @@ -296,7 +296,7 @@ export const getAnalyticsOverviewServer = async (storeId?: string): Promise => { const params = new URLSearchParams({ period }); if (storeId) params.append('storeId', storeId); - + const url = `/analytics/revenue-trends?${params.toString()}`; return fetchServer(url); }; @@ -314,7 +314,7 @@ export const getCustomerInsightsServer = async (storeId?: string): Promise => { const params = new URLSearchParams({ period }); if (storeId) params.append('storeId', storeId); - + const url = `/analytics/order-analytics?${params.toString()}`; return fetchServer(url); }; \ No newline at end of file diff --git a/hooks/use-chromebook-keyboard.tsx b/lib/hooks/use-chromebook-keyboard.tsx similarity index 100% rename from hooks/use-chromebook-keyboard.tsx rename to lib/hooks/use-chromebook-keyboard.tsx diff --git a/hooks/use-chromebook-scroll.tsx b/lib/hooks/use-chromebook-scroll.tsx similarity index 100% rename from hooks/use-chromebook-scroll.tsx rename to lib/hooks/use-chromebook-scroll.tsx diff --git a/hooks/use-mobile.tsx b/lib/hooks/use-mobile.tsx similarity index 100% rename from hooks/use-mobile.tsx rename to lib/hooks/use-mobile.tsx diff --git a/components/ui/use-toast.ts b/lib/hooks/use-toast.ts similarity index 99% rename from components/ui/use-toast.ts rename to lib/hooks/use-toast.ts index 02e111d..714ad09 100644 --- a/components/ui/use-toast.ts +++ b/lib/hooks/use-toast.ts @@ -6,7 +6,7 @@ import * as React from "react" import type { ToastActionElement, ToastProps, -} from "@/components/ui/toast" +} from "@/components/common/toast" const TOAST_LIMIT = 1 const TOAST_REMOVE_DELAY = 1000000 diff --git a/hooks/useFilterState.ts b/lib/hooks/useFilterState.ts similarity index 100% rename from hooks/useFilterState.ts rename to lib/hooks/useFilterState.ts diff --git a/hooks/useKeepOnline.ts b/lib/hooks/useKeepOnline.ts similarity index 100% rename from hooks/useKeepOnline.ts rename to lib/hooks/useKeepOnline.ts diff --git a/hooks/useUser.ts b/lib/hooks/useUser.ts similarity index 94% rename from hooks/useUser.ts rename to lib/hooks/useUser.ts index d8ca321..9aa2785 100644 --- a/hooks/useUser.ts +++ b/lib/hooks/useUser.ts @@ -1,7 +1,7 @@ "use client" import { useState, useEffect } from 'react' -import { clientFetch } from '@/lib/api-client' +import { clientFetch } from '@/lib/api/api-client' interface Vendor { _id: string; diff --git a/hooks/useWidgetLayout.ts b/lib/hooks/useWidgetLayout.ts similarity index 79% rename from hooks/useWidgetLayout.ts rename to lib/hooks/useWidgetLayout.ts index 51be753..bffebad 100644 --- a/hooks/useWidgetLayout.ts +++ b/lib/hooks/useWidgetLayout.ts @@ -1,57 +1,7 @@ "use client" import { useState, useEffect, useCallback } from "react" - -// Per-widget settings types -export interface RecentActivitySettings { - itemCount: number // 5, 10, 15 -} - -export interface TopProductsSettings { - itemCount: number // 3, 5, 10 - showRevenue: boolean -} - -export interface OverviewSettings { - showChange: boolean // Show % change from previous period -} - -export interface RevenueChartSettings { - days: number // 7, 14, 30 - showComparison: boolean -} - -export interface LowStockSettings { - threshold: number // Show items with stock below this - itemCount: number -} - -export interface RecentCustomersSettings { - itemCount: number - showSpent: boolean -} - -export interface PendingChatsSettings { - showPreview: boolean -} - -export type WidgetSettings = - | { type: "quick-actions" } - | { type: "overview"; settings: OverviewSettings } - | { type: "recent-activity"; settings: RecentActivitySettings } - | { type: "top-products"; settings: TopProductsSettings } - | { type: "revenue-chart"; settings: RevenueChartSettings } - | { type: "low-stock"; settings: LowStockSettings } - | { type: "recent-customers"; settings: RecentCustomersSettings } - | { type: "pending-chats"; settings: PendingChatsSettings } - -export interface WidgetConfig { - id: string - title: string - visible: boolean - order: number - settings?: Record -} +import type { WidgetConfig, WidgetSettings } from "@/lib/types/dashboard" const DEFAULT_WIDGETS: WidgetConfig[] = [ { id: "quick-actions", title: "Quick Actions", visible: true, order: 0 }, diff --git a/models/categories.ts b/lib/models/categories.ts similarity index 100% rename from models/categories.ts rename to lib/models/categories.ts diff --git a/models/products.ts b/lib/models/products.ts similarity index 100% rename from models/products.ts rename to lib/models/products.ts diff --git a/lib/notification-context.tsx b/lib/notification-context.tsx index 0a500fe..3ab209e 100644 --- a/lib/notification-context.tsx +++ b/lib/notification-context.tsx @@ -4,7 +4,7 @@ import React, { createContext, useContext, useState, useEffect, useRef, ReactNod import { clientFetch } from "@/lib/api"; import { toast } from "sonner"; import { getCookie } from "@/lib/api"; -import { cacheUtils } from '@/lib/api-client'; +import { cacheUtils } from '@/lib/api/api-client'; import { Package } from "lucide-react"; interface Order { @@ -343,4 +343,4 @@ export function useNotifications() { throw new Error('useNotifications must be used within a NotificationProvider'); } return context; -} \ No newline at end of file +} diff --git a/lib/services/analytics-service.ts b/lib/services/analytics-service.ts index d59c507..f74d926 100644 --- a/lib/services/analytics-service.ts +++ b/lib/services/analytics-service.ts @@ -1,6 +1,7 @@ "use client"; -import { clientFetch } from "../api-client"; +import { clientFetch } from '@/lib/api/api-client'; +import { formatGBP } from '@/lib/utils/format'; // Analytics Types export interface AnalyticsOverview { @@ -293,15 +294,6 @@ export const getGrowthAnalyticsWithStore = return getGrowthAnalytics(storeId); }; -export function formatGBP(value: number) { - return value.toLocaleString("en-GB", { - style: "currency", - currency: "GBP", - minimumFractionDigits: 2, - maximumFractionDigits: 2, - }); -} - // Prediction Types export interface SalesPrediction { predicted: number | null; diff --git a/services/customerService.ts b/lib/services/customerService.ts similarity index 100% rename from services/customerService.ts rename to lib/services/customerService.ts diff --git a/lib/services/index.ts b/lib/services/index.ts index da3dbb0..b4117f5 100644 --- a/lib/services/index.ts +++ b/lib/services/index.ts @@ -1,5 +1,3 @@ -// Re-export all service functionality -export * from './product-service'; -export * from './shipping-service'; -export * from './stats-service'; -export * from '../api-client'; \ No newline at end of file +// Re-export all services from the lib directory +// This provides backward compatibility +export * from '../lib/api'; \ No newline at end of file diff --git a/lib/services/product-service.ts b/lib/services/product-service.ts index 21db135..5cfe057 100644 --- a/lib/services/product-service.ts +++ b/lib/services/product-service.ts @@ -1,4 +1,4 @@ -import { clientFetch } from '../api-client'; +import { clientFetch } from '@/lib/api/api-client'; // Product data types export interface Product { diff --git a/lib/services/shipping-service.ts b/lib/services/shipping-service.ts index 092c3e6..6d59975 100644 --- a/lib/services/shipping-service.ts +++ b/lib/services/shipping-service.ts @@ -1,4 +1,4 @@ -import { clientFetch } from '../api-client'; +import { clientFetch } from '@/lib/api/api-client'; /** * Shipping service - Handles shipping options diff --git a/lib/services/stats-service.ts b/lib/services/stats-service.ts index 110cafd..b594630 100644 --- a/lib/services/stats-service.ts +++ b/lib/services/stats-service.ts @@ -1,4 +1,4 @@ -import { clientFetch } from '../api-client'; +import { clientFetch } from '@/lib/api/api-client'; // Stats data types export interface PlatformStats { diff --git a/lib/types/dashboard.ts b/lib/types/dashboard.ts new file mode 100644 index 0000000..c9e0e09 --- /dev/null +++ b/lib/types/dashboard.ts @@ -0,0 +1,61 @@ +export interface RecentActivitySettings { + itemCount: number // 5, 10, 15 +} + +export interface TopProductsSettings { + itemCount: number // 3, 5, 10 + showRevenue: boolean +} + +export interface OverviewSettings { + showChange: boolean // Show % change from previous period +} + +export interface RevenueChartSettings { + days: number // 7, 14, 30 + showComparison: boolean +} + +export interface LowStockSettings { + threshold: number // Show items with stock below this + itemCount: number +} + +export interface RecentCustomersSettings { + itemCount: number + showSpent: boolean +} + +export interface PendingChatsSettings { + showPreview: boolean +} + +export type WidgetSettings = + | { type: "quick-actions" } + | { type: "overview"; settings: OverviewSettings } + | { type: "recent-activity"; settings: RecentActivitySettings } + | { type: "top-products"; settings: TopProductsSettings } + | { type: "revenue-chart"; settings: RevenueChartSettings } + | { type: "low-stock"; settings: LowStockSettings } + | { type: "recent-customers"; settings: RecentCustomersSettings } + | { type: "pending-chats"; settings: PendingChatsSettings } + +export interface WidgetConfig { + id: string + title: string + visible: boolean + order: number + colSpan?: number + settings?: Record +} + +export interface TopProduct { + id: string; + name: string; + price: number | number[]; + image: string; + count: number; + revenue: number; + unitType?: string; + currentStock?: number; +} diff --git a/lib/utils/format.ts b/lib/utils/format.ts new file mode 100644 index 0000000..3ebb021 --- /dev/null +++ b/lib/utils/format.ts @@ -0,0 +1,28 @@ +export const formatCurrency = (amount: number | undefined | null): string => { + if (amount === undefined || amount === null || isNaN(Number(amount))) { + return '£0.00'; + } + return new Intl.NumberFormat('en-GB', { + style: 'currency', + currency: 'GBP' + }).format(Number(amount)); +}; + +export function formatGBP(value: number | undefined | null) { + if (value === undefined || value === null || isNaN(Number(value))) { + return '£0.00'; + } + return Number(value).toLocaleString('en-GB', { + style: 'currency', + currency: 'GBP', + minimumFractionDigits: 2, + maximumFractionDigits: 2, + }); +} + +export function formatNumber(value: number | undefined | null, options: Intl.NumberFormatOptions = {}) { + if (value === undefined || value === null || isNaN(Number(value))) { + return '0'; + } + return Number(value).toLocaleString('en-GB', options); +} \ No newline at end of file diff --git a/middleware.ts b/middleware.ts new file mode 100644 index 0000000..77e3cff --- /dev/null +++ b/middleware.ts @@ -0,0 +1,25 @@ +import { NextResponse } from 'next/server'; +import type { NextRequest } from 'next/server'; + +export function middleware(request: NextRequest) { + const { pathname } = request.nextUrl; + + // Protect dashboard routes + if (pathname.startsWith('/dashboard')) { + const authToken = request.cookies.get('Authorization')?.value; + + if (!authToken) { + // Redirect to login if no token is found + const loginUrl = new URL('/auth/login', request.url); + loginUrl.searchParams.set('redirectUrl', pathname); + return NextResponse.redirect(loginUrl); + } + } + + return NextResponse.next(); +} + +// See "Matching Paths" below to learn more +export const config = { + matcher: ['/dashboard/:path*'], +}; diff --git a/public/git-info.json b/public/git-info.json index be281d7..c6ce719 100644 --- a/public/git-info.json +++ b/public/git-info.json @@ -1,4 +1,4 @@ { - "commitHash": "a6b7286", - "buildTime": "2026-01-12T10:20:09.966Z" + "commitHash": "a6e6cd0", + "buildTime": "2026-01-13T04:57:00.870Z" } \ No newline at end of file diff --git a/services/index.ts b/services/index.ts deleted file mode 100644 index b4117f5..0000000 --- a/services/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -// Re-export all services from the lib directory -// This provides backward compatibility -export * from '../lib/api'; \ No newline at end of file diff --git a/tailwind.config.ts b/tailwind.config.ts index 439b464..f7d21f2 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -8,8 +8,6 @@ const config: Config = { "./app/**/*.{js,ts,jsx,tsx,mdx}", "./src/**/*.{ts,tsx}", "./lib/**/*.{js,ts,jsx,tsx,mdx}", - "./hooks/**/*.{js,ts,jsx,tsx,mdx}", - "./utils/**/*.{js,ts,jsx,tsx,mdx}", ], theme: { container: { @@ -46,11 +44,11 @@ const config: Config = { '50%': { opacity: '1', transform: 'scale(1) rotate(180deg)' } }, glow: { - '0%, 100%': { - boxShadow: '0 0 5px hsl(0 84% 50%), 0 0 10px hsl(0 84% 50%), 0 0 15px hsl(0 84% 50%)' + '0%, 100%': { + boxShadow: '0 0 5px hsl(0 84% 50%), 0 0 10px hsl(0 84% 50%), 0 0 15px hsl(0 84% 50%)' }, - '50%': { - boxShadow: '0 0 10px hsl(142 76% 36%), 0 0 20px hsl(142 76% 36%), 0 0 30px hsl(142 76% 36%)' + '50%': { + boxShadow: '0 0 10px hsl(142 76% 36%), 0 0 20px hsl(142 76% 36%), 0 0 30px hsl(142 76% 36%)' } } }, diff --git a/utils/format.ts b/utils/format.ts deleted file mode 100644 index 62d055f..0000000 --- a/utils/format.ts +++ /dev/null @@ -1,15 +0,0 @@ -export const formatCurrency = (amount: number): string => { - return new Intl.NumberFormat('en-GB', { - style: 'currency', - currency: 'GBP' - }).format(amount); -}; - -export function formatGBP(value: number) { - return value.toLocaleString('en-GB', { - style: 'currency', - currency: 'GBP', - minimumFractionDigits: 2, - maximumFractionDigits: 2, - }); -} \ No newline at end of file