import moment from "jalali-moment"; import { useEffect, useRef, useState } from "react"; import Typography from "../components/Typography/Typography"; import { useUserProfileStore } from "../context/zustand-store/userStore"; import { ItemWithSubItems } from "../types/userPermissions"; import { getUserPermissions } from "../utils/getUserAvalableItems"; import { getFaPermissions } from "../utils/getFaPermissions"; import { motion, AnimatePresence } from "framer-motion"; import { MagnifyingGlassIcon, Squares2X2Icon, XMarkIcon, ClockIcon, CalendarIcon, ArrowRightCircleIcon, } from "@heroicons/react/24/outline"; import { checkIsMobile } from "../utils/checkIsMobile"; import { useNavigate } from "@tanstack/react-router"; import { useDashboardTabStore } from "../context/zustand-store/dashboardTabStore"; interface Tab { id: string; title: string; component: React.ComponentType; path: string; icon?: React.ComponentType<{ className?: string }>; } export default function Dashboard() { const { profile } = useUserProfileStore(); const { dashboarTabs, setDashboardTabs, activeTabId, setActiveTabId } = useDashboardTabStore(); const menuItems: ItemWithSubItems[] = getUserPermissions( profile?.permissions ); const [tabs, setTabs] = useState(dashboarTabs || []); const [search, setSearch] = useState(""); const navigate = useNavigate(); useEffect(() => { setTabs(dashboarTabs || []); }, [dashboarTabs]); useEffect(() => { setDashboardTabs(tabs); }, [tabs, setDashboardTabs]); const persianDate = moment().locale("fa").format("dddd D MMMM YYYY"); const [time, setTime] = useState( new Date().toLocaleTimeString("fa-IR", { hour: "2-digit", minute: "2-digit", hour12: false, }) ); useEffect(() => { const interval = setInterval(() => { setTime( new Date().toLocaleTimeString("fa-IR", { hour: "2-digit", minute: "2-digit", hour12: false, }) ); }, 60000); return () => clearInterval(interval); }, []); const openTab = (subItem: ItemWithSubItems["subItems"][0]) => { const existingTab = tabs.find((tab) => tab.path === subItem.path); if (existingTab) { setActiveTabId(existingTab.id); } else { const newTab = { id: `tab-${Date.now()}`, title: getFaPermissions(subItem.name), component: subItem.component, path: subItem.path, }; setTabs((prev) => [...prev, newTab]); setActiveTabId(newTab.id); } }; const closeTab = (id: string, e: React.MouseEvent) => { e.stopPropagation(); const newTabs = tabs.filter((tab) => tab.id !== id); setTabs(newTabs); if (activeTabId === id) { setActiveTabId( newTabs.length > 0 ? newTabs[newTabs.length - 1].id : null ); } }; const closeAllTabs = () => { setTabs([]); setActiveTabId(null); }; const filteredMenuItems = menuItems .map((item) => ({ ...item, subItems: item.subItems.filter( (subItem) => !subItem.path.includes("$") && (search.trim() === "" || getFaPermissions(subItem.name).includes(search.trim())) ), })) .filter((item) => item.subItems.length > 0); function findSubItemByPath( items: ItemWithSubItems[], path: string ): ItemWithSubItems["subItems"][0] | null { for (const item of items) { for (const subItem of item.subItems) { if (subItem.path === path) return subItem; } } return null; } const activeTabObj = tabs.find((tab) => tab.id === activeTabId); const activeComponentItem = activeTabObj && findSubItemByPath(menuItems, activeTabObj.path); const ActiveComponent = activeComponentItem?.component || null; const draggedTabIndex = useRef(null); const onDragStart = (e: React.DragEvent, index: number) => { draggedTabIndex.current = index; e.dataTransfer.effectAllowed = "move"; }; const onDragOver = (e: React.DragEvent) => { e.preventDefault(); }; const onDrop = (e: React.DragEvent, dropIndex: number) => { e.preventDefault(); if ( draggedTabIndex.current === null || draggedTabIndex.current === dropIndex ) return; const newTabs = [...tabs]; const draggedItem = newTabs[draggedTabIndex.current]; newTabs.splice(draggedTabIndex.current, 1); newTabs.splice(dropIndex, 0, draggedItem); draggedTabIndex.current = null; setTabs(newTabs); }; const onDragEnd = () => { draggedTabIndex.current = null; }; return (
داشبورد
setSearch(e.target.value)} className="w-full pr-8 pl-3 py-2 text-xs rounded-lg backdrop-blur-sm bg-white/30 dark:bg-dark-800/30 border border-white/40 dark:border-dark-600/40 text-dark-700 dark:text-dark-200 placeholder:text-dark-400 focus:outline-none focus:ring-1 focus:ring-primary-500/50 focus:bg-white/50 dark:focus:bg-dark-700/50 transition-all duration-200" />
{persianDate} {time}
{filteredMenuItems.length === 0 ? (
موردی یافت نشد هیچ آیتمی با عبارت "{search}" مطابقت ندارد
) : (
{checkIsMobile() ? filteredMenuItems.map(({ fa, icon: Icon, subItems }, index) => { const filteredSubItems = subItems.filter( (item) => !item.path.includes("$") && getFaPermissions(item.name).includes(search.trim()) ); if (filteredSubItems.length === 0) return null; return (

{fa}

{filteredSubItems.map((sub, subIndex) => ( navigate({ to: sub.path })} whileHover={{ scale: 1.03 }} whileTap={{ scale: 0.97 }} className="flex items-center gap-2 cursor-pointer bg-gray-50 dark:bg-dark-700 text-right border border-gray-200 dark:border-dark-600 hover:border-primary-500 dark:hover:border-primary-400 shadow-sm rounded-xl p-3 transition-all duration-200" > {getFaPermissions(sub.name)} ))}
); }) : filteredMenuItems.map(({ fa, icon: Icon, subItems }, index) => (
{fa}
{subItems.map((sub, subIndex) => { const isActive = tabs.some( (tab) => tab.path === sub.path && activeTabId === tab.id ); return ( openTab(sub)} className={`flex items-center gap-1.5 px-2 py-1.5 text-xs rounded-md cursor-pointer transition-all duration-200 focus:outline-none ${ isActive ? "backdrop-blur-sm bg-primary-500/20 dark:bg-primary-400/20 text-primary-700 dark:text-primary-300 " : "hover:backdrop-blur-sm hover:bg-white/30 dark:hover:bg-dark-600/30 border-none" }`} >
{getFaPermissions(sub.name)} ); })}
))}
)}
{tabs.length > 0 && !checkIsMobile() && (
صفحات باز {tabs.length}
{tabs.length > 1 && ( )}
{tabs.map((tab, index) => ( onDragStart(e, index)} onDragOver={onDragOver} onDrop={(e) => onDrop(e, index)} onDragEnd={onDragEnd} initial={{ opacity: 0, x: -10 }} animate={{ opacity: 1, x: 0 }} exit={{ opacity: 0, x: 10 }} transition={{ duration: 0.15 }} onClick={() => setActiveTabId(tab.id)} className={`group flex items-center gap-1.5 px-3 py-1 cursor-pointer transition-all duration-200 border-b-2 focus:outline-none ${ activeTabId === tab.id ? "backdrop-blur-sm bg-primary-500/20 dark:bg-primary-400/20 text-primary-700 dark:text-primary-300 border-primary-500 dark:border-primary-400" : "text-dark-600 dark:text-dark-300 hover:backdrop-blur-sm hover:bg-white/30 dark:hover:bg-dark-600/30 border-transparent hover:border-dark-300 dark:hover:border-dark-500" }`} > {tab.icon && ( )} {tab.title} ))}
{activeTabId && ( {ActiveComponent && } )}
)}
); }