From deda1f1603ed695a80ff0132c1941c15f37d8010 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Mon, 29 Dec 2025 16:21:00 +0330 Subject: [PATCH] sms count --- src/config/Pages.ts | 1 + src/langs/fa.json | 5 +- src/pages/dmenu/hooks/useIconData.ts | 15 ++++ src/pages/dmenu/restaurant/List.tsx | 39 +++++++--- src/pages/dmenu/restaurant/SmsCountList.tsx | 53 ++++++++++++++ .../components/RestaurantAdminsModal.tsx | 71 +++++++++++++++++++ src/pages/dmenu/service/IconService.ts | 15 ++++ src/pages/dmenu/types/Types.ts | 26 +++++++ src/router/Main.tsx | 2 + src/shared/SideBar.tsx | 12 +++- 10 files changed, 229 insertions(+), 10 deletions(-) create mode 100644 src/pages/dmenu/restaurant/SmsCountList.tsx create mode 100644 src/pages/dmenu/restaurant/components/RestaurantAdminsModal.tsx diff --git a/src/config/Pages.ts b/src/config/Pages.ts index 3b93268..c5c2c4c 100644 --- a/src/config/Pages.ts +++ b/src/config/Pages.ts @@ -132,6 +132,7 @@ export const Pages = { }, restaurants: { list: "/dmenu/restaurants/list", + smsCountList: "/dmenu/sms-count/list", }, }, }; diff --git a/src/langs/fa.json b/src/langs/fa.json index 1460603..8f4a1e8 100644 --- a/src/langs/fa.json +++ b/src/langs/fa.json @@ -872,6 +872,7 @@ }, "restaurant": { "list_restaurant": "لیست رستوران‌ها", + "list_sms_count": "لیست تعداد پیامک‌های رستوران‌ها", "name": "نام", "phone": "شماره تماس", "address": "آدرس", @@ -880,7 +881,9 @@ "plan": "پلن", "created_at": "تاریخ ایجاد", "active": "فعال", - "inactive": "غیرفعال" + "inactive": "غیرفعال", + "admins": "مدیران", + "sms_count": "تعداد پیامک" }, "cancel": "لغو" } diff --git a/src/pages/dmenu/hooks/useIconData.ts b/src/pages/dmenu/hooks/useIconData.ts index 1815ff7..5f91c91 100644 --- a/src/pages/dmenu/hooks/useIconData.ts +++ b/src/pages/dmenu/hooks/useIconData.ts @@ -53,3 +53,18 @@ export const useGetRestaurants = () => { queryFn: api.getRestaurants, }); }; + +export const useGetRestaurantAdmins = (restaurantId: string) => { + return useQuery({ + queryKey: ["restaurant-admins", restaurantId], + queryFn: () => api.getRestaurantAdmins(restaurantId), + enabled: !!restaurantId, + }); +}; + +export const useGetRestaurantSmsCount = () => { + return useQuery({ + queryKey: ["restaurant-sms-count"], + queryFn: api.getRestaurantSmsCount, + }); +}; diff --git a/src/pages/dmenu/restaurant/List.tsx b/src/pages/dmenu/restaurant/List.tsx index cb674d6..d9bdf7c 100644 --- a/src/pages/dmenu/restaurant/List.tsx +++ b/src/pages/dmenu/restaurant/List.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react' +import { FC, useState } from 'react' import { useTranslation } from 'react-i18next' import { useGetRestaurants } from '../hooks/useIconData' import PageLoading from '../../../components/PageLoading' @@ -7,14 +7,28 @@ import { RestaurantType } from '../types/Types' import moment from 'moment-jalaali' import { Copy } from 'iconsax-react' import { toast } from 'react-toastify' +import Button from '../../../components/Button' +import RestaurantAdminsModal from './components/RestaurantAdminsModal' const RestaurantsList: FC = () => { const { t } = useTranslation('global') const { data: restaurants, isLoading } = useGetRestaurants() + const [selectedRestaurantId, setSelectedRestaurantId] = useState('') + const [isAdminsModalOpen, setIsAdminsModalOpen] = useState(false) const restaurantsList = (restaurants as { data?: RestaurantType[] })?.data || [] + const handleOpenAdminsModal = (restaurantId: string) => { + setSelectedRestaurantId(restaurantId) + setIsAdminsModalOpen(true) + } + + const handleCloseAdminsModal = () => { + setIsAdminsModalOpen(false) + setSelectedRestaurantId('') + } + const handleCopyAddress = async (address: string | null) => { if (!address) return @@ -87,21 +101,30 @@ const RestaurantsList: FC = () => { {moment(item.createdAt).format('jYYYY-jMM-jDD HH:mm')} - + +
+ +
+ ) }) } - - {restaurantsList.length === 0 && ( -
-
هیچ رستورانی یافت نشد
-
- )} } + + ) } diff --git a/src/pages/dmenu/restaurant/SmsCountList.tsx b/src/pages/dmenu/restaurant/SmsCountList.tsx new file mode 100644 index 0000000..e8b6cbc --- /dev/null +++ b/src/pages/dmenu/restaurant/SmsCountList.tsx @@ -0,0 +1,53 @@ +import { FC } from 'react' +import { useTranslation } from 'react-i18next' +import { useGetRestaurantSmsCount } from '../hooks/useIconData' +import PageLoading from '../../../components/PageLoading' +import Td from '../../../components/Td' +import { RestaurantSmsCountItem } from '../types/Types' + +const SmsCountList: FC = () => { + const { t } = useTranslation('global') + const { data: smsCount, isLoading } = useGetRestaurantSmsCount() + + const smsCountList = (smsCount as { data?: RestaurantSmsCountItem[] })?.data || [] + + return ( +
+
+
+ {t('restaurant.list_sms_count')} +
+
+ + { + isLoading ? + + : +
+ + + + + + + { + smsCountList.map((item: RestaurantSmsCountItem) => { + return ( + + + ) + }) + } + +
+ +
+ +
+
+ } +
+ ) +} + +export default SmsCountList \ No newline at end of file diff --git a/src/pages/dmenu/restaurant/components/RestaurantAdminsModal.tsx b/src/pages/dmenu/restaurant/components/RestaurantAdminsModal.tsx new file mode 100644 index 0000000..a324f9d --- /dev/null +++ b/src/pages/dmenu/restaurant/components/RestaurantAdminsModal.tsx @@ -0,0 +1,71 @@ +import { FC } from 'react' +import { useTranslation } from 'react-i18next' +import DefaulModal from '../../../../components/DefaulModal' +import { useGetRestaurantAdmins } from '../../hooks/useIconData' +import PageLoading from '../../../../components/PageLoading' +import Td from '../../../../components/Td' +import { RestaurantAdminType } from '../../types/Types' +import moment from 'moment-jalaali' + +interface RestaurantAdminsModalProps { + open: boolean + close: () => void + restaurantId: string +} + +const RestaurantAdminsModal: FC = ({ open, close, restaurantId }) => { + const { t } = useTranslation('global') + const { data: adminsData, isLoading } = useGetRestaurantAdmins(restaurantId) + + const adminsList = (adminsData as { data?: RestaurantAdminType[] })?.data || [] + + return ( + +
+ { + isLoading ? + + : +
+ + + + + + + { + adminsList.map((admin: RestaurantAdminType) => { + return ( + + + + ) + }) + } + +
+ + + +
+ + + +
+ {moment(admin.createdAt).format('jYYYY-jMM-jDD HH:mm')} +
+
+
+ } +
+
+ ) +} + +export default RestaurantAdminsModal + diff --git a/src/pages/dmenu/service/IconService.ts b/src/pages/dmenu/service/IconService.ts index 4958413..679a798 100644 --- a/src/pages/dmenu/service/IconService.ts +++ b/src/pages/dmenu/service/IconService.ts @@ -6,6 +6,7 @@ import { IconsResponse, ReportsResponse, RestaurantsResponse, + RestaurantSmsCountResponse, } from "../types/Types"; export const getIcons = async (): Promise => { @@ -47,3 +48,17 @@ export const getRestaurants = async (): Promise => { const { data } = await axios.get("/admin/dmenu/restaurants"); return data; }; + +export const getRestaurantAdmins = async (restaurantId: string) => { + const { data } = await axios.get( + `/admin/dmenu/restaurants/${restaurantId}/admins` + ); + return data; +}; + +export const getRestaurantSmsCount = async (): Promise< + RestaurantSmsCountResponse +> => { + const { data } = await axios.get(`/admin/dmenu/restaurants/sms-count`); + return data; +}; diff --git a/src/pages/dmenu/types/Types.ts b/src/pages/dmenu/types/Types.ts index 0c4dd30..99ee898 100644 --- a/src/pages/dmenu/types/Types.ts +++ b/src/pages/dmenu/types/Types.ts @@ -106,3 +106,29 @@ export type RestaurantType = { export interface RestaurantsResponse extends IResponse { statusCode: number; } + +export type RestaurantAdminType = { + id: string; + firstName: string; + lastName: string; + email: string; + phone: string; + createdAt: string; + updatedAt: string; +}; + +export interface RestaurantAdminsResponse + extends IResponse { + statusCode: number; +} + +export type RestaurantSmsCountItem = { + restaurantId: string; + restaurantName: string; + smsCount: number; +}; + +export interface RestaurantSmsCountResponse + extends IResponse { + statusCode: number; +} diff --git a/src/router/Main.tsx b/src/router/Main.tsx index 5e29f02..bc81848 100644 --- a/src/router/Main.tsx +++ b/src/router/Main.tsx @@ -81,6 +81,7 @@ import IconsList from '../pages/dmenu/icon/List' import GroupIconList from '../pages/dmenu/icon/GroupList' import WarningsList from '../pages/dmenu/report/List.tsx' import RestaurantsList from '../pages/dmenu/restaurant/List.tsx' +import SmsCountList from '../pages/dmenu/restaurant/SmsCountList.tsx' // import WarningsList from '../pages/dmenu/reports/List' // TODO: Create this component const MainRouter: FC = () => { @@ -175,6 +176,7 @@ const MainRouter: FC = () => { } /> } /> } /> + } /> diff --git a/src/shared/SideBar.tsx b/src/shared/SideBar.tsx index 3ec5a7f..60a2c96 100644 --- a/src/shared/SideBar.tsx +++ b/src/shared/SideBar.tsx @@ -2,7 +2,7 @@ import { 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 { Card, Code, CodeCircle, DocumentLike, DocumentText, Element3, Gallery, Headphone, Home2, Logout, Message, Messages3, Money3, NotificationStatus, People, Profile, Receipt21, Setting2, SmsTracking, Teacher, TicketDiscount, UserSquare, Activity, Icon, Category, Warning2, Building } from 'iconsax-react' +import { Card, Code, CodeCircle, DocumentLike, DocumentText, Element3, Gallery, Headphone, Home2, Logout, Message, Messages3, Money3, NotificationStatus, People, Profile, Receipt21, Setting2, SmsTracking, Teacher, TicketDiscount, UserSquare, Activity, Icon, Category, Warning2, Building, Sms } from 'iconsax-react' import SideBarItem from './SideBarItem' import { useLocation } from 'react-router-dom' import { Pages } from '../config/Pages' @@ -344,6 +344,16 @@ const SideBar: FC = () => { activeName='dmenu' /> + +
+ } + title={t('sidebar.sms_count')} + isActive={isActive('sms-count')} + link={Pages.dmenu.restaurants.smsCountList} + activeName='dmenu' + /> +
}