---
name: danak-admin
description: 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.ts` — `import 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:

```typescript
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.success(t('success'))` on success, `toast.error(error.response?.data?.error.message[0])` on error (`ErrorType` from `src/helpers/types.ts`). 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](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 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]`)

## 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
