mirror of
https://github.com/R0m1k3/LogiFlow.git
synced 2026-10-21 05:58:23 +02:00
Introduce a mobile-friendly phone mode with a bottom navigation bar
Add phone mode functionality with a new bottom navigation component and adjust layout styles for smaller screens. Includes logic for auto-detection and user preference saving for phone mode. Also, redirects authenticated users from `/auth` to the dashboard. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 95e8aab4-f39f-4b48-aa57-a759ec15ba3d Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/95e8aab4-f39f-4b48-aa57-a759ec15ba3d/oL3c3As
This commit is contained in:
1 parent
6f5b5cb054
commit
9930f40105
6 files changed
+397
-16
No files matched your search
@@ -1,13 +1,16 @@
|
||||
import { ReactNode, useState, useEffect } from "react";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useLocation } from "wouter";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { LogOut, Store, Menu, AlertTriangle } from "lucide-react";
|
||||
import { LogOut, Store, Menu, AlertTriangle, Smartphone, Monitor } from "lucide-react";
|
||||
import { useAuthUnified } from "@/hooks/useAuthUnified";
|
||||
import { useIsMobile } from "@/hooks/use-mobile";
|
||||
import { useScreenSize } from "@/hooks/use-screen-size";
|
||||
import { usePhoneMode } from "@/hooks/use-phone-mode";
|
||||
import { StoreProvider } from "@/contexts/StoreContext";
|
||||
import Sidebar from "./Sidebar";
|
||||
import PhoneBottomNav from "./PhoneBottomNav";
|
||||
import WeatherWidget from "./WeatherWidget";
|
||||
import DateWidget from "./DateWidget";
|
||||
import type { Group } from "@shared/schema";
|
||||
@@ -19,9 +22,11 @@ interface LayoutProps {
|
||||
|
||||
export default function Layout({ children }: LayoutProps) {
|
||||
const { user } = useAuthUnified();
|
||||
const [location] = useLocation();
|
||||
const queryClient = useQueryClient();
|
||||
const isMobile = useIsMobile();
|
||||
const { screenSize, isMobileOrTablet, isTablet } = useScreenSize();
|
||||
const { isPhoneMode, setPhoneMode, canUsePhoneMode } = usePhoneMode();
|
||||
|
||||
const [selectedStoreId, setSelectedStoreId] = useState<number | null>(() => {
|
||||
// Restaurer le selectedStoreId depuis localStorage si disponible
|
||||
@@ -120,28 +125,35 @@ export default function Layout({ children }: LayoutProps) {
|
||||
|
||||
return (
|
||||
<StoreProvider value={{ selectedStoreId, setSelectedStoreId, stores, sidebarCollapsed, setSidebarCollapsed, mobileMenuOpen, setMobileMenuOpen, storeInitialized }}>
|
||||
<div className="layout-container flex bg-gray-50">
|
||||
{/* Mobile overlay */}
|
||||
{isMobile && mobileMenuOpen && (
|
||||
<div className={`layout-container flex bg-gray-50 ${isPhoneMode ? 'phone-mode' : ''}`}>
|
||||
{/* Mobile overlay for normal mode */}
|
||||
{!isPhoneMode && isMobile && mobileMenuOpen && (
|
||||
<div
|
||||
className="fixed inset-0 bg-black bg-opacity-50 z-40"
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Sidebar />
|
||||
{/* Sidebar for normal mode */}
|
||||
{!isPhoneMode && <Sidebar />}
|
||||
|
||||
<main className={`flex-1 flex flex-col h-full ${
|
||||
// Marge gauche uniquement si la sidebar est en position fixed (tablet expanded)
|
||||
isMobile ? 'ml-0' : (isTablet && !sidebarCollapsed) ? 'ml-48' : 'ml-0'
|
||||
// Ajustement des marges selon le mode
|
||||
isPhoneMode
|
||||
? 'ml-0 mb-20' // Mode téléphone : pas de marge gauche, marge bas pour bottom nav
|
||||
: isMobile
|
||||
? 'ml-0'
|
||||
: (isTablet && !sidebarCollapsed) ? 'ml-48' : 'ml-0'
|
||||
}`}>
|
||||
{/* Header with mobile menu and store selector */}
|
||||
<header className={`h-16 bg-white border-b border-gray-200 flex items-center justify-between ${
|
||||
<header className={`${
|
||||
isPhoneMode ? 'h-12' : 'h-16'
|
||||
} bg-white border-b border-gray-200 flex items-center justify-between ${
|
||||
isMobileOrTablet ? 'px-3' : 'px-6'
|
||||
}`}>
|
||||
<div className="flex items-center gap-2 sm:gap-4 min-w-0 flex-1">
|
||||
{/* Mobile menu button */}
|
||||
{isMobile && (
|
||||
{/* Mobile menu button (only in normal mode) */}
|
||||
{!isPhoneMode && isMobile && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
@@ -157,13 +169,47 @@ export default function Layout({ children }: LayoutProps) {
|
||||
<div className={`flex items-center ${
|
||||
isMobile ? 'gap-1' : 'gap-3'
|
||||
} min-w-0`}>
|
||||
<WeatherWidget />
|
||||
{!isMobile && <DateWidget />}
|
||||
{/* En mode téléphone, affichage simplifié */}
|
||||
{isPhoneMode ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<WeatherWidget />
|
||||
{/* Phone mode toggle button */}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => setPhoneMode(!isPhoneMode)}
|
||||
className="min-h-[44px] min-w-[44px] p-2 flex-shrink-0"
|
||||
data-testid="button-phone-mode-toggle"
|
||||
title="Basculer vers le mode normal"
|
||||
>
|
||||
<Monitor className="h-4 w-4 text-blue-600" />
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<WeatherWidget />
|
||||
{!isMobile && <DateWidget />}
|
||||
|
||||
{/* Phone mode toggle button */}
|
||||
{canUsePhoneMode && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => setPhoneMode(!isPhoneMode)}
|
||||
className="min-h-[44px] min-w-[44px] p-2 flex-shrink-0"
|
||||
data-testid="button-phone-mode-toggle"
|
||||
title="Basculer vers le mode téléphone"
|
||||
>
|
||||
<Smartphone className="h-4 w-4 text-gray-600" />
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Store selector for admin, directeur, and manager - responsive */}
|
||||
{user && (user.role === 'admin' || user.role === 'directeur' || user.role === 'manager') && stores.length > 0 && (
|
||||
{!isPhoneMode && user && (user.role === 'admin' || user.role === 'directeur' || user.role === 'manager') && stores.length > 0 && (
|
||||
<div className="flex items-center gap-1 sm:gap-2 flex-shrink-0">
|
||||
<Store className="h-4 w-4 text-gray-500 hidden sm:block" />
|
||||
<Select
|
||||
@@ -253,11 +299,16 @@ export default function Layout({ children }: LayoutProps) {
|
||||
)}
|
||||
|
||||
<div className={`flex-1 bg-gray-50 h-full overflow-y-auto ${
|
||||
isMobileOrTablet ? 'p-3' : 'p-6'
|
||||
isPhoneMode
|
||||
? 'p-2' // Mode téléphone : padding réduit
|
||||
: isMobileOrTablet ? 'p-3' : 'p-6'
|
||||
}`}>
|
||||
{children}
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* Bottom navigation for phone mode (only when authenticated) */}
|
||||
{isPhoneMode && user && <PhoneBottomNav user={user} location={location} />}
|
||||
</div>
|
||||
</StoreProvider>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user