----------
از آنجایی که فرانتیوم علاقهی زیادی به گربهها داشت، تعداد زیادی گربه در خانهاش نگه میداشت.
او برای آنها یک زمین بازی در حیاط خانهاش ساخته بود. در طول روز، همیشه تعدادی از گربهها در زمین بازی بودند، اما گاهی فرانتیوم نمیدانست کدام گربهها مشغول بازی هستند.
به همین دلیل به ذهنش رسید که چرا برای گربهها یک سامانهی ورود و خروج درست نکند؟

# **پروژهی اولیه**
برای دانلود **پروژهی اولیه** روی [این لینک](/problemset/assignments/4367/download_problem_initial_project/316811/) کلیک کنید.
<details class="red">
<summary>**ساختار فایلها**</summary>
```
samane/
├─ public/
│ └─ vite.svg
├─ src/
│ ├─ api/
│ │ ├─ attendance.api.ts
│ │ ├─ client.ts
│ │ ├─ products.api.ts
│ │ └─ users.api.ts
│ ├─ app/
│ │ ├─ App.tsx
│ │ └─ routes.tsx
│ ├─ components/
│ │ ├─ Layout/
│ │ │ ├─ MainLayout.tsx
│ │ │ └─ Sidebar.tsx
│ │ ├─ Modal/
│ │ │ └─ GenericModal.tsx
│ │ └─ Table/
│ │ └─ GenericTable.tsx
│ ├─ features/
│ │ ├─ dashboard/
│ │ │ ├─ DashboardPage.tsx
│ │ │ ├─ EntryModal.tsx
│ │ │ ├─ ExitModal.tsx
│ │ │ └─ useAttendance.ts
│ │ ├─ products/
│ │ │ ├─ ProductFormModal.tsx
│ │ │ ├─ ProductPage.tsx
│ │ │ └─ useProducts.ts
│ │ └─ users/
│ │ ├─ starter/
│ │ │ ├─ UserFormModal_starter.tsx
│ │ │ └─ useUsers_starter.ts
│ │ ├─ UserFormModal.tsx
│ │ ├─ UsersPage.tsx
│ │ └─ useUsers.ts
│ ├─ types/
│ │ └─ index.ts
│ ├─ index.css
│ └─ main.tsx
├─ eslint.config.js
├─ index.html
├─ package.json
├─ README.md
├─ tsconfig.json
├─ tsconfig.node.json
└─ vite.config.ts
```
</details>
# **پیشنمایشهای پیادهسازی**
در گیفهای زیر، میتوانید تمام عملکرد برنامه را مشاهده کنید:



# **جزئیات پیادهسازی**
<details class="purple">
<summary>**فایل index.ts**</summary>
در این فایل شما باید **تایپهای مورد نیاز پروژه** را تعریف کنید، چرا که در ادامه در **تمامی کامپوننتها، فرمها و APIها** از این تایپها استفاده خواهد شد.
کامنتهای موجود در فایل به طور دقیق مشخص کردهاند که **هر تایپ چه پراپرتیهایی** نیاز دارد و نوع دادهی آنها چیست. بنابراین با دقت و صرف زمان مناسب، تایپها را **به درستی و کامل** تعریف کنید تا در مراحل بعدی پروژه با خطاهای تایپاسکریپتی مواجه نشوید.
**نکات مهم هنگام پیادهسازی:**
+ از نامهای پیشنهادی در کامنتها استفاده کنید تا هماهنگی با سایر بخشها حفظ شود.
+ برای مقادیر محدود، مثل جنسیت، حتماً **نوع محدود (union type)** تعریف کنید تا مقدار دیگری پذیرفته نشود.
+ پراپرتیهای اختیاری را با `?` مشخص کنید.
+ تایپهای مرتبط با پاسخ API یا payload ها باید دقیقاً مشابه کامنتها تعریف شوند تا سایر بخشها بتوانند بدون خطا با آنها کار کنند.
**توجه:** پس از تکمیل تایپها حتما تمام کامنتها را پاک کنید!
</details>
<details class="purple">
<summary>**کامپوننت main.tsx**</summary>
+ یک `QueryClient` بسازید و آن را با `QueryClientProvider` در بالاترین سطح پروژه قرار دهید.
+ بعد از اینکار، میتوانید در کل پروژه از `useQuery`, `useMutation` و سایر hooks های React Query استفاده کنید.
+ این ساختار پایه برای مدیریت state های async و دادههای API است و نیازی به تغییر `App` یا فایلهای دیگر نیست.
</details>
<details class="purple">
<summary>**پیادهسازی Routes.ts و App.tsx**</summary>
<details class="yellow">
<summary>**فایل Routes.ts**</summary>
**وظیفه:**
+ پروژه را به router وصل میکند تا مسیریابی در اپلیکیشن کار کند.
+ بالاترین سطح اپلیکیشن را مدیریت میکند و `RouterProvider` از `react-router-dom` را رندر میکند.
**نکات مهم:**
+ `router` که از فایل `routes.tsx` صادر شده، باید به `RouterProvider` داده شود.
</details>
<details class="yellow">
<summary>**کامپوننت App.tsx**</summary>
**وظیفه:**
+ تعریف مسیرهای اپلیکیشن و تعیین component هایی که در هر مسیر نمایش داده میشوند.
+ استفاده از `createBrowserRouter` برای مدیریت مسیرهای SPA.
**نکات مهم:**
+ مسیر اصلی `/` با `MainLayout` نمایش داده میشود.
+ `MainLayout` شامل نوار کناری، header و فضای نمایش صفحات است.
+ مسیرهای داخلی:
+ `/` → `DashboardPage`
+ `/users` → `UsersPage`
+ `/products` → `ProductPage`
+ مسیرها باید با `children` زیر `MainLayout` تعریف شوند تا layout ثابت بماند.
</details>
</details>
<details class="purple">
<summary>**دایرکتوری api**</summary>
<details class="yellow">
<summary>**فایل client.ts**</summary>
## پیادهسازی `axiosClient`
### هدف
ساخت یک **کلاینت استاندارد Axios** برای مدیریت یکپارچهی درخواستها و پاسخهای API.
این کلاینت باید در تمام بخشهای پروژه برای ارتباط با سرور استفاده شود و مسئول مدیریت خطاها نیز باشد.
### مقدمه
[`axios`](https://axios-http.com/docs/intro) یک کتابخانهی HTTP Client برای مرورگر و Node.js است که:
+ از `Promise` پشتیبانی میکند.
+ امکان ارسال درخواستهای `GET`, `POST`, `PUT`, `DELETE` و ... را فراهم میکند.
+ با TypeScript سازگار است و قابلیت تایپ کردن `request` و `response` دارد.
### گامهای پیادهسازی
1. **ایجاد کلاینت Axios**
ابتدا یک کلاینت Axios با تنظیمات پایه بسازید:
`baseURL`
تمام مسیرهای API باید با مقدار `/api` آغاز شوند. مثلاً اگر `axiosClient.get("/users")` فراخوانی شود، مسیر نهایی `/api/users` خواهد بود.
`headers`
هدر پیشفرض تمام درخواستها باید شامل `"Content-Type": "application/json"` باشد.
2. **افزودن Interceptor برای پاسخها**
+ در `axios` میتوانید از **interceptors** استفاده کنید تا قبل یا بعد از ارسال درخواست، منطق خاصی اجرا کنید.
+ در این پروژه، فقط نیاز است **interceptor پاسخ (response interceptor)** را پیادهسازی کنید.
+ این interceptor باید:
+ در حالت موفق، پاسخ را بدون تغییر بازگرداند.
+ در حالت خطا، جزئیات خطا (مثلاً `error.response`) را در کنسول چاپ کند تا در زمان توسعه قابل بررسی باشد.
+ سپس، خطا را بازگرداند تا در لایههای بالاتر (مثلاً در React Query) بتوان آن را مدیریت کرد.
3. **برگرداندن مقدار نهایی**
+ در پایان، `axiosClient` را export کنید تا در سایر بخشهای پروژه قابل استفاده باشد.
#### نکته
در این فایل نیازی به مدیریت توکن یا احراز هویت نیست. هدف تنها ایجاد یک ساختار اولیهی استاندارد برای ارسال درخواستها و هندل کردن خطاهاست.
</details>
<details class="yellow">
<summary>**فایل users.api.ts**</summary>
این فایل شامل سه تابع اصلی برای مدیریت دادههای کاربر بهصورت **mock (شبیهسازیشده)** است.
هدف از این فایل، فراهم کردن رابطی ساده برای دریافت، اضافهکردن و ریستکردن لیست کاربران است.
<details class="purple">
<summary>**تابع getUsers**</summary>
**توضیح:**
این تابع برای دریافت لیست کاربران استفاده میشود.
در صورت ارسال پارامتر `q`، کاربران بر اساس نام یا نام خانوادگی فیلتر میشوند.
**ورودی:**
+ `q` (اختیاری): رشتهای برای جستوجو در نام یا نام خانوادگی.
**خروجی:**
+ `Promise<User[]>` → لیستی از کاربران (بهصورت async).
</details>
<details class="purple">
<summary>**تابع createUser**</summary>
**توضیح:**
برای افزودن کاربر جدید به لیست استفاده میشود.
تابع بهصورت خودکار شناسه (id) تولید کرده و کاربر جدید را به آرایه اضافه میکند.
**ورودی:**
+ `newUser`: شیئی شامل مشخصات کاربر **بهجز فیلد `id`**
(زیرا `id` بهصورت خودکار ساخته میشود)
**خروجی:**
+ `Promise<User>` → کاربر ایجاد شده همراه با `id` جدید.
</details>
<details class="purple">
<summary>**تابع resetUsers**</summary>
**توضیح:**
لیست کاربران را به حالت اولیه (۱۰ کاربر اول) برمیگرداند.
در واقع تمام کاربران جدید اضافهشده حذف میشوند.
</details>
**نکته:** تمام توابع بهصورت شبیهسازیشده دارای تأخیر (delay) هستند تا رفتار واقعی API را تداعی کنند.
</details>
<details class="yellow">
<summary>**فایل products.api.ts**</summary>
این فایل شامل توابعی برای **مدیریت دادههای محصولات بهصورت mock** است.
<details class="purple">
<summary>**تابع getProducts**</summary>
**توضیح:**
این تابع لیست کامل محصولات را برمیگرداند.
همه دادهها از یک آرایهی شبیهسازیشده (`mockProducts`) خوانده میشوند.
**ورودی:**
ندارد.
**خروجی:**
+ `Promise<Product[]>` → لیستی از تمام محصولات.
</details>
<details class="purple">
<summary>**تابع createProduct**</summary>
**توضیح:**
برای افزودن محصول جدید استفاده میشود.
شناسه (`id`) بهصورت خودکار تولید شده و محصول جدید به لیست افزوده میشود.
**ورودی:**
+ `newProduct`: شیئی شامل نام و قیمت محصول (بدون `id`).
**خروجی:**
+ `Promise<Product>` → محصول ایجادشده همراه با `id` تصادفی.
</details>
<details class="purple">
<summary>**تابع resetProducts**</summary>
**توضیح:**
لیست محصولات را به حالت اولیه بازمیگرداند.
تمام محصولاتی که بعداً اضافه شدهاند حذف میشوند و دادهها به آرایهی اولیه برمیگردند.
</details>
**نکته:** همهی توابع شامل تأخیر مصنوعی هستند تا رفتار واقعی درخواستهای شبکه را شبیهسازی کنند
</details>
<details class="yellow">
<summary>**فایل attendance.api.ts**</summary>
این فایل مسئول **مدیریت ورود و خروج کاربران** و محاسبهی هزینهی حضور آنهاست.
همچنین ارتباط بین کاربران (`user`)، محصولات (`product`) و سوابق حضور (`attendance`) را شبیهسازی میکند.
## ثابتها و تنظیمات
```ts
const BASE_FEE_PER_HOUR = 10000;
```
هر کاربر بهازای هر **ساعت حضور** باید مبلغ ۱۰٬۰۰۰ تومان پرداخت کند.
هزینه بر اساس دقیقه محاسبه میشود (`ratePerMinute = BASE_FEE_PER_HOUR / 60`).
<details class="purple">
<summary>**تابع getPresentUsers**</summary>
**توضیح:**
لیست تمام کاربرانی را برمیگرداند که **وارد شدهاند اما هنوز خارج نشدهاند**.
**ورودی:**
ندارد.
**خروجی:**
+ `Promise<AttendanceRecord[]>` → لیست کاربران حاضر.
</details>
<details class="purple">
<summary>**تابع enterUser**</summary>
**توضیح:**
ثبت ورود یک کاربر جدید به سیستم.
اگر کاربر هنوز خارج نشده باشد، خطا میدهد.
**ورودی:**
+ `payload.userId` → شناسهی کاربر.
+ `payload.enteredAt` (اختیاری) → زمان ورود (در صورت عدم ارسال، زمان فعلی ثبت میشود).
**خروجی:**
+ `Promise<AttendanceRecord>` → رکورد ثبتشدهی ورود.
</details>
<details class="purple">
<summary>**تابع exitUser**</summary>
**توضیح:**
ثبت خروج کاربر از سیستم و محاسبهی هزینهی نهایی.
در زمان خروج، مدت حضور و محصولات خریداریشده لحاظ میشوند.
**مراحل عملکرد تابع:**
1. بررسی میکند که رکورد حضور وجود داشته باشد و خروج قبلاً ثبت نشده باشد.
2. مدت حضور (برحسب دقیقه) محاسبه میشود.
3. هزینهی پایه بر اساس زمان محاسبه میشود.
4. قیمت محصولات انتخابشده (از `getProducts()`) جمع زده میشود.
5. مجموع کل (`total`) = `baseFee + productsTotal`.
6. مقدار خروج (`exitedAt`) و محصولات (`productIds`) در رکورد ذخیره میشوند.
</details>
<details class="purple">
<summary>**تابع resetAttendance**</summary>
**توضیح:**
تمام سوابق حضور را پاک کرده و سیستم را به حالت اولیه بازمیگرداند.
</details>
**نکته:** مثل سایر فایلهای API، همهی توابع شامل تأخیر شبیهسازیشده هستند
</details>
</details>
<details class="purple">
<summary>**دایرکتوری components**</summary>
<details class="yellow">
<summary>**فایل Layout**</summary>
<details class="purple">
<summary>**کامپوننت MainLayout**</summary>
در این فایل، ساختار اصلی صفحه تعریف شده است که شامل دو بخش اصلی میباشد:
+ `Sidebar` برای نمایش منوی کناری
+ `Content` برای نمایش محتوای متغیر (داینامیک)
در قسمت مشخصشده با کامنت `Content`، باید محتوای هر صفحه (مثلاً داشبورد، کاربران، تنظیمات و ...) بهصورت **داینامیک** نمایش داده شود.
هدف این است که هنگام تغییر مسیر (Route)، فقط بخش محتوایی بهروز شود و ساختار کلی صفحه (مثل Sidebar) ثابت بماند.
</details>
<details class="purple">
<summary>**کامپوننت Sidebar.tsx**</summary>
در این فایل باید منوی کناری (Sidebar) را از نظر **منطق عملکرد** پیادهسازی کنید.
تمام ساختار و استایل مورد نیاز از قبل آماده است، اما هیچ رفتار یا دادهی منطقی وجود ندارد.
### هدف:
نمایش یک منوی ناوبری در سمت راست صفحه که کاربر بتواند با کلیک بر روی هر آیتم، بین صفحات مختلف جابهجا شود و آیتم فعال مشخص باشد.
### گامهای پیادهسازی
#### 1. **ایمپورتهای مورد نیاز**
از کتابخانههای زیر استفاده کنید:
+ `useNavigate` و `useLocation` از `react-router-dom` برای مدیریت مسیرها
+ آیکونهای مورد نیاز از `@mui/icons-material`
(مثلاً `DashboardIcon`, `PeopleIcon`, `InventoryIcon`)
#### 2. **ایجاد آرایه آیتمها**
در داخل کامپوننت، آرایهای به نام `items` بسازید که شامل آبجکتهایی با ساختار زیر باشد:
```ts
{
text: string; // عنوان آیتم (مثلاً "کاربران")
icon: JSX.Element; // آیکون مربوطه
path: string; // مسیر صفحه (مثلاً "/users")
}
```
به عنوان مثال، سه آیتم با مسیرهای زیر نیاز است:
+ `/` برای صفحهی داشبورد
+ `/users` برای صفحهی کاربران
+ `/products` برای صفحهی هزینههای مازاد
#### 3. **رندر کردن آیتمها**
درون تگ `<List>`، از متد `map` برای نمایش تمام آیتمها استفاده کنید.
در هر `ListItemButton`:
+ مسیر فعلی را با `location.pathname` مقایسه کنید تا آیتم فعال (`selected`) مشخص شود.
+ هنگام کلیک، با استفاده از `navigate(path)` کاربر را به صفحهی جدید هدایت کنید.
#### 4. **نکته مهم**
شما **نباید ساختار، استایل یا layout** را تغییر دهید.
فقط منطق مربوط به:
+ ایجاد آرایه آیتمها
+ تشخیص مسیر فعال
+ جابهجایی بین صفحات
را پیادهسازی کنید.
</details>
</details>
<details class="yellow">
<summary>**فایل Modal**</summary>
</details>
<details class="yellow">
<summary>**فایل Table**</summary>
در این بخش باید یک **کامپوننت عمومی جدول (Generic Table)** پیادهسازی کنید که بتواند هر نوع دادهای را بر اساس ستونهای دادهشده نمایش دهد.
### هدف:
ساخت کامپوننتی که با دریافت آرایهای از ستونها و دادهها، جدول را بهصورت داینامیک نمایش دهد.
این کامپوننت باید بتواند برای هر نوع دادهای (Users، Products، Records و...) قابل استفاده باشد.
### مشخصات Props
#### 1. `columns: Column[]`
هر ستون شامل دو مقدار است:
```ts
{
key: string; // کلید مربوط به فیلد داده (مثلاً "name" یا "price")
label: string; // عنوان نمایشی در هدر جدول
}
```
#### 2. `data: T[]`
آرایهای از آبجکتها که هرکدام یک ردیف جدول هستند.
هر شیء میتواند شامل هر کلید دلخواهی باشد (بنابراین باید از `Generic Type` استفاده کنید).
### وظیفه شما
درون جدول، باید موارد زیر را پیادهسازی کنید:
#### بخش سرستون (TableHead)
+ با استفاده از `columns.map` تمام ستونها را رندر کنید.
+ مقدار `col.label` باید در هر سلول نمایش داده شود.
+ جهت متن در سلولها باید راستچین باشد (`align="right"`).
#### بخش بدنه (TableBody)
+ با استفاده از `data.map`، تمام سطرهای جدول را ایجاد کنید.
+ برای هر ردیف (`row`) از `columns.map` استفاده کنید تا ترتیب ستونها مطابق `columns` باشد.
+ مقدار هر سلول باید از `row[col.key]` خوانده شود.
### نکات مهم
1. جدول باید **کاملاً داینامیک** باشد — هیچ ستونی نباید بهصورت دستی نوشته شود.
2. برای کلیدهای `TableRow` و `TableCell` از مقادیر منحصربهفرد (مثل index یا key) استفاده کنید.
3. نوع دادهی ورودی را بهصورت **Generic** تعریف کنید تا برای هر مدل داده قابل استفاده باشد:
```ts
const GenericTable = <T extends Record<string, any>>({...}: GenericTableProps<T>)
```
### نتیجه مورد انتظار
هنگام استفاده از این کامپوننت به شکل زیر:
```tsx
<GenericTable
columns={[
{ key: "name", label: "نام" },
{ key: "price", label: "قیمت" },
]}
data={[
{ name: "آب معدنی", price: 2000 },
{ name: "چیپس", price: 3000 },
]}
/>
```
</details>
</details>
<details class="purple">
<summary>**دایرکتوری features**</summary>
در این بخش سه ویژگی (Feature) با نامهای زیر وجود دارد:
1. **users**
2. **products**
3. **dashboard**
در ادامه، هر سه دایرکتوری را بهصورت جداگانه بررسی میکنیم و تمام مواردی را که باید پیادهسازی کنید، توضیح خواهیم داد.
<details class="yellow">
<summary>**هوکها**</summary>
در هر فایل باید یکسری هوک نوشته شوند که آنها را شرح میدهیم
<details class="purple">
<summary>**فایل useUsers.ts**</summary>
در این فایل، دو هوک مرتبط با مدیریت کاربران باید پیادهسازی شوند:
1. **`useUsers`**
2. **`useCreateUser`**
هر دو هوک از کتابخانهی **React Query (TanStack Query)** برای مدیریت دادههای سمت سرور و بهروزرسانی خودکار UI استفاده میکنند.
### پیادهسازی هوک `useUsers`
در این بخش، باید از هوک `useQuery` مربوط به **React Query** استفاده کنید.
مراحل کلی به این صورت است:
1. ابتدا یک کلید ثابت برای کش دادهها با نام مثلاً `"users"` تعریف کنید.
2. سپس از `useQuery` برای فراخوانی تابعی مانند `getUsers` استفاده کنید که دادهها را از API برمیگرداند.
3. اگر در ورودی هوک یک مقدار جستجو (`q`) دریافت میکنید، آن را هم در `queryKey` لحاظ کنید تا کش برای هر مقدار جستجو منحصربهفرد باشد.
4. در نهایت، هوک باید دادهها، وضعیت بارگذاری و خطا را برگرداند.
**نکته:**
تابع `getUsers` را از مسیر `../../api/users.api` ایمپورت کنید و نوع دادهی خروجی را از `User` تعریفشده در `../../types` بگیرید.
### پیادهسازی هوک `useCreateUser`
در این بخش باید از هوک `useMutation` استفاده کنید تا امکان **افزودن کاربر جدید** فراهم شود.
مراحل پیشنهادی:
1. از `useQueryClient` برای دسترسی به کش سراسری React Query استفاده کنید.
2. از `useMutation` برای فراخوانی تابعی مانند `createUser` بهره بگیرید. این تابع باید اطلاعات کاربر جدید را به API ارسال کند.
3. در بخش `onSuccess`، با استفاده از `invalidateQueries` کش مربوط به کلید `"users"` را پاک کنید تا پس از افزودن کاربر جدید، لیست کاربران بهروز شود.
**نکته:**
برای ورودی تابع ایجاد کاربر، از نوع `Omit<User, "id">` استفاده کنید تا شناسه (`id`) که توسط سرور ایجاد میشود، ارسال نگردد.
</details>
<details class="purple">
<summary>**فایل useProducts.ts**</summary>
در این فایل باید دو هوک برای مدیریت دادههای مربوط به محصولات پیادهسازی شوند:
1. **`useProducts`** برای دریافت فهرست محصولات از سرور
2. **`useCreateProduct`** برای ایجاد محصول جدید و بهروزرسانی دادهها پس از آن
### پیادهسازی هوک `useProducts`
در این قسمت، باید با استفاده از `useQuery` دادههای مربوط به محصولات را از API دریافت کنید.
مراحل کلی:
1. ابتدا یک کلید کش برای دادههای محصولات با نام `"products"` تعریف کنید تا React Query دادهها را بر اساس آن ذخیره و مدیریت کند.
2. سپس از `useQuery` برای فراخوانی تابع `getProducts` استفاده کنید. این تابع دادهها را از سرور برمیگرداند.
3. هوک باید دادهها، وضعیت بارگذاری (`isLoading`)، خطا (`error`) و سایر وضعیتهای مربوط به Query را برگرداند تا در کامپوننتهای دیگر قابل استفاده باشد.
**نکته:**
تابع `getProducts` باید از مسیر `../../api/products.api` ایمپورت شود و نوع دادهی خروجی آن `Product[]` باشد که از مسیر `../../types` در دسترس است.
### پیادهسازی هوک `useCreateProduct`
در این بخش باید هوکی برای ایجاد محصول جدید پیادهسازی کنید. برای این کار از `useMutation` استفاده میشود.
مراحل پیشنهادی:
1. از `useQueryClient` برای دسترسی به کش سراسری React Query استفاده کنید.
2. از `useMutation` برای ارسال دادههای محصول جدید با تابع `createProduct` بهره بگیرید.
3. در قسمت `onSuccess`، با استفاده از `invalidateQueries` کش مربوط به `"products"` را پاک کنید تا پس از ایجاد محصول، لیست محصولات بهروزرسانی شود.
**نکته:**
در این بخش باید نوع ورودی تابع ایجاد محصول را بهصورت `Omit<Product, "id">` تعریف کنید، چون شناسه محصول توسط سرور ساخته میشود.
</details>
<details class="purple">
<summary>**فایل useAttendance.ts**</summary>
در این فایل چهار هوک مهم برای مدیریت حضور و غیاب کاربران وجود دارد:
1. **`usePresentUsers`** → دریافت لیست کاربران حاضر
2. **`useEnterUser`** → ثبت ورود کاربر
3. **`useExitUser`** → ثبت خروج کاربر
4. **`useResetAttendance`** → ریست کردن دادههای حضور و غیاب
### پیادهسازی هوک `usePresentUsers`
+ این هوک برای دریافت تمام رکوردهای حاضر کاربران استفاده میشود.
+ باید از `useQuery` استفاده کنید و یک **کلید کش سراسری** تعریف کنید، مثلاً `"attendance"`.
+ تابع `queryFn` باید `getPresentUsers` باشد تا دادهها را از سرور بگیرد.
+ هوک باید وضعیت بارگذاری (`isLoading`)، دادهها (`data`) و خطا (`error`) را برگرداند تا در کامپوننتها قابل استفاده باشد.
### پیادهسازی هوک `useEnterUser`
+ این هوک برای ثبت ورود یک کاربر جدید است.
+ از `useMutation` استفاده کنید و تابع `mutationFn` آن `enterUser` باشد.
+ بعد از موفقیت، باید کش مربوط به `"attendance"` را با `invalidateQueries` تازه کنید تا لیست کاربران حاضر بروز شود.
+ نوع ورودی دادهها (`payload`) باید مطابق `EnterPayload` باشد.
### پیادهسازی هوک `useExitUser`
+ مشابه `useEnterUser` است ولی برای ثبت خروج کاربران.
+ `mutationFn` اینجا تابع `exitUser` است و بعد از موفقیت کش `"attendance"` باید تازه شود.
+ نوع دادهی ورودی `ExitPayload` و خروجی `ExitResponse` است.
### پیادهسازی هوک `useResetAttendance`
+ این هوک برای ریست کردن کل دادههای حضور و غیاب استفاده میشود.
+ از `useMutation` استفاده کنید و تابع `mutationFn` آن `resetAttendance` باشد.
+ پس از موفقیت، کش `"attendance"` را با `invalidateQueries` تازه کنید.
+ این هوک هیچ دادهای به عنوان ورودی نمیگیرد و خروجی آن هم `void` است.
</details>
</details>
</details>