From f1d6f27e3d58d40c86cab36ae1c0b258e7110eaf Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Tue, 12 Aug 2025 19:44:39 +0000 Subject: [PATCH] Adapt layout and sidebar for responsive mobile experience Introduce a `useResponsive` hook, implement mobile-first sidebar behavior with a toggleable menu, and adjust layout for various screen sizes, along with minor type and deposit value handling in `CustomerOrderForm`. Replit-Commit-Author: Agent Replit-Commit-Session-Id: cc8ba926-557c-4bf1-a2ea-ceabbcf38824 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/cc8ba926-557c-4bf1-a2ea-ceabbcf38824/f2TM8xQ --- client/src/components/CustomerOrderForm.tsx | 8 +- client/src/components/Layout.tsx | 77 +++++++++-- client/src/components/Sidebar.tsx | 134 +++++++++++--------- client/src/hooks/useResponsive.ts | 57 +++++++++ client/src/index.css | 38 ++++++ 5 files changed, 241 insertions(+), 73 deletions(-) create mode 100644 client/src/hooks/useResponsive.ts diff --git a/client/src/components/CustomerOrderForm.tsx b/client/src/components/CustomerOrderForm.tsx index 7f0575c..da78519 100644 --- a/client/src/components/CustomerOrderForm.tsx +++ b/client/src/components/CustomerOrderForm.tsx @@ -99,7 +99,7 @@ export function CustomerOrderForm({ quantity: order?.quantity || 1, supplierId: order?.supplierId || undefined, status: "En attente de Commande", // Statut fixe - deposit: order?.deposit || 0, + deposit: Number(order?.deposit) || 0, isPromotionalPrice: order?.isPromotionalPrice || false, customerNotified: order?.customerNotified || false, groupId: getDefaultGroupId(), // ✅ PRIORITÉ CORRECTE APPLIQUÉE @@ -125,7 +125,7 @@ export function CustomerOrderForm({ selectedStoreId, userHasGroups: !!user?.userGroups, userGroupsLength: user?.userGroups?.length, - userGroups: user?.userGroups?.map(ug => ({ + userGroups: user?.userGroups?.map((ug: any) => ({ groupId: ug.groupId || ug.group?.id, groupName: ug.group?.name, fullGroupData: ug @@ -156,7 +156,7 @@ export function CustomerOrderForm({ contactNumber: data.contactNumber || '', productName: data.productName || '', quantity: data.quantity, - groupId: typeof groupId === 'number' ? groupId : parseInt(groupId.toString()), + groupId: typeof groupId === 'number' ? groupId : parseInt(groupId?.toString() || '1'), isPickup: false, notes: data.notes, deposit: data.deposit || 0, @@ -173,7 +173,7 @@ export function CustomerOrderForm({ // Get available groups for the user const availableGroups = user?.role === 'admin' ? groups - : user?.userGroups?.map(ug => ug.group) || []; + : user?.userGroups?.map((ug: any) => ug.group) || []; // Auto-select group for users respecting admin store selection const currentGroupId = form.getValues('groupId'); diff --git a/client/src/components/Layout.tsx b/client/src/components/Layout.tsx index 6acc5be..99b8f49 100644 --- a/client/src/components/Layout.tsx +++ b/client/src/components/Layout.tsx @@ -2,8 +2,9 @@ import { ReactNode, useState, createContext, useContext } from "react"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Button } from "@/components/ui/button"; -import { LogOut, Store } from "lucide-react"; +import { LogOut, Store, Menu, X } from "lucide-react"; import { useAuthUnified } from "@/hooks/useAuthUnified"; +import { useResponsive } from "@/hooks/useResponsive"; import Sidebar from "./Sidebar"; import type { Group } from "@shared/schema"; @@ -13,6 +14,8 @@ interface StoreContextType { stores: Group[]; sidebarCollapsed: boolean; setSidebarCollapsed: (collapsed: boolean) => void; + mobileMenuOpen: boolean; + setMobileMenuOpen: (open: boolean) => void; } const StoreContext = createContext(undefined); @@ -32,6 +35,8 @@ interface LayoutProps { export default function Layout({ children }: LayoutProps) { const { user } = useAuthUnified(); const queryClient = useQueryClient(); + const { isMobile, isTablet, isDesktop } = useResponsive(); + const [selectedStoreId, setSelectedStoreId] = useState(() => { // Restaurer le selectedStoreId depuis localStorage si disponible const saved = localStorage.getItem('selectedStoreId'); @@ -43,9 +48,12 @@ export default function Layout({ children }: LayoutProps) { const [sidebarCollapsed, setSidebarCollapsed] = useState(() => { // Restaurer l'état de la sidebar depuis localStorage const saved = localStorage.getItem('sidebarCollapsed'); - return saved ? JSON.parse(saved) : false; + // Sur mobile, toujours collapsé par défaut + return saved ? JSON.parse(saved) : isMobile; }); + const [mobileMenuOpen, setMobileMenuOpen] = useState(false); + const { data: stores = [] } = useQuery({ queryKey: ['/api/groups'], enabled: !!user, @@ -56,20 +64,56 @@ export default function Layout({ children }: LayoutProps) { }; return ( - -
- -
+ +
+ {/* Mobile Sidebar Overlay */} + {isMobile && mobileMenuOpen && ( + <> +
setMobileMenuOpen(false)} + /> +
+ +
+ + )} + + {/* Desktop Sidebar */} + {!isMobile && } + +
{/* Header with store selector for admin */} -
+
-

LogiFlow

+ {/* Mobile menu button */} + {isMobile && ( + + )} +

LogiFlow

{/* Store selector for admin - moved to top right */} {user?.role === 'admin' && stores.length > 0 && (
- +