part 1
This commit is contained in:
@@ -12,6 +12,7 @@ import { IApiErrorRepsonse } from './types/error.types'
|
|||||||
import MainRouter from './router/Main'
|
import MainRouter from './router/Main'
|
||||||
import AuthRouter from './router/Auth'
|
import AuthRouter from './router/Auth'
|
||||||
import { Pages } from './config/Pages'
|
import { Pages } from './config/Pages'
|
||||||
|
import useConvertNumbers from './hooks/useConvertNumbers';
|
||||||
|
|
||||||
i18next.init({
|
i18next.init({
|
||||||
interpolation: { escapeValue: false },
|
interpolation: { escapeValue: false },
|
||||||
@@ -43,6 +44,7 @@ const queryClient = new QueryClient({
|
|||||||
const App: FC = () => {
|
const App: FC = () => {
|
||||||
|
|
||||||
// useNumberFont()
|
// useNumberFont()
|
||||||
|
useConvertNumbers()
|
||||||
|
|
||||||
const [isLogin, setIsLogin] = useState<'checking' | 'isLogin' | 'isNotLogin'>('checking')
|
const [isLogin, setIsLogin] = useState<'checking' | 'isLogin' | 'isNotLogin'>('checking')
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const DefaulModal: FC<Props> = (props: Props) => {
|
|||||||
props.open && (
|
props.open && (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div style={{ maxWidth: props.width }} className='xl:justify-center xl:items-center items-end flex overflow-x-hidden overflow-y-auto fixed inset-0 z-[60] h-auto top-0 bottom-0 m-auto outline-none focus:outline-none xl:max-w-xl mx-auto'>
|
<div style={{ maxWidth: props.width }} className='xl:justify-center xl:items-center items-end flex overflow-x-hidden overflow-y-auto fixed inset-0 z-[60] h-auto top-0 bottom-0 m-auto outline-none focus:outline-none xl:max-w-xl mx-auto'>
|
||||||
<div className='relative xl:h-full h-[80%] bottom-0 left-0 flex xl:items-center sm:h-auto w-full xl:my-6 xl:p-2'>
|
<div className='relative xl:h-full max-h-[80%] bottom-0 left-0 flex xl:items-center sm:h-auto w-full xl:my-6 xl:p-2'>
|
||||||
<div className='border-0 h-auto p-5 lg:min-w-full overflow-y-auto rounded-3xl rounded-b-none xl:rounded-b-3xl relative flex flex-col w-full modalGlass2 outline-none focus:outline-none'>
|
<div className='border-0 h-auto p-5 lg:min-w-full overflow-y-auto rounded-3xl rounded-b-none xl:rounded-b-3xl relative flex flex-col w-full modalGlass2 outline-none focus:outline-none'>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,6 @@ const ServiceItem: FC<Props> = (props: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className='mt-4 text-xs'>
|
<div className='mt-4 text-xs'>
|
||||||
<div className='font-extralight'>{item.description} </div>
|
<div className='font-extralight'>{item.description} </div>
|
||||||
<p dangerouslySetInnerHTML={{ __html: item.metaDescription }} className='text-description mt-2'>
|
|
||||||
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='mt-4'>
|
<div className='mt-4'>
|
||||||
@@ -38,7 +35,7 @@ const ServiceItem: FC<Props> = (props: Props) => {
|
|||||||
className='h-8 w-fit px-5 text-xs text-black bg-description bg-opacity-20 rounded-xl'
|
className='h-8 w-fit px-5 text-xs text-black bg-description bg-opacity-20 rounded-xl'
|
||||||
>
|
>
|
||||||
<div className='flex gap-2'>
|
<div className='flex gap-2'>
|
||||||
<div>{t('service.buy')}</div>
|
<div>{t('service.detail')}</div>
|
||||||
<ArrowLeft color='black' size={16} />
|
<ArrowLeft color='black' size={16} />
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const ServiceSection: FC<Props> = (props: Props) => {
|
|||||||
const { item } = props
|
const { item } = props
|
||||||
return (
|
return (
|
||||||
<div className='flex gap-4'>
|
<div className='flex gap-4'>
|
||||||
<div className='size-10 rounded-xl'>
|
<div className='size-10 min-w-10 rounded-xl'>
|
||||||
<img src={item.icon} alt={item.name} className='w-full h-full' />
|
<img src={item.icon} alt={item.name} className='w-full h-full' />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ export const Pages = {
|
|||||||
learning: "/learning",
|
learning: "/learning",
|
||||||
setting: "/setting",
|
setting: "/setting",
|
||||||
wallet: "/wallet",
|
wallet: "/wallet",
|
||||||
|
callback: "/wallet/callback/",
|
||||||
profile: "/profile",
|
profile: "/profile",
|
||||||
discounts: "/discounts",
|
discounts: "/discounts",
|
||||||
financial: "/financial",
|
financial: "/financial",
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
const toPersianDigits = (text: string): string => {
|
||||||
|
return text.replace(/\d/g, (d) => "۰۱۲۳۴۵۶۷۸۹"[parseInt(d, 10)]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const convertNumbersInDOM = (node: Node): void => {
|
||||||
|
if (node.nodeType === Node.TEXT_NODE) {
|
||||||
|
node.nodeValue = toPersianDigits(node.nodeValue || "");
|
||||||
|
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
||||||
|
node.childNodes.forEach(convertNumbersInDOM);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const useConvertNumbers = (): void => {
|
||||||
|
useEffect(() => {
|
||||||
|
const observer = new MutationObserver((mutations) => {
|
||||||
|
mutations.forEach((mutation) => {
|
||||||
|
if (mutation.type === "childList") {
|
||||||
|
mutation.addedNodes.forEach(convertNumbersInDOM);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
observer.observe(document.body, { childList: true, subtree: true });
|
||||||
|
|
||||||
|
// اجرای اولیه روی کل صفحه
|
||||||
|
convertNumbersInDOM(document.body);
|
||||||
|
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}, []);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useConvertNumbers;
|
||||||
+21
-5
@@ -39,7 +39,9 @@
|
|||||||
"login_with_otp": "ورود با رمز عبور یکبار مصرف",
|
"login_with_otp": "ورود با رمز عبور یکبار مصرف",
|
||||||
"otp_sent": "کد تایید ارسال شد",
|
"otp_sent": "کد تایید ارسال شد",
|
||||||
"mobile_number": "شماره موبایل",
|
"mobile_number": "شماره موبایل",
|
||||||
"enter_mobile_number": "شماره موبایل خود را وارد کنید"
|
"enter_mobile_number": "شماره موبایل خود را وارد کنید",
|
||||||
|
"try_again": "ارسال مجدد",
|
||||||
|
"toast_resend_code": "کد جدیدی برای شما ارسال شد"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"required": "این فیلد اجباری می باشد",
|
"required": "این فیلد اجباری می باشد",
|
||||||
@@ -85,13 +87,17 @@
|
|||||||
"add_access": "دسترسی سریع تازه ایجاد کنید.",
|
"add_access": "دسترسی سریع تازه ایجاد کنید.",
|
||||||
"danak_learning": "آموزش داناک",
|
"danak_learning": "آموزش داناک",
|
||||||
"see_all": "دیدن همه",
|
"see_all": "دیدن همه",
|
||||||
"create_new_access": "ایجاد دسترسی سریع"
|
"create_new_access": "ایجاد دسترسی سریع",
|
||||||
|
"receip": "صورتحساب پرداخت نشده دارید",
|
||||||
|
"balance": "موجودی",
|
||||||
|
"cannot_find_service": "سرویسی پیدا نشد",
|
||||||
|
"not_active_service": "شما هنوز سرویس فعالی ندارید"
|
||||||
},
|
},
|
||||||
"all": "همه",
|
"all": "همه",
|
||||||
"service": {
|
"service": {
|
||||||
"my_service": "سرویس های من",
|
"my_service": "سرویس های من",
|
||||||
"search": "جستجو در سرویس ها",
|
"search": "جستجو در سرویس ها",
|
||||||
"active_menu": "منو فعال",
|
"active_menu": "سرویس فعال",
|
||||||
"selected_danak": "انتخاب داناک",
|
"selected_danak": "انتخاب داناک",
|
||||||
"buy": "خرید",
|
"buy": "خرید",
|
||||||
"other_services": "سایر سرویس ها",
|
"other_services": "سایر سرویس ها",
|
||||||
@@ -115,7 +121,8 @@
|
|||||||
"enter_title_comment": "عنوان نظر خود را وارد کنید",
|
"enter_title_comment": "عنوان نظر خود را وارد کنید",
|
||||||
"your_comment": "نظر شما",
|
"your_comment": "نظر شما",
|
||||||
"write_your_comment": "نظر خود را راجع به این سرویس بنویسید",
|
"write_your_comment": "نظر خود را راجع به این سرویس بنویسید",
|
||||||
"users_comments": "نظرات کاربران"
|
"users_comments": "نظرات کاربران",
|
||||||
|
"detail": "جزییات بیشتر"
|
||||||
},
|
},
|
||||||
"loading": "در حال بارگذاری",
|
"loading": "در حال بارگذاری",
|
||||||
"footer": {
|
"footer": {
|
||||||
@@ -173,6 +180,7 @@
|
|||||||
},
|
},
|
||||||
"date": "تاریخ",
|
"date": "تاریخ",
|
||||||
"receip": {
|
"receip": {
|
||||||
|
"receip": "صورتحساب",
|
||||||
"receip_list": "لیست صورتحساب ها",
|
"receip_list": "لیست صورتحساب ها",
|
||||||
"dont_pay": "پرداخت نشده",
|
"dont_pay": "پرداخت نشده",
|
||||||
"dont_confrim": "تایید نشده",
|
"dont_confrim": "تایید نشده",
|
||||||
@@ -400,5 +408,13 @@
|
|||||||
},
|
},
|
||||||
"man": "مرد",
|
"man": "مرد",
|
||||||
"woman": "زن",
|
"woman": "زن",
|
||||||
"success": "عملیات با موفقیت انجام شد"
|
"success": "عملیات با موفقیت انجام شد",
|
||||||
|
"callback": {
|
||||||
|
"title_success": "پرداخت موفق بود!",
|
||||||
|
"desc_success": "پرداخت شما با موفقیت انجام شد. از خرید شما متشکریم!",
|
||||||
|
"order_number": "شماره سفارش",
|
||||||
|
"amount": "مبلغ پرداختی",
|
||||||
|
"date": "تاریخ",
|
||||||
|
"back": "بازگشت"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import OTPInput from 'react-otp-input'
|
|||||||
import { useCountDown } from '../../../hooks/useCountDown'
|
import { useCountDown } from '../../../hooks/useCountDown'
|
||||||
// import ArrowLeftIcon from '../../../assets/images/arrow-left.svg'
|
// import ArrowLeftIcon from '../../../assets/images/arrow-left.svg'
|
||||||
import { Pages } from '../../../config/Pages'
|
import { Pages } from '../../../config/Pages'
|
||||||
import { useOtpVerify } from '../hooks/useAuthData'
|
import { useLoginWithOtp, useOtpVerify } from '../hooks/useAuthData'
|
||||||
import { ErrorType } from '../../../helpers/types'
|
import { ErrorType } from '../../../helpers/types'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
|
|
||||||
@@ -17,8 +17,9 @@ const LoginStep2: FC = () => {
|
|||||||
|
|
||||||
const { t } = useTranslation('global')
|
const { t } = useTranslation('global')
|
||||||
const { phone, setStepLogin } = useAuthStore()
|
const { phone, setStepLogin } = useAuthStore()
|
||||||
const { value } = useCountDown(2, true)
|
const { value, reset } = useCountDown(2, true)
|
||||||
const otpVerify = useOtpVerify()
|
const otpVerify = useOtpVerify()
|
||||||
|
const loginWithOtp = useLoginWithOtp()
|
||||||
|
|
||||||
const formik = useFormik<OtpVerifyType>({
|
const formik = useFormik<OtpVerifyType>({
|
||||||
initialValues: {
|
initialValues: {
|
||||||
@@ -69,6 +70,18 @@ const LoginStep2: FC = () => {
|
|||||||
return () => ac.abort();
|
return () => ac.abort();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const reSend = () => {
|
||||||
|
loginWithOtp.mutate({ phone: phone }, {
|
||||||
|
onSuccess: () => {
|
||||||
|
reset()
|
||||||
|
toast.success(t('auth.toast_resend_code'))
|
||||||
|
},
|
||||||
|
onError: (error: ErrorType) => {
|
||||||
|
toast.error(error.response?.data?.error.message[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className='mt-5'>
|
<div className='mt-5'>
|
||||||
@@ -103,6 +116,7 @@ const LoginStep2: FC = () => {
|
|||||||
renderInput={(props) =>
|
renderInput={(props) =>
|
||||||
<input
|
<input
|
||||||
{...props}
|
{...props}
|
||||||
|
type='tel'
|
||||||
autoComplete="one-time-code"
|
autoComplete="one-time-code"
|
||||||
inputMode="numeric"
|
inputMode="numeric"
|
||||||
className='w-full h-[50px] flex-1 mx-2 bg-white border rounded-2.5' />
|
className='w-full h-[50px] flex-1 mx-2 bg-white border rounded-2.5' />
|
||||||
@@ -116,10 +130,21 @@ const LoginStep2: FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
<div className='flex mt-4 justify-end'>
|
<div className='flex mt-4 justify-end'>
|
||||||
|
{
|
||||||
|
value !== '00:00' ?
|
||||||
<div className='flex gap-1 text-description text-xs'>
|
<div className='flex gap-1 text-description text-xs'>
|
||||||
<div>{value}</div>
|
<div>{value}</div>
|
||||||
<div>{t('auth.counter_otp')}</div>
|
<div>{t('auth.counter_otp')}</div>
|
||||||
</div>
|
</div>
|
||||||
|
:
|
||||||
|
<div onClick={reSend} className='flex cursor-pointer gap-1 pl-2 text-black text-sm'>
|
||||||
|
<div className=''>
|
||||||
|
{t('auth.try_again')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const Financial: FC = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <ProfileCircle color={activeTab === 'personal' ? 'black' : '#8C90A3'} size={22} />,
|
icon: <ProfileCircle color={activeTab === 'personal' ? 'black' : '#8C90A3'} size={22} />,
|
||||||
label: t('financial.legal'),
|
label: t('financial.personal'),
|
||||||
value: 'personal'
|
value: 'personal'
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { FC } from 'react'
|
import { FC } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { ArrowLeft, Element3, Messages3, NotificationStatus, Teacher } from 'iconsax-react'
|
import { ArrowLeft, Element3, Messages3, NotificationStatus, Receipt21 } from 'iconsax-react'
|
||||||
import ItemDashboard from './components/ItemDashboard'
|
import ItemDashboard from './components/ItemDashboard'
|
||||||
import TitleLine from '../../components/TitleLine'
|
import TitleLine from '../../components/TitleLine'
|
||||||
import AccessbilityImage from '../../assets/images/accessbility.jpg'
|
import AccessbilityImage from '../../assets/images/accessbility.jpg'
|
||||||
@@ -73,6 +73,14 @@ const Home: FC = () => {
|
|||||||
description={t('home.unread_messages')}
|
description={t('home.unread_messages')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<ItemDashboard
|
||||||
|
title={t('receip.receip')}
|
||||||
|
icon={<Receipt21 size={20} color='black' />}
|
||||||
|
color='#0047FF'
|
||||||
|
count={4}
|
||||||
|
description={t('home.receip')}
|
||||||
|
/>
|
||||||
|
|
||||||
<ItemDashboard
|
<ItemDashboard
|
||||||
title={t('home.announcement')}
|
title={t('home.announcement')}
|
||||||
icon={<NotificationStatus size={20} color='black' />}
|
icon={<NotificationStatus size={20} color='black' />}
|
||||||
@@ -81,14 +89,6 @@ const Home: FC = () => {
|
|||||||
description={t('home.unread_announcement')}
|
description={t('home.unread_announcement')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ItemDashboard
|
|
||||||
title={t('home.learnings')}
|
|
||||||
icon={<Teacher size={20} color='black' />}
|
|
||||||
color='#0047FF'
|
|
||||||
count={4}
|
|
||||||
description={t('home.learning')}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='w-full mt-8'>
|
<div className='w-full mt-8'>
|
||||||
|
|||||||
@@ -3,13 +3,17 @@ import { FC, useState } from 'react'
|
|||||||
import DefaulModal from '../../../components/DefaulModal'
|
import DefaulModal from '../../../components/DefaulModal'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import Input from '../../../components/Input'
|
import Input from '../../../components/Input'
|
||||||
import Select from '../../../components/Select'
|
|
||||||
import SwitchComponent from '../../../components/Switch'
|
import SwitchComponent from '../../../components/Switch'
|
||||||
|
import { useGetMyServices } from '../../service/hooks/useServiceData'
|
||||||
|
import { MyServicesItem } from '../../service/types/ServiecTypes'
|
||||||
|
import PageLoading from '../../../components/PageLoading'
|
||||||
|
|
||||||
const BoxNewAccessbility: FC = () => {
|
const BoxNewAccessbility: FC = () => {
|
||||||
|
|
||||||
|
const [search, setSearch] = useState<string>('')
|
||||||
const [open, setOpen] = useState<boolean>(false)
|
const [open, setOpen] = useState<boolean>(false)
|
||||||
const { t } = useTranslation('global')
|
const { t } = useTranslation('global')
|
||||||
|
const getMyservices = useGetMyServices(search)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -63,68 +67,42 @@ const BoxNewAccessbility: FC = () => {
|
|||||||
<Input
|
<Input
|
||||||
variant='search'
|
variant='search'
|
||||||
className='bg-opacity-25 bg-white'
|
className='bg-opacity-25 bg-white'
|
||||||
|
onChangeSearchFinal={setSearch}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Select
|
|
||||||
items={[
|
|
||||||
{ value: '1', label: '1' },
|
|
||||||
{ value: '2', label: '2' },
|
|
||||||
{ value: '3', label: '3' },
|
|
||||||
]}
|
|
||||||
placeholder={t('all')}
|
|
||||||
className='bg-opacity-25 bg-white w-[100px]'
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{
|
||||||
|
getMyservices.isPending ?
|
||||||
|
<div className='mt-6'>
|
||||||
|
<PageLoading />
|
||||||
|
</div>
|
||||||
|
:
|
||||||
<div className='mt-6 flex flex-wrap gap-6'>
|
<div className='mt-6 flex flex-wrap gap-6'>
|
||||||
<div className='flex-1 xl:min-w-[40%] min-w-full flex justify-between items-center border-b border-[#8C90A3] border-opacity-30 py-2'>
|
{
|
||||||
|
getMyservices.data?.data?.subscriptions?.length === 0 ?
|
||||||
|
<div className='text-center w-full mt-4'>
|
||||||
|
{
|
||||||
|
search === '' ?
|
||||||
|
t('home.not_active_service')
|
||||||
|
:
|
||||||
|
t('home.cannot_find_service')
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
getMyservices.data?.data?.subscriptions?.map((item: MyServicesItem) => {
|
||||||
|
return (
|
||||||
|
<div key={item.id} className='flex-1 xl:min-w-[40%] min-w-full flex justify-between items-center border-b border-[#8C90A3] border-opacity-30 py-2'>
|
||||||
<div className='flex gap-4'>
|
<div className='flex gap-4'>
|
||||||
<div className='size-10 rounded-xl bg-red-300'></div>
|
<div className='size-10 rounded-xl overflow-hidden'>
|
||||||
|
<img src={item.plan?.service?.icon} className='size-full' />
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className='text-sm'>
|
<div className='text-sm'>
|
||||||
دی منو
|
{item.plan.service?.name}
|
||||||
</div>
|
</div>
|
||||||
<div className='text-xs text-description'>
|
<div className='text-xs text-description'>
|
||||||
منو رستوران
|
{item.plan.service?.title}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<SwitchComponent
|
|
||||||
active
|
|
||||||
onChange={() => { }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='flex-1 xl:min-w-[40%] min-w-full flex justify-between items-center border-b border-[#8C90A3] border-opacity-30 py-2'>
|
|
||||||
<div className='flex gap-4'>
|
|
||||||
<div className='size-10 rounded-xl bg-blue-300'></div>
|
|
||||||
<div>
|
|
||||||
<div className='text-sm'>
|
|
||||||
دی منو
|
|
||||||
</div>
|
|
||||||
<div className='text-xs text-description'>
|
|
||||||
منو رستوران
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<SwitchComponent
|
|
||||||
active
|
|
||||||
onChange={() => { }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='flex-1 xl:min-w-[40%] min-w-full flex justify-between items-center border-b border-[#8C90A3] border-opacity-30 py-2'>
|
|
||||||
<div className='flex gap-4'>
|
|
||||||
<div className='size-10 rounded-xl bg-green-300'></div>
|
|
||||||
<div>
|
|
||||||
<div className='text-sm'>
|
|
||||||
دی منو
|
|
||||||
</div>
|
|
||||||
<div className='text-xs text-description'>
|
|
||||||
منو رستوران
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -135,8 +113,12 @@ const BoxNewAccessbility: FC = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
<div className='flex-1 min-w-[40%]'></div>
|
<div className='flex-1 min-w-[40%]'></div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</DefaulModal>
|
</DefaulModal>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ const DetailService: FC = () => {
|
|||||||
|
|
||||||
{
|
{
|
||||||
getAdsLeft.isSuccess && getAdsLeft.data.data.ads[0] &&
|
getAdsLeft.isSuccess && getAdsLeft.data.data.ads[0] &&
|
||||||
<a href={getAdsLeft.data?.data?.ads[0].link} target='_blank' className='bg-white w-sidebar h-fit hidden xl:block rounded-3xl overflow-hidden relative'>
|
<a href={getAdsLeft.data?.data?.ads[0].link} target='_blank' className='bg-white w-sidebar h-fit hidden xl:block rounded-3xl overflow-hidden sticky top-4'>
|
||||||
<img
|
<img
|
||||||
src={getAdsLeft.data.data.ads[0].imageUrl}
|
src={getAdsLeft.data.data.ads[0].imageUrl}
|
||||||
className='w-full backdrop-blur-[100px] h-[550px] object-cover'
|
className='w-full backdrop-blur-[100px] h-[550px] object-cover'
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ const MyServices: FC = () => {
|
|||||||
|
|
||||||
{
|
{
|
||||||
getAdsLeft.isSuccess && getAdsLeft.data.data.ads[0] &&
|
getAdsLeft.isSuccess && getAdsLeft.data.data.ads[0] &&
|
||||||
<a href={getAdsLeft.data?.data?.ads[0].link} target='_blank' className='bg-white w-sidebar h-fit hidden xl:block rounded-3xl overflow-hidden relative'>
|
<a href={getAdsLeft.data?.data?.ads[0].link} target='_blank' className='bg-white w-sidebar h-fit hidden xl:block rounded-3xl overflow-hidden sticky top-0'>
|
||||||
<img
|
<img
|
||||||
src={getAdsLeft.data.data.ads[0].imageUrl}
|
src={getAdsLeft.data.data.ads[0].imageUrl}
|
||||||
className='w-full backdrop-blur-[100px] h-[550px] object-cover'
|
className='w-full backdrop-blur-[100px] h-[550px] object-cover'
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ const OtherServices: FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
getAdsLeft.isSuccess && getAdsLeft.data.data.ads[0] &&
|
getAdsLeft.isSuccess && getAdsLeft.data.data.ads[0] &&
|
||||||
<a href={getAdsLeft.data?.data?.ads[0].link} target='_blank' className='bg-white w-sidebar h-fit hidden xl:block rounded-3xl overflow-hidden relative'>
|
<a href={getAdsLeft.data?.data?.ads[0].link} target='_blank' className='bg-white w-sidebar h-fit hidden xl:block rounded-3xl overflow-hidden sticky top-0'>
|
||||||
<img
|
<img
|
||||||
src={getAdsLeft.data.data.ads[0].imageUrl}
|
src={getAdsLeft.data.data.ads[0].imageUrl}
|
||||||
className='w-full backdrop-blur-[100px] h-[550px] object-cover'
|
className='w-full backdrop-blur-[100px] h-[550px] object-cover'
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ const OtherServicesComponent: FC = () => {
|
|||||||
getServices.data?.data?.category?.danakServices?.map((item: ItemServiceType) => {
|
getServices.data?.data?.category?.danakServices?.map((item: ItemServiceType) => {
|
||||||
return (
|
return (
|
||||||
<div className='flex-1 min-w-full xl:min-w-0 bg-white rounded-3xl py-4 px-6'>
|
<div className='flex-1 min-w-full xl:min-w-0 bg-white rounded-3xl py-4 px-6'>
|
||||||
<div className='flex justify-between items-center'>
|
<div className='flex gap-2 justify-between items-center'>
|
||||||
<ServiceSection
|
<ServiceSection
|
||||||
item={item}
|
item={item}
|
||||||
/>
|
/>
|
||||||
@@ -77,7 +77,7 @@ const OtherServicesComponent: FC = () => {
|
|||||||
className='h-8 w-fit px-2 text-xs text-black bg-description bg-opacity-20 rounded-xl'
|
className='h-8 w-fit px-2 text-xs text-black bg-description bg-opacity-20 rounded-xl'
|
||||||
>
|
>
|
||||||
<div className='flex gap-2'>
|
<div className='flex gap-2'>
|
||||||
<div>{t('service.buy')}</div>
|
<div className='whitespace-nowrap'>{t('service.detail')}</div>
|
||||||
<ArrowLeft color='black' size={16} />
|
<ArrowLeft color='black' size={16} />
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -88,7 +88,6 @@ const TicketDetail: FC = () => {
|
|||||||
<div className='mt-4'>
|
<div className='mt-4'>
|
||||||
<div className='flex gap-1'>
|
<div className='flex gap-1'>
|
||||||
<div>{t('ticket.ticket_number')}</div>
|
<div>{t('ticket.ticket_number')}</div>
|
||||||
<div>12312</div>
|
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
getMessages.isPending ?
|
getMessages.isPending ?
|
||||||
@@ -115,7 +114,7 @@ const TicketDetail: FC = () => {
|
|||||||
|
|
||||||
{
|
{
|
||||||
getMessages.data?.data?.messages.map((item: any) => {
|
getMessages.data?.data?.messages.map((item: any) => {
|
||||||
if (item?.author?.role?.name === 'user') {
|
if (item?.author?.roles[0]?.name === 'user') {
|
||||||
return (
|
return (
|
||||||
<div key={item.id} className='mt-6 xl:text-sm text-xs bg-[#F6F7FA] p-6 rounded-3xl rounded-tr-none xl:max-w-[70%] max-w-[90%]'>
|
<div key={item.id} className='mt-6 xl:text-sm text-xs bg-[#F6F7FA] p-6 rounded-3xl rounded-tr-none xl:max-w-[70%] max-w-[90%]'>
|
||||||
<div className='leading-7'>
|
<div className='leading-7'>
|
||||||
@@ -154,8 +153,8 @@ const TicketDetail: FC = () => {
|
|||||||
<div className='leading-7 mt-4'>
|
<div className='leading-7 mt-4'>
|
||||||
{item.content}
|
{item.content}
|
||||||
</div>
|
</div>
|
||||||
<div className='flex justify-end mt-6 text-xs text-description'>
|
<div className='flex dltr end mt-6 text-xs text-description'>
|
||||||
10:07 | 1403/09/30
|
{moment(item.createdAt).format('jYYYY-jMM-jDD HH:mm')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import moment from 'moment-jalaali'
|
|||||||
const TicketList: FC = () => {
|
const TicketList: FC = () => {
|
||||||
|
|
||||||
const { t } = useTranslation('global')
|
const { t } = useTranslation('global')
|
||||||
const [activeTab, setActiveTab] = useState<'ANSWERED' | 'PENDING' | 'CLOSED'>('ANSWERED')
|
const [activeTab, setActiveTab] = useState<'ANSWERED' | 'PENDING' | 'CLOSED'>('PENDING')
|
||||||
const getTickets = useGetTickets(activeTab)
|
const getTickets = useGetTickets(activeTab)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -40,16 +40,16 @@ const TicketList: FC = () => {
|
|||||||
<Tabs
|
<Tabs
|
||||||
active={activeTab}
|
active={activeTab}
|
||||||
items={[
|
items={[
|
||||||
{
|
|
||||||
icon: <MessageTick color={activeTab === 'ANSWERED' ? 'black' : '#8C90A3'} size={22} />,
|
|
||||||
label: t('ticket.answered'),
|
|
||||||
value: 'ANSWERED'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
icon: <MessageTime color={activeTab === 'PENDING' ? 'black' : '#8C90A3'} size={22} />,
|
icon: <MessageTime color={activeTab === 'PENDING' ? 'black' : '#8C90A3'} size={22} />,
|
||||||
label: t('ticket.checking'),
|
label: t('ticket.checking'),
|
||||||
value: 'PENDING'
|
value: 'PENDING'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
icon: <MessageTick color={activeTab === 'ANSWERED' ? 'black' : '#8C90A3'} size={22} />,
|
||||||
|
label: t('ticket.answered'),
|
||||||
|
value: 'ANSWERED'
|
||||||
|
},
|
||||||
// {
|
// {
|
||||||
// icon: <Message2 color={activeTab === 'wating' ? 'black' : '#8C90A3'} size={22} />,
|
// icon: <Message2 color={activeTab === 'wating' ? 'black' : '#8C90A3'} size={22} />,
|
||||||
// label: t('ticket.wait_answered'),
|
// label: t('ticket.wait_answered'),
|
||||||
|
|||||||
@@ -56,7 +56,16 @@ export const useAddMessageTicket = (id: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const useCloseTicket = () => {
|
export const useCloseTicket = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: (id: string) => api.closeTicket(id),
|
mutationFn: (id: string) => api.closeTicket(id),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.refetchQueries({
|
||||||
|
queryKey: ["tickets"],
|
||||||
|
});
|
||||||
|
queryClient.refetchQueries({
|
||||||
|
queryKey: ["ticket-messages"],
|
||||||
|
});
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ const TransactionList: FC = () => {
|
|||||||
<tr key={item.id}>
|
<tr key={item.id}>
|
||||||
<Td text={item.numericId + ''} />
|
<Td text={item.numericId + ''} />
|
||||||
<Td text={item.description} />
|
<Td text={item.description} />
|
||||||
<Td text={item.amount} />
|
<Td text={NumberFormat(+item.amount)} />
|
||||||
<Td text={moment(item.createdAt).format('jYYYY-jMM-jDD')} />
|
<Td text={moment(item.createdAt).format('jYYYY-jMM-jDD')} />
|
||||||
<Td text={''}>
|
<Td text={''}>
|
||||||
<Detail />
|
<Detail />
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import { TickCircle } from 'iconsax-react'
|
||||||
|
import { FC } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { NumberFormat } from '../../config/func'
|
||||||
|
import Button from '../../components/Button'
|
||||||
|
|
||||||
|
const CallBack: FC = () => {
|
||||||
|
|
||||||
|
const { t } = useTranslation('global')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='flex mt-10 flex-col justify-center items-center flex-1 h-full'>
|
||||||
|
<TickCircle
|
||||||
|
size={64}
|
||||||
|
color='#00712D'
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className='mt-7 text-xl'>
|
||||||
|
{t('callback.title_success')}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='mt-7'>
|
||||||
|
{t('callback.desc_success')}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='mt-16 xl:min-w-[560px] bg-[#FBFBFD] p-8 text-sm'>
|
||||||
|
<div className='flex justify-between'>
|
||||||
|
<div>
|
||||||
|
{t('callback.order_number')}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
#1234
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='flex justify-between mt-6'>
|
||||||
|
<div>
|
||||||
|
{t('callback.amount')}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{NumberFormat(200000) + ' ' + t('toman')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='flex justify-between mt-6'>
|
||||||
|
<div>
|
||||||
|
{t('callback.date')}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
۲۹ بهمن ۱۴۰۳
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
label={t('callback.back')}
|
||||||
|
className='xl:max-w-[560px] mt-8'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CallBack
|
||||||
@@ -11,6 +11,7 @@ import { DepositTransferType } from '../types/WalletTypes'
|
|||||||
import * as Yup from 'yup'
|
import * as Yup from 'yup'
|
||||||
import { useSingleUpload } from '../../ticket/hooks/useTicketData'
|
import { useSingleUpload } from '../../ticket/hooks/useTicketData'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
|
import { ErrorType } from '../../../helpers/types'
|
||||||
|
|
||||||
const CardtoCard: FC = () => {
|
const CardtoCard: FC = () => {
|
||||||
|
|
||||||
@@ -42,6 +43,9 @@ const CardtoCard: FC = () => {
|
|||||||
formik.resetForm()
|
formik.resetForm()
|
||||||
setFile(undefined)
|
setFile(undefined)
|
||||||
toast.success(t('wallet.successful_transfer'))
|
toast.success(t('wallet.successful_transfer'))
|
||||||
|
},
|
||||||
|
onError: (error: ErrorType) => {
|
||||||
|
toast.error(error.response?.data?.error.message[0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { DepositTransferType } from '../types/WalletTypes'
|
|||||||
import * as Yup from 'yup'
|
import * as Yup from 'yup'
|
||||||
import { useSingleUpload } from '../../ticket/hooks/useTicketData'
|
import { useSingleUpload } from '../../ticket/hooks/useTicketData'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
|
import { ErrorType } from '../../../helpers/types'
|
||||||
|
|
||||||
const CardtoCard: FC = () => {
|
const CardtoCard: FC = () => {
|
||||||
|
|
||||||
@@ -43,6 +44,9 @@ const CardtoCard: FC = () => {
|
|||||||
setFile(undefined)
|
setFile(undefined)
|
||||||
toast.success(t('wallet.successful_transfer'))
|
toast.success(t('wallet.successful_transfer'))
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
|
},
|
||||||
|
onError: (error: ErrorType) => {
|
||||||
|
toast.error(error.response?.data?.error.message[0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -25,6 +25,7 @@ import TicketList from '../pages/ticket/TicketList'
|
|||||||
import CreateTicket from '../pages/ticket/CreateTicket'
|
import CreateTicket from '../pages/ticket/CreateTicket'
|
||||||
import TicketDetail from '../pages/ticket/Detail'
|
import TicketDetail from '../pages/ticket/Detail'
|
||||||
import Financial from '../pages/financial/Financial'
|
import Financial from '../pages/financial/Financial'
|
||||||
|
import CallBack from '../pages/wallet/CallBack'
|
||||||
|
|
||||||
const MainRouter: FC = () => {
|
const MainRouter: FC = () => {
|
||||||
return (
|
return (
|
||||||
@@ -33,7 +34,7 @@ const MainRouter: FC = () => {
|
|||||||
<Header />
|
<Header />
|
||||||
<div className='flex-1 xl:ms-[269px] mt-[68px] xl:mt-[81px]'>
|
<div className='flex-1 xl:ms-[269px] mt-[68px] xl:mt-[81px]'>
|
||||||
<div className={`overflow-auto w-[${window.innerWidth}] max-h-[calc(100vh-113px)]`}>
|
<div className={`overflow-auto w-[${window.innerWidth}] max-h-[calc(100vh-113px)]`}>
|
||||||
<div>
|
<div className='pb-16'>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path={Pages.dashboard} element={<Home />} />
|
<Route path={Pages.dashboard} element={<Home />} />
|
||||||
<Route path={Pages.services.mine} element={<MyServices />} />
|
<Route path={Pages.services.mine} element={<MyServices />} />
|
||||||
@@ -51,6 +52,7 @@ const MainRouter: FC = () => {
|
|||||||
<Route path={Pages.learning} element={<LearningList />} />
|
<Route path={Pages.learning} element={<LearningList />} />
|
||||||
<Route path={Pages.setting} element={<Setting />} />
|
<Route path={Pages.setting} element={<Setting />} />
|
||||||
<Route path={Pages.wallet} element={<Wallet />} />
|
<Route path={Pages.wallet} element={<Wallet />} />
|
||||||
|
<Route path={Pages.callback + ':id'} element={<CallBack />} />
|
||||||
<Route path={Pages.profile} element={<Profile />} />
|
<Route path={Pages.profile} element={<Profile />} />
|
||||||
<Route path={Pages.financial} element={<Financial />} />
|
<Route path={Pages.financial} element={<Financial />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
|
|||||||
+22
-1
@@ -10,6 +10,8 @@ import { useSharedStore } from './store/sharedStore'
|
|||||||
import { useGetProfile } from '../pages/profile/hooks/useProfileData'
|
import { useGetProfile } from '../pages/profile/hooks/useProfileData'
|
||||||
import { Popover, PopoverButton, PopoverPanel } from '@headlessui/react'
|
import { Popover, PopoverButton, PopoverPanel } from '@headlessui/react'
|
||||||
import SideBarItem from './SideBarItem'
|
import SideBarItem from './SideBarItem'
|
||||||
|
import { useGetWalletBalance } from '../pages/wallet/hooks/useWalletData'
|
||||||
|
import { NumberFormat } from '../config/func'
|
||||||
|
|
||||||
const Header: FC = () => {
|
const Header: FC = () => {
|
||||||
|
|
||||||
@@ -18,6 +20,7 @@ const Header: FC = () => {
|
|||||||
const { t } = useTranslation('global')
|
const { t } = useTranslation('global')
|
||||||
const { setOpenSidebar, openSidebar } = useSharedStore()
|
const { setOpenSidebar, openSidebar } = useSharedStore()
|
||||||
const { data } = useGetProfile()
|
const { data } = useGetProfile()
|
||||||
|
const getWalletBalance = useGetWalletBalance()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setPopoverKey((prevKey) => prevKey + 1);
|
setPopoverKey((prevKey) => prevKey + 1);
|
||||||
@@ -40,9 +43,19 @@ const Header: FC = () => {
|
|||||||
<Link to={Pages.services.other}>
|
<Link to={Pages.services.other}>
|
||||||
<Element3 color='black' className='xl:size-[18px] size-[17px]' />
|
<Element3 color='black' className='xl:size-[18px] size-[17px]' />
|
||||||
</Link>
|
</Link>
|
||||||
<Link to={Pages.wallet}>
|
<Link className='xl:hidden' to={Pages.wallet}>
|
||||||
<Wallet className='xl:size-[18px] size-[17px]' color='black' />
|
<Wallet className='xl:size-[18px] size-[17px]' color='black' />
|
||||||
</Link>
|
</Link>
|
||||||
|
<Link className='hidden xl:block' to={Pages.wallet}>
|
||||||
|
<div className='flex items-center h-8 pl-2 rounded-full bg-[#EEF0F7]'>
|
||||||
|
<div className='px-3 text-xs'>
|
||||||
|
{NumberFormat(getWalletBalance.data?.data?.balance) + ' ' + t('toman')}
|
||||||
|
</div>
|
||||||
|
<div className='size-[26px] flex justify-center items-center bg-white rounded-xl'>
|
||||||
|
<Wallet className='xl:size-[18px] size-[17px]' color='black' />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
<Notifications />
|
<Notifications />
|
||||||
{
|
{
|
||||||
data && (
|
data && (
|
||||||
@@ -80,6 +93,7 @@ const Header: FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='pb-6 px-6 border-b border-[#EAEDF5]'>
|
<div className='pb-6 px-6 border-b border-[#EAEDF5]'>
|
||||||
|
<div className='flex justify-between items-center'>
|
||||||
<SideBarItem
|
<SideBarItem
|
||||||
icon={<Wallet size={20} color='black' />}
|
icon={<Wallet size={20} color='black' />}
|
||||||
title={t('header.wallet')}
|
title={t('header.wallet')}
|
||||||
@@ -87,6 +101,13 @@ const Header: FC = () => {
|
|||||||
isActive
|
isActive
|
||||||
isWithoutLine
|
isWithoutLine
|
||||||
/>
|
/>
|
||||||
|
<div className='flex items-center mt-4 h-8 pl-2 rounded-full bg-[#EEF0F7]'>
|
||||||
|
<div className='ps-3'>{t('home.balance')}</div>
|
||||||
|
<div className='px-3 text-xs'>
|
||||||
|
{NumberFormat(getWalletBalance.data?.data?.balance) + ' ' + t('toman')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<SideBarItem
|
<SideBarItem
|
||||||
icon={<Card color={'black'} size={20} />}
|
icon={<Card color={'black'} size={20} />}
|
||||||
|
|||||||
Reference in New Issue
Block a user