Files
shop-admin/src/shared/SideBar.tsx
T
2025-09-21 10:45:52 +03:30

937 lines
35 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { type FC, useEffect } from 'react'
import LogoImage from '../assets/images/logo.svg'
import LogoSmall from '../assets/images/logo-small.svg'
import { useTranslation } from 'react-i18next'
import {
Home2,
Element3,
Receipt21,
TicketDiscount,
DocumentText,
Truck,
Money3,
People,
UserSquare,
Profile,
Messages3,
Chart,
Setting2,
Logout,
Briefcase,
Headphone,
SmsTracking
} from 'iconsax-react'
import SideBarItem from './SideBarItem'
import { useLocation } from 'react-router-dom'
import { useSharedStore } from './store/sharedStore'
import { clx } from '../helpers/utils'
import BlogSubMenu from './components/BlogSubMenu'
import SubMenuItem from './components/SubMenuItem'
import { Pages } from '../config/Pages'
const SideBar: FC = () => {
const { t } = useTranslation('global')
const { openSidebar, setOpenSidebar, hasSubMenu, setSubMenuName, setSubtMenu, subMenuName } = useSharedStore()
const location = useLocation()
const isActive = (name: string) => {
return location.pathname.includes(name)
}
useEffect(() => {
const split = location.pathname.split('/')
if (split[1] === 'dashboard' || split[1] === 'products' || split[1] === 'orders' ||
split[1] === 'blog' || split[1] === 'shipping' || split[1] === 'financial' ||
split[1] === 'sellers' || split[1] === 'buyers' || split[1] === 'users' ||
split[1] === 'tickets' || split[1] === 'reports' || split[1] === 'chat' ||
split[1] === 'contact' || split[1] === 'settings' || split[1] === 'pages' ||
split[1] === 'jobs' || split[1] === 'category') {
setSubMenuName(split[1])
setSubtMenu(true)
} else {
setSubMenuName('')
setSubtMenu(false)
}
}, [location.pathname, setSubMenuName, setSubtMenu])
const iconSizeSideBar = 20
return (
<>
{
openSidebar && <div className='fixed top-0 left-0 right-0 bottom-0 bg-black bg-opacity-50 z-10' onClick={() => setOpenSidebar(false)} />
}
<div
className={clx(
'fixed xl:flex translate-x-[400px] xl:translate-x-0 transition-all ease-in-out opacity-0 invisible xl:visible xl:opacity-100 xl:right-4 right-0 xl:top-4 top-0 xl:bottom-4 bottom-0 xl:rounded-[32px] w-[250px] bg-white flex-col py-12',
openSidebar && 'opacity-100 visible -translate-x-[0px] block z-40',
hasSubMenu && 'w-24 !rounded-tl-none !rounded-bl-none'
)}
>
<div className='flex justify-center'>
{
!hasSubMenu ?
<img src={LogoImage} className='w-[140px]' />
:
<img src={LogoSmall} className='w-7' />
}
</div>
<div className='flex-1 flex flex-col h-full overflow-y-auto no-scrollbar'>
<div className={clx(
'mt-10 px-12 text-header text-sm font-normal',
hasSubMenu && 'px-2 text-center'
)}>
{t('sidebar.menu')}
</div>
<div className='text-xs text-[#8C90A3]'>
{/* داشبورد */}
<SideBarItem
icon={<Home2 variant={isActive('dashboard') ? 'Bold' : 'Outline'} color={isActive('dashboard') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="داشبورد"
isActive={isActive('dashboard')}
link="/dashboard"
activeName='dashboard'
/>
{/* محصولات */}
<SideBarItem
icon={<Element3 variant={isActive('products') ? 'Bold' : 'Outline'} color={isActive('products') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="محصولات"
isActive={isActive('products')}
link="/products"
activeName='products'
/>
{/* سفارشات */}
<SideBarItem
icon={<Receipt21 variant={isActive('orders') ? 'Bold' : 'Outline'} color={isActive('orders') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="سفارشات"
isActive={isActive('orders')}
link="/orders"
activeName='orders'
/>
{/* تخفیف ها */}
<SideBarItem
icon={<TicketDiscount variant={isActive('discounts') ? 'Bold' : 'Outline'} color={isActive('discounts') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="تخفیف ها"
isActive={isActive('discounts')}
link="/discounts"
activeName='discounts'
/>
{/* بلاگ */}
<SideBarItem
icon={<DocumentText variant={isActive('blog') ? 'Bold' : 'Outline'} color={isActive('blog') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="بلاگ"
isActive={isActive('blog')}
link="/blog"
activeName='blog'
/>
{/* روش های ارسال */}
<SideBarItem
icon={<Truck variant={isActive('shipping') ? 'Bold' : 'Outline'} color={isActive('shipping') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="روش های ارسال"
isActive={isActive('shipping')}
link="/shipping"
activeName='shipping'
/>
{/* مالی */}
<SideBarItem
icon={<Money3 variant={isActive('financial') ? 'Bold' : 'Outline'} color={isActive('financial') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="مالی"
isActive={isActive('financial')}
link="/financial"
activeName='financial'
/>
{/* فروشندگان */}
<SideBarItem
icon={<People variant={isActive('sellers') ? 'Bold' : 'Outline'} color={isActive('sellers') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="فروشندگان"
isActive={isActive('sellers')}
link="/sellers"
activeName='sellers'
/>
{/* خریداران */}
<SideBarItem
icon={<UserSquare variant={isActive('buyers') ? 'Bold' : 'Outline'} color={isActive('buyers') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="خریداران"
isActive={isActive('buyers')}
link="/buyers"
activeName='buyers'
/>
{/* کاربران */}
<SideBarItem
icon={<Profile variant={isActive('users') ? 'Bold' : 'Outline'} color={isActive('users') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="کاربران"
isActive={isActive('users')}
link="/users"
activeName='users'
/>
{/* تیکت ها */}
<SideBarItem
icon={<Messages3 variant={isActive('tickets') ? 'Bold' : 'Outline'} color={isActive('tickets') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="تیکت ها"
isActive={isActive('tickets')}
link="/tickets"
activeName='tickets'
/>
{/* گزارش ها */}
<SideBarItem
icon={<Chart variant={isActive('reports') ? 'Bold' : 'Outline'} color={isActive('reports') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="گزارش ها"
isActive={isActive('reports')}
link="/reports"
activeName='reports'
/>
{/* گفت و گو */}
<SideBarItem
icon={<SmsTracking variant={isActive('chat') ? 'Bold' : 'Outline'} color={isActive('chat') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="گفت و گو"
isActive={isActive('chat')}
link="/chat"
activeName='chat'
/>
{/* ارتباط با ما */}
<SideBarItem
icon={<Headphone variant={isActive('contact') ? 'Bold' : 'Outline'} color={isActive('contact') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="ارتباط با ما"
isActive={isActive('contact')}
link="/contact"
activeName='contact'
/>
{/* تنظیمات */}
<SideBarItem
icon={<Setting2 variant={isActive('settings') ? 'Bold' : 'Outline'} color={isActive('settings') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="تنظیمات"
isActive={isActive('settings')}
link="/settings"
activeName='settings'
/>
{/* مدیریت صفحات */}
<SideBarItem
icon={<DocumentText variant={isActive('pages') ? 'Bold' : 'Outline'} color={isActive('pages') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="مدیریت صفحات"
isActive={isActive('pages')}
link="/pages"
activeName='pages'
/>
{/* مشاغل */}
<SideBarItem
icon={<Briefcase variant={isActive('jobs') ? 'Bold' : 'Outline'} color={isActive('jobs') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="مشاغل"
isActive={isActive('jobs')}
link="/jobs"
activeName='jobs'
/>
</div>
<div className='flex-1 flex flex-col justify-end mt-14'>
<div className='text-xs text-[#8C90A3]'>
<SideBarItem
icon={<Logout variant={isActive('logout') ? 'Bold' : 'Outline'} color={isActive('logout') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="خروج"
isActive={isActive('logout')}
link={`#`}
isLogout
activeName=''
/>
</div>
</div>
</div>
</div>
{/* منوی فرعی */}
{
hasSubMenu && (openSidebar || window.innerWidth > 1139) &&
<div className='fixed xl:right-[112px] right-[96px] bg-white z-20 xl:top-4 xl:bottom-4 top-0 bottom-0 rounded-tl-[32px] rounded-bl-[32px] w-[190px] border-r border-border'>
{
subMenuName === 'blog' ? <BlogSubMenu />
: subMenuName === 'dashboard' ? <DashboardSubMenu />
: subMenuName === 'products' ? <ProductsSubMenu />
: subMenuName === 'orders' ? <OrdersSubMenu />
: subMenuName === 'shipping' ? <ShippingSubMenu />
: subMenuName === 'financial' ? <FinancialSubMenu />
: subMenuName === 'sellers' ? <SellersSubMenu />
: subMenuName === 'buyers' ? <BuyersSubMenu />
: subMenuName === 'users' ? <UsersSubMenu />
: subMenuName === 'tickets' ? <TicketsSubMenu />
: subMenuName === 'reports' ? <ReportsSubMenu />
: subMenuName === 'chat' ? <ChatSubMenu />
: subMenuName === 'contact' ? <ContactSubMenu />
: subMenuName === 'settings' ? <SettingsSubMenu />
: subMenuName === 'pages' ? <PagesSubMenu />
: subMenuName === 'jobs' ? <JobsSubMenu />
: subMenuName === 'category' ? <CategorySubMenu />
: null
}
</div>
}
</>
)
}
// کامپوننت‌های SubMenu برای هر بخش - دقیقاً مثل BlogSubMenu
const DashboardSubMenu: FC = () => {
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<Home2
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
داشبورد
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={'تعداد محصولات'}
isActive={isActive('products-count')}
link="/dashboard/products-count"
/>
<SubMenuItem
title={'تعداد سفارشات'}
isActive={isActive('orders-count')}
link="/dashboard/orders-count"
/>
<SubMenuItem
title={'کامنت های خوانده نشده'}
isActive={isActive('unread-comments')}
link="/dashboard/unread-comments"
/>
<SubMenuItem
title={'تعداد کاربران'}
isActive={isActive('users-count')}
link="/dashboard/users-count"
/>
<SubMenuItem
title={'نمودار سفارشات'}
isActive={isActive('orders-chart')}
link="/dashboard/orders-chart"
/>
</div>
</div>
)
}
const ProductsSubMenu: FC = () => {
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<Element3
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
محصولات
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={'دسته بندی ها'}
isActive={isActive('category')}
link={Pages.category.list}
/>
<SubMenuItem
title={'برند ها'}
isActive={isActive('brands')}
link="/products/brands"
/>
<SubMenuItem
title={'تنوع ها'}
isActive={isActive('variants')}
link="/products/variants"
/>
<SubMenuItem
title={'محصولات'}
isActive={isActive('list')}
link="/products/list"
/>
<SubMenuItem
title={'گارانتی ها'}
isActive={isActive('warranties')}
link="/products/warranties"
/>
</div>
</div>
)
}
const OrdersSubMenu: FC = () => {
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<Receipt21
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
سفارشات
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={'لیست سفارشات (فروشندگان)'}
isActive={isActive('sellers')}
link="/orders/sellers"
/>
<SubMenuItem
title={'لیست سفارشات (مدیر)'}
isActive={isActive('admin')}
link="/orders/admin"
/>
<SubMenuItem
title={'سفارشات کنسل شده'}
isActive={isActive('cancelled')}
link="/orders/cancelled"
/>
<SubMenuItem
title={'دسته بندی کنسلی ها'}
isActive={isActive('cancellation-categories')}
link="/orders/cancellation-categories"
/>
<SubMenuItem
title={'دسته بندی مرجوعی ها'}
isActive={isActive('return-categories')}
link="/orders/return-categories"
/>
</div>
</div>
)
}
const ShippingSubMenu: FC = () => {
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<Truck
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
روش های ارسال
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={'لیست روش های ارسال'}
isActive={isActive('methods')}
link="/shipping/methods"
/>
<SubMenuItem
title={'تنظیمات ارسال'}
isActive={isActive('settings')}
link="/shipping/settings"
/>
</div>
</div>
)
}
const FinancialSubMenu: FC = () => {
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<Money3
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
مالی
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={'تراکنش ها'}
isActive={isActive('transactions')}
link="/financial/transactions"
/>
<SubMenuItem
title={'جریمه ها'}
isActive={isActive('penalties')}
link="/financial/penalties"
/>
</div>
</div>
)
}
const SellersSubMenu: FC = () => {
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<People
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
فروشندگان
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={'لیست فروشندگان'}
isActive={isActive('list')}
link="/sellers/list"
/>
<SubMenuItem
title={'کیف پول فروشندگان'}
isActive={isActive('wallet')}
link="/sellers/wallet"
/>
<SubMenuItem
title={'درخواست ها عمده فروشی'}
isActive={isActive('wholesale-requests')}
link="/sellers/wholesale-requests"
/>
<SubMenuItem
title={'ارسال اطلاعیه'}
isActive={isActive('notifications')}
link="/sellers/notifications"
/>
<SubMenuItem
title={'درخواست های ثبت محصول'}
isActive={isActive('product-requests')}
link="/sellers/product-requests"
/>
<SubMenuItem
title={'قرار داد'}
isActive={isActive('contracts')}
link="/sellers/contracts"
/>
<SubMenuItem
title={'آموزش ها'}
isActive={isActive('trainings')}
link="/sellers/trainings"
/>
<SubMenuItem
title={'دسته بندی آموزش ها'}
isActive={isActive('training-categories')}
link="/sellers/training-categories"
/>
</div>
</div>
)
}
const BuyersSubMenu: FC = () => {
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<UserSquare
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
خریداران
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={'لیست خریداران'}
isActive={isActive('list')}
link="/buyers/list"
/>
</div>
</div>
)
}
const UsersSubMenu: FC = () => {
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b pb-10 px-6'>
<Profile
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
کاربران
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={'لیست کاربران'}
isActive={isActive('list')}
link="/users/list"
/>
<SubMenuItem
title={'تعریف نقش'}
isActive={isActive('roles')}
link="/users/roles"
/>
<SubMenuItem
title={'تعریف گروه کاربری'}
isActive={isActive('groups')}
link="/users/groups"
/>
</div>
</div>
)
}
const TicketsSubMenu: FC = () => {
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<Messages3
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
تیکت ها
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={'لیست تیکت ها'}
isActive={isActive('list')}
link="/tickets/list"
/>
</div>
</div>
)
}
const ReportsSubMenu: FC = () => {
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<Chart
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
گزارش ها
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={'گزارش فروش'}
isActive={isActive('sales')}
link="/reports/sales"
/>
<SubMenuItem
title={'گزارش محصولات'}
isActive={isActive('products')}
link="/reports/products"
/>
</div>
</div>
)
}
const ChatSubMenu: FC = () => {
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<SmsTracking
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
گفت و گو
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={'چت بین کاربران'}
isActive={isActive('users')}
link="/chat/users"
/>
<SubMenuItem
title={'چت با مدیر سایت'}
isActive={isActive('admin')}
link="/chat/admin"
/>
</div>
</div>
)
}
const ContactSubMenu: FC = () => {
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<Headphone
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
ارتباط با ما
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={'پیام های دریافتی'}
isActive={isActive('messages')}
link="/contact/messages"
/>
</div>
</div>
)
}
const SettingsSubMenu: FC = () => {
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<Setting2
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
تنظیمات
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={'تنظیمات فروشگاه'}
isActive={isActive('shop')}
link="/settings/shop"
/>
<SubMenuItem
title={'تنظیمات فوتر'}
isActive={isActive('footer')}
link="/settings/footer"
/>
<SubMenuItem
title={'تنظیمات بنرها'}
isActive={isActive('banners')}
link="/settings/banners"
/>
</div>
</div>
)
}
const PagesSubMenu: FC = () => {
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<DocumentText
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
مدیریت صفحات
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={'درباره ما'}
isActive={isActive('about')}
link="/pages/about"
/>
<SubMenuItem
title={'سوالات متداول'}
isActive={isActive('faq')}
link="/pages/faq"
/>
<SubMenuItem
title={'صفحه روش های ارسال'}
isActive={isActive('shipping')}
link="/pages/shipping"
/>
<SubMenuItem
title={'حریم خصوصی'}
isActive={isActive('privacy')}
link="/pages/privacy"
/>
<SubMenuItem
title={'قوانین مرجوعی'}
isActive={isActive('return-policy')}
link="/pages/return-policy"
/>
<SubMenuItem
title={'مشاغل'}
isActive={isActive('jobs')}
link="/pages/jobs"
/>
<SubMenuItem
title={'اسناد'}
isActive={isActive('documents')}
link="/pages/documents"
/>
<SubMenuItem
title={'تعرفه درآمد'}
isActive={isActive('income-tariff')}
link="/pages/income-tariff"
/>
</div>
</div>
)
}
const JobsSubMenu: FC = () => {
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<Briefcase
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
مشاغل
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={'لیست مشاغل'}
isActive={isActive('list')}
link="/jobs/list"
/>
<SubMenuItem
title={'لیست رزومه ها'}
isActive={isActive('resumes')}
link="/jobs/resumes"
/>
</div>
</div>
)
}
const CategorySubMenu: FC = () => {
const location = useLocation()
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<Element3
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
دسته بندی ها
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={'لیست دسته ها'}
isActive={isActive('list')}
link={Pages.category.list}
/>
<SubMenuItem
title={'افزودن دسته جدید'}
isActive={isActive('create')}
link={Pages.category.create}
/>
</div>
</div>
)
}
export default SideBar