From e7b6a4fd86ec023733eec0428698513e333f978a Mon Sep 17 00:00:00 2001 From: Mqhele-dot <89026892+Mqhele-dot@users.noreply.github.com> Date: Tue, 6 Jan 2026 20:00:21 +0200 Subject: [PATCH 1/9] Redesign home for freelancer hiring --- client/src/pages/home.tsx | 980 +++++++++----------------------------- 1 file changed, 226 insertions(+), 754 deletions(-) diff --git a/client/src/pages/home.tsx b/client/src/pages/home.tsx index 4d6f2d52..13335ee3 100644 --- a/client/src/pages/home.tsx +++ b/client/src/pages/home.tsx @@ -1,793 +1,265 @@ import React from "react"; -import { useQuery } from "@tanstack/react-query"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle, CardFooter } from "@/components/ui/card"; -import { - BarChart, - Bar, - XAxis, - YAxis, - CartesianGrid, - Tooltip, - Legend, - ResponsiveContainer, - PieChart, - Pie, - Cell, -} from "recharts"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { useToast } from "@/hooks/use-toast"; -import TutorialButton from "@/components/ui/tutorial-button"; -import { type InventoryItem, type Category, type InventoryStats } from "@shared/schema"; -import { Skeleton } from "@/components/ui/skeleton"; -import { formatCurrency } from "@/lib/utils"; -import { Link, useLocation } from "wouter"; -import { - BarChart3, - Boxes, - ClipboardList, - Clock, - FileBarChart, - PackageOpen, - QrCode, - Settings, - ShoppingCart, - TrendingUp, - Truck, - Users, - AlertCircle, - Download -} from "lucide-react"; -import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { MapPin, Star, Globe, Filter, Search, CheckCircle2, Briefcase, Zap } from "lucide-react"; -// Define quick access menu items -interface QuickAccessItem { - name: string; - description: string; - icon: React.ReactNode; - path: string; - badge?: string; - badgeColor?: "default" | "secondary" | "destructive" | "outline"; -} +const quickStats = [ + { label: "Skilled pros nearby", value: "128" }, + { label: "Avg. hourly rate", value: "$42/hr" }, + { label: "Median response time", value: "12 min" }, + { label: "Verified freelancers", value: "94%" }, +]; -const quickAccessItems: QuickAccessItem[] = [ - { - name: "Inventory", - description: "Manage your inventory items", - icon: , - path: "/inventory", - }, - { - name: "Orders", - description: "View and process orders", - icon: , - path: "/orders", - badge: "New", - badgeColor: "secondary", - }, - { - name: "Reorder Requests", - description: "Manage reorder requests", - icon: , - path: "/reorder", - badge: "3", - badgeColor: "destructive", - }, - { - name: "Suppliers", - description: "Manage your suppliers", - icon: , - path: "/suppliers", - }, - { - name: "Barcode Scanner", - description: "Scan barcodes to lookup items", - icon: , - path: "/barcode-scanner", - }, - { - name: "Reports", - description: "Generate inventory reports", - icon: , - path: "/reports", - }, - { - name: "Analytics", - description: "Inventory analytics and insights", - icon: , - path: "/reports", - }, - { - name: "Real-time Sync", - description: "Monitor inventory synchronization", - icon: , - path: "/sync-dashboard", - }, +const skillHighlights = ["UI/UX Design", "Mobile Development", "Home Repair", "Video Editing", "Tutoring", "Translation"]; + +const freelancers = [ { - name: "User Roles", - description: "Manage user permissions", - icon: , - path: "/user-roles", + name: "Amira Bello", + title: "Product Designer", + rate: "$65/hr", + distance: "2.1 mi", + rating: 4.9, + reviews: 118, + languages: ["English", "French"], + skills: ["UX Research", "Figma", "Design Systems"], + availability: "Available today", }, { - name: "Settings", - description: "Configure application settings", - icon: , - path: "/settings", + name: "Carlos Nguyen", + title: "Full-stack Developer", + rate: "$58/hr", + distance: "3.4 mi", + rating: 4.8, + reviews: 96, + languages: ["English", "Spanish"], + skills: ["React", "Node.js", "PostgreSQL"], + availability: "Next-day start", }, { - name: "Low Stock Items", - description: "View items needing reorder", - icon: , - path: "/inventory?filter=low_stock", - badge: "Alert", - badgeColor: "destructive", + name: "Mina Okafor", + title: "Event Photographer", + rate: "$120/session", + distance: "1.6 mi", + rating: 5.0, + reviews: 54, + languages: ["English", "Yoruba"], + skills: ["Portraits", "Corporate", "Retouching"], + availability: "Weekend slots", }, { - name: "Desktop App", - description: "Download desktop application", - icon: , - path: "/download", - badge: "New", - badgeColor: "secondary", + name: "Jordan Patel", + title: "Handyman & Home Repair", + rate: "$45/hr", + distance: "4.8 mi", + rating: 4.7, + reviews: 203, + languages: ["English", "Hindi"], + skills: ["Plumbing", "Drywall", "Furniture Assembly"], + availability: "Same-day calls", }, ]; -// Custom colors for charts -const COLORS = [ - "#0088FE", // Blue - "#00C49F", // Green - "#FFBB28", // Yellow - "#FF8042", // Orange - "#8884D8", // Purple - "#FF6B6B", // Pink - "#4CAF50", // Dark Green - "#9C27B0", // Violet +const mapPins = [ + { label: "Designers", count: 24 }, + { label: "Developers", count: 32 }, + { label: "Skilled Trades", count: 18 }, + { label: "Creative", count: 21 }, ]; -// Custom tooltip for charts -const CustomTooltip = ({ active, payload, label }: any) => { - if (active && payload && payload.length) { - return ( -
-

{`${label}`}

- {payload.map((entry: any, index: number) => ( -

- {`${entry.name}: ${entry.value}`} -

- ))} -
- ); - } - return null; -}; - export default function Home() { - const { toast } = useToast(); - - // Fetch inventory items - const { data: inventoryItems, isLoading: itemsLoading } = useQuery({ - queryKey: ["/api/inventory"], - queryFn: async () => { - const response = await fetch("/api/inventory"); - if (!response.ok) { - throw new Error("Failed to fetch inventory items"); - } - return response.json() as Promise; - }, - }); - - // Fetch categories - const { data: categories } = useQuery({ - queryKey: ["/api/categories"], - queryFn: async () => { - const response = await fetch("/api/categories"); - if (!response.ok) { - throw new Error("Failed to fetch categories"); - } - return response.json() as Promise; - }, - }); - - // Fetch inventory stats - const { data: stats, isLoading: statsLoading } = useQuery({ - queryKey: ["/api/inventory/stats"], - queryFn: async () => { - const response = await fetch("/api/inventory/stats"); - if (!response.ok) { - throw new Error("Failed to fetch inventory stats"); - } - return response.json() as Promise; - }, - }); - - // Prepare data for inventory by category chart - const inventoryByCategoryData = React.useMemo(() => { - if (!inventoryItems || !categories) return []; - - const categoryMap = new Map(); - - // Initialize with all categories - categories.forEach(cat => { - categoryMap.set(cat.id, { name: cat.name, count: 0 }); - }); - - // Count items per category - inventoryItems.forEach(item => { - if (item.categoryId) { - const category = categoryMap.get(item.categoryId); - if (category) { - category.count += 1; - } - } - }); - - return Array.from(categoryMap.values()) - .filter(cat => cat.count > 0) // Only include categories with items - .map(cat => ({ - name: cat.name, - items: cat.count - })); - }, [inventoryItems, categories]); - - // Prepare data for inventory value by category chart - const inventoryValueByCategoryData = React.useMemo(() => { - if (!inventoryItems || !categories) return []; - - const categoryMap = new Map(); - - // Initialize with all categories - categories.forEach(cat => { - categoryMap.set(cat.id, { name: cat.name, value: 0 }); - }); - - // Sum value per category - inventoryItems.forEach(item => { - if (item.categoryId) { - const category = categoryMap.get(item.categoryId); - if (category) { - category.value += item.price * item.quantity; - } - } - }); - - return Array.from(categoryMap.values()) - .filter(cat => cat.value > 0) // Only include categories with value - .map(cat => ({ - name: cat.name, - value: cat.value - })); - }, [inventoryItems, categories]); - - // Prepare data for inventory quantity by item chart - const inventoryQuantityByItemData = React.useMemo(() => { - if (!inventoryItems) return []; - - return inventoryItems - .filter(item => item.quantity > 0) // Filter out zero quantity items - .map(item => ({ - name: item.name, - quantity: item.quantity - })) - .sort((a, b) => b.quantity - a.quantity) // Sort by quantity descending - .slice(0, 10); // Take top 10 - }, [inventoryItems]); - - // Prepare data for item value chart - const inventoryValueByItemData = React.useMemo(() => { - if (!inventoryItems) return []; - - return inventoryItems - .map(item => ({ - name: item.name, - value: item.price * item.quantity - })) - .sort((a, b) => b.value - a.value) // Sort by value descending - .slice(0, 10); // Take top 10 - }, [inventoryItems]); - - // Prepare data for status distribution - const statusDistributionData = React.useMemo(() => { - if (!stats) return []; - - return [ - { name: "In Stock", value: stats.totalItems - stats.lowStockItems - stats.outOfStockItems }, - { name: "Low Stock", value: stats.lowStockItems }, - { name: "Out of Stock", value: stats.outOfStockItems } - ].filter(item => item.value > 0); - }, [stats]); - return ( -
-
-
-

Inventory Management System

-

- Complete solution for your business inventory needs -

+
+
+
+
+ Local Freelancer Network +

Hire trusted talent right around the corner.

+

+ Discover verified freelancers by skill, rate, distance, and language. Compare reviews, view availability, + and book the right pro in minutes. +

+
+
+ + +
- -
- - {/* Quick Access Menu */} -
-

Quick Access

-
- {quickAccessItems.map((item, index) => ( - - - -
- {item.icon} - {item.badge && ( - - {item.badge} - - )} -
-
-

{item.name}

-

{item.description}

-
-
-
- +
+
+ + +
+ + +
+
+ {quickStats.map((stat) => ( + + +

{stat.label}

+

{stat.value}

+
+
))}
-
+ - {/* Summary Stats Section */} -
-
- - -
-
-

Total Items

-

- {statsLoading ? : stats?.totalItems || 0} -

-
- -
-
-
- - - -
-
-

Low Stock Items

-

- {statsLoading ? : stats?.lowStockItems || 0} -

-
- +
+ + + + + Live talent map + + View freelancers clustered by skill and distance from you. + + +
+
+
+ {mapPins.map((pin) => ( +
+ + {pin.label} + {pin.count} +
+ ))}
- - - - - -
-
-

Out of Stock

-

- {statsLoading ? : stats?.outOfStockItems || 0} -

+
+
+

3.2 mi radius

+

92 freelancers active now

- -
- - - - - -
-
-

Total Value

-

- {statsLoading ? - : - formatCurrency(stats?.inventoryValue || 0) - } -

+
+

Avg. rating 4.8

+

12 new reviews today

-
- - -
-
+
+
+
-
-

Inventory Analytics

-

- Visual insights into your inventory data -

-
+ + + Recommended filters + Refine by project type, budget, and language. + + +
+

Popular skills

+
+ {skillHighlights.map((skill) => ( + {skill} + ))} +
+
+
+

Budget range

+
+ Under $50/hr + $50 - $100/hr + Fixed price +
+
+
+

Language preference

+
+ English + Spanish + French + Mandarin +
+
+ +
+
+
- -
- - Overview - Categories - Items - +
+
+
+

Freelancers near you

+

Compare rates, availability, reviews, and languages at a glance.

+
+
- - -
- - - Inventory Status Distribution - - Distribution of items by stock status - - - - {statsLoading ? ( -
- -
- ) : ( - - - `${name}: ${(percent * 100).toFixed(0)}%`} - > - {statusDistributionData.map((entry, index) => ( - - ))} - - } /> - - - - )} -
-
- - - - Items by Category - - Number of inventory items per category - - - - {itemsLoading ? ( -
- +
+ {freelancers.map((freelancer) => ( + + +
+
+ {freelancer.name} + {freelancer.title}
- ) : ( - - - - - - } /> - - - - - )} - - -
- - - - - - Inventory Value by Category - - Total value of inventory items per category - - - - {itemsLoading ? ( -
- + + + {freelancer.rating} + +
+
+ {freelancer.rate} + {freelancer.distance} away + {freelancer.languages.join(", ")}
- ) : ( - - - - - `$${value}`} - /> - [`$${value}`, "Value"]} - content={} - /> - - - - - )} -
-
-
- - -
- - - Top Items by Quantity - - Inventory items with highest quantity in stock - - - {itemsLoading ? ( -
- + +
+ {freelancer.skills.map((skill) => ( + {skill} + ))} +
+
+
+ + {freelancer.reviews} reviews
- ) : ( - - - - - - value.length > 15 ? `${value.substring(0, 15)}...` : value - } - /> - } /> - - - - - )} - - - - - - Top Items by Value - - Inventory items with highest total value - - - - {itemsLoading ? ( -
- +
+ + {freelancer.availability}
- ) : ( - - - - `$${value}`} - /> - - value.length > 15 ? `${value.substring(0, 15)}...` : value - } - /> - [`$${value}`, "Value"]} - content={} - /> - - - - - )} +
+
+ + +
-
- - - - {/* Recent Activity and Alerts Section */} -
-

Recent Activity & Alerts

-
- - - - Recent Activities - - - - -
- {statsLoading ? ( -
- - - -
- ) : ( - <> -
-
- -
-
-

New inventory items added

-

10 new items were added to Electronics category

-
-
2 hours ago
-
- -
-
- -
-
-

Low stock alert triggered

-

3 items have reached their reorder point

-
-
5 hours ago
-
- -
-
- -
-
-

Order completed

-

Order #1234 has been fulfilled and shipped

-
-
Yesterday
-
- - )} -
-
-
- - - - - Upcoming Tasks - - - - -
- {statsLoading ? ( -
- - - -
- ) : ( - <> -
-
- -
-
-

Critical: 3 items out of stock

-

Please process reorder requests immediately

-
-
- High -
-
- -
-
- -
-
-

Inventory audit scheduled

-

Complete quarterly inventory audit by Friday

-
-
- Medium -
-
- -
-
- -
-
-

Generate monthly report

-

End of month inventory and sales report needed

-
-
- Normal -
-
- - )} -
-
-
-
-
- - {/* App Information Footer */} -
-
-
-

Inventory Management System

-

Version 1.0.0 | Desktop App Available

-
-
- - - -
+ ))}
-
+
+ +
+ + + Verified credentials + We verify licenses, portfolios, and local references. + + + + + Transparent pricing + Compare rates and fixed bids with no hidden fees. + + + + + Multilingual support + Filter by language to match your communication needs. + + +
); -} \ No newline at end of file +} From ee33f200634b4d536a2e60089584124e335a9cde Mon Sep 17 00:00:00 2001 From: Mqhele-dot <89026892+Mqhele-dot@users.noreply.github.com> Date: Tue, 6 Jan 2026 20:28:19 +0200 Subject: [PATCH 2/9] Rebrand app for freelancer marketplace --- client/src/App.tsx | 99 +- client/src/components/electron/title-bar.tsx | 18 +- client/src/components/layout/title-bar.tsx | 17 +- client/src/components/sidebar.tsx | 109 +- client/src/pages/auth-page.tsx | 985 ++----------------- client/src/pages/discover.tsx | 67 ++ client/src/pages/jobs.tsx | 65 ++ client/src/pages/messages.tsx | 59 ++ client/src/pages/profile.tsx | 839 ++-------------- client/src/pages/reviews.tsx | 48 + client/src/pages/settings.tsx | 161 ++- 11 files changed, 542 insertions(+), 1925 deletions(-) create mode 100644 client/src/pages/discover.tsx create mode 100644 client/src/pages/jobs.tsx create mode 100644 client/src/pages/messages.tsx create mode 100644 client/src/pages/reviews.tsx diff --git a/client/src/App.tsx b/client/src/App.tsx index 20dc8019..66dadae3 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,47 +1,31 @@ -import React from "react"; +import React, { useEffect } from "react"; import { Switch, Route } from "wouter"; -import { queryClient } from "./lib/queryClient"; import { QueryClientProvider } from "@tanstack/react-query"; -import { Toaster } from "@/components/ui/toaster"; -import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Button } from "@/components/ui/button"; +import { Toaster } from "@/components/ui/toaster"; import { RefreshCw } from "lucide-react"; -import NotFound from "@/pages/not-found"; -import Dashboard from "@/pages/dashboard"; -import Inventory from "@/pages/inventory"; -import InventoryItemDetail from "@/pages/inventory-item"; -import OrdersPage from "@/pages/orders"; -import SuppliersPage from "@/pages/suppliers"; -import Reports from "@/pages/reports"; -import SettingsPage from "@/pages/settings"; -import UserRolesPage from "@/pages/user-roles"; -import Home from "@/pages/home"; -import ReorderPage from "@/pages/reorder"; -import AuthPage from "@/pages/auth-page"; -import BarcodeScannerPage from "@/pages/barcode-scanner-page"; -import RealTimeUpdatesPage from "@/pages/real-time-updates-page"; -import SyncTestPage from "@/pages/sync-test-page"; -import SyncDashboard from "@/pages/sync-dashboard"; -import DownloadPage from "@/pages/download"; -import BillingPage from "@/pages/billing"; -import ProfilePage from "@/pages/profile"; -import ImageRecognitionPage from "@/pages/image-recognition-page"; -import DocumentExtractorPage from "@/pages/document-extractor-page"; -import WarehousesPage from "@/pages/warehouses"; +import { queryClient } from "./lib/queryClient"; import { ThemeProvider } from "@/components/theme-provider"; -import { useState, useEffect } from "react"; import { TutorialProvider } from "@/contexts/tutorial-context"; -import { TutorialSteps } from "@/components/tutorial/tutorial-steps"; import { AuthProvider } from "@/hooks/use-auth"; import { ProtectedRoute } from "@/lib/protected-route"; import { isElectronEnvironment } from "./lib/electron-bridge"; import { ElectronProvider } from "./contexts/electron-provider"; -import { TitleBar, UpdateNotification } from "./components/electron"; +import { UpdateNotification } from "./components/electron"; import { DesktopLayout } from "./components/layout/desktop-layout"; +import NotFound from "@/pages/not-found"; +import Home from "@/pages/home"; +import Discover from "@/pages/discover"; +import JobsPage from "@/pages/jobs"; +import MessagesPage from "@/pages/messages"; +import ReviewsPage from "@/pages/reviews"; +import ProfilePage from "@/pages/profile"; +import SettingsPage from "@/pages/settings"; +import AuthPage from "@/pages/auth-page"; -// Error boundary component -class ErrorBoundary extends React.Component<{children: React.ReactNode}, {hasError: boolean, error: Error | null}> { - constructor(props: {children: React.ReactNode}) { +class ErrorBoundary extends React.Component<{ children: React.ReactNode }, { hasError: boolean; error: Error | null }> { + constructor(props: { children: React.ReactNode }) { super(props); this.state = { hasError: false, error: null }; } @@ -64,11 +48,7 @@ class ErrorBoundary extends React.Component<{children: React.ReactNode}, {hasErr
{this.state.error?.message || "An unexpected error occurred"}
- @@ -86,25 +66,12 @@ function Router() { return ( - - - - - - - - - - - - - - - + + + + - - - + @@ -120,23 +87,15 @@ function AppLayout({ children }: { children: React.ReactNode }) { ); } -// Function to set up Electron-specific features function setupElectronApp() { if (isElectronEnvironment()) { - // Add a class to the HTML element to allow for Electron-specific styling - document.documentElement.classList.add('electron-app'); - - // Disable drag and drop file behavior that may interfere with the app - document.addEventListener('dragover', (e) => e.preventDefault()); - document.addEventListener('drop', (e) => e.preventDefault()); - - // Override the context menu for custom behavior if needed - // document.addEventListener('contextmenu', (e) => e.preventDefault()); + document.documentElement.classList.add("electron-app"); + document.addEventListener("dragover", (e) => e.preventDefault()); + document.addEventListener("drop", (e) => e.preventDefault()); } } function App() { - // Set up Electron-specific HTML classes when in Electron environment useEffect(() => { setupElectronApp(); }, []); @@ -154,18 +113,12 @@ function App() { {(params) => { - // Don't wrap non-auth routes with AppLayout const pathname = params["*"] || ""; if (pathname === "auth") return null; - return ( - - - - ); + return ; }}
- diff --git a/client/src/components/electron/title-bar.tsx b/client/src/components/electron/title-bar.tsx index f1ea4cec..2c845085 100644 --- a/client/src/components/electron/title-bar.tsx +++ b/client/src/components/electron/title-bar.tsx @@ -1,13 +1,13 @@ -import React from 'react'; -import { useElectron } from '../../contexts/electron-provider'; -import { X, Minus, Square } from 'lucide-react'; -import { Button } from '@/components/ui/button'; +import React from "react"; +import { useElectron } from "../../contexts/electron-provider"; +import { X, Minus, Square } from "lucide-react"; +import { Button } from "@/components/ui/button"; interface TitleBarProps { title?: string; } -export const TitleBar: React.FC = ({ title = 'Inventory Management System' }) => { +export const TitleBar: React.FC = ({ title = "SkillRadius · Local Freelancer Marketplace" }) => { const { isElectron, electron } = useElectron(); if (!isElectron) { @@ -16,19 +16,19 @@ export const TitleBar: React.FC = ({ title = 'Inventory Managemen const handleMinimize = () => { if (electron) { - electron.invoke('window-minimize'); + electron.invoke("window-minimize"); } }; const handleMaximize = () => { if (electron) { - electron.invoke('window-maximize'); + electron.invoke("window-maximize"); } }; const handleClose = () => { if (electron) { - electron.invoke('window-close'); + electron.invoke("window-close"); } }; @@ -71,4 +71,4 @@ export const TitleBar: React.FC = ({ title = 'Inventory Managemen
); -}; \ No newline at end of file +}; diff --git a/client/src/components/layout/title-bar.tsx b/client/src/components/layout/title-bar.tsx index f64b16d9..5d035489 100644 --- a/client/src/components/layout/title-bar.tsx +++ b/client/src/components/layout/title-bar.tsx @@ -1,32 +1,31 @@ -import React from 'react'; -import { Minus, Square, X } from 'lucide-react'; -import { useElectron } from '@/contexts/electron-provider'; +import React from "react"; +import { Minus, Square, X } from "lucide-react"; +import { useElectron } from "@/contexts/electron-provider"; export function TitleBar() { const { isElectron, isMaximized, toggleMaximize, minimizeWindow, closeWindow } = useElectron(); - // Only show the custom title bar in Electron environment if (!isElectron) return null; return (
-
InvTrack - Inventory Management System
+
SkillRadius · Local Freelancer Marketplace
- - -
); -} \ No newline at end of file +} diff --git a/client/src/components/sidebar.tsx b/client/src/components/sidebar.tsx index 3b9bd236..66a10292 100644 --- a/client/src/components/sidebar.tsx +++ b/client/src/components/sidebar.tsx @@ -2,7 +2,18 @@ import { Link, useLocation } from "wouter"; import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; import { useTheme } from "@/components/theme-provider"; -import { Archive, BarChart3, Building, ChevronRight, FileText, Home, Moon, Settings, ShoppingCart, Sun, Users, X, LayoutDashboard, RefreshCw, QrCode, Activity, Zap, FileUp, Camera } from "lucide-react"; +import { + Briefcase, + Home, + Map, + MessageSquare, + Moon, + Settings, + Star, + Sun, + User, + X, +} from "lucide-react"; interface SidebarProps { open: boolean; @@ -17,7 +28,7 @@ export default function Sidebar({ open, setOpen }: SidebarProps) { return location === path; }; - const NavItem = ({ path, icon, children }: { path: string, icon: React.ReactNode, children: React.ReactNode }) => { + const NavItem = ({ path, icon, children }: { path: string; icon: React.ReactNode; children: React.ReactNode }) => { return (
{icon} @@ -37,99 +48,63 @@ export default function Sidebar({ open, setOpen }: SidebarProps) { return ( <> - {/* Mobile backdrop */} - {open && ( -
setOpen(false)} - /> - )} + {open &&
setOpen(false)} />} - {/* Sidebar */}