feat: implementar Modo Smart touch-first com comutador bidirecional sem logout
This commit is contained in:
@@ -67,6 +67,13 @@ function wrapWithGuard(
|
||||
</ProtectedRouteByResource>
|
||||
);
|
||||
|
||||
case 'smart':
|
||||
return (
|
||||
<ProtectedRoute>
|
||||
{element}
|
||||
</ProtectedRoute>
|
||||
);
|
||||
|
||||
default:
|
||||
return element;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
|
||||
import React, { useState, useMemo } from "react";
|
||||
import { logger } from "@/utils/logger";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu } from "@/components/ui/sidebar";
|
||||
import { useSidebar } from "@/components/ui/sidebar";
|
||||
import { useUserRole } from "@/hooks/useUserRole";
|
||||
import { useIconStyle } from "@/hooks/useIconStyle";
|
||||
import { useIsMobile } from "@/hooks/use-mobile";
|
||||
import { useUserPermissions } from "@/hooks/useUserPermissions";
|
||||
import { Zap } from "lucide-react";
|
||||
import { usePermissionControl } from "@/hooks/usePermissionControl";
|
||||
import { menuGroups } from "./sidebar/menuConfig";
|
||||
import { AppSidebarMenuItem } from "./sidebar/SidebarMenuItem";
|
||||
|
||||
export function AppSidebar() {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const { setOpenMobile } = useSidebar();
|
||||
const { isAdmin, loading: roleLoading } = useUserRole();
|
||||
const { iconStyle } = useIconStyle();
|
||||
@@ -140,6 +142,41 @@ export function AppSidebar() {
|
||||
return (
|
||||
<Sidebar>
|
||||
<SidebarContent>
|
||||
{/* Banner de atalho para Modo Smart */}
|
||||
<div className="px-3 pt-3 pb-1">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
try {
|
||||
localStorage.setItem('tracksteel_app_mode', 'smart');
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
if (isMobile) setOpenMobile(false);
|
||||
navigate('/smart');
|
||||
}}
|
||||
className="w-full flex items-center justify-between p-2.5 rounded-xl bg-gradient-to-r from-amber-500/15 via-amber-500/10 to-orange-500/10 border border-amber-500/30 hover:border-amber-500/60 transition-all text-left group shadow-sm active:scale-[0.98]"
|
||||
title="Alternar para o Modo Smart (Chão de Fábrica Touch-First)"
|
||||
>
|
||||
<div className="flex items-center gap-2.5">
|
||||
<div className="p-1.5 rounded-lg bg-amber-500/20 text-amber-500 group-hover:bg-amber-500 group-hover:text-white transition-colors">
|
||||
<Zap className="h-4 w-4 fill-amber-500 group-hover:fill-white" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs font-bold text-amber-600 dark:text-amber-400 tracking-wide uppercase">
|
||||
Modo Smart
|
||||
</div>
|
||||
<div className="text-[11px] text-muted-foreground leading-tight">
|
||||
Chão de Fábrica Touch
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span className="text-[10px] font-semibold px-1.5 py-0.5 rounded bg-amber-500/20 text-amber-600 dark:text-amber-300">
|
||||
RÁPIDO
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{menuGroups.map(group => {
|
||||
// Filter admin groups for non-admin users
|
||||
if (!isAdmin && group.name === 'Administração') {
|
||||
|
||||
@@ -1,26 +1,52 @@
|
||||
|
||||
import React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { SidebarProvider, SidebarTrigger } from '@/components/ui/sidebar';
|
||||
import { AppSidebar } from '@/components/AppSidebar';
|
||||
import { ApontamentoAutomaticoListener } from '@/components/expedicao/ApontamentoAutomaticoListener';
|
||||
import { ThemeToggle } from '@/components/ThemeToggle';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Zap } from 'lucide-react';
|
||||
|
||||
interface LayoutProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const Layout = ({ children }: LayoutProps) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleIrParaModoSmart = () => {
|
||||
try {
|
||||
localStorage.setItem('tracksteel_app_mode', 'smart');
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
navigate('/smart');
|
||||
};
|
||||
|
||||
return (
|
||||
<SidebarProvider>
|
||||
<div className="min-h-screen flex w-full">
|
||||
<AppSidebar />
|
||||
<main className="flex-1 overflow-hidden flex flex-col">
|
||||
{/* Header fixo com SidebarTrigger e ThemeToggle */}
|
||||
{/* Header fixo com SidebarTrigger, Modo Smart e ThemeToggle */}
|
||||
<header className="h-14 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 flex items-center justify-between px-4 shrink-0">
|
||||
<div className="flex items-center">
|
||||
<SidebarTrigger />
|
||||
</div>
|
||||
<ThemeToggle />
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleIrParaModoSmart}
|
||||
className="h-9 px-3 gap-2 font-semibold border-amber-500/40 bg-amber-500/10 hover:bg-amber-500/20 text-amber-600 dark:text-amber-400 hover:text-amber-600 dark:hover:text-amber-300 transition-all rounded-full shadow-sm hover:shadow active:scale-95"
|
||||
title="Alternar para o Modo Smart (Chão de Fábrica Touch-First)"
|
||||
>
|
||||
<Zap className="h-4 w-4 fill-amber-500 text-amber-500 animate-pulse" />
|
||||
<span className="text-xs sm:text-sm font-bold tracking-wide">Modo Smart</span>
|
||||
</Button>
|
||||
<ThemeToggle />
|
||||
</div>
|
||||
</header>
|
||||
{/* Conteúdo principal */}
|
||||
<div className="flex-1 overflow-auto">
|
||||
|
||||
Reference in New Issue
Block a user