uikit/README.md
2026-06-16 10:25:51 +03:30

632 lines
14 KiB
Markdown
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.

# uikit
کتابخانه‌ی مشترک React برای استفاده بین پروژه‌های BI.
این پکیج به چند entry جدا تقسیم شده تا پروژه‌ها فقط همان بخشی را import کنند که لازم دارند و مجبور نباشند برای یک helper ساده، dependencyهای سنگین مثل Chakra، Keycloak یا React Query نصب کنند.
---
## نصب
```bash
yarn add git+https://git.d.aiengines.ir/bi/uikit.git
```
یا اگر branch/tag خاصی لازم داری:
```bash
yarn add git+https://git.d.aiengines.ir/bi/uikit.git#main
```
---
## آپدیت
```bash
yarn upgrade uikit
```
اگر از git dependency استفاده می‌کنی و نسخه جدید نگرفتی، lockfile را هم بررسی کن:
```bash
yarn remove uikit
yarn add git+https://git.d.aiengines.ir/bi/uikit.git
```
---
# ساختار importها
| مسیر | کاربرد | dependency اضافی |
| ------------------ | ------------------------------------- | --------------------------------------- |
| `uikit` | خروجی سبک، فعلاً فقط utils | ندارد |
| `uikit/utils` | helperهای ساده مثل تبدیل عدد | ندارد |
| `uikit/pagination` | کامپوننت‌های pagination | Chakra + React + react-icons |
| `uikit/layout` | کامپوننت‌های layout مثل Header | Chakra + React |
| `uikit/core` | API، BiProvider، Keycloak، Permission | Chakra + React Query + Axios + Keycloak |
| `uikit/table` | DataTable | Chakra + TanStack Table + Pagination |
---
# استفاده از utils
برای helperهای ساده نیازی به نصب هیچ dependency اضافه‌ای نیست.
```js
import { toFaDigits, toEnDigits, toFaNumber } from "uikit/utils";
toFaDigits(123456); // ۱۲۳۴۵۶
toEnDigits("۱۲۳۴۵۶"); // 123456
toFaNumber(123456); // عدد فارسی‌شده
```
همچنین چون root package فقط utils را export می‌کند، این هم قابل استفاده است:
```js
import { toFaDigits } from "uikit";
```
---
# استفاده از pagination
اگر از pagination استفاده می‌کنی، این dependencyها باید در پروژه نصب باشند:
```bash
yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion react-icons
```
استفاده:
```jsx
import { Pagination, LightPagination, SimplePagination } from "uikit/pagination";
function Page() {
return (
<Pagination
currentPage={1}
totalCount={100}
totalPages={5}
onPageChange={(page) => console.log(page)}
/>
);
}
```
---
# استفاده از Header
`Header` داخل مسیر `uikit/layout` قرار دارد.
dependencyهای لازم:
```bash
yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion
```
استفاده:
```jsx
import { Header } from "uikit/layout";
function AppHeader() {
return (
<Header>
<Header.BrandSection>
<Header.Logo src="/logo.png" />
<Header.Brand>
<Header.Title>عنوان سامانه</Header.Title>
<Header.Description>توضیح کوتاه سامانه</Header.Description>
</Header.Brand>
</Header.BrandSection>
<Header.Bi />
</Header>
);
}
```
اجزای موجود:
```jsx
<Header />
<Header.BrandSection />
<Header.Logo />
<Header.Brand />
<Header.Title />
<Header.Description />
<Header.Bi />
```
---
# استفاده از core
بخش core شامل این موارد است:
* API config
* `createApi`
* `BiProvider`
* Keycloak
* Permission
* React Query provider
* Chakra provider
برای استفاده از core این dependencyها باید در پروژه نصب باشند:
```bash
yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion @tanstack/react-query axios keycloak-js
```
---
## استفاده از BiProvider
```jsx
import { BiProvider } from "uikit/core";
export default function App() {
return (
<BiProvider
apiBaseUrl="https://api.example.com"
keycloakClientId="front-client"
permissionClientId="permission-client"
>
<YourApp />
</BiProvider>
);
}
```
`BiProvider` به صورت داخلی این کارها را انجام می‌دهد:
* تنظیم base url برای API
* راه‌اندازی Keycloak در صورت فعال بودن
* گرفتن permissionها در صورت فعال بودن
* اضافه کردن `ChakraProvider`
* اضافه کردن `QueryClientProvider`
* اضافه کردن فونت و theme داخلی
* فعال کردن اختیاری `UpdateChecker`
---
## props مربوط به BiProvider
| Prop | توضیح |
| -------------------- | ------------------------------------------------------ |
| `apiBaseUrl` | آدرس اصلی API |
| `keycloakClientId` | client id مربوط به Keycloak |
| `permissionClientId` | client id مربوط به Permission |
| `loading` | کامپوننت loading هنگام init شدن Keycloak یا Permission |
| `updateChecker` | فعال یا غیرفعال کردن بررسی آپدیت |
| `updateCheckerProps` | props مربوط به UpdateChecker |
| `keycloakUrl` | آدرس Keycloak |
| `keycloakRealm` | realm مربوط به Keycloak |
| `permissionUrl` | آدرس API مربوط به permission |
| `keycloakEnabled` | فعال یا غیرفعال کردن Keycloak به صورت دستی |
| `permissionEnabled` | فعال یا غیرفعال کردن Permission به صورت دستی |
---
## مقدارهای پیش‌فرض BiProvider
```js
keycloakUrl = "https://auth.ibagher.ir";
keycloakRealm = "bi";
permissionUrl = "https://api.d.aiengines.ir/user_api/v1/permissions/list";
updateChecker = false;
```
نکته: اگر `keycloakClientId` داده شود، Keycloak فعال می‌شود. اگر `permissionClientId` داده شود، Permission فعال می‌شود.
برای کنترل دستی:
```jsx
<BiProvider
apiBaseUrl="https://api.example.com"
keycloakEnabled={false}
permissionEnabled={false}
>
<YourApp />
</BiProvider>
```
---
# UpdateChecker
به صورت پیش‌فرض `updateChecker` خاموش است.
برای فعال کردن:
```jsx
<BiProvider
apiBaseUrl="https://api.example.com"
keycloakClientId="front-client"
permissionClientId="permission-client"
updateChecker
>
<YourApp />
</BiProvider>
```
اگر `updateChecker` را فعال می‌کنی، پروژه باید فایل version تولید کند. معمولاً باید یک اسکریپت مثل `write-version.js` در root پروژه داشته باشی و در `package.json` پروژه target، قبل از build اجرا شود.
نمونه:
```json
{
"scripts": {
"prebuild": "node write-version.js",
"build": "next build"
}
}
```
---
# استفاده از API پایه
```js
import { api, fetcher, configureApi, getApi } from "uikit/core";
```
اگر از `BiProvider` استفاده می‌کنی، معمولاً نیازی نیست دستی `configureApi` را صدا بزنی، چون `BiProvider` این کار را انجام می‌دهد.
نمونه استفاده مستقیم:
```js
import { api } from "uikit/core";
const response = await api.get("/users");
```
یا:
```js
import { fetcher } from "uikit/core";
const data = await fetcher("/users");
```
---
# استفاده از createApi
`createApi` برای ساختن یک API ساده بر پایه React Query استفاده می‌شود.
```js
import { createApi } from "uikit/core";
export const profileApi = createApi({
key: "profile",
url: "/content/rokn/profiles",
actions: {
update: {
method: "patch",
url: (id) => `/content/rokn/profiles/${id}`,
},
delete: {
method: "delete",
},
generate: {
method: "post",
url: "/content/rokn/generate/profile",
},
updateImages: {
method: "post",
url: (id) => `/content/rokn/profile-update/${id}/images`,
body: ({ formData }) => formData,
},
},
});
```
---
## گرفتن لیست
```jsx
const { data, isLoading, error } = profileApi.useGet({
page: 1,
size: 20,
is_confirmed: true,
});
```
این request ساخته می‌شود:
```txt
GET /content/rokn/profiles?page=1&size=20&is_confirmed=true
```
---
## اجرای action
```jsx
const updateProfile = profileApi.useAction("update");
await updateProfile.mutateAsync({
id: 10,
username: "new_username",
});
```
در این حالت:
```txt
PATCH /content/rokn/profiles/10
```
body:
```js
{
username: "new_username"
}
```
`id` به صورت پیش‌فرض از body حذف می‌شود، چون برای ساختن URL استفاده شده است.
---
## action با همان URL اصلی
اگر action همان URL اصلی را لازم دارد، نیازی نیست `url` را دوباره بنویسی.
```js
export const identityGenerateApi = createApi({
key: "identity-generate",
url: "/content/rokn/identity-generate/logs",
actions: {
delete: {
method: "delete",
},
},
});
```
یعنی:
```txt
DELETE /content/rokn/identity-generate/logs
```
---
## action با FormData
```js
const updateImages = profileApi.useAction("updateImages");
const formData = new FormData();
formData.append("image", file);
await updateImages.mutateAsync({
id: 10,
formData,
});
```
در تعریف action:
```js
updateImages: {
method: "post",
url: (id) => `/content/rokn/profile-update/${id}/images`,
body: ({ formData }) => formData,
}
```
`body` مشخص می‌کند چه چیزی واقعاً به عنوان body ارسال شود.
---
# استفاده از Keycloak
```js
import {
getKeycloakToken,
loginKeycloak,
logoutKeycloak,
updateKeycloakToken,
} from "uikit/core";
const token = getKeycloakToken();
await updateKeycloakToken(30);
loginKeycloak();
logoutKeycloak({
redirectUri: window.location.origin,
});
```
---
# استفاده از Permission
```jsx
import { Can, usePermission } from "uikit/core";
function Page() {
const { can, cannot, permissions } = usePermission();
return (
<>
{can("users:list") && <div>لیست کاربران</div>}
<Can perm="users:create" fallback={null}>
<button>ایجاد کاربر</button>
</Can>
</>
);
}
```
نکته: prop کامپوننت `Can` برابر `perm` است.
```jsx
<Can perm="users:list">
<UsersList />
</Can>
```
---
# استفاده از DataTable
`DataTable` داخل مسیر `uikit/table` قرار دارد.
dependencyهای لازم:
```bash
yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion @tanstack/react-table react-icons
```
استفاده:
```jsx
import { DataTable } from "uikit/table";
function UsersTable({ data, columns }) {
return (
<DataTable
data={data}
columns={columns}
page={1}
size={20}
pagination={{
totalCount: 100,
totalPages: 5,
}}
onPageChange={(page) => console.log(page)}
getRowId={(row) => String(row.id)}
enableSelection
showIndex
>
<DataTable.Topbar>
<DataTable.Title>لیست کاربران</DataTable.Title>
<DataTable.Spacer />
<DataTable.Actions>
<DataTable.SelectAll />
</DataTable.Actions>
</DataTable.Topbar>
<DataTable.Content>
<DataTable.Table />
<DataTable.Pagination />
</DataTable.Content>
</DataTable>
);
}
```
---
# dependencyهای پیشنهادی بر اساس نیاز
## فقط utils
نیازی به نصب dependency اضافه نیست.
```bash
yarn add git+https://git.d.aiengines.ir/bi/uikit.git
```
---
## pagination یا layout
```bash
yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion react-icons
```
برای `layout` معمولاً `react-icons` لازم نیست، ولی اگر پروژه از pagination هم استفاده می‌کند، نصبش کن.
---
## core
```bash
yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion @tanstack/react-query axios keycloak-js
```
---
## table
```bash
yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion @tanstack/react-table react-icons
```
---
# نکات مهم توسعه
بعد از تغییر فایل‌ها، build بگیر:
```bash
yarn build
```
فایل‌های خروجی مورد انتظار:
```txt
dist/index.js
dist/utils.js
dist/pagination.js
dist/layout.js
dist/core.js
dist/table.js
```
اگر entry جدید اضافه شد، باید هم در `vite.config.js` و هم در `package.json > exports` ثبت شود.
---
# قانون کلی
هر چیزی که dependency سنگین ندارد:
```txt
uikit/utils
```
هر چیزی که UI سبک است و Chakra می‌خواهد:
```txt
uikit/pagination
uikit/layout
```
هر چیزی که مربوط به API، auth، permission و provider است:
```txt
uikit/core
```
هر چیزی که مربوط به table است:
```txt
uikit/table
```
Root package یعنی:
```txt
uikit
```
باید سبک بماند و فقط چیزهایی مثل utils را export کند.