From 2a3b9a7d6a0accb2559e5419c2e226dce07eb3c2 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Sun, 16 Nov 2025 09:07:43 +0330 Subject: [PATCH] list of schedules --- src/config/Pages.ts | 5 +- src/langs/fa.json | 1 + src/pages/schedule/List.tsx | 68 +++++++++++++++++++ .../components/ScheduleFiltersFields.tsx | 13 ++++ .../components/ScheduleTableColumns.tsx | 65 ++++++++++++++++++ src/pages/schedule/hooks/useScheduleData.ts | 19 ++++++ .../schedule/hooks/useScheduleFilters.ts | 43 ++++++++++++ src/pages/schedule/service/ScheduleService.ts | 16 +++++ src/pages/schedule/types/Types.ts | 14 ++++ src/router/Main.tsx | 2 + src/shared/SideBar.tsx | 15 ++-- 11 files changed, 253 insertions(+), 8 deletions(-) create mode 100644 src/pages/schedule/List.tsx create mode 100644 src/pages/schedule/components/ScheduleFiltersFields.tsx create mode 100644 src/pages/schedule/components/ScheduleTableColumns.tsx create mode 100644 src/pages/schedule/hooks/useScheduleData.ts create mode 100644 src/pages/schedule/hooks/useScheduleFilters.ts create mode 100644 src/pages/schedule/service/ScheduleService.ts create mode 100644 src/pages/schedule/types/Types.ts diff --git a/src/config/Pages.ts b/src/config/Pages.ts index a3ca234..db3298b 100644 --- a/src/config/Pages.ts +++ b/src/config/Pages.ts @@ -5,11 +5,14 @@ export const Pages = { forgotPassword: "/auth/forgot", }, dashboard: "/dashboard", + schedule: { + list: "/schedule/list", + update: "/schedule/update/", + }, foods: { list: "/foods/list", add: "/foods/add", category: "/foods/category", - detail: "/foods/detail/", update: "/foods/update/", }, orders: { diff --git a/src/langs/fa.json b/src/langs/fa.json index a93441e..45b426f 100644 --- a/src/langs/fa.json +++ b/src/langs/fa.json @@ -45,6 +45,7 @@ "sidebar": { "menu": "منو", "mainpage": "صفحه اصلی", + "schedule": "برنامه زمان‌بندی", "foods": "غذا ها", "orders": "سفارشات", "customers": "مشتریان", diff --git a/src/pages/schedule/List.tsx b/src/pages/schedule/List.tsx new file mode 100644 index 0000000..fcba159 --- /dev/null +++ b/src/pages/schedule/List.tsx @@ -0,0 +1,68 @@ +import { type FC } from 'react' +import Table from '@/components/Table' +import Filters from '@/components/Filters' +import { Add } from 'iconsax-react' +import Button from '@/components/Button' +import { useGetSchedules, useDeleteSchedule } from './hooks/useScheduleData' +import { useScheduleFilters } from './hooks/useScheduleFilters' +import { getScheduleTableColumns } from './components/ScheduleTableColumns' +import { useScheduleFiltersFields } from './components/ScheduleFiltersFields' + +const ScheduleList: FC = () => { + const { + filters, + currentPage, + apiParams, + handleFiltersChange, + handlePageChange, + limit, + } = useScheduleFilters() + + const { data: schedulesData, isLoading } = useGetSchedules(apiParams) + const { mutate: deleteSchedule, isPending: isDeleting } = useDeleteSchedule() + + const schedules = schedulesData?.data || [] + const columns = getScheduleTableColumns({ + onDelete: (id: string) => deleteSchedule(id), + isDeleting + }) + const filterFields = useScheduleFiltersFields() + + const totalPages = Math.ceil(schedules.length / limit) || 1 + + return ( +
+
+

لیست زمانبندی

+ +
+ +
+ +
+ + + + ) +} + +export default ScheduleList \ No newline at end of file diff --git a/src/pages/schedule/components/ScheduleFiltersFields.tsx b/src/pages/schedule/components/ScheduleFiltersFields.tsx new file mode 100644 index 0000000..ec775ba --- /dev/null +++ b/src/pages/schedule/components/ScheduleFiltersFields.tsx @@ -0,0 +1,13 @@ +import { useMemo } from 'react' +import type { FieldType } from '@/components/Filters' + +export const useScheduleFiltersFields = (): FieldType[] => { + return useMemo(() => [ + { + type: 'input', + name: 'search', + placeholder: 'جستجو', + }, + ], []) +} + diff --git a/src/pages/schedule/components/ScheduleTableColumns.tsx b/src/pages/schedule/components/ScheduleTableColumns.tsx new file mode 100644 index 0000000..731f57e --- /dev/null +++ b/src/pages/schedule/components/ScheduleTableColumns.tsx @@ -0,0 +1,65 @@ +import type { ColumnType } from '@/components/types/TableTypes' +import type { Schedule } from '../types/Types' +import Status from '@/components/Status' +import TrashWithConfrim from '@/components/TrashWithConfrim' +import { Eye } from 'iconsax-react' +import { Link } from 'react-router-dom' +import { Pages } from '@/config/Pages' + +interface GetScheduleTableColumnsParams { + onDelete?: (id: string) => void + isDeleting?: boolean +} + +export const getScheduleTableColumns = ({ onDelete, isDeleting }: GetScheduleTableColumnsParams = {}): ColumnType[] => { + return [ + { + key: 'openTime', + title: 'زمان باز', + }, + { + key: 'closeTime', + title: 'زمان بسته', + }, + { + key: 'isActive', + title: 'وضعیت', + render: (item: Schedule) => { + return ( + + ) + } + }, + { + key: 'createdAt', + title: 'تاریخ ایجاد', + render: (item: Schedule) => { + return new Date(item.createdAt).toLocaleDateString('fa-IR') + } + }, + { + key: 'actions', + title: '', + render: (item: Schedule) => { + return ( +
+ + + + {onDelete && ( + onDelete(item.id)} + isLoading={isDeleting} + /> + )} +
+ ) + } + }, + ] +} + diff --git a/src/pages/schedule/hooks/useScheduleData.ts b/src/pages/schedule/hooks/useScheduleData.ts new file mode 100644 index 0000000..b33a46d --- /dev/null +++ b/src/pages/schedule/hooks/useScheduleData.ts @@ -0,0 +1,19 @@ +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import * as api from "../service/ScheduleService"; + +export const useGetSchedules = (params?: Record) => { + return useQuery({ + queryKey: ["schedules", params], + queryFn: () => api.getSchedules(params), + }); +}; + +export const useDeleteSchedule = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: api.deleteSchedule, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ["schedules"] }); + }, + }); +}; diff --git a/src/pages/schedule/hooks/useScheduleFilters.ts b/src/pages/schedule/hooks/useScheduleFilters.ts new file mode 100644 index 0000000..a729ebc --- /dev/null +++ b/src/pages/schedule/hooks/useScheduleFilters.ts @@ -0,0 +1,43 @@ +import { useState, useMemo } from 'react' +import type { FilterValues } from '@/components/Filters' + +const DEFAULT_PAGE = 1 +const DEFAULT_LIMIT = 10 + +export const useScheduleFilters = () => { + const [filters, setFilters] = useState({}) + const [currentPage, setCurrentPage] = useState(DEFAULT_PAGE) + const [limit] = useState(DEFAULT_LIMIT) + + const apiParams = useMemo(() => { + const params: Record = { + page: currentPage, + limit: limit, + } + + if (filters.search) { + params.search = filters.search + } + + return params + }, [filters, currentPage, limit]) + + const handleFiltersChange = (newFilters: FilterValues) => { + setFilters(newFilters) + setCurrentPage(DEFAULT_PAGE) + } + + const handlePageChange = (page: number) => { + setCurrentPage(page) + } + + return { + filters, + currentPage, + apiParams, + handleFiltersChange, + handlePageChange, + limit, + } +} + diff --git a/src/pages/schedule/service/ScheduleService.ts b/src/pages/schedule/service/ScheduleService.ts new file mode 100644 index 0000000..d92e7e4 --- /dev/null +++ b/src/pages/schedule/service/ScheduleService.ts @@ -0,0 +1,16 @@ +import axios from "@/config/axios"; +import type { GetSchedulesResponseType } from "../types/Types"; + +export const getSchedules = async ( + params?: Record +): Promise => { + const { data } = await axios.get("/schedules", { + params, + }); + return data; +}; + +export const deleteSchedule = async (id: string) => { + const { data } = await axios.delete(`/schedules/${id}`); + return data; +}; diff --git a/src/pages/schedule/types/Types.ts b/src/pages/schedule/types/Types.ts new file mode 100644 index 0000000..8effde8 --- /dev/null +++ b/src/pages/schedule/types/Types.ts @@ -0,0 +1,14 @@ +import type { IResponse } from "@/types/response.types"; + +export type Schedule = { + id: string; + createdAt: string; + updatedAt: string; + deletedAt: string | null; + openTime: string; + closeTime: string; + isActive: boolean; + restId: string; +}; + +export type GetSchedulesResponseType = IResponse; diff --git a/src/router/Main.tsx b/src/router/Main.tsx index 04499e3..4ad1496 100644 --- a/src/router/Main.tsx +++ b/src/router/Main.tsx @@ -17,6 +17,7 @@ import OrdersList from '@/pages/orders/List' import OrderDetails from '@/pages/orders/Details' import CommentsList from '@/pages/comments/List' import CommentsDetails from '@/pages/comments/Details' +import ScheduleList from '@/pages/schedule/List' const MainRouter: FC = () => { const { hasSubMenu } = useSharedStore() @@ -45,6 +46,7 @@ const MainRouter: FC = () => { } /> } /> } /> + } /> diff --git a/src/shared/SideBar.tsx b/src/shared/SideBar.tsx index 0f96502..a8450dd 100644 --- a/src/shared/SideBar.tsx +++ b/src/shared/SideBar.tsx @@ -2,7 +2,7 @@ import { type FC, useEffect } from 'react' import LogoImage from '../assets/images/logo.svg' import LogoSmall from '../assets/images/logo-small.svg' import { useTranslation } from 'react-i18next' -import { Element3, DocumentText, Home2, Logout, Message, NotificationStatus, People, Setting2, TicketDiscount, Chart } from 'iconsax-react' +import { DocumentText, Home2, Logout, Message, NotificationStatus, People, Setting2, TicketDiscount, Chart, Calendar } from 'iconsax-react' import SideBarItem from './SideBarItem' import { useLocation } from 'react-router-dom' import { Pages } from '../config/Pages' @@ -77,13 +77,14 @@ const SideBar: FC = () => { activeName='' /> } - title={t('sidebar.foods')} - isActive={isActive('foods')} - link={Pages.foods.list} - name='foods' - activeName='foods' + icon={} + title={t('sidebar.schedule')} + isActive={isActive('schedule')} + link={Pages.schedule.list} + name='schedule' + activeName='schedule' /> + } title={t('sidebar.orders')}