Files
danak-admin/.cursor/skills/danak-admin/SKILL.md
T
hamid zarghami d3fd21177b
deploy to danak / build_and_deploy (push) Has been cancelled
change toast
2026-07-20 10:55:33 +03:30

4.7 KiB

name, description
name description
danak-admin Documents danak-admin React admin panel conventions — page structure, routing, TanStack Query hooks, axios services, sidebar, and Persian i18n. Use when adding pages or features, wiring API calls, updating navigation, or working in this repository.

Danak Admin

Persian (RTL) admin panel: React 19, Vite, TypeScript, React Router 7, TanStack Query, Formik/Yup, Tailwind, iconsax-react.

Stack

Layer Location / tool
Routes (paths) src/config/Pages.ts
Route components src/router/Main.tsx
Auth routes src/router/Auth.tsx
HTTP client src/config/axios.tsimport axios from "../../../config/axios"
Shared UI src/components/
Layout src/shared/ (Header, SideBar, Footer)
i18n src/langs/fa.json, namespace global, useTranslation('global')
Env VITE_BASE_URL, VITE_TOKEN_NAME, VITE_REFRESH_TOKEN_NAME

Feature folder layout

Each domain lives under src/pages/{feature}/:

{feature}/
├── List.tsx              # index table view
├── Create.tsx            # create form
├── Update.tsx            # edit form (uses :id param)
├── hooks/use{Feature}Data.ts
├── service/{Feature}Service.ts
├── types/{Feature}Types.ts
└── components/           # feature-specific UI (Delete, filters, etc.)

Mirror an existing feature (e.g. customer/, ads/) before inventing new patterns.

Data layer

Service — plain async functions, one API call each:

import axios from "../../../config/axios";
import { CreateCustomerType } from "../types/CustomerTypes";

export const getCustomers = async (page: number) => {
  const { data } = await axios.get(`/users/customers?page=${page}&paginate=1`);
  return data;
};

export const createCustomer = async (params: CreateCustomerType) => {
  const { data } = await axios.post(`/users/customers`, params);
  return data;
};

Hooks — TanStack Query wrappers in hooks/use{Feature}Data.ts:

  • Lists: useQuery({ queryKey: ["customers", page], queryFn: () => api.getCustomers(page) })
  • Detail: add enabled: !!id
  • Mutations: useMutation + queryClient.invalidateQueries({ queryKey: ["customers"] })
  • Export hooks as useGetX, useCreateX, useUpdateX, useDeleteX

Types{Feature}ItemType, Create{Feature}Type in types/.

Page patterns

List — header + optional filters + PageLoading while pending + <table> with Td + Pagination. Link actions via Pages.{feature}.*.

Create / Update — Formik + Yup validation, toast(t('success'), 'success') on success, toast(error.response?.data?.error.message[0], 'error') on error (ErrorType from src/helpers/types.ts). Import toast from src/components/Toast. Navigate back to list with useNavigate() + Pages.*.

Delete — small component using ModalConfrim + mutation hook; call refetch() or rely on query invalidation.

Adding a feature

Follow the checklist in add-feature.md. Minimum steps:

  1. Add paths to src/config/Pages.ts
  2. Create page files under src/pages/{feature}/
  3. Register <Route> entries in src/router/Main.tsx (static imports, no lazy loading)
  4. Add sidebar entry in src/shared/SideBar.tsx if user-facing
  5. Add translation keys to src/langs/fa.json

Dynamic routes use string concat: Pages.customer.update + ":id".

Sidebar & submenu

  • 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

  • Components: const MyPage: FC = () => { ... }; export default MyPage
  • Styling: Tailwind utility classes; clx() from src/helpers/utils for conditional classes
  • Icons: iconsax-react (Outline/Bold variants, #8C90A3 inactive / black active)
  • Do not add lazy-loaded routes — project uses direct imports in Main.tsx
  • Keep API paths relative to VITE_BASE_URL; auth token is attached automatically by axios interceptor
  • Prefer reusing Button, Input, Select, Textarea, Pagination, PageLoading, ModalConfrim from src/components/

Do not

  • Commit .env or secrets
  • Introduce new state libraries (Zustand is only used in sharedStore for layout)
  • Add English-only UI strings — add keys to fa.json
  • Change axios/auth/token refresh logic unless explicitly requested