From 1b838e7a4ddb11d04fb2f2cae75bb48795521fd0 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Sun, 18 May 2025 12:41:42 +0330 Subject: [PATCH] auth + companies + invoice --- .env | 9 + .gitignore | 2 - src/App.tsx | 16 +- src/config/Pages.ts | 3 + src/config/axios.ts | 3 + src/config/axiosDanak.ts | 22 ++ src/config/func.ts | 12 +- src/index.css | 9 + src/langs/fa.json | 7 +- src/pages/ads/AdsList.tsx | 157 --------- src/pages/ads/CreateAds.tsx | 180 ----------- src/pages/ads/Update.tsx | 258 --------------- src/pages/ads/components/ImageUploader.tsx | 49 --- src/pages/ads/components/ToggleStatus.tsx | 28 -- src/pages/ads/hooks/useAdsData.ts | 47 --- src/pages/ads/service/AdsService.ts | 48 --- src/pages/ads/types/AdsTypes.ts | 36 --- src/pages/auth/service/AuthService.ts | 2 +- src/pages/cardBank/Create.tsx | 159 --------- src/pages/cardBank/Edit.tsx | 179 ----------- src/pages/cardBank/List.tsx | 84 ----- src/pages/cardBank/hooks/useCardBankData.ts | 46 --- src/pages/cardBank/service/CardBankService.ts | 22 -- src/pages/cardBank/types/CardBankTypes.ts | 15 - .../company/components/CreateIndustry.tsx | 4 + src/pages/customer/List.tsx | 12 +- src/pages/customer/hooks/useCustomerData.ts | 6 +- src/pages/customer/service/CustomerService.ts | 6 +- src/pages/discounts/CreateDiscount.tsx | 273 ---------------- src/pages/discounts/DiscountsList.tsx | 142 --------- src/pages/discounts/UpdateDiscount.tsx | 301 ------------------ .../discounts/components/ImageUploader.tsx | 49 --- .../components/ToggleStatusDiscount.tsx | 28 -- src/pages/discounts/hooks/useDiscountData.ts | 43 --- .../discounts/service/DiscountService.ts | 35 -- src/pages/discounts/types/DiscountTypes.ts | 52 --- src/pages/home/Home.tsx | 90 +++--- src/pages/home/hooks/useHomeData.ts | 6 +- src/pages/home/service/HomeService.ts | 8 +- src/pages/home/types/HomeTypes.ts | 48 +++ src/pages/learning/Category.tsx | 74 ----- src/pages/learning/Create.tsx | 167 ---------- src/pages/learning/List.tsx | 79 ----- .../learning/components/CreateCategory.tsx | 81 ----- .../components/CreateLearningSidebar.tsx | 40 --- src/pages/learning/hooks/useLearningData.ts | 34 -- src/pages/learning/service/LearningService.ts | 25 -- src/pages/learning/types/LearningTypes.ts | 34 -- src/pages/notification/Notification.tsx | 6 +- .../service/NotificationService.ts | 2 +- src/pages/profile/Profile.tsx | 4 +- src/pages/profile/service/ProfileService.ts | 3 +- src/pages/receipts/Create.tsx | 55 ++-- src/pages/receipts/List.tsx | 11 +- src/pages/receipts/service/ReceiptService.ts | 2 +- src/pages/receipts/types/ReceiptTypes.ts | 7 +- src/pages/slider/Create.tsx | 141 -------- src/pages/slider/List.tsx | 106 ------ src/pages/slider/Update.tsx | 149 --------- src/pages/slider/hooks/useSliderData.ts | 35 -- src/pages/slider/service/SliderService.ts | 27 -- src/pages/slider/types/SliderTypes.ts | 20 -- src/pages/support/Create.tsx | 212 ------------ src/pages/support/List.tsx | 85 ----- src/pages/support/PlanUsers.tsx | 56 ---- src/pages/support/Update.tsx | 233 -------------- src/pages/support/components/Delete.tsx | 36 --- src/pages/support/components/PlanItem.tsx | 50 --- src/pages/support/enum/SupportEnum.ts | 13 - src/pages/support/hooks/useSupportData.ts | 44 --- src/pages/support/service/SupportService.ts | 32 -- src/pages/support/types/SupportTypes.ts | 49 --- src/pages/ticket/Category.tsx | 30 +- .../ticket/components/DeleteCategory.tsx | 44 +++ src/pages/ticket/components/EditCategory.tsx | 101 ++++++ src/pages/ticket/hooks/useTicketData.ts | 33 +- src/pages/ticket/service/TicketServiec.ts | 19 +- src/pages/ticket/types/TicketTypes.ts | 7 +- src/pages/wallet/Wallet.tsx | 113 ------- src/pages/wallet/hooks/useWalletData.ts | 37 --- src/pages/wallet/service/WalletService.ts | 27 -- src/pages/wallet/types/WalletTypes.ts | 23 -- src/router/Main.tsx | 47 +-- src/shared/SideBar.tsx | 254 +++++---------- src/shared/components/TicketSubMenu.tsx | 5 - 85 files changed, 513 insertions(+), 4635 deletions(-) create mode 100644 .env create mode 100644 src/config/axiosDanak.ts delete mode 100644 src/pages/ads/AdsList.tsx delete mode 100644 src/pages/ads/CreateAds.tsx delete mode 100644 src/pages/ads/Update.tsx delete mode 100644 src/pages/ads/components/ImageUploader.tsx delete mode 100644 src/pages/ads/components/ToggleStatus.tsx delete mode 100644 src/pages/ads/hooks/useAdsData.ts delete mode 100644 src/pages/ads/service/AdsService.ts delete mode 100644 src/pages/ads/types/AdsTypes.ts delete mode 100644 src/pages/cardBank/Create.tsx delete mode 100644 src/pages/cardBank/Edit.tsx delete mode 100644 src/pages/cardBank/List.tsx delete mode 100644 src/pages/cardBank/hooks/useCardBankData.ts delete mode 100644 src/pages/cardBank/service/CardBankService.ts delete mode 100644 src/pages/cardBank/types/CardBankTypes.ts delete mode 100644 src/pages/discounts/CreateDiscount.tsx delete mode 100644 src/pages/discounts/DiscountsList.tsx delete mode 100644 src/pages/discounts/UpdateDiscount.tsx delete mode 100644 src/pages/discounts/components/ImageUploader.tsx delete mode 100644 src/pages/discounts/components/ToggleStatusDiscount.tsx delete mode 100644 src/pages/discounts/hooks/useDiscountData.ts delete mode 100644 src/pages/discounts/service/DiscountService.ts delete mode 100644 src/pages/discounts/types/DiscountTypes.ts create mode 100644 src/pages/home/types/HomeTypes.ts delete mode 100644 src/pages/learning/Category.tsx delete mode 100644 src/pages/learning/Create.tsx delete mode 100644 src/pages/learning/List.tsx delete mode 100644 src/pages/learning/components/CreateCategory.tsx delete mode 100644 src/pages/learning/components/CreateLearningSidebar.tsx delete mode 100644 src/pages/learning/hooks/useLearningData.ts delete mode 100644 src/pages/learning/service/LearningService.ts delete mode 100644 src/pages/learning/types/LearningTypes.ts delete mode 100644 src/pages/slider/Create.tsx delete mode 100644 src/pages/slider/List.tsx delete mode 100644 src/pages/slider/Update.tsx delete mode 100644 src/pages/slider/hooks/useSliderData.ts delete mode 100644 src/pages/slider/service/SliderService.ts delete mode 100644 src/pages/slider/types/SliderTypes.ts delete mode 100644 src/pages/support/Create.tsx delete mode 100644 src/pages/support/List.tsx delete mode 100644 src/pages/support/PlanUsers.tsx delete mode 100644 src/pages/support/Update.tsx delete mode 100644 src/pages/support/components/Delete.tsx delete mode 100644 src/pages/support/components/PlanItem.tsx delete mode 100644 src/pages/support/enum/SupportEnum.ts delete mode 100644 src/pages/support/hooks/useSupportData.ts delete mode 100644 src/pages/support/service/SupportService.ts delete mode 100644 src/pages/support/types/SupportTypes.ts create mode 100644 src/pages/ticket/components/DeleteCategory.tsx create mode 100644 src/pages/ticket/components/EditCategory.tsx delete mode 100644 src/pages/wallet/Wallet.tsx delete mode 100644 src/pages/wallet/hooks/useWalletData.ts delete mode 100644 src/pages/wallet/service/WalletService.ts delete mode 100644 src/pages/wallet/types/WalletTypes.ts diff --git a/.env b/.env new file mode 100644 index 0000000..ae06a45 --- /dev/null +++ b/.env @@ -0,0 +1,9 @@ +VITE_TOKEN_NAME = 'dsc_token' +VITE_REFRESH_TOKEN_NAME = 'dsc_refresh_token' +VITE_BASE_URL = 'http://192.168.1.113:4001' +# VITE_BASE_URL = 'https://danak-zone-api.dev.danakcorp.com' +VITE_DANAK_BASE_URL ='http://192.168.1.113:4000' +VITE_SERVICE_ID = '7e3c2f08-b7e7-4402-ae5f-fea99cff56bd' +VITE_WORKSPACE_ID = 'workspace_id' +# VITE_LOGIN_URL = 'https://console.danakcorp.com/auth/login' +VITE_LOGIN_URL = 'http://localhost:5174/auth/login' \ No newline at end of file diff --git a/.gitignore b/.gitignore index 259ba03..b459371 100644 --- a/.gitignore +++ b/.gitignore @@ -28,8 +28,6 @@ yarn-error.log* *.sublime-workspace # environment variables -.env - # cache .cache/ .eslintcache diff --git a/src/App.tsx b/src/App.tsx index 53d9b4c..bebd607 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -36,7 +36,6 @@ const queryClient = new QueryClient({ queryCache: new QueryCache({ onError: async (error: IApiErrorRepsonse) => { if (error?.response?.status === 401) { - return try { // Use a flag to track if refresh is in progress if (window.isRefreshingToken) { @@ -60,15 +59,12 @@ const queryClient = new QueryClient({ const { data } = await refreshToken({ refreshToken: refreshTokenValue || '' }); if (data?.accessToken?.token) { - // Save the new token await setToken(data?.accessToken?.token); - // If refresh token also returned, update it if (data.refreshToken?.token) { await setRefreshToken(data.refreshToken?.token); } - // Retry the failed request queryClient.invalidateQueries(); return; } else { @@ -82,7 +78,7 @@ const queryClient = new QueryClient({ // Clear tokens and redirect to login await removeToken(); await removeRefreshToken(); - window.location.href = '/auth/login'; + window.location.href = `${import.meta.env.VITE_LOGIN_URL}?redirect=${window.location.href}`; } } } @@ -110,11 +106,15 @@ const App: FC = () => { } } + const urlParams = new URLSearchParams(window.location.search); + const workspaceId = urlParams.get('workspaceId'); + if (workspaceId) { + localStorage.setItem(import.meta.env.VITE_WORKSPACE_ID, workspaceId); + window.location.href = window.location.pathname + } + }, []) - - - return ( diff --git a/src/config/Pages.ts b/src/config/Pages.ts index 4aa3b42..908648f 100644 --- a/src/config/Pages.ts +++ b/src/config/Pages.ts @@ -4,6 +4,9 @@ export const Pages = { register: "/auth/register", forgotPassword: "/auth/forgot", }, + requests: { + list: "/requests/list", + }, dashboard: "/dashboard", services: { mine: "/services", diff --git a/src/config/axios.ts b/src/config/axios.ts index fd0803b..2af51c6 100644 --- a/src/config/axios.ts +++ b/src/config/axios.ts @@ -16,6 +16,9 @@ axiosInstance.interceptors.request.use(async function (config) { const token = getToken(); config.headers.Authorization = "Bearer " + token; + config.headers["x-business-id"] = localStorage.getItem( + import.meta.env.VITE_WORKSPACE_ID + ); return config; }); diff --git a/src/config/axiosDanak.ts b/src/config/axiosDanak.ts new file mode 100644 index 0000000..580452f --- /dev/null +++ b/src/config/axiosDanak.ts @@ -0,0 +1,22 @@ +import axios from "axios"; +import { getToken } from "./func"; + +const axiosDanak = axios.create({ + baseURL: import.meta.env.VITE_DANAK_BASE_URL, +}); + +axiosDanak.interceptors.response.use( + (response) => response, + (error) => { + return Promise.reject(error); + } +); + +axiosDanak.interceptors.request.use(async function (config) { + const token = getToken(); + + config.headers.Authorization = "Bearer " + token; + return config; +}); + +export default axiosDanak; diff --git a/src/config/func.ts b/src/config/func.ts index fcf928f..1dc7af7 100644 --- a/src/config/func.ts +++ b/src/config/func.ts @@ -20,19 +20,21 @@ export const getRefreshToken = () => { const isProduction = import.meta.env.MODE === "production"; const domain = isProduction ? ".danakcorp.com" : undefined; -export const setToken = (token: string) => { +export const setToken = async (token: string) => { Cookie.set(import.meta.env.VITE_TOKEN_NAME, token, { domain }); }; -export const setRefreshToken = (refreshToken: string) => { - Cookie.set(import.meta.env.VITE_REFRESH_TOKEN_NAME, refreshToken, { domain }); +export const setRefreshToken = async (refreshToken: string) => { + Cookie.set(import.meta.env.VITE_REFRESH_TOKEN_NAME, refreshToken, { + domain, + }); }; -export const removeToken = () => { +export const removeToken = async () => { Cookie.remove(import.meta.env.VITE_TOKEN_NAME, { domain, path: "/" }); }; -export const removeRefreshToken = () => { +export const removeRefreshToken = async () => { Cookie.remove(import.meta.env.VITE_REFRESH_TOKEN_NAME, { domain, path: "/" }); }; diff --git a/src/index.css b/src/index.css index dec5e0f..41cceed 100644 --- a/src/index.css +++ b/src/index.css @@ -181,3 +181,12 @@ tbody tr { background-color: #c9c9c9 !important; border-radius: 5px !important; } + +* { + scrollbar-width: none; + -ms-overflow-style: none; +} + +*::-webkit-scrollbar { + display: none; +} diff --git a/src/langs/fa.json b/src/langs/fa.json index 6a4606f..68eaf02 100644 --- a/src/langs/fa.json +++ b/src/langs/fa.json @@ -55,7 +55,7 @@ "ads": "تبلیغات", "blog": "بلاگ", "messages": "پیام ها", - + "requests": "درخواست ها", "mainpage": "صفحه اصلی", "myservice": "سرویس های من", "other_service": "سایر سرویس ها", @@ -836,6 +836,9 @@ "company_developed": "شرکت توسعه دهنده", "slug": "اسلاگ", "industries": "صنعت ها", - "invoice_count": "تعداد صورتحساب" + "invoice_count": "تعداد صورتحساب", + "select_company": "انتخاب شرکت", + "register_date": "تاریخ ثبت نام", + "company": "شرکت" } } diff --git a/src/pages/ads/AdsList.tsx b/src/pages/ads/AdsList.tsx deleted file mode 100644 index 58bcdd2..0000000 --- a/src/pages/ads/AdsList.tsx +++ /dev/null @@ -1,157 +0,0 @@ -import { FC, useState } from 'react' -import { useTranslation } from 'react-i18next' -import Button from '../../components/Button' -import { Add, Eye, Trash } from 'iconsax-react' -import Td from '../../components/Td' -import { Link } from 'react-router-dom' -import { Pages } from '../../config/Pages' -import DatePickerComponent from '../../components/DatePicker' -import Select from '../../components/Select' -import Input from '../../components/Input' -import { useDeleteAds, useGetAdsList } from './hooks/useAdsData' -import { AdsItemType } from './types/AdsTypes' -import moment from 'moment-jalaali' -import ToggleStatusAds from './components/ToggleStatus' -import PageLoading from '../../components/PageLoading' -import Pagination from '../../components/Pagination' -const AddList: FC = () => { - - const { t } = useTranslation('global') - const [search, setSearch] = useState('') - const [isActive, setIsActive] = useState(true) - const [since, setSince] = useState('') - const [page, setPage] = useState(1) - const getAds = useGetAdsList(page, search, isActive, since) - const deleteAds = useDeleteAds() - - const handleDelete = (id: string) => { - deleteAds.mutate(id, { - onSuccess: () => { - getAds.refetch() - } - }) - } - - return ( -
-
-
- {t('ads.ads')} -
- - - - -
-
-
-
-
- setSince(moment(date, 'jYYYY-jMM-jDD').format('YYYY-MM-DD'))} - placeholder='' - /> -
-
- setSearch(value)} - /> -
- -
-
- - { - getAds.isPending ? -
- -
- : -
- - - - - - - { - getAds.data?.data?.ads?.map((item: AdsItemType, index: number) => { - return ( - - - - - ) - }) - } - -
- - - - - - -
- - - - - - - -
- - - - handleDelete(item.id)} size={20} color='#8C90A3' /> -
-
-
- } - - setPage(page)} - totalPages={getAds.data?.data?.pager?.totalPages} - /> -
- ) -} - -export default AddList \ No newline at end of file diff --git a/src/pages/ads/CreateAds.tsx b/src/pages/ads/CreateAds.tsx deleted file mode 100644 index f148c3e..0000000 --- a/src/pages/ads/CreateAds.tsx +++ /dev/null @@ -1,180 +0,0 @@ -import { FC, useState } from 'react' -import { useTranslation } from 'react-i18next' -import Input from '../../components/Input' -import Button from '../../components/Button' -import SwitchComponent from '../../components/Switch' -import { TickCircle, Link2 } from 'iconsax-react' -import DatePickerComponent from '../../components/DatePicker' -import { useFormik } from 'formik' -import { AdsDisplayLocation, CreateAdsType } from './types/AdsTypes' -import * as Yup from 'yup' -import UploadBoxDraggble from '../../components/UploadBoxDraggble' -import CheckBoxComponent from '../../components/CheckBoxComponent' -import { useSingleUpload } from '../service/hooks/useServiceData' -import { useCreateAds } from './hooks/useAdsData' -import { ErrorType } from '../../helpers/types' -import { toast } from 'react-toastify' -import { clx } from '../../helpers/utils' -import { useNavigate } from 'react-router-dom' -import { Pages } from '../../config/Pages' -import moment from 'moment-jalaali' - -const CreateAd: FC = () => { - - const navigate = useNavigate() - const { t } = useTranslation('global') - const [file, setFile] = useState() - const singleUpload = useSingleUpload() - const createAds = useCreateAds() - - const formik = useFormik({ - initialValues: { - displayLocation: '', - endDate: '', - imageUrl: '', - isActive: true, - link: '', - serviceId: undefined, - startDate: '', - title: '' - }, - validationSchema: Yup.object().shape({ - title: Yup.string().required(t('errors.required')), - displayLocation: Yup.string().required(t('errors.required')), - endDate: Yup.string().required(t('errors.required')), - link: Yup.string().required(t('errors.required')), - startDate: Yup.string().required(t('errors.required')) - }), - onSubmit: async (values) => { - if (file) { - const formData = new FormData() - formData.append('file', file) - await singleUpload.mutateAsync(formData, { - onSuccess: (data) => { - values.imageUrl = data?.data?.url - }, - onError: (error: ErrorType) => { - toast.error(error.response?.data?.error?.message[0]) - } - }) - - createAds.mutate(values, { - onSuccess: () => { - toast.success(t('success')) - navigate(Pages.ads.list) - }, - onError: (error: ErrorType) => { - toast.error(error.response?.data?.error?.message[0]) - } - }) - } else { - toast.error(t('ads.file_error')) - } - } - }) - - return ( -
-
-
- {t('ads.new_ads')} -
- -
-
-
-
- -
-
- formik.setFieldValue('startDate', moment(value, 'jYYYY-jMM-jDD').format('YYYY-MM-DD'))} - placeholder='' - error_text={formik.touched.startDate && formik.errors.startDate ? formik.errors.startDate : ''} - /> - formik.setFieldValue('endDate', moment(value, 'jYYYY-jMM-jDD').format('YYYY-MM-DD'))} - placeholder='' - error_text={formik.touched.endDate && formik.errors.endDate ? formik.errors.endDate : ''} - /> -
-
- - -
-
-
-
-

- وضعیت تبلیغ -

-
-
- {t('ads.deactive')} -
- formik.setFieldValue('isActive', value)} - /> -
-
-

{t('ads.location')}

- -
- - {Object.values(AdsDisplayLocation).map((location) => ( -
-
- formik.setFieldValue('displayLocation', location)} - /> -
-
- {t(`ads.${location}`)} -
-
- ))} - - -
-
- setFile(value[0])} - /> -
-
-
- -
- ) -} - -export default CreateAd \ No newline at end of file diff --git a/src/pages/ads/Update.tsx b/src/pages/ads/Update.tsx deleted file mode 100644 index 8317f0a..0000000 --- a/src/pages/ads/Update.tsx +++ /dev/null @@ -1,258 +0,0 @@ -import { FC, useEffect, useState } from 'react' -import { useTranslation } from 'react-i18next' -import Input from '../../components/Input' -import Button from '../../components/Button' -import SwitchComponent from '../../components/Switch' -import { TickCircle, Link2 } from 'iconsax-react' -import DatePickerComponent from '../../components/DatePicker' -import { useFormik } from 'formik' -import { AdsDisplayLocation, CreateAdsType } from './types/AdsTypes' -import * as Yup from 'yup' -import UploadBoxDraggble from '../../components/UploadBoxDraggble' -import CheckBoxComponent from '../../components/CheckBoxComponent' -import { useSingleUpload } from '../service/hooks/useServiceData' -import { useGetDetailAds, useUpdateAds } from './hooks/useAdsData' -import { ErrorType } from '../../helpers/types' -import { toast } from 'react-toastify' -import { clx } from '../../helpers/utils' -import { useNavigate, useParams } from 'react-router-dom' -import { Pages } from '../../config/Pages' -import moment from 'moment-jalaali' - -const UpdateAds: FC = () => { - - const { id } = useParams() - const navigate = useNavigate() - const { t } = useTranslation('global') - const [file, setFile] = useState() - const singleUpload = useSingleUpload() - const updateAds = useUpdateAds(id ? id : '') - const getDetail = useGetDetailAds(id) - - const formik = useFormik({ - initialValues: { - displayLocation: '', - endDate: '', - imageUrl: '', - isActive: true, - link: '', - serviceId: undefined, - startDate: '', - title: '' - }, - validationSchema: Yup.object().shape({ - title: Yup.string().required(t('errors.required')), - displayLocation: Yup.string().required(t('errors.required')), - endDate: Yup.string().required(t('errors.required')), - link: Yup.string().required(t('errors.required')), - startDate: Yup.string().required(t('errors.required')) - }), - onSubmit: async (values) => { - if (file) { - const formData = new FormData() - formData.append('file', file) - await singleUpload.mutateAsync(formData, { - onSuccess: (data) => { - values.imageUrl = data?.data?.url - }, - onError: (error: ErrorType) => { - toast.error(error.response?.data?.error?.message[0]) - } - }) - } - - updateAds.mutate(values, { - onSuccess: () => { - toast.success(t('success')) - navigate(Pages.ads.list) - }, - onError: (error: ErrorType) => { - toast.error(error.response?.data?.error?.message[0]) - } - }) - - } - }) - - useEffect(() => { - - if (getDetail.data) { - console.log(getDetail.data); - - formik.setValues({ - displayLocation: getDetail.data?.data?.ads?.displayLocation, - endDate: moment(getDetail.data?.data?.ads?.endDate).format('jYYYY-jMM-jDD'), - imageUrl: getDetail.data?.data?.ads?.imageUrl, - isActive: getDetail.data?.data?.ads?.isActive, - link: getDetail.data?.data?.ads?.link, - serviceId: getDetail.data?.data?.ads?.serviceId, - startDate: moment(getDetail.data?.data?.ads?.startDate).format('jYYYY-jMM-jDD'), - title: getDetail.data?.data?.ads?.title - }) - } - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [getDetail.data]) - - - return ( -
-
-
- {t('ads.new_ads')} -
- -
-
-
-
- -
-
- formik.setFieldValue('startDate', moment(value, 'jYYYY-jMM-jDD').format('YYYY-MM-DD'))} - placeholder='' - error_text={formik.touched.startDate && formik.errors.startDate ? formik.errors.startDate : ''} - defaulValue={formik.values.startDate} - /> - formik.setFieldValue('endDate', moment(value, 'jYYYY-jMM-jDD').format('YYYY-MM-DD'))} - placeholder='' - error_text={formik.touched.endDate && formik.errors.endDate ? formik.errors.endDate : ''} - defaulValue={formik.values.endDate} - /> -
-
- - -
-
-
-
-

- وضعیت تبلیغ -

-
-
- {t('ads.deactive')} -
- formik.setFieldValue('isActive', value)} - /> -
-
-

{t('ads.location')}

- -
-
-
- formik.setFieldValue('displayLocation', AdsDisplayLocation.HOMEPAGE_TOP)} - /> -
-
- {t(`ads.${AdsDisplayLocation.HOMEPAGE_TOP}`)} -
-
-
-
- formik.setFieldValue('displayLocation', AdsDisplayLocation.SINGLE_SERVICE_PAGE)} - /> -
-
- {t(`ads.${AdsDisplayLocation.SINGLE_SERVICE_PAGE}`)} -
-
-
-
- formik.setFieldValue('displayLocation', AdsDisplayLocation.MY_SERVICES_PAGE)} - /> -
-
- {t(`ads.${AdsDisplayLocation.MY_SERVICES_PAGE}`)} -
-
-
-
- formik.setFieldValue('displayLocation', AdsDisplayLocation.OTHER_SERVICES_TOP)} - /> -
-
- {t(`ads.${AdsDisplayLocation.OTHER_SERVICES_TOP}`)} -
-
-
-
- formik.setFieldValue('displayLocation', AdsDisplayLocation.OTHER_SERVICES_LEFT)} - /> -
-
- {t(`ads.${AdsDisplayLocation.OTHER_SERVICES_LEFT}`)} -
-
-
-
- formik.setFieldValue('displayLocation', AdsDisplayLocation.SERVICE)} - /> -
-
- {t(`ads.${AdsDisplayLocation.SERVICE}`)} -
-
- -
-
- setFile(value[0])} - /> -
-
- ads -
-
-
- -
- ) -} - -export default UpdateAds \ No newline at end of file diff --git a/src/pages/ads/components/ImageUploader.tsx b/src/pages/ads/components/ImageUploader.tsx deleted file mode 100644 index ad623e9..0000000 --- a/src/pages/ads/components/ImageUploader.tsx +++ /dev/null @@ -1,49 +0,0 @@ - -import { FC, useCallback, useState } from 'react' -import { useTranslation } from 'react-i18next' -import { Image, DocumentUpload } from 'iconsax-react' -import { useDropzone } from 'react-dropzone' - - - -const ImageUploader: FC = () => { - const { t } = useTranslation('global') - const [file, setFile] = useState() - const onDrop = useCallback((acceptedFiles: File[]) => { - setFile(acceptedFiles[0]) - }, []) - const { getRootProps, getInputProps } = useDropzone({ onDrop }) - - return ( - <> -

{t('ads.upload_picture')}

-
-
- -

- { - file ? - file.name - : - t('ads.to_upload_message') - - } -

-
- - -
-
-
- - ) -} -export default ImageUploader \ No newline at end of file diff --git a/src/pages/ads/components/ToggleStatus.tsx b/src/pages/ads/components/ToggleStatus.tsx deleted file mode 100644 index 1debde1..0000000 --- a/src/pages/ads/components/ToggleStatus.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { FC, useState } from 'react' -import SwitchComponent from '../../../components/Switch' -import { useToggleStatusAds } from '../hooks/useAdsData' - -type Props = { - defaultActive: boolean, - id: string -} - -const ToggleStatusAds: FC = (props: Props) => { - - const [isActive, setIsActive] = useState(props.defaultActive) - const toggleStatus = useToggleStatusAds() - - const handleChange = (value: boolean) => { - setIsActive(value) - toggleStatus.mutate(props.id) - } - - return ( - - ) -} - -export default ToggleStatusAds \ No newline at end of file diff --git a/src/pages/ads/hooks/useAdsData.ts b/src/pages/ads/hooks/useAdsData.ts deleted file mode 100644 index abefbab..0000000 --- a/src/pages/ads/hooks/useAdsData.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { useMutation, useQuery } from "@tanstack/react-query"; -import * as api from "../service/AdsService"; -import { CreateAdsType } from "../types/AdsTypes"; - -export const useGetAdsList = ( - page: number, - search: string, - isActive: boolean, - since: string -) => { - return useQuery({ - queryKey: ["ads", page, search, isActive, since], - queryFn: () => api.getAdsList({ page, search, isActive, since }), - }); -}; - -export const useCreateAds = () => { - return useMutation({ - mutationFn: (variables: CreateAdsType) => api.createAds(variables), - }); -}; - -export const useToggleStatusAds = () => { - return useMutation({ - mutationFn: (variables: string) => api.toggleStatusAds(variables), - }); -}; - -export const useGetDetailAds = (id?: string) => { - return useQuery({ - queryKey: ["ads-detail", id], - queryFn: () => api.getDetailAds(id ? id : ""), - enabled: !!id, - }); -}; - -export const useUpdateAds = (id: string) => { - return useMutation({ - mutationFn: (variables: CreateAdsType) => api.updateAds(id, variables), - }); -}; - -export const useDeleteAds = () => { - return useMutation({ - mutationFn: (variables: string) => api.deleteAds(variables), - }); -}; diff --git a/src/pages/ads/service/AdsService.ts b/src/pages/ads/service/AdsService.ts deleted file mode 100644 index d946b58..0000000 --- a/src/pages/ads/service/AdsService.ts +++ /dev/null @@ -1,48 +0,0 @@ -import axios from "../../../config/axios"; -import { CreateAdsType } from "../types/AdsTypes"; - -interface GetAdsListParams { - page: number; - search?: string; - isActive?: boolean; - since?: string; -} - -export const getAdsList = async ({ - page, - search, - isActive, - since, -}: GetAdsListParams) => { - let query = `?page=${page}&q=${search}&isActive=${isActive ? "1" : "0"}`; - if (since) { - query += `&since=${since}`; - } - const { data } = await axios.get(`/advertise/list${query}`); - return data; -}; - -export const createAds = async (params: CreateAdsType) => { - const { data } = await axios.post(`/advertise`, params); - return data; -}; - -export const toggleStatusAds = async (id: string) => { - const { data } = await axios.patch(`/advertise/toggle-status/${id}`); - return data; -}; - -export const getDetailAds = async (id: string) => { - const { data } = await axios.get(`/advertise/${id}`); - return data; -}; - -export const updateAds = async (id: string, params: CreateAdsType) => { - const { data } = await axios.patch(`/advertise/${id}`, params); - return data; -}; - -export const deleteAds = async (id: string) => { - const { data } = await axios.delete(`/advertise/${id}`); - return data; -}; diff --git a/src/pages/ads/types/AdsTypes.ts b/src/pages/ads/types/AdsTypes.ts deleted file mode 100644 index 427a644..0000000 --- a/src/pages/ads/types/AdsTypes.ts +++ /dev/null @@ -1,36 +0,0 @@ -export type CreateAdsType = { - title: string; - displayLocation: string; - startDate: string; - endDate: string; - isActive: boolean; - imageUrl: string; - link: string; - serviceId?: string; -}; - -export enum AdsDisplayLocation { - HOMEPAGE_TOP = "HOMEPAGE_TOP", - SINGLE_SERVICE_PAGE = "SINGLE_SERVICE_PAGE", - MY_SERVICES_PAGE = "MY_SERVICES_PAGE", - OTHER_SERVICES_TOP = "OTHER_SERVICES_TOP", - OTHER_SERVICES_LEFT = "OTHER_SERVICES_LEFT", - SERVICE = "SERVICE", - BLOG_PAGE_TOP_RIGHT = "BLOG_PAGE_TOP_RIGHT", - BLOG_PAGE_BOTTOM_RIGHT = "BLOG_PAGE_BOTTOM_RIGHT", - BLOG_PAGE_TOP_LEFT = "BLOG_PAGE_TOP_LEFT", -} - -export type AdsItemType = { - id: string; - title: string; - displayLocation: AdsDisplayLocation; - startDate: string; - endDate: string; - isActive: boolean; - imageUrl: string; - link: string; - service?: string | null; - createdAt: string; - updatedAt: string; -}; diff --git a/src/pages/auth/service/AuthService.ts b/src/pages/auth/service/AuthService.ts index 41f9f20..f66d6d8 100644 --- a/src/pages/auth/service/AuthService.ts +++ b/src/pages/auth/service/AuthService.ts @@ -1,4 +1,4 @@ -import axios from "../../../config/axios"; +import axios from "../../../config/axiosDanak"; import { CheckHasAccountPhoneType, CheckHasAccountType, diff --git a/src/pages/cardBank/Create.tsx b/src/pages/cardBank/Create.tsx deleted file mode 100644 index d53b62f..0000000 --- a/src/pages/cardBank/Create.tsx +++ /dev/null @@ -1,159 +0,0 @@ -import { FC } from 'react' -import { useTranslation } from 'react-i18next' -import Button from '../../components/Button' -import { TickCircle, TickSquare } from 'iconsax-react' -import SwitchComponent from '../../components/Switch' -import Input from '../../components/Input' -import { useFormik } from 'formik' -import { CreateBankType } from './types/CardBankTypes' -import * as Yup from 'yup' -import { useCreateBank } from './hooks/useCardBankData' -import { useNavigate } from 'react-router-dom' -import { Pages } from '../../config/Pages' -import { ErrorType } from '../../helpers/types' -import { toast } from 'react-toastify' - -const CreateBankCard: FC = () => { - - const navigate = useNavigate() - const { t } = useTranslation('global') - const createBank = useCreateBank() - - const formik = useFormik({ - initialValues: { - accountOwnerName: '', - bankName: '', - cardNumber: '', - IBan: '', - isActive: true, - }, - validationSchema: Yup.object({ - accountOwnerName: Yup.string().required(t('errors.required')), - bankName: Yup.string().required(t('errors.required')), - cardNumber: Yup.string().required(t('errors.required')), - IBan: Yup.string().required(t('errors.required')), - }), - onSubmit: (values) => { - createBank.mutate(values, { - onSuccess: () => { - formik.resetForm() - navigate(Pages.cardBank.list) - }, - onError: (error: ErrorType) => { - toast.error(error.response?.data?.error?.message[0]) - } - }) - } - }) - - return ( -
-
-
- {t('cardBank.new_account')} -
-
- -
-
- -
-
-
- {t('cardBank.account_information')} -
- -
-
- {t('cardBank.status_account')} -
- formik.setFieldValue('isActive', value)} - /> -
- -
- - -
-
- - -
-
- -
-
- {t('ticket.title_hint')} -
- -
-
-
- -
-
- سوالات - مشکلاتی که به یک موضوع مربوط میشوند را در یک درخواست پشتیبانی پیگیر باشید و چند درخواست برای یک موضوع باز نکنید. -
-
-
-
- -
-
- لطفاً برای بررسی و رفع مشکلات احتمالی صبور باشید بررسی و رفع مشکلات در برخی موارد زمان گیر است. -
-
-
-
- -
-
- پاسخگویی 24 ساعته تلفنی را تنها از میهن وب هاست می توانید انتظار داشته باشید .بخش پشتیبانی در هر ساعتی حتی در روز های تعطیل آماده پیگیری سریع مشکلات کاربران است. -
-
-
-
-
-
- ) -} - -export default CreateBankCard \ No newline at end of file diff --git a/src/pages/cardBank/Edit.tsx b/src/pages/cardBank/Edit.tsx deleted file mode 100644 index c374ab8..0000000 --- a/src/pages/cardBank/Edit.tsx +++ /dev/null @@ -1,179 +0,0 @@ -import { FC, useEffect } from 'react' -import { useTranslation } from 'react-i18next' -import Button from '../../components/Button' -import { TickCircle, TickSquare } from 'iconsax-react' -import SwitchComponent from '../../components/Switch' -import Input from '../../components/Input' -import { useFormik } from 'formik' -import { CreateBankType } from './types/CardBankTypes' -import * as Yup from 'yup' -import { useGetCardBankDetail, useUpdateBank } from './hooks/useCardBankData' -import { useNavigate, useParams } from 'react-router-dom' -import { Pages } from '../../config/Pages' -import { ErrorType } from '../../helpers/types' -import { toast } from 'react-toastify' - -const EditBankCard: FC = () => { - - const { id } = useParams() - const navigate = useNavigate() - const { t } = useTranslation('global') - const updateBank = useUpdateBank(id ? id : '') - const getCard = useGetCardBankDetail(id ? id : '') - - const formik = useFormik({ - initialValues: { - accountOwnerName: '', - bankName: '', - cardNumber: '', - IBan: '', - isActive: true, - }, - validationSchema: Yup.object({ - accountOwnerName: Yup.string().required(t('errors.required')), - bankName: Yup.string().required(t('errors.required')), - cardNumber: Yup.string().required(t('errors.required')), - IBan: Yup.string().required(t('errors.required')), - }), - onSubmit: (values) => { - updateBank.mutate(values, { - onSuccess: () => { - formik.resetForm() - navigate(Pages.cardBank.list) - }, - onError: (error: ErrorType) => { - toast.error(error.response?.data?.error?.message[0]) - } - }) - } - }) - - useEffect(() => { - - if (getCard.data?.data?.bankAccount) { - const data = getCard.data?.data?.bankAccount - - formik.setValues({ - accountOwnerName: data.accountOwnerName, - bankName: data.bankName, - cardNumber: data.cardNumber, - IBan: data.IBan, - isActive: data.isActive, - }) - } - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [getCard.data]) - - - return ( -
-
-
- {t('cardBank.new_account')} -
-
- -
-
- -
-
-
- {t('cardBank.account_information')} -
- -
-
- {t('cardBank.status_account')} -
- formik.setFieldValue('isActive', value)} - /> -
- -
- - -
-
- - -
-
- -
-
- {t('ticket.title_hint')} -
- -
-
-
- -
-
- سوالات - مشکلاتی که به یک موضوع مربوط میشوند را در یک درخواست پشتیبانی پیگیر باشید و چند درخواست برای یک موضوع باز نکنید. -
-
-
-
- -
-
- لطفاً برای بررسی و رفع مشکلات احتمالی صبور باشید بررسی و رفع مشکلات در برخی موارد زمان گیر است. -
-
-
-
- -
-
- پاسخگویی 24 ساعته تلفنی را تنها از میهن وب هاست می توانید انتظار داشته باشید .بخش پشتیبانی در هر ساعتی حتی در روز های تعطیل آماده پیگیری سریع مشکلات کاربران است. -
-
-
-
-
-
- ) -} - -export default EditBankCard \ No newline at end of file diff --git a/src/pages/cardBank/List.tsx b/src/pages/cardBank/List.tsx deleted file mode 100644 index 994812d..0000000 --- a/src/pages/cardBank/List.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { FC } from 'react' -import { useGetCardBanks } from './hooks/useCardBankData' -import PageLoading from '../../components/PageLoading' -import Td from '../../components/Td' -import { useTranslation } from 'react-i18next' -import { CreateBankItemType } from './types/CardBankTypes' -import { Link } from 'react-router-dom' -import { Pages } from '../../config/Pages' -import Button from '../../components/Button' -import { Add, Eye } from 'iconsax-react' - -const CardBankList: FC = () => { - - const { t } = useTranslation('global') - const getCardBanks = useGetCardBanks() - - return ( -
- -
-
- - {t('cardBank.manage_banks')} -
-
- - - -
-
- { - getCardBanks.isPending ? - - : -
- - - - - - - { - getCardBanks.data?.data?.bankAccounts?.map((item: CreateBankItemType) => { - return ( - - - - ) - }) - } - - -
- - - - -
- - - - - - - -
- -
- } -
- ) -} - -export default CardBankList \ No newline at end of file diff --git a/src/pages/cardBank/hooks/useCardBankData.ts b/src/pages/cardBank/hooks/useCardBankData.ts deleted file mode 100644 index 8ad8a8b..0000000 --- a/src/pages/cardBank/hooks/useCardBankData.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { CreateBankType } from "../types/CardBankTypes"; -import * as api from "../service/CardBankService"; - -export const useCreateBank = () => { - const queryClient = useQueryClient(); - return useMutation({ - mutationFn: (variables: CreateBankType) => api.createCardBank(variables), - onSuccess: () => { - queryClient.refetchQueries({ - queryKey: ["cardBanks"], - }); - }, - }); -}; - -export const useGetCardBanks = () => { - return useQuery({ - queryKey: ["cardBanks"], - queryFn: api.getCardBanks, - }); -}; - -export const useGetCardBankDetail = (id: string) => { - return useQuery({ - queryKey: ["cardBank", id], - queryFn: () => api.getCardBankDetail(id), - enabled: !!id, - }); -}; - -export const useUpdateBank = (id: string) => { - const queryClient = useQueryClient(); - return useMutation({ - mutationFn: (variables: CreateBankType) => - api.updateCardBank(id, variables), - onSuccess: () => { - queryClient.refetchQueries({ - queryKey: ["cardBanks"], - }); - queryClient.refetchQueries({ - queryKey: ["cardBank", id], - }); - }, - }); -}; diff --git a/src/pages/cardBank/service/CardBankService.ts b/src/pages/cardBank/service/CardBankService.ts deleted file mode 100644 index bea9319..0000000 --- a/src/pages/cardBank/service/CardBankService.ts +++ /dev/null @@ -1,22 +0,0 @@ -import axios from "../../../config/axios"; -import { CreateBankType } from "../types/CardBankTypes"; - -export const createCardBank = async (params: CreateBankType) => { - const { data } = await axios.post(`/payments/bank-account`, params); - return data; -}; - -export const getCardBanks = async () => { - const { data } = await axios.get(`/payments/bank-account`); - return data; -}; - -export const getCardBankDetail = async (id: string) => { - const { data } = await axios.get(`/payments/bank-account/${id}`); - return data; -}; - -export const updateCardBank = async (id: string, params: CreateBankType) => { - const { data } = await axios.patch(`/payments/bank-account/${id}`, params); - return data; -}; diff --git a/src/pages/cardBank/types/CardBankTypes.ts b/src/pages/cardBank/types/CardBankTypes.ts deleted file mode 100644 index d482ffd..0000000 --- a/src/pages/cardBank/types/CardBankTypes.ts +++ /dev/null @@ -1,15 +0,0 @@ -export type CreateBankType = { - cardNumber: string; - IBan: string; - bankName: string; - accountOwnerName: string; - isActive: boolean; -}; -export type CreateBankItemType = { - id: string; - cardNumber: string; - IBan: string; - bankName: string; - accountOwnerName: string; - isActive: boolean; -}; diff --git a/src/pages/company/components/CreateIndustry.tsx b/src/pages/company/components/CreateIndustry.tsx index 556aeb9..0a7cdb9 100644 --- a/src/pages/company/components/CreateIndustry.tsx +++ b/src/pages/company/components/CreateIndustry.tsx @@ -10,6 +10,7 @@ import { TickCircle } from 'iconsax-react' import { toast } from 'react-toastify' import { useSingleUpload } from '../../service/hooks/useServiceData' import { useCreateIndustry } from '../hooks/useCompanyData' +import { ErrorType } from '../../../helpers/types' type Props = { refetch: () => void @@ -45,6 +46,9 @@ const CreateIndustry: FC = ({ refetch }) => { onSuccess: () => { toast.success('صنعت با موفقیت ثبت شد') refetch() + }, + onError: (error: ErrorType) => { + toast.error(error?.response?.data?.error.message[0]) } }) } diff --git a/src/pages/customer/List.tsx b/src/pages/customer/List.tsx index 1149be2..a0a8fc4 100644 --- a/src/pages/customer/List.tsx +++ b/src/pages/customer/List.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react' +import { FC, useState } from 'react' import { useTranslation } from 'react-i18next' import Button from '../../components/Button' import { Add, Eye } from 'iconsax-react' @@ -10,11 +10,13 @@ import { Pages } from '../../config/Pages' import { useGetCustomers } from './hooks/useCustomerData' import PageLoading from '../../components/PageLoading' import { CustomerItemType } from './types/CustomerTypes' +import Pagination from '../../components/Pagination' const CustomerList: FC = () => { const { t } = useTranslation('global') - const getCustomers = useGetCustomers() + const [page, setPage] = useState(1) + const getCustomers = useGetCustomers(page) return (
@@ -117,6 +119,12 @@ const CustomerList: FC = () => { + +
}
diff --git a/src/pages/customer/hooks/useCustomerData.ts b/src/pages/customer/hooks/useCustomerData.ts index 2cdec6e..432879b 100644 --- a/src/pages/customer/hooks/useCustomerData.ts +++ b/src/pages/customer/hooks/useCustomerData.ts @@ -2,10 +2,10 @@ import * as api from "../service/CustomerService"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { CreateCustomerType } from "../types/CustomerTypes"; -export const useGetCustomers = () => { +export const useGetCustomers = (page: number, withoutPaginate?: boolean) => { return useQuery({ - queryKey: ["customers"], - queryFn: () => api.getCustomers(), + queryKey: ["customers", page], + queryFn: () => api.getCustomers(page, withoutPaginate), }); }; diff --git a/src/pages/customer/service/CustomerService.ts b/src/pages/customer/service/CustomerService.ts index 6b31634..c7ffce8 100644 --- a/src/pages/customer/service/CustomerService.ts +++ b/src/pages/customer/service/CustomerService.ts @@ -1,8 +1,10 @@ import axios from "../../../config/axios"; import { CreateCustomerType } from "../types/CustomerTypes"; -export const getCustomers = async () => { - const { data } = await axios.get(`/users/customers`); +export const getCustomers = async (page: number, withoutPaginate?: boolean) => { + const { data } = await axios.get( + `/users/customers?page=${page}&paginate=${withoutPaginate ? "0" : "1"}` + ); return data; }; diff --git a/src/pages/discounts/CreateDiscount.tsx b/src/pages/discounts/CreateDiscount.tsx deleted file mode 100644 index b4886b0..0000000 --- a/src/pages/discounts/CreateDiscount.tsx +++ /dev/null @@ -1,273 +0,0 @@ -import { FC, Fragment, useState } from 'react' -import { useTranslation } from 'react-i18next' -import Input from '../../components/Input' -import Button from '../../components/Button' -import SwitchComponent from '../../components/Switch' -import { TickCircle } from 'iconsax-react' -import DatePickerComponent from '../../components/DatePicker' -import RadioGroup from '../../components/RadioGroup' -import { useFormik } from 'formik' -import { CreateDiscountType } from './types/DiscountTypes' -import * as Yup from 'yup' -import { useGetAllServices } from '../service/hooks/useServiceData' -import { ServiceItemType } from '../service/types/ServiceTypes' -import CheckBoxComponent from '../../components/CheckBoxComponent' -import { toast } from 'react-toastify' -import { useCreateDiscount } from './hooks/useDiscountData' -import { useNavigate } from 'react-router-dom' -import { Pages } from '../../config/Pages' -import { ErrorType } from '../../helpers/types' -import moment from 'moment-jalaali' - -const CreateDiscount: FC = () => { - - const navigate = useNavigate() - const { t } = useTranslation('global') - const [serviceId, setServiceId] = useState([]) - // const [planId, setPlanId] = useState('') - // const [customerId, setCustomerId] = useState('') - const getServices = useGetAllServices('', 1, '', '', undefined, 50) - // const getPlans = useGetPlans(serviceId) - // const getCustomers = useGetCustomers() - const createDiscount = useCreateDiscount() - - const formik = useFormik({ - initialValues: { - endDate: '', - startDate: '', - title: '', - type: 1, - targetServices: [], - direct: true, - value: 0, - isActive: true, - userPhone: '' - }, - validationSchema: Yup.object({ - value: Yup.number().required(t('errors.required')), - endDate: Yup.string().required(t('errors.required')), - startDate: Yup.string().required(t('errors.required')), - title: Yup.string().required(t('errors.required')), - type: Yup.string().required(t('errors.required')), - }), - onSubmit(values) { - values.targetServices = serviceId - values.type = +values.type - if (values.userPhone === '') { - values.userPhone = undefined - } - const params: CreateDiscountType = { - ...values, - startDate: moment(values.startDate, 'jYYYY-jMM-jDD').format('YYYY-MM-DD'), - endDate: moment(values.endDate, 'jYYYY-jMM-jDD').format('YYYY-MM-DD'), - value: +values.value - } - createDiscount.mutate(params, { - onSuccess: () => { - toast.success(t('success')) - navigate(Pages.discount.list) - }, - onError: (error: ErrorType) => { - toast.error(error.response?.data?.error?.message[0]) - } - }) - }, - }) - return ( -
-
-
- {t('discount.new_discount')} -
- -
-
-
-
- {t('discount.type')} -
- formik.setFieldValue('direct', value)} - selected={formik.values.direct} - /> -
-
-
- - {/*
- -
*/} -
-
-
- {t('discount.price')} -
- formik.setFieldValue('type', value)} - selected={formik.values.type.toString()} - /> -
-
- -
-
- formik.setFieldValue('startDate', value)} - placeholder='' - error_text={formik.touched.startDate && formik.errors.startDate ? formik.errors.startDate : ''} - /> - formik.setFieldValue('endDate', value)} - placeholder='' - error_text={formik.touched.endDate && formik.errors.endDate ? formik.errors.endDate : ''} - /> -
- - { - !formik.values.direct && -
- -
- } -
-
-
-

- {'وضعیت تخفیف'} -

-
- formik.setFieldValue('isActive', value)} - /> -
-
- - { - formik.values.direct && - -

{t('discount.availabe_service')}

-
- - { - getServices.data?.data?.services?.map((item: ServiceItemType) => ( -
-
- setServiceId(e.target.checked ? [...serviceId, item.id] : serviceId.filter(id => id !== item.id))} - /> -
-
- {item.name} -
-
- )) - } -
-
- } - - {/* { - getPlans.data && -
- { - getPlans.data?.data?.subscriptions?.map((item: PlanItemType) => ( -
-
- setPlanId(e.target.checked ? item.id : '')} - /> -
-
- {item.name} -
-
- )) - } -
- } - - { - planId && getCustomers.data && -
- { - getCustomers.data?.data?.customers?.map((item: CustomerItemType) => ( -
-
- setCustomerId(e.target.checked ? item.id : '')} - /> -
-
- {item.firstName + ' ' + item.lastName} -
-
- )) - } -
- } */} -
-
-
- ) -} -export default CreateDiscount \ No newline at end of file diff --git a/src/pages/discounts/DiscountsList.tsx b/src/pages/discounts/DiscountsList.tsx deleted file mode 100644 index 5fa6442..0000000 --- a/src/pages/discounts/DiscountsList.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import { FC, useState } from 'react' -import { useTranslation } from 'react-i18next' -import Button from '../../components/Button' -import { Add, Edit, Trash } from 'iconsax-react' -import Td from '../../components/Td' -import { Link } from 'react-router-dom' -import { Pages } from '../../config/Pages' -import Input from '../../components/Input' -import { useGetDiscounts, useDeleteDiscount } from './hooks/useDiscountData' -import { DiscountItemType } from './types/DiscountTypes' -import moment from 'moment-jalaali' -import ToggleStatusDiscount from './components/ToggleStatusDiscount' -import PageLoading from '../../components/PageLoading' -import { NumberFormat } from '../../config/func' -import { toast } from 'react-toastify' -import { ErrorType } from '../../helpers/types' - -const DiscountList: FC = () => { - - const { t } = useTranslation('global') - const [search, setSearch] = useState('') - const getDiscounts = useGetDiscounts(search) - const deleteDiscount = useDeleteDiscount() - - const handleDelete = (id: string) => { - deleteDiscount.mutate(id, { - onSuccess: () => { - getDiscounts.refetch() - toast.success(t('success')) - }, - onError: (error: ErrorType) => { - toast.error(error.response?.data?.error.message[0]) - } - }) - } - return ( -
-
-
- {t('discount.list')} -
- - - - -
- - - - -
-
- -
- setSearch(value)} - /> -
- -
-
- - - - - { - getDiscounts.isPending ? - - : -
- - - - - - - { - getDiscounts.data?.data?.discounts?.map((item: DiscountItemType) => { - return ( - - - - - ) - }) - } - -
- - - - - - - - -
- - - - - - - - - -
- - - - - handleDelete(item.id)} - /> -
-
-
- } -
- ) -} - -export default DiscountList \ No newline at end of file diff --git a/src/pages/discounts/UpdateDiscount.tsx b/src/pages/discounts/UpdateDiscount.tsx deleted file mode 100644 index 22e068c..0000000 --- a/src/pages/discounts/UpdateDiscount.tsx +++ /dev/null @@ -1,301 +0,0 @@ -import { FC, Fragment, useEffect, useState } from 'react' -import { useTranslation } from 'react-i18next' -import Input from '../../components/Input' -import Button from '../../components/Button' -import SwitchComponent from '../../components/Switch' -import { TickCircle } from 'iconsax-react' -import DatePickerComponent from '../../components/DatePicker' -import RadioGroup from '../../components/RadioGroup' -import { useFormik } from 'formik' -import { CreateDiscountType, SubscriptionPlanType } from './types/DiscountTypes' -import * as Yup from 'yup' -import { useGetAllServices } from '../service/hooks/useServiceData' -import { ServiceItemType } from '../service/types/ServiceTypes' -import CheckBoxComponent from '../../components/CheckBoxComponent' -import { toast } from 'react-toastify' -import { useGetDiscountDetail, useUpdateDiscount } from './hooks/useDiscountData' -import { useNavigate, useParams } from 'react-router-dom' -import { Pages } from '../../config/Pages' -import { ErrorType } from '../../helpers/types' -import moment from 'moment-jalaali' - -const UpdateDiscount: FC = () => { - - const { id } = useParams() - const navigate = useNavigate() - const { t } = useTranslation('global') - const [serviceId, setServiceId] = useState([]) - // const [planId, setPlanId] = useState('') - // const [customerId, setCustomerId] = useState('') - const getServices = useGetAllServices('', 1, '', '', undefined, 50) - // const getPlans = useGetPlans(serviceId) - // const getCustomers = useGetCustomers() - const getDiscountDetail = useGetDiscountDetail(id || '') - const updateDiscount = useUpdateDiscount() - - const formik = useFormik({ - initialValues: { - endDate: '', - startDate: '', - title: '', - type: 1, - targetServices: [], - direct: true, - value: 0, - isActive: true, - userPhone: '' - }, - validationSchema: Yup.object({ - value: Yup.number().required(t('errors.required')), - endDate: Yup.string().required(t('errors.required')), - startDate: Yup.string().required(t('errors.required')), - title: Yup.string().required(t('errors.required')), - type: Yup.string().required(t('errors.required')), - }), - onSubmit(values) { - if (values.userPhone === '') { - values.userPhone = undefined - } - values.targetServices = serviceId - const params: CreateDiscountType = { - ...values, - startDate: moment(values.startDate, 'jYYYY-jMM-jDD').format('YYYY-MM-DD'), - endDate: moment(values.endDate, 'jYYYY-jMM-jDD').format('YYYY-MM-DD'), - value: +values.value, - type: +values.type - } - updateDiscount.mutate({ id: id || '', params }, { - onSuccess: () => { - toast.success(t('success')) - navigate(Pages.discount.list) - }, - onError: (error: ErrorType) => { - toast.error(error.response?.data?.error?.message[0]) - } - }) - }, - }) - - useEffect(() => { - if (getDiscountDetail.data?.data?.discount) { - formik.setValues({ - ...getDiscountDetail.data?.data?.discount, - startDate: moment(getDiscountDetail.data?.data?.discount.startDate, 'YYYY-MM-DD').format('jYYYY-jMM-jDD'), - endDate: moment(getDiscountDetail.data?.data?.discount.endDate, 'YYYY-MM-DD').format('jYYYY-jMM-jDD'), - direct: getDiscountDetail.data?.data?.discount.applicationType === 'DIRECT', - }) - - if (getDiscountDetail.data?.data?.discount.user) { - formik.setFieldValue('userPhone', getDiscountDetail.data?.data?.discount.user?.phone) - } - - // delete getDiscountDetail.data?.data?.discount.subscriptionPlans - - const ids = getDiscountDetail.data?.data?.discount.subscriptionPlans.map((item: SubscriptionPlanType) => item?.service?.id) - // Create an array of unique service IDs by removing duplicates - const uniqueIds = [...new Set(ids)]; - setServiceId(uniqueIds as string[]); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [getDiscountDetail.data]) - - return ( -
-
-
- {t('discount.update_discount')} -
- -
-
-
-
- {t('discount.type')} -
- formik.setFieldValue('direct', value)} - selected={formik.values.direct} - /> -
-
-
- - {/*
- -
*/} -
-
-
- {t('discount.price')} -
- formik.setFieldValue('type', value)} - selected={formik.values.type.toString()} - /> -
-
- -
-
- formik.setFieldValue('startDate', value)} - placeholder='' - error_text={formik.touched.startDate && formik.errors.startDate ? formik.errors.startDate : ''} - defaulValue={formik.values.startDate} - /> - formik.setFieldValue('endDate', value)} - placeholder='' - error_text={formik.touched.endDate && formik.errors.endDate ? formik.errors.endDate : ''} - defaulValue={formik.values.endDate} - /> -
- { - !formik.values.direct && -
- -
- } -
-
-
-

- {'وضعیت تخفیف'} -

-
- formik.setFieldValue('isActive', value)} - /> -
-
- - { - formik.values.direct && - -

{t('discount.availabe_service')}

-
- - { - getServices.data?.data?.services?.map((item: ServiceItemType) => ( -
-
- setServiceId(e.target.checked ? [...serviceId, item.id] : serviceId.filter(id => id !== item.id))} - /> -
-
- {item.name} -
-
- )) - } -
-
- } - - {/* { - getPlans.data && -
- { - getPlans.data?.data?.subscriptions?.map((item: PlanItemType) => ( -
-
- setPlanId(e.target.checked ? item.id : '')} - /> -
-
- {item.name} -
-
- )) - } -
- } - - { - planId && getCustomers.data && -
- { - getCustomers.data?.data?.customers?.map((item: CustomerItemType) => ( -
-
- setCustomerId(e.target.checked ? item.id : '')} - /> -
-
- {item.firstName + ' ' + item.lastName} -
-
- )) - } -
- } */} -
-
-
- ) -} -export default UpdateDiscount \ No newline at end of file diff --git a/src/pages/discounts/components/ImageUploader.tsx b/src/pages/discounts/components/ImageUploader.tsx deleted file mode 100644 index 966c176..0000000 --- a/src/pages/discounts/components/ImageUploader.tsx +++ /dev/null @@ -1,49 +0,0 @@ - -import { FC, useCallback, useState } from 'react' -import { useTranslation } from 'react-i18next' -import { Image, DocumentUpload } from 'iconsax-react' -import { useDropzone } from 'react-dropzone' - - - -const ImageUploader: FC = () => { - const { t } = useTranslation('global') - const [file, setFile] = useState() - const onDrop = useCallback((acceptedFiles: File[]) => { - setFile(acceptedFiles[0]) - }, []) - const { getRootProps, getInputProps } = useDropzone({ onDrop }) - - return( - <> -

{t('ads.upload_picture')}

-
-
- -

- { - file ? - file.name - : - t('ads.to_upload_message') - - } -

-
- - -
-
-
- - ) -} -export default ImageUploader \ No newline at end of file diff --git a/src/pages/discounts/components/ToggleStatusDiscount.tsx b/src/pages/discounts/components/ToggleStatusDiscount.tsx deleted file mode 100644 index 592fc87..0000000 --- a/src/pages/discounts/components/ToggleStatusDiscount.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { FC, useState } from 'react' -import SwitchComponent from '../../../components/Switch' -import { useToggleStatusDiscount } from '../hooks/useDiscountData' - -type Props = { - defaultActive: boolean, - id: string -} - -const ToggleStatusDiscount: FC = (props: Props) => { - - const [isActive, setIsActive] = useState(props.defaultActive) - const toggleStatus = useToggleStatusDiscount() - - const handleChange = (value: boolean) => { - setIsActive(value) - toggleStatus.mutate(props.id) - } - - return ( - - ) -} - -export default ToggleStatusDiscount \ No newline at end of file diff --git a/src/pages/discounts/hooks/useDiscountData.ts b/src/pages/discounts/hooks/useDiscountData.ts deleted file mode 100644 index 659bd36..0000000 --- a/src/pages/discounts/hooks/useDiscountData.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { useMutation, useQuery } from "@tanstack/react-query"; -import * as api from "../service/DiscountService"; -import { CreateDiscountType } from "../types/DiscountTypes"; - -export const useCreateDiscount = () => { - return useMutation({ - mutationFn: (variables: CreateDiscountType) => - api.createDiscount(variables), - }); -}; - -export const useGetDiscounts = (search: string) => { - return useQuery({ - queryKey: ["discounts", search], - queryFn: () => api.getDiscounts(search), - }); -}; - -export const useToggleStatusDiscount = () => { - return useMutation({ - mutationFn: (variables: string) => api.toggleStatusDiscount(variables), - }); -}; - -export const useGetDiscountDetail = (id: string) => { - return useQuery({ - queryKey: ["discount", id], - queryFn: () => api.getDiscountDetail(id), - }); -}; - -export const useUpdateDiscount = () => { - return useMutation({ - mutationFn: (variables: { id: string; params: CreateDiscountType }) => - api.updateDiscount(variables.id, variables.params), - }); -}; - -export const useDeleteDiscount = () => { - return useMutation({ - mutationFn: (id: string) => api.deleteDiscount(id), - }); -}; diff --git a/src/pages/discounts/service/DiscountService.ts b/src/pages/discounts/service/DiscountService.ts deleted file mode 100644 index bb9cd7c..0000000 --- a/src/pages/discounts/service/DiscountService.ts +++ /dev/null @@ -1,35 +0,0 @@ -import axios from "../../../config/axios"; -import { CreateDiscountType } from "../types/DiscountTypes"; - -export const createDiscount = async (params: CreateDiscountType) => { - const { data } = await axios.post(`/discounts`, params); - return data; -}; - -export const getDiscounts = async (search: string) => { - const { data } = await axios.get(`/discounts?q=${search}`); - return data; -}; - -export const toggleStatusDiscount = async (id: string) => { - const { data } = await axios.post(`/discounts/${id}/toggle-status`); - return data; -}; - -export const getDiscountDetail = async (id: string) => { - const { data } = await axios.get(`/discounts/${id}`); - return data; -}; - -export const updateDiscount = async ( - id: string, - params: CreateDiscountType -) => { - const { data } = await axios.patch(`/discounts/${id}`, params); - return data; -}; - -export const deleteDiscount = async (id: string) => { - const { data } = await axios.delete(`/discounts/${id}`); - return data; -}; diff --git a/src/pages/discounts/types/DiscountTypes.ts b/src/pages/discounts/types/DiscountTypes.ts deleted file mode 100644 index c819313..0000000 --- a/src/pages/discounts/types/DiscountTypes.ts +++ /dev/null @@ -1,52 +0,0 @@ -export type CreateDiscountType = { - title: string; - type: number; - direct: boolean; - value: number; - startDate: string; - endDate: string; - isActive: boolean; - targetServices: string[]; - userPhone?: string; -}; - -export enum DiscountType { - DIRECT = "DIRECT", - CODE = "CODE", -} - -export enum DiscountCalculationType { - FIXED = "FIXED", - PERCENTAGE = "PERCENTAGE", -} - -export type DiscountItemType = { - id: string; - title: string; - type: DiscountType; - calculationType: DiscountCalculationType; - value: string | number; - startDate: string; - endDate: string; - subscriptionPlans: { id: string; createdAt: string; name: string }[]; - userIds: string[]; - code: string; - createdAt: string; - updatedAt: string; - isActive: boolean; - users: { firstName: string; lastName: string }[]; - user: { firstName: string; lastName: string; phone: string }; -}; - -export type SubscriptionPlanType = { - createdAt: string; - deletedAt: string | null; - duration: number; - id: string; - isActive: boolean; - name: string; - originalPrice: number; - price: number; - service: { id: string; createdAt: string }; - author: string; -}; diff --git a/src/pages/home/Home.tsx b/src/pages/home/Home.tsx index ed1bc66..175c87e 100644 --- a/src/pages/home/Home.tsx +++ b/src/pages/home/Home.tsx @@ -1,69 +1,53 @@ -import { FC } from 'react' -import { useTranslation } from 'react-i18next' -import { Element3, Messages3, NotificationStatus, People, Receipt2 } from 'iconsax-react' -import ItemDashboard from './components/ItemDashboard' -import { useGetDashboard } from './hooks/useHomeData' -import { Pages } from '../../config/Pages' - +import { FC, useEffect, useState } from 'react' +import { useWorkspaces } from './hooks/useHomeData' +import { workspaceItem } from './types/HomeTypes' +import moment from 'moment-jalaali' const Home: FC = () => { - const { t } = useTranslation('global') - const getDashboard = useGetDashboard() + const getWorkspaces = useWorkspaces() + const [selectedWorkspace, setSelectedWorkspace] = useState(null) + + useEffect(() => { + setSelectedWorkspace(localStorage.getItem(import.meta.env.VITE_WORKSPACE_ID)) + }, []) + + const handleChangeWorkspace = (id: string) => { + localStorage.setItem(import.meta.env.VITE_WORKSPACE_ID, id) + setSelectedWorkspace(id) + window.location.reload() + } return (
- } - color='#00D16C' - count={getDashboard.data?.data?.danakServicesCount} - description={t('home.service')} - to={Pages.services.list} - /> + { + getWorkspaces.data?.data?.workspaces?.map((item: workspaceItem) => { + return ( +
handleChangeWorkspace(item.id)} + > +
+ {item.businessName} +
- } - color='#00D16C' - count={getDashboard.data?.data?.customersCount} - description={t('home.customer')} - to={Pages.customers.list} - /> +
+ {item.plan?.name} +
- } - color='#FF7B00' - count={getDashboard.data?.data?.unreadTickets} - description={t('home.unread_messages')} - to={Pages.ticket.list} - /> - - } - color='#FF0000' - count={getDashboard.data?.data?.adsCount} - description={t('home.active_ads')} - to={Pages.ads.list} - /> - - } - color='#0047FF' - count={getDashboard.data?.data?.invoicesCount} - description={t('home.new_invoice')} - to={Pages.receipts.index} - /> +
+
تاریخ پایان:
+
{moment(item?.endDate).format('jYYYY/jMM/jDD')}
+
+
+ ) + }) + } +
- -
) diff --git a/src/pages/home/hooks/useHomeData.ts b/src/pages/home/hooks/useHomeData.ts index c2e0289..3e3f463 100644 --- a/src/pages/home/hooks/useHomeData.ts +++ b/src/pages/home/hooks/useHomeData.ts @@ -1,9 +1,9 @@ import { useQuery } from "@tanstack/react-query"; import * as api from "../service/HomeService"; -export const useGetDashboard = () => { +export const useWorkspaces = () => { return useQuery({ - queryKey: ["dashboard"], - queryFn: api.getDashboard, + queryKey: ["workspaces"], + queryFn: api.getWorkspaces, }); }; diff --git a/src/pages/home/service/HomeService.ts b/src/pages/home/service/HomeService.ts index 1ff8895..5a94ff0 100644 --- a/src/pages/home/service/HomeService.ts +++ b/src/pages/home/service/HomeService.ts @@ -1,6 +1,8 @@ -import axios from "../../../config/axios"; +import danakAxios from "../../../config/axiosDanak"; -export const getDashboard = async () => { - const { data } = await axios.get(`/dashboards/reports`); +export const getWorkspaces = async () => { + const { data } = await danakAxios.get( + `/subscriptions/workspaces/${import.meta.env.VITE_SERVICE_ID}` + ); return data; }; diff --git a/src/pages/home/types/HomeTypes.ts b/src/pages/home/types/HomeTypes.ts new file mode 100644 index 0000000..d3aea94 --- /dev/null +++ b/src/pages/home/types/HomeTypes.ts @@ -0,0 +1,48 @@ +import { UserItemType } from "../../users/types/UserTypes"; + +export type workspaceItem = { + id: string; + createdAt: string; + updatedAt: string; + plan: { + id: string; + createdAt: string; + updatedAt: string; + name: string; + duration: number; + price: number; + originalPrice: number; + isActive: boolean; + service: { + id: string; + createdAt: string; + updatedAt: string; + name: string; + title: string; + slug: string; + isDanakSuggest: boolean; + description: string; + author: string; + createDate: string; + userCount: number; + serviceLanguage: string; + softwareLanguage: string; + metaDescription: string; + isActive: boolean; + showInSlider: boolean; + link: string; + icon: string; + coverUrl: string; + deletedAt: string | null; + }; + deletedAt: string | null; + }; + startDate: string; + endDate: string; + businessName: string; + businessPhone: string; + description: string; + slug: string; + status: string; + staff: UserItemType[]; +}; diff --git a/src/pages/learning/Category.tsx b/src/pages/learning/Category.tsx deleted file mode 100644 index 3e94302..0000000 --- a/src/pages/learning/Category.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { FC, useState } from 'react' -import { useTranslation } from 'react-i18next' -import Td from '../../components/Td' -import PageLoading from '../../components/PageLoading' -import Pagination from '../../components/Pagination' -import { useGetCategory } from './hooks/useLearningData' -import { CategoryLearningType } from './types/LearningTypes' -import CreateCategory from './components/CreateCategory' - - -const LearningCategory: FC = () => { - - const { t } = useTranslation('global') - const [page, setPage] = useState(1) - const getCategory = useGetCategory() - - return ( -
-
- {t('service.cateory_services')} -
- -
-
- -
- { - getCategory.isPending ? -
- -
- : -
- - - - - - - { - getCategory.data?.data?.categories?.map((item: CategoryLearningType) => { - return ( - - - ) - }) - } - -
- -
- -
-
- -
-
- } - - -
-
- - -
-
- ) -} - -export default LearningCategory \ No newline at end of file diff --git a/src/pages/learning/Create.tsx b/src/pages/learning/Create.tsx deleted file mode 100644 index 2a0b193..0000000 --- a/src/pages/learning/Create.tsx +++ /dev/null @@ -1,167 +0,0 @@ -import { FC, useState } from 'react' -import { useTranslation } from 'react-i18next' -import Button from '../../components/Button' -import { useFormik } from 'formik' -import { CategoryLearningType, CreateLearningType } from './types/LearningTypes' -import * as Yup from 'yup' -import { useCreateLearning, useGetCategory } from './hooks/useLearningData' -import { useSingleUpload } from '../service/hooks/useServiceData' -import { TickCircle } from 'iconsax-react' -import Input from '../../components/Input' -import Select from '../../components/Select' -import Textarea from '../../components/Textarea' -import PageLoading from '../../components/PageLoading' -import CreateLearningSidebar from './components/CreateLearningSidebar' -import { ErrorType } from '../../helpers/types' -import { toast } from 'react-toastify' -import { useNavigate } from 'react-router-dom' -import { Pages } from '../../config/Pages' - -const CreateLearning: FC = () => { - - const navigate = useNavigate() - const { t } = useTranslation('global') - const singleUpload = useSingleUpload() - const createLearning = useCreateLearning() - const getCategory = useGetCategory() - const [videoFile, setVideoFile] = useState() - const [coverFile, setCoverFile] = useState() - - const formik = useFormik({ - initialValues: { - title: '', - description: '', - coverUrl: '', - videoUrl: '', - videoDuration: '', - categoryId: '' - }, - validationSchema: Yup.object().shape({ - title: Yup.string().required(t('errors.required')), - description: Yup.string().required(t('errors.required')), - videoDuration: Yup.string().required(t('errors.required')), - categoryId: Yup.string().required(t('errors.required')) - }), - onSubmit: async (values) => { - if (videoFile && coverFile) { - - const formData = new FormData() - formData.append('file', videoFile) - await singleUpload.mutateAsync(formData, { - onSuccess: (data) => { - values.videoUrl = data?.data?.url - }, - onError: (error: ErrorType) => { - toast.error(error.response?.data?.error?.message[0]) - } - }) - - const formDataCover = new FormData() - formDataCover.append('file', coverFile) - await singleUpload.mutateAsync(formDataCover, { - onSuccess: (data) => { - values.coverUrl = data?.data?.url - }, - onError: (error: ErrorType) => { - toast.error(error.response?.data?.error?.message[0]) - } - }) - - createLearning.mutate(values, { - onSuccess: () => { - toast.success(t('success')) - navigate(Pages.learning.list) - }, - onError: (error: ErrorType) => { - toast.error(error.response?.data?.error?.message[0]) - } - }) - } else { - toast.error(t('learning.error_video_cover_required')) - } - } - }) - - return ( -
-
-
- {t('learning.new_learning')} -
-
- -
-
- - { - getCategory.isPending ? - - : -
-
-
- - - -
- -
- -
-
{t('learning.description')}
-
-