324 lines
11 KiB
TypeScript
324 lines
11 KiB
TypeScript
|
|
import React, { useState } from "react";
|
||
|
|
import { View } from "../types";
|
||
|
|
import DashboardDayView from "../components/dashboard/DashboardDayView";
|
||
|
|
import DashboardSellerView from "../components/dashboard/DashboardSellerView";
|
||
|
|
import OrdersView from "../components/dashboard/OrdersView";
|
||
|
|
import ProductsSoldView from "../components/dashboard/ProductsSoldView";
|
||
|
|
import PreorderView from "../components/dashboard/PreorderView";
|
||
|
|
import ConfirmDialog from "../components/ConfirmDialog";
|
||
|
|
import { shoppingService } from "../src/services/shopping.service";
|
||
|
|
|
||
|
|
interface SalesDashboardViewProps {
|
||
|
|
onNavigate: (view: View) => void;
|
||
|
|
onNewOrder?: () => void;
|
||
|
|
}
|
||
|
|
|
||
|
|
const SalesDashboardView: React.FC<SalesDashboardViewProps> = ({
|
||
|
|
onNavigate,
|
||
|
|
onNewOrder,
|
||
|
|
}) => {
|
||
|
|
const [activeTab, setActiveTab] = useState("dashboard");
|
||
|
|
const [showNewOrderDialog, setShowNewOrderDialog] = useState(false);
|
||
|
|
const [showContinueOrNewDialog, setShowContinueOrNewDialog] = useState(false);
|
||
|
|
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
|
||
|
|
|
||
|
|
// Verificar se há carrinho (itens no carrinho)
|
||
|
|
const hasCartItems = () => {
|
||
|
|
return localStorage.getItem("cart");
|
||
|
|
};
|
||
|
|
|
||
|
|
// Verificar se há dados do pedido atual
|
||
|
|
const hasOrderData = () => {
|
||
|
|
const hasCart = localStorage.getItem("cart");
|
||
|
|
const hasCustomer = localStorage.getItem("customer");
|
||
|
|
const hasAddress = localStorage.getItem("address");
|
||
|
|
const hasPaymentPlan = localStorage.getItem("paymentPlan");
|
||
|
|
const hasBilling = localStorage.getItem("billing");
|
||
|
|
const hasDataDelivery = localStorage.getItem("dataDelivery");
|
||
|
|
const hasInvoiceStore = localStorage.getItem("invoiceStore");
|
||
|
|
const hasPartner = localStorage.getItem("partner");
|
||
|
|
|
||
|
|
return (
|
||
|
|
hasCart ||
|
||
|
|
hasCustomer ||
|
||
|
|
hasAddress ||
|
||
|
|
hasPaymentPlan ||
|
||
|
|
hasBilling ||
|
||
|
|
hasDataDelivery ||
|
||
|
|
hasInvoiceStore ||
|
||
|
|
hasPartner
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleNewOrderClick = () => {
|
||
|
|
// Se houver carrinho, perguntar se quer continuar ou iniciar novo
|
||
|
|
if (hasCartItems()) {
|
||
|
|
setShowContinueOrNewDialog(true);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Se não houver carrinho mas houver outros dados, mostrar confirmação normal
|
||
|
|
if (hasOrderData()) {
|
||
|
|
setShowNewOrderDialog(true);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Se não houver nenhum dado, limpar direto sem confirmação
|
||
|
|
if (onNewOrder) {
|
||
|
|
onNewOrder();
|
||
|
|
} else {
|
||
|
|
// Se não tiver onNewOrder, fazer a limpeza localmente
|
||
|
|
shoppingService.clearShoppingData();
|
||
|
|
onNavigate(View.PRODUCT_SEARCH);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleContinueOrder = () => {
|
||
|
|
// Fechar o dialog e navegar para /sales/home (já estamos na dashboard, apenas fechar)
|
||
|
|
setShowContinueOrNewDialog(false);
|
||
|
|
// Se já estamos na dashboard, não precisa navegar, apenas fechar o dialog
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleStartNewOrder = () => {
|
||
|
|
// Fechar o dialog de continuar/iniciar e abrir o de confirmação
|
||
|
|
setShowContinueOrNewDialog(false);
|
||
|
|
setShowNewOrderDialog(true);
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleConfirmNewOrder = () => {
|
||
|
|
if (onNewOrder) {
|
||
|
|
onNewOrder();
|
||
|
|
} else {
|
||
|
|
// Se não tiver onNewOrder, fazer a limpeza localmente
|
||
|
|
shoppingService.clearShoppingData();
|
||
|
|
onNavigate(View.PRODUCT_SEARCH);
|
||
|
|
}
|
||
|
|
setShowNewOrderDialog(false);
|
||
|
|
};
|
||
|
|
|
||
|
|
const sidebarItems = [
|
||
|
|
{
|
||
|
|
id: "new",
|
||
|
|
label: "Novo pedido",
|
||
|
|
primary: true,
|
||
|
|
action: () => onNavigate(View.PRODUCT_SEARCH),
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: "dashboard",
|
||
|
|
label: "Dashboard Venda dia",
|
||
|
|
icon: "M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: "dashboardseller",
|
||
|
|
label: "Dashboard Vendedor",
|
||
|
|
icon: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: "orders",
|
||
|
|
label: "Pedidos de venda",
|
||
|
|
icon: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: "product-order",
|
||
|
|
label: "Produtos Vendidos",
|
||
|
|
icon: "M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: "preorder",
|
||
|
|
label: "Orçamentos pendentes",
|
||
|
|
icon: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z",
|
||
|
|
primary: false,
|
||
|
|
},
|
||
|
|
];
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="flex h-full bg-[#f8fafc] relative">
|
||
|
|
{/* Overlay para mobile quando sidebar está aberto */}
|
||
|
|
{isSidebarOpen && (
|
||
|
|
<div
|
||
|
|
className="fixed inset-0 bg-black/50 z-40 lg:hidden"
|
||
|
|
onClick={() => setIsSidebarOpen(false)}
|
||
|
|
/>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* Sidebar Modernizada - Drawer em mobile, sidebar em desktop */}
|
||
|
|
<aside
|
||
|
|
className={`fixed lg:relative inset-y-0 left-0 z-50 lg:z-auto w-72 bg-white border-r border-slate-200 flex flex-col p-4 lg:p-6 overflow-y-auto transform transition-transform duration-300 ease-out ${
|
||
|
|
isSidebarOpen ? "translate-x-0" : "-translate-x-full lg:translate-x-0"
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
{/* Botão fechar em mobile */}
|
||
|
|
<div className="flex justify-end mb-4 lg:hidden">
|
||
|
|
<button
|
||
|
|
onClick={() => setIsSidebarOpen(false)}
|
||
|
|
className="p-2 text-slate-400 hover:text-slate-600 rounded-lg"
|
||
|
|
>
|
||
|
|
<svg
|
||
|
|
className="w-6 h-6"
|
||
|
|
fill="none"
|
||
|
|
stroke="currentColor"
|
||
|
|
viewBox="0 0 24 24"
|
||
|
|
>
|
||
|
|
<path
|
||
|
|
strokeLinecap="round"
|
||
|
|
strokeLinejoin="round"
|
||
|
|
strokeWidth="2"
|
||
|
|
d="M6 18L18 6M6 6l12 12"
|
||
|
|
/>
|
||
|
|
</svg>
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="mb-6 lg:mb-8">
|
||
|
|
<button
|
||
|
|
onClick={() => {
|
||
|
|
handleNewOrderClick();
|
||
|
|
setIsSidebarOpen(false);
|
||
|
|
}}
|
||
|
|
className="w-full bg-orange-500 text-white p-3 lg:p-4 rounded-2xl font-extrabold uppercase text-xs tracking-widest shadow-lg shadow-orange-500/20 hover:bg-orange-600 transition-all flex items-center justify-center group touch-manipulation"
|
||
|
|
>
|
||
|
|
<svg
|
||
|
|
className="w-5 h-5 mr-2 group-hover:rotate-90 transition-transform"
|
||
|
|
fill="none"
|
||
|
|
stroke="currentColor"
|
||
|
|
viewBox="0 0 24 24"
|
||
|
|
>
|
||
|
|
<path
|
||
|
|
strokeLinecap="round"
|
||
|
|
strokeLinejoin="round"
|
||
|
|
strokeWidth="2.5"
|
||
|
|
d="M12 4v16m8-8H4"
|
||
|
|
/>
|
||
|
|
</svg>
|
||
|
|
Novo Pedido
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<nav className="flex-1 space-y-2">
|
||
|
|
{sidebarItems.slice(1).map((item) => (
|
||
|
|
<button
|
||
|
|
key={item.id}
|
||
|
|
onClick={() => {
|
||
|
|
if (item.action) {
|
||
|
|
item.action();
|
||
|
|
} else {
|
||
|
|
setActiveTab(item.id);
|
||
|
|
}
|
||
|
|
setIsSidebarOpen(false); // Fechar sidebar em mobile após seleção
|
||
|
|
}}
|
||
|
|
className={`w-full flex items-center px-4 py-3 lg:py-4 rounded-2xl text-sm font-bold transition-all touch-manipulation ${
|
||
|
|
activeTab === item.id
|
||
|
|
? "bg-[#002147] text-white shadow-xl shadow-blue-900/10"
|
||
|
|
: item.id === "preorder"
|
||
|
|
? "text-blue-600 hover:bg-blue-50 border border-blue-200"
|
||
|
|
: "text-slate-500 hover:bg-slate-50"
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
<svg
|
||
|
|
className="w-5 h-5 mr-3"
|
||
|
|
fill="none"
|
||
|
|
stroke="currentColor"
|
||
|
|
viewBox="0 0 24 24"
|
||
|
|
>
|
||
|
|
<path
|
||
|
|
strokeLinecap="round"
|
||
|
|
strokeLinejoin="round"
|
||
|
|
strokeWidth="2"
|
||
|
|
d={item.icon}
|
||
|
|
/>
|
||
|
|
</svg>
|
||
|
|
{item.label}
|
||
|
|
</button>
|
||
|
|
))}
|
||
|
|
</nav>
|
||
|
|
</aside>
|
||
|
|
|
||
|
|
{/* Botão para abrir sidebar em mobile */}
|
||
|
|
<button
|
||
|
|
onClick={() => setIsSidebarOpen(true)}
|
||
|
|
className="fixed top-20 left-4 z-30 lg:hidden bg-white p-3 rounded-xl shadow-lg border border-slate-200 text-slate-600 hover:bg-slate-50 transition-all touch-manipulation"
|
||
|
|
>
|
||
|
|
<svg
|
||
|
|
className="w-6 h-6"
|
||
|
|
fill="none"
|
||
|
|
stroke="currentColor"
|
||
|
|
viewBox="0 0 24 24"
|
||
|
|
>
|
||
|
|
<path
|
||
|
|
strokeLinecap="round"
|
||
|
|
strokeLinejoin="round"
|
||
|
|
strokeWidth="2"
|
||
|
|
d="M4 6h16M4 12h16M4 18h16"
|
||
|
|
/>
|
||
|
|
</svg>
|
||
|
|
</button>
|
||
|
|
|
||
|
|
{/* Área de Conteúdo */}
|
||
|
|
<main className="flex-1 p-3 lg:p-6 overflow-auto custom-scrollbar">
|
||
|
|
<div className="max-w-[1400px] mx-auto">
|
||
|
|
{activeTab === "dashboard" && <DashboardDayView />}
|
||
|
|
{activeTab === "orders" && <OrdersView />}
|
||
|
|
{activeTab === "dashboardseller" && <DashboardSellerView />}
|
||
|
|
{activeTab === "product-order" && <ProductsSoldView />}
|
||
|
|
{activeTab === "preorder" && <PreorderView />}
|
||
|
|
</div>
|
||
|
|
</main>
|
||
|
|
|
||
|
|
{/* Dialog - Continuar ou Iniciar Novo Pedido */}
|
||
|
|
<ConfirmDialog
|
||
|
|
isOpen={showContinueOrNewDialog}
|
||
|
|
onClose={handleContinueOrder}
|
||
|
|
onConfirm={handleStartNewOrder}
|
||
|
|
type="info"
|
||
|
|
title="Carrinho Existente"
|
||
|
|
message={
|
||
|
|
<>
|
||
|
|
Você já possui um carrinho com itens.
|
||
|
|
<br />
|
||
|
|
<br />
|
||
|
|
Deseja iniciar um novo pedido e limpar todos os dados do pedido
|
||
|
|
atual?
|
||
|
|
</>
|
||
|
|
}
|
||
|
|
confirmText="Iniciar Novo Pedido"
|
||
|
|
cancelText="Cancelar"
|
||
|
|
/>
|
||
|
|
|
||
|
|
{/* Dialog de Confirmação - Novo Pedido */}
|
||
|
|
<ConfirmDialog
|
||
|
|
isOpen={showNewOrderDialog}
|
||
|
|
onClose={() => setShowNewOrderDialog(false)}
|
||
|
|
onConfirm={handleConfirmNewOrder}
|
||
|
|
type="warning"
|
||
|
|
title="Novo Pedido"
|
||
|
|
message={
|
||
|
|
<>
|
||
|
|
Deseja iniciar um novo pedido?
|
||
|
|
<br />
|
||
|
|
<br />
|
||
|
|
<span className="text-sm font-bold text-slate-700">
|
||
|
|
Todos os dados do pedido atual serão perdidos:
|
||
|
|
</span>
|
||
|
|
<ul className="text-xs text-slate-600 mt-2 space-y-1 list-disc list-inside">
|
||
|
|
<li>Itens do carrinho</li>
|
||
|
|
<li>Dados do cliente</li>
|
||
|
|
<li>Endereço de entrega</li>
|
||
|
|
<li>Plano de pagamento</li>
|
||
|
|
<li>Dados financeiros</li>
|
||
|
|
<li>Informações de entrega</li>
|
||
|
|
</ul>
|
||
|
|
<br />
|
||
|
|
<span className="text-xs text-slate-400 block">
|
||
|
|
Esta ação não pode ser desfeita.
|
||
|
|
</span>
|
||
|
|
</>
|
||
|
|
}
|
||
|
|
confirmText="Sim, Iniciar Novo Pedido"
|
||
|
|
cancelText="Cancelar"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
export default SalesDashboardView;
|