sidebar change
deploy to danak / build_and_deploy (push) Has been cancelled

This commit is contained in:
hamid zarghami
2026-07-19 09:17:12 +03:30
parent a335f2b66c
commit 1fb0091aa2
25 changed files with 1008 additions and 1376 deletions
+6 -4
View File
@@ -87,10 +87,12 @@ Dynamic routes use string concat: `Pages.customer.update + ":id"`.
## Sidebar & submenu
- Main items: `SideBarItem` in `SideBar.tsx` with `link`, `isActive`, `activeName`
- Features with sub-nav: add segment to `SideBarItemHasSubMenu` in `src/config/SideBarSubMenu.ts`, create `{Feature}SubMenu.tsx` in `src/shared/components/`, render it in the `subMenuName === "..."` block at bottom of `SideBar.tsx`
- Submenu items use `SubMenuItem` with `Pages.*` links
- `subMenuName` is derived from first URL segment (`location.pathname.split("/")[1]`)
- Main sidebar shows **group** items (`menu`, `financial`, `other`, `content`, …) via `SideBarItem` with `name` matching the group key
- Each group opens a side panel: `{Group}SubMenu.tsx` in `src/shared/components/` (e.g. `MenuSubMenu.tsx`)
- Map URL → group in `getSubMenuNameFromPath` (`src/config/SideBarSubMenu.ts`)
- Flat links inside a group: `SubMenuItem`
- Nested feature menus inside a group: `SubMenuAccordion` (arrow open/close) wrapping `SubMenuItem` children
- `subMenuName` comes from the group key, not the feature path segment
## Conventions
+4 -4
View File
@@ -58,10 +58,10 @@ import CouponsList from "../pages/coupons/List";
**Multi-page feature** — also:
1. Add `"coupons"` to `SideBarItemHasSubMenu` in `src/config/SideBarSubMenu.ts`
2. Create `src/shared/components/CouponsSubMenu.tsx` (copy `CustomerSubMenu.tsx`)
3. Import and add branch in `SideBar.tsx`: `subMenuName === "coupons" ? <CouponsSubMenu /> : ...`
4. Point main sidebar link to list path; first URL segment must match `activeName` / submenu key
1. Add the features URL segment → group mapping in `getSubMenuNameFromPath` / `pathSegmentToSubMenu` (`src/config/SideBarSubMenu.ts`)
2. Add links under the matching group SubMenu (e.g. `MenuSubMenu.tsx`) using `SubMenuItem`
3. If the feature has nested pages, wrap them in `SubMenuAccordion` (arrow open/close) inside that group SubMenu
4. Do not add a new top-level sidebar group unless the feature is a new section (reseller/dmenu-style)
## 5. Translations
+57 -9
View File
@@ -1,11 +1,59 @@
export const SideBarItemHasSubMenu = [
"services",
"customers",
"receipts",
"users",
"tickets",
"learning",
"blog",
"support",
"accessLogs",
"menu",
"financial",
"other",
"content",
"reseller",
"dmenu",
"dkala",
"dpage",
"dmail",
];
const pathSegmentToSubMenu: Record<string, string> = {
dashboard: "menu",
services: "menu",
support: "menu",
customers: "menu",
representatives: "menu",
developers: "menu",
payments: "menu",
"referral-code": "menu",
users: "menu",
sliders: "menu",
subscriptions: "financial",
receipts: "financial",
transactions: "financial",
discounts: "financial",
"card-bank": "financial",
tickets: "other",
feedback: "other",
"access-logs": "other",
criticisms: "other",
workspace: "other",
project: "other",
taskmanager: "other",
ads: "content",
announcement: "content",
blog: "content",
learning: "content",
messages: "content",
reseller: "reseller",
dmenu: "dmenu",
dkala: "dkala",
dpage: "dpage",
dmail: "dmail",
};
export const getSubMenuNameFromPath = (pathname: string): string => {
if (pathname.startsWith("/customers/subscriptions")) {
return "financial";
}
if (pathname.startsWith("/workspace") || pathname.startsWith("/project") || pathname.startsWith("/taskmanager")) {
return "other";
}
const segment = pathname.split("/")[1] ?? "";
return pathSegmentToSubMenu[segment] ?? "";
};
+164 -814
View File
File diff suppressed because it is too large Load Diff
@@ -1,62 +0,0 @@
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { useLocation } from 'react-router-dom'
import { Pages } from '../../config/Pages'
import SideBarItem from '../SideBarItem'
import { DocumentText, Activity, Warning2, Shield } from 'iconsax-react'
const AccessLogsSubMenu: FC = () => {
const { t } = useTranslation('global')
const location = useLocation()
const iconSizeSideBar = 20
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='flex flex-col h-full'>
<div className='px-6 py-4 text-header text-sm font-normal'>
{t('sidebar.accessLogs')}
</div>
<div className='flex-1 px-6'>
<div className='text-xs text-[#8C90A3] space-y-2'>
<SideBarItem
icon={<Activity variant={isActive('access-logs/list') ? 'Bold' : 'Outline'} color={isActive('access-logs/list') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="لیست لاگ‌ها"
isActive={isActive('access-logs/list')}
link={Pages.accessLogs.list}
activeName='access_logs_list'
/>
<SideBarItem
icon={<DocumentText variant={isActive('access-logs/stats') ? 'Bold' : 'Outline'} color={isActive('access-logs/stats') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="آمار لاگ‌ها"
isActive={isActive('access-logs/stats')}
link={Pages.accessLogs.stats}
activeName='access_logs_stats'
/>
<SideBarItem
icon={<Warning2 variant={isActive('access-logs/errors') ? 'Bold' : 'Outline'} color={isActive('access-logs/errors') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="لاگ‌های خطا"
isActive={isActive('access-logs/errors')}
link={Pages.accessLogs.errors}
activeName='access_logs_errors'
/>
<SideBarItem
icon={<Shield variant={isActive('access-logs/permissions') ? 'Bold' : 'Outline'} color={isActive('access-logs/permissions') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="لاگ‌های مجوز"
isActive={isActive('access-logs/permissions')}
link={Pages.accessLogs.permissions}
activeName='access_logs_permissions'
/>
</div>
</div>
</div>
)
}
export default AccessLogsSubMenu
-50
View File
@@ -1,50 +0,0 @@
import { DocumentText } from 'iconsax-react'
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import SubMenuItem from './SubMenuItem'
import { Pages } from '../../config/Pages'
const BlogSubMenu: FC = () => {
const { t } = useTranslation('global')
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'>
<DocumentText
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
{t('sidebar.blog')}
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={'لیست'}
isActive={isActive('list')}
link={Pages.blog.list}
/>
<SubMenuItem
title={'دسته بندی'}
isActive={isActive('create')}
link={Pages.blog.category}
/>
<SubMenuItem
title={'نظرات'}
isActive={isActive('comments')}
link={Pages.blog.comments}
/>
</div>
</div>
)
}
export default BlogSubMenu
+95
View File
@@ -0,0 +1,95 @@
import { DocumentLike } from "iconsax-react";
import { FC } from "react";
import { useTranslation } from "react-i18next";
import { useLocation } from "react-router-dom";
import { Pages } from "../../config/Pages";
import SubMenuAccordion from "./SubMenuAccordion";
import SubMenuItem from "./SubMenuItem";
const ContentSubMenu: FC = () => {
const location = useLocation();
const { t } = useTranslation("global");
const isActive = (name: string) => location.pathname.includes(name);
return (
<div className="py-12">
<div className="flex gap-3 items-center border-b pb-10 px-6">
<DocumentLike
size={24}
color="#000"
variant="Bold"
/>
<div className="text-xs">{t("sidebar.mnage_content")}</div>
</div>
<div className="flex flex-col mt-10 gap-4">
<SubMenuItem
title={t("sidebar.ads")}
isActive={isActive("ads")}
link={Pages.ads.list}
activeName="advertisements"
/>
<SubMenuItem
title={t("sidebar.announcement")}
isActive={isActive("announcement")}
link={Pages.announcement.list}
activeName="announcements"
/>
<SubMenuAccordion
title={t("sidebar.blog")}
isActive={isActive("blog")}
activeName="blogs"
>
<SubMenuItem
title="لیست"
isActive={isActive("/blog/list")}
link={Pages.blog.list}
/>
<SubMenuItem
title="دسته بندی"
isActive={isActive("/blog/category")}
link={Pages.blog.category}
/>
<SubMenuItem
title="نظرات"
isActive={isActive("/blog/comments")}
link={Pages.blog.comments}
/>
</SubMenuAccordion>
<SubMenuAccordion
title={t("sidebar.learning")}
isActive={isActive("learning")}
activeName="learnings"
>
<SubMenuItem
title={t("learning.learnings")}
isActive={isActive("/learning/list")}
link={Pages.learning.list}
/>
<SubMenuItem
title={t("learning.new_learning")}
isActive={isActive("/learning/create")}
link={Pages.learning.create}
/>
<SubMenuItem
title={t("learning.category_learning")}
isActive={isActive("/learning/category")}
link={Pages.learning.category}
/>
</SubMenuAccordion>
<SubMenuItem
title={t("sidebar.messages")}
isActive={isActive("messages")}
link={Pages.messages.list}
activeName="contacts_us"
/>
</div>
</div>
);
};
export default ContentSubMenu;
-50
View File
@@ -1,50 +0,0 @@
import { People } from 'iconsax-react'
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import SubMenuItem from './SubMenuItem'
import { Pages } from '../../config/Pages'
const CustomerSubMenu: FC = () => {
const { t } = useTranslation('global')
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'>
<People
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
{t('sidebar.customers')}
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={t('submenu.customer_list')}
isActive={isActive('list')}
link={Pages.customer.list}
/>
<SubMenuItem
title={t('submenu.create_customer')}
isActive={isActive('create')}
link={Pages.customer.create}
/>
<SubMenuItem
title={t('sidebar.subscriptions')}
isActive={isActive('subscriptions')}
link={Pages.subscriptions.list}
/>
</div>
</div>
)
}
export default CustomerSubMenu
+61
View File
@@ -0,0 +1,61 @@
import { Building } from "iconsax-react";
import { FC } from "react";
import { useTranslation } from "react-i18next";
import { useLocation } from "react-router-dom";
import { Pages } from "../../config/Pages";
import SubMenuItem from "./SubMenuItem";
const DkalaSubMenu: FC = () => {
const location = useLocation();
const { t } = useTranslation("global");
const isActive = (name: string) => location.pathname.includes(name);
return (
<div className="py-12">
<div className="flex gap-3 items-center border-b pb-10 px-6">
<Building
size={24}
color="#000"
variant="Bold"
/>
<div className="text-xs">{t("sidebar.dkala")}</div>
</div>
<div className="flex flex-col mt-10 gap-4">
<SubMenuItem
title={t("sidebar.icons")}
isActive={isActive("dkala/icons/list") && !isActive("group")}
link={Pages.dkala.icons.list}
activeName="dkala"
/>
<SubMenuItem
title={t("sidebar.groups_icon")}
isActive={isActive("dkala/icons/group")}
link={Pages.dkala.icons.groupList}
activeName="dkala"
/>
<SubMenuItem
title={t("sidebar.reports")}
isActive={isActive("dkala/reports")}
link={Pages.dkala.warnings.list}
activeName="dkala"
/>
<SubMenuItem
title={t("sidebar.shops")}
isActive={isActive("dkala/shops")}
link={Pages.dkala.shops.list}
activeName="dkala"
/>
<SubMenuItem
title={t("sidebar.sms_count")}
isActive={isActive("dkala/sms-count")}
link={Pages.dkala.shops.smsCountList}
activeName="dkala"
/>
</div>
</div>
);
};
export default DkalaSubMenu;
+37
View File
@@ -0,0 +1,37 @@
import { Global } from "iconsax-react";
import { FC } from "react";
import { useTranslation } from "react-i18next";
import { useLocation } from "react-router-dom";
import { Pages } from "../../config/Pages";
import SubMenuItem from "./SubMenuItem";
const DmailSubMenu: FC = () => {
const location = useLocation();
const { t } = useTranslation("global");
const isActive = (name: string) => location.pathname.includes(name);
return (
<div className="py-12">
<div className="flex gap-3 items-center border-b pb-10 px-6">
<Global
size={24}
color="#000"
variant="Bold"
/>
<div className="text-xs">{t("sidebar.dmail")}</div>
</div>
<div className="flex flex-col mt-10 gap-4">
<SubMenuItem
title={t("sidebar.domain")}
isActive={isActive("dmail/domain/list")}
link={Pages.dmail.list}
activeName="dmail"
/>
</div>
</div>
);
};
export default DmailSubMenu;
+61
View File
@@ -0,0 +1,61 @@
import { Building } from "iconsax-react";
import { FC } from "react";
import { useTranslation } from "react-i18next";
import { useLocation } from "react-router-dom";
import { Pages } from "../../config/Pages";
import SubMenuItem from "./SubMenuItem";
const DmenuSubMenu: FC = () => {
const location = useLocation();
const { t } = useTranslation("global");
const isActive = (name: string) => location.pathname.includes(name);
return (
<div className="py-12">
<div className="flex gap-3 items-center border-b pb-10 px-6">
<Building
size={24}
color="#000"
variant="Bold"
/>
<div className="text-xs">{t("sidebar.dmenu")}</div>
</div>
<div className="flex flex-col mt-10 gap-4">
<SubMenuItem
title={t("sidebar.icons")}
isActive={isActive("dmenu/icons/list") && !isActive("group")}
link={Pages.dmenu.icons.list}
activeName="dmenu"
/>
<SubMenuItem
title={t("sidebar.groups_icon")}
isActive={isActive("dmenu/icons/group")}
link={Pages.dmenu.icons.groupList}
activeName="dmenu"
/>
<SubMenuItem
title={t("sidebar.reports")}
isActive={isActive("dmenu/reports")}
link={Pages.dmenu.warnings.list}
activeName="dmenu"
/>
<SubMenuItem
title={t("sidebar.restaurants")}
isActive={isActive("restaurants")}
link={Pages.dmenu.restaurants.list}
activeName="dmenu"
/>
<SubMenuItem
title={t("sidebar.sms_count")}
isActive={isActive("dmenu/sms-count")}
link={Pages.dmenu.restaurants.smsCountList}
activeName="dmenu"
/>
</div>
</div>
);
};
export default DmenuSubMenu;
+37
View File
@@ -0,0 +1,37 @@
import { Gallery } from "iconsax-react";
import { FC } from "react";
import { useTranslation } from "react-i18next";
import { useLocation } from "react-router-dom";
import { Pages } from "../../config/Pages";
import SubMenuItem from "./SubMenuItem";
const DpageSubMenu: FC = () => {
const location = useLocation();
const { t } = useTranslation("global");
const isActive = (name: string) => location.pathname.includes(name);
return (
<div className="py-12">
<div className="flex gap-3 items-center border-b pb-10 px-6">
<Gallery
size={24}
color="#000"
variant="Bold"
/>
<div className="text-xs">{t("sidebar.dpage")}</div>
</div>
<div className="flex flex-col mt-10 gap-4">
<SubMenuItem
title={t("sidebar.sticker")}
isActive={isActive("dpage/stickers/list")}
link={Pages.dpage.stickers.list}
activeName="dpage"
/>
</div>
</div>
);
};
export default DpageSubMenu;
@@ -0,0 +1,74 @@
import { Money3 } from "iconsax-react";
import { FC } from "react";
import { useTranslation } from "react-i18next";
import { useLocation } from "react-router-dom";
import { Pages } from "../../config/Pages";
import SubMenuAccordion from "./SubMenuAccordion";
import SubMenuItem from "./SubMenuItem";
const FinancialSubMenu: FC = () => {
const location = useLocation();
const { t } = useTranslation("global");
const isActive = (name: string) => location.pathname.includes(name);
return (
<div className="py-12">
<div className="flex gap-3 items-center border-b pb-10 px-6">
<Money3
size={24}
color="#000"
variant="Bold"
/>
<div className="text-xs">{t("sidebar.financial")}</div>
</div>
<div className="flex flex-col mt-10 gap-4">
<SubMenuItem
title={t("sidebar.subscriptions")}
isActive={isActive("subscriptions")}
link={Pages.subscriptions.list}
activeName="payments"
/>
<SubMenuAccordion
title={t("sidebar.receipt_list")}
isActive={isActive("receipts")}
activeName="invoices"
>
<SubMenuItem
title={t("receip.receip_list")}
isActive={isActive("/receipts/list")}
link={Pages.receipts.index}
/>
<SubMenuItem
title={t("receip.add_receip")}
isActive={isActive("/receipts/create")}
link={Pages.receipts.create}
/>
</SubMenuAccordion>
<SubMenuItem
title={t("sidebar.transactions")}
isActive={isActive("transactions")}
link={Pages.transactions}
activeName="transactions"
/>
<SubMenuItem
title={t("sidebar.discounts")}
isActive={isActive("discounts")}
link={Pages.discount.list}
activeName="discounts"
/>
<SubMenuItem
title={t("sidebar.card")}
isActive={isActive("card-bank")}
link={Pages.cardBank.list}
activeName="bank_accounts"
/>
</div>
</div>
);
};
export default FinancialSubMenu;
-52
View File
@@ -1,52 +0,0 @@
import { Teacher } from 'iconsax-react'
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import SubMenuItem from './SubMenuItem'
import { useLocation } from 'react-router-dom'
import { Pages } from '../../config/Pages'
const LearningSubMenu: FC = () => {
const { t } = useTranslation('global')
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 pb-10 px-6'>
<Teacher
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
{t('sidebar.learning')}
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={t('learning.learnings')}
isActive={isActive('list')}
link={Pages.learning.list}
/>
<SubMenuItem
title={t('learning.new_learning')}
isActive={isActive('create')}
link={Pages.learning.create}
/>
<SubMenuItem
title={t('learning.category_learning')}
isActive={isActive('category')}
link={Pages.learning.category}
/>
</div>
</div>
)
}
export default LearningSubMenu
+176
View File
@@ -0,0 +1,176 @@
import { Element3 } from "iconsax-react";
import { FC } from "react";
import { useTranslation } from "react-i18next";
import { useLocation } from "react-router-dom";
import { Pages } from "../../config/Pages";
import { useGetProfile } from "../../pages/profile/hooks/useProfileData";
import SubMenuAccordion from "./SubMenuAccordion";
import SubMenuItem from "./SubMenuItem";
const MenuSubMenu: FC = () => {
const location = useLocation();
const { t } = useTranslation("global");
const { data: profile } = useGetProfile();
const isActive = (name: string) => location.pathname.includes(name);
return (
<div className="py-12">
<div className="flex gap-3 items-center border-b pb-10 px-6">
<Element3
size={24}
color="#000"
variant="Bold"
/>
<div className="text-xs">{t("sidebar.menu")}</div>
</div>
<div className="flex flex-col mt-10 gap-4">
<SubMenuItem
title={t("sidebar.mainpage")}
isActive={isActive("dashboard")}
link={Pages.dashboard}
/>
<SubMenuAccordion
title={t("sidebar.services")}
isActive={isActive("services")}
activeName="services"
>
<SubMenuItem
title={t("submenu.services_list")}
isActive={isActive("/services/list")}
link={Pages.services.list}
/>
<SubMenuItem
title={t("submenu.add_service")}
isActive={isActive("/services/add")}
link={Pages.services.add}
/>
<SubMenuItem
title={t("submenu.service_category")}
isActive={isActive("/services/category")}
link={Pages.services.category}
/>
<SubMenuItem
title={t("submenu.reviews")}
isActive={isActive("/services/reviews")}
link={Pages.services.review}
/>
</SubMenuAccordion>
<SubMenuAccordion
title={t("sidebar.support")}
isActive={isActive("support")}
activeName="support_plan"
>
<SubMenuItem
title={t("submenu.plan_list")}
isActive={isActive("/support/list")}
link={Pages.support.list}
/>
<SubMenuItem
title={t("submenu.create_plan")}
isActive={isActive("/support/create")}
link={Pages.support.create}
/>
</SubMenuAccordion>
<SubMenuAccordion
title={t("sidebar.customers")}
isActive={isActive("customers") && !isActive("subscriptions")}
activeName="customers"
>
<SubMenuItem
title={t("submenu.customer_list")}
isActive={isActive("/customers/list")}
link={Pages.customer.list}
/>
<SubMenuItem
title={t("submenu.create_customer")}
isActive={isActive("/customers/create")}
link={Pages.customer.create}
/>
<SubMenuItem
title={t("sidebar.subscriptions")}
isActive={isActive("subscriptions")}
link={Pages.subscriptions.list}
/>
</SubMenuAccordion>
<SubMenuItem
title={t("sidebar.representatives")}
isActive={isActive("representatives")}
link={Pages.representative.list}
activeName="agents"
/>
<SubMenuItem
title={t("sidebar.developers")}
isActive={isActive("developers")}
link={Pages.developers.list}
activeName="developers"
/>
<SubMenuItem
title={t("sidebar.payments")}
isActive={isActive("payments")}
link={Pages.payment.list}
activeName="payments"
/>
<SubMenuItem
title={t("sidebar.code_referral")}
isActive={isActive("referral-code")}
link={Pages.referralCode.list}
activeName="referralCode"
/>
<SubMenuAccordion
title={t("sidebar.users")}
isActive={isActive("users")}
activeName="admins"
>
<SubMenuItem
title={t("submenu.user_list")}
isActive={isActive("/users/list")}
link={Pages.users.list}
/>
<SubMenuItem
title={t("submenu.add_user")}
isActive={isActive("/users/create")}
link={Pages.users.create}
/>
<SubMenuItem
title={t("submenu.role_list")}
isActive={isActive("roles-all")}
link={Pages.users.roleList}
/>
<SubMenuItem
title={t("submenu.role_create")}
isActive={isActive("roles-add")}
link={Pages.users.roleCreate}
/>
<SubMenuItem
title={t("user.add_user_group")}
isActive={isActive("group-add")}
link={Pages.users.groupAdd}
/>
<SubMenuItem
title={t("user.list_user_group")}
isActive={isActive("/users/groups")}
link={Pages.users.groupList}
/>
</SubMenuAccordion>
{profile?.data?.user?.roles?.some((role: { name: string }) => role.name === "super_admin") && (
<SubMenuItem
title={t("sidebar.sliders")}
isActive={isActive("sliders")}
link={Pages.sliders.list}
activeName="blogs"
/>
)}
</div>
</div>
);
};
export default MenuSubMenu;
+108
View File
@@ -0,0 +1,108 @@
import { Category } from "iconsax-react";
import { FC } from "react";
import { useTranslation } from "react-i18next";
import { useLocation } from "react-router-dom";
import { Pages } from "../../config/Pages";
import SubMenuAccordion from "./SubMenuAccordion";
import SubMenuItem from "./SubMenuItem";
const OtherSubMenu: FC = () => {
const location = useLocation();
const { t } = useTranslation("global");
const isActive = (name: string) => location.pathname.includes(name);
const isTaskManagerActive =
location.pathname.startsWith(Pages.taskmanager.workspace) ||
location.pathname === Pages.taskmanager.workspaceList ||
location.pathname.startsWith(Pages.taskmanager.updateWorkspace) ||
location.pathname === Pages.taskmanager.createWorkspace ||
location.pathname === Pages.taskmanager.createProject ||
location.pathname.startsWith(Pages.taskmanager.updateProject) ||
location.pathname.startsWith(Pages.taskmanager.projectList);
return (
<div className="py-12">
<div className="flex gap-3 items-center border-b pb-10 px-6">
<Category
size={24}
color="#000"
variant="Bold"
/>
<div className="text-xs">{t("sidebar.other")}</div>
</div>
<div className="flex flex-col mt-10 gap-4">
<SubMenuAccordion
title={t("sidebar.ticket")}
isActive={isActive("tickets")}
activeName="tickets"
>
<SubMenuItem
title={t("submenu.ticket_list")}
isActive={isActive("/tickets/list")}
link={Pages.ticket.list}
/>
<SubMenuItem
title={t("submenu.send_ticket")}
isActive={isActive("/tickets/create")}
link={Pages.ticket.create}
/>
<SubMenuItem
title={t("submenu.category")}
isActive={isActive("/tickets/category")}
link={Pages.ticket.category}
/>
</SubMenuAccordion>
<SubMenuItem
title={t("sidebar.feedback")}
isActive={isActive("feedback")}
link={Pages.feedback.list}
activeName="services"
/>
<SubMenuAccordion
title={t("sidebar.accessLogs")}
isActive={isActive("access-logs")}
activeName="logs"
>
<SubMenuItem
title={t("submenu.access_logs_list")}
isActive={isActive("access-logs/list")}
link={Pages.accessLogs.list}
/>
<SubMenuItem
title={t("submenu.access_logs_stats")}
isActive={isActive("access-logs/stats")}
link={Pages.accessLogs.stats}
/>
<SubMenuItem
title={t("submenu.access_logs_errors")}
isActive={isActive("access-logs/errors")}
link={Pages.accessLogs.errors}
/>
<SubMenuItem
title="لاگ‌های مجوز"
isActive={isActive("access-logs/permissions")}
link={Pages.accessLogs.permissions}
/>
</SubMenuAccordion>
<SubMenuItem
title={t("sidebar.criticisms")}
isActive={isActive("criticisms")}
link={Pages.criticisms.list}
activeName="criticisms"
/>
<SubMenuItem
title={t("sidebar.taskmanager")}
isActive={isTaskManagerActive}
link={Pages.taskmanager.workspaceList}
/>
</div>
</div>
);
};
export default OtherSubMenu;
-46
View File
@@ -1,46 +0,0 @@
import { Receipt21 } from 'iconsax-react'
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import SubMenuItem from './SubMenuItem'
import { useLocation } from 'react-router-dom'
import { Pages } from '../../config/Pages'
const ReceiptSubMenu: FC = () => {
const location = useLocation()
const { t } = useTranslation('global')
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'>
<Receipt21
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
{t('receip.receips')}
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={t('receip.receip_list')}
isActive={isActive('list')}
link={Pages.receipts.index}
/>
<SubMenuItem
title={t('receip.add_receip')}
isActive={isActive('create')}
link={Pages.receipts.create}
/>
</div>
</div>
)
}
export default ReceiptSubMenu
+43
View File
@@ -0,0 +1,43 @@
import { UserTick } from "iconsax-react";
import { FC } from "react";
import { useTranslation } from "react-i18next";
import { useLocation } from "react-router-dom";
import { Pages } from "../../config/Pages";
import SubMenuItem from "./SubMenuItem";
const ResellerSubMenu: FC = () => {
const location = useLocation();
const { t } = useTranslation("global");
const isActive = (name: string) => location.pathname.includes(name);
return (
<div className="py-12">
<div className="flex gap-3 items-center border-b pb-10 px-6">
<UserTick
size={24}
color="#000"
variant="Bold"
/>
<div className="text-xs">{t("sidebar.reseller")}</div>
</div>
<div className="flex flex-col mt-10 gap-4">
<SubMenuItem
title={t("sidebar.resellers")}
isActive={isActive("reseller/list")}
link={Pages.reseller.list}
activeName="reseller"
/>
<SubMenuItem
title={t("sidebar.withdraw")}
isActive={isActive("reseller/withdraw")}
link={Pages.reseller.withdraw}
activeName="reseller"
/>
</div>
</div>
);
};
export default ResellerSubMenu;
-57
View File
@@ -1,57 +0,0 @@
import { Element3 } from 'iconsax-react'
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import SubMenuItem from './SubMenuItem'
import { useLocation } from 'react-router-dom'
import { Pages } from '../../config/Pages'
const ServicesSubMenu: FC = () => {
const location = useLocation()
const { t } = useTranslation('global')
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'>
<Element3
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
{t('sidebar.services')}
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={t('submenu.services_list')}
isActive={isActive('list')}
link={Pages.services.list}
/>
<SubMenuItem
title={t('submenu.add_service')}
isActive={isActive('add')}
link={Pages.services.add}
/>
<SubMenuItem
title={t('submenu.service_category')}
isActive={isActive('category')}
link={Pages.services.category}
/>
<SubMenuItem
title={t('submenu.reviews')}
isActive={isActive('reviews')}
link={Pages.services.review}
/>
</div>
</div>
)
}
export default ServicesSubMenu
@@ -0,0 +1,53 @@
import { ArrowDown2 } from "iconsax-react";
import { FC, ReactNode, useEffect, useState } from "react";
import { clx } from "../../helpers/utils";
import { useGetAdminPermissions } from "../../pages/users/hooks/useUserData";
type Props = {
title: string;
isActive: boolean;
activeName?: string;
children: ReactNode;
};
const SubMenuAccordion: FC<Props> = ({ title, isActive, activeName = "", children }) => {
const { data: adminPermissions } = useGetAdminPermissions();
const [open, setOpen] = useState(isActive);
useEffect(() => {
if (isActive) {
setOpen(true);
}
}, [isActive]);
if (
activeName !== "" &&
!adminPermissions?.data?.permissions?.some((permission: { name: string }) => permission.name === activeName)
) {
return null;
}
return (
<div>
<button
type="button"
onClick={() => setOpen((prev) => !prev)}
className="flex text-xs gap-6 mt-1 w-full cursor-pointer"
>
<div className={clx("w-1 bg-black h-6", !isActive && "invisible")} />
<div className="flex gap-2 items-center flex-1 justify-between mt-1 pl-4">
<div className={isActive ? "text-black" : "text-description"}>{title}</div>
<div className={clx("transition-all", !open && "rotate-180")}>
<ArrowDown2
size={14}
color="#c3c7dd"
/>
</div>
</div>
</button>
{open && <div className="flex flex-col gap-2 mr-3 mt-2">{children}</div>}
</div>
);
};
export default SubMenuAccordion;
+32 -27
View File
@@ -1,33 +1,38 @@
import { FC } from 'react'
import { Link } from 'react-router-dom'
import { clx } from '../../helpers/utils'
import { FC } from "react";
import { Link } from "react-router-dom";
import { clx } from "../../helpers/utils";
import { useGetAdminPermissions } from "../../pages/users/hooks/useUserData";
type Props = {
title: string,
isActive: boolean,
link: string,
isLogout?: boolean,
}
title: string;
isActive: boolean;
link: string;
isLogout?: boolean;
activeName?: string;
};
const SubMenuItem: FC<Props> = (props: Props) => {
return (
<Link to={props.link} className={clx(
'flex text-xs gap-6 mt-1',
)}>
<div className={clx(
'w-1 bg-black h-6',
!props.isActive && 'invisible',
)}></div>
<div className={clx(
'flex gap-3 items-center mt-1',
)}>
<div className={props.isActive ? 'text-black' : 'text-description'}>
{props.title}
</div>
</div>
const { data: adminPermissions } = useGetAdminPermissions();
</Link>
)
}
if (
props.activeName !== undefined &&
props.activeName !== "" &&
!adminPermissions?.data?.permissions?.some((permission: { name: string }) => permission.name === props.activeName)
) {
return null;
}
export default SubMenuItem
return (
<Link
to={props.link}
className={clx("flex text-xs gap-6 mt-1")}
>
<div className={clx("w-1 bg-black h-6", !props.isActive && "invisible")}></div>
<div className={clx("flex gap-3 items-center mt-1")}>
<div className={props.isActive ? "text-black" : "text-description"}>{props.title}</div>
</div>
</Link>
);
};
export default SubMenuItem;
-47
View File
@@ -1,47 +0,0 @@
import { Headphone } from 'iconsax-react'
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { useLocation } from 'react-router-dom'
import { Pages } from '../../config/Pages'
import SubMenuItem from './SubMenuItem'
const SupportSubMenu: FC = () => {
const location = useLocation()
const { t } = useTranslation('global')
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'>
<Headphone
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
{t('sidebar.support')}
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={t('submenu.plan_list')}
isActive={isActive('list')}
link={Pages.support.list}
/>
<SubMenuItem
title={t('submenu.create_plan')}
isActive={isActive('create')}
link={Pages.support.create}
/>
</div>
</div>
}
export default SupportSubMenu
-52
View File
@@ -1,52 +0,0 @@
import { Messages3 } from 'iconsax-react'
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import SubMenuItem from './SubMenuItem'
import { useLocation } from 'react-router-dom'
import { Pages } from '../../config/Pages'
const TicketSubMenu: FC = () => {
const location = useLocation()
const { t } = useTranslation('global')
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'>
<Messages3
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
{t('sidebar.ticket')}
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={t('submenu.ticket_list')}
isActive={isActive('list')}
link={Pages.ticket.list}
/>
<SubMenuItem
title={t('submenu.send_ticket')}
isActive={isActive('create')}
link={Pages.ticket.create}
/>
<SubMenuItem
title={t('submenu.category')}
isActive={isActive('category')}
link={Pages.ticket.category}
/>
</div>
</div>
)
}
export default TicketSubMenu
@@ -1,38 +0,0 @@
import { Card } from 'iconsax-react'
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import SubMenuItem from './SubMenuItem'
const TransactionsSubMenu: FC = () => {
const { t } = useTranslation('global')
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'>
<Card
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
{t('sidebar.transactions')}
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={t('sidebar.services')}
isActive={isActive('services')}
link='/services'
/>
</div>
</div>
)
}
export default TransactionsSubMenu
-64
View File
@@ -1,64 +0,0 @@
import { Profile } from 'iconsax-react'
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import SubMenuItem from './SubMenuItem'
import { Pages } from '../../config/Pages'
const UsersSubMenu: FC = () => {
const { t } = useTranslation('global')
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'>
{t('sidebar.users')}
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={t('submenu.user_list')}
isActive={isActive('list')}
link={Pages.users.list}
/>
<SubMenuItem
title={t('submenu.add_user')}
isActive={isActive('create')}
link={Pages.users.create}
/>
<SubMenuItem
title={t('submenu.role_list')}
isActive={isActive('all')}
link={Pages.users.roleList}
/>
<SubMenuItem
title={t('submenu.role_create')}
isActive={isActive('roles-add')}
link={Pages.users.roleCreate}
/>
<SubMenuItem
title={t('user.add_user_group')}
isActive={isActive('group-add')}
link={Pages.users.groupAdd}
/>
<SubMenuItem
title={t('user.list_user_group')}
isActive={isActive('groups')}
link={Pages.users.groupList}
/>
</div>
</div>
)
}
export default UsersSubMenu