This commit is contained in:
hamid zarghami
2025-02-23 16:58:51 +03:30
parent bc3d068dfd
commit 158da6ce8a
16 changed files with 138 additions and 53 deletions
+1 -1
View File
@@ -33,7 +33,7 @@ const DefaulModal: FC<Props> = (props: Props) => {
{ {
props.isHeader && props.title_header && props.isHeader && props.title_header &&
<div className='pb-6 border-b border-white border-opacity-20'> <div onClick={props.close} className='pb-6 border-b border-white border-opacity-20'>
<div className='h-[5px] w-[200px] mx-auto bg-[#D1D3D7] rounded-full mb-4 xl:hidden'></div> <div className='h-[5px] w-[200px] mx-auto bg-[#D1D3D7] rounded-full mb-4 xl:hidden'></div>
<HeaderModal close={props.close} label={props.title_header} /> <HeaderModal close={props.close} label={props.title_header} />
</div> </div>
+8 -6
View File
@@ -78,9 +78,9 @@
"myservice": "سرویس های من", "myservice": "سرویس های من",
"active_service": "سرویس های فعال", "active_service": "سرویس های فعال",
"ticket": "تیکت ها", "ticket": "تیکت ها",
"unread_messages": "پیام خوانده نشده دارید ", "unread_messages": "پیام خوانده نشده ",
"announcement": "اطلاعیه ها", "announcement": "اطلاعیه ها",
"unread_announcement": "اطلاعیه خوانده نشده دارید", "unread_announcement": "اطلاعیه خوانده نشده",
"learnings": "آموزش ها", "learnings": "آموزش ها",
"learning": "آموزش", "learning": "آموزش",
"access": "دسترسی سریع", "access": "دسترسی سریع",
@@ -88,7 +88,7 @@
"danak_learning": "آموزش داناک", "danak_learning": "آموزش داناک",
"see_all": "دیدن همه", "see_all": "دیدن همه",
"create_new_access": "ایجاد دسترسی سریع", "create_new_access": "ایجاد دسترسی سریع",
"receip": "صورتحساب پرداخت نشده دارید", "receip": "صورتحساب پرداخت نشده ",
"balance": "موجودی", "balance": "موجودی",
"cannot_find_service": "سرویسی پیدا نشد", "cannot_find_service": "سرویسی پیدا نشد",
"not_active_service": "شما هنوز سرویس فعالی ندارید" "not_active_service": "شما هنوز سرویس فعالی ندارید"
@@ -176,7 +176,8 @@
"PENDING": "در انتظار", "PENDING": "در انتظار",
"ANSWERED": "پاسخ داده شده", "ANSWERED": "پاسخ داده شده",
"CLOSED": "بسته شده", "CLOSED": "بسته شده",
"service": "سرویس" "service": "سرویس",
"all": "همه"
}, },
"date": "تاریخ", "date": "تاریخ",
"receip": { "receip": {
@@ -336,14 +337,15 @@
"enter_sheba_deposit": "مبلغ شبا شده شده را وارد کنید", "enter_sheba_deposit": "مبلغ شبا شده شده را وارد کنید",
"all_cards": "تمام کارت های عضو شتاب", "all_cards": "تمام کارت های عضو شتاب",
"error_select_price": "لطفا مبلغ مورد نظر خود را انتخاب کنید", "error_select_price": "لطفا مبلغ مورد نظر خود را انتخاب کنید",
"error_min_price": "حداقل مبلغ ۱۰۰ هزار تومان می باشد", "error_min_price": "حداقل مبلغ ۵۰۰ هزار تومان می باشد",
"transfer_to_getway": "در حال انتقال به درگاه پرداخت", "transfer_to_getway": "در حال انتقال به درگاه پرداخت",
"select_bank_account": "انتخاب کارت", "select_bank_account": "انتخاب کارت",
"successful_transfer": "درخواست انتقال وجه با موفقیت انجام شد", "successful_transfer": "درخواست انتقال وجه با موفقیت انجام شد",
"balance": "اعتبار فعلی شما " "balance": "اعتبار فعلی شما "
}, },
"notif": { "notif": {
"natification": "اعلان ها" "natification": "اعلان ها",
"all_read": "پاک کردن همه"
}, },
"profile": { "profile": {
"account_user": "حساب کاربری", "account_user": "حساب کاربری",
+9
View File
@@ -82,6 +82,15 @@ const LoginStep2: FC = () => {
}) })
} }
useEffect(() => {
if (formik.values.code.length === 5) {
formik.handleSubmit()
}
}, [formik.values.code])
return ( return (
<div> <div>
<div className='mt-5'> <div className='mt-5'>
+18 -18
View File
@@ -194,24 +194,24 @@ const Legal: FC = () => {
<div>{t('financial.notice_cannot_edit_legal')}</div> <div>{t('financial.notice_cannot_edit_legal')}</div>
</div> </div>
{
!isReadOnly && <div className='mt-8 flex justify-end'>
<div className='mt-8 flex justify-end'> <Button
<Button disabled={isReadOnly}
className='w-fit px-7' className='w-fit px-7'
onClick={() => formik.handleSubmit()} onClick={() => formik.handleSubmit()}
isLoading={createLegalUser.isPending} isLoading={createLegalUser.isPending}
> >
<div className='flex gap-2 items-center'> <div className='flex gap-2 items-center'>
<TickCircle <TickCircle
size={24} size={24}
color='white' color='white'
/> />
<div>{t('save')}</div> <div>{t('save')}</div>
</div> </div>
</Button> </Button>
</div> </div>
}
</div> </div>
</div> </div>
@@ -113,12 +113,14 @@ const Personal: FC = () => {
]} ]}
{...formik.getFieldProps('gender')} {...formik.getFieldProps('gender')}
error_text={formik.touched.gender && formik.errors.gender ? formik.errors.gender : ''} error_text={formik.touched.gender && formik.errors.gender ? formik.errors.gender : ''}
readOnly={isReadOnly}
/> />
<Input <Input
label={t('financial.father_name')} label={t('financial.father_name')}
{...formik.getFieldProps('fatherName')} {...formik.getFieldProps('fatherName')}
error_text={formik.touched.fatherName && formik.errors.fatherName ? formik.errors.fatherName : ''} error_text={formik.touched.fatherName && formik.errors.fatherName ? formik.errors.fatherName : ''}
readOnly={isReadOnly}
/> />
</div> </div>
@@ -148,6 +150,7 @@ const Personal: FC = () => {
label={t('financial.nationality')} label={t('financial.nationality')}
{...formik.getFieldProps('nationality')} {...formik.getFieldProps('nationality')}
error_text={formik.touched.nationality && formik.errors.nationality ? formik.errors.nationality : ''} error_text={formik.touched.nationality && formik.errors.nationality ? formik.errors.nationality : ''}
readOnly={isReadOnly}
/> />
</div> </div>
@@ -204,6 +207,7 @@ const Personal: FC = () => {
label={t('financial.company_postal_code')} label={t('financial.company_postal_code')}
{...formik.getFieldProps('postalCode')} {...formik.getFieldProps('postalCode')}
error_text={formik.touched.postalCode && formik.errors.postalCode ? formik.errors.postalCode : ''} error_text={formik.touched.postalCode && formik.errors.postalCode ? formik.errors.postalCode : ''}
readOnly={isReadOnly}
/> />
</div> </div>
@@ -212,6 +216,7 @@ const Personal: FC = () => {
{...formik.getFieldProps('address')} {...formik.getFieldProps('address')}
error_text={formik.touched.address && formik.errors.address ? formik.errors.address : ''} error_text={formik.touched.address && formik.errors.address ? formik.errors.address : ''}
label={t('financial.address')} label={t('financial.address')}
readOnly={isReadOnly}
/> />
</div> </div>
@@ -228,6 +233,7 @@ const Personal: FC = () => {
className='w-fit px-7' className='w-fit px-7'
onClick={() => formik.handleSubmit()} onClick={() => formik.handleSubmit()}
isLoading={createRealUser.isPending} isLoading={createRealUser.isPending}
disabled={isReadOnly}
> >
<div className='flex gap-2 items-center'> <div className='flex gap-2 items-center'>
<TickCircle <TickCircle
+5
View File
@@ -9,6 +9,7 @@ import DanakLearning from './components/DanakLearning'
import { Carousel } from "@material-tailwind/react"; import { Carousel } from "@material-tailwind/react";
import { useGetAds } from '../ads/hooks/useAdsData' import { useGetAds } from '../ads/hooks/useAdsData'
import { AdsDisplayLocation, AdsItemType } from '../ads/types/AdsTypes' import { AdsDisplayLocation, AdsItemType } from '../ads/types/AdsTypes'
import { Pages } from '../../config/Pages'
const Home: FC = () => { const Home: FC = () => {
@@ -63,6 +64,7 @@ const Home: FC = () => {
color='#00D16C' color='#00D16C'
count={4} count={4}
description={t('home.active_service')} description={t('home.active_service')}
link={Pages.services.mine}
/> />
<ItemDashboard <ItemDashboard
@@ -71,6 +73,7 @@ const Home: FC = () => {
color='#FF7B00' color='#FF7B00'
count={4} count={4}
description={t('home.unread_messages')} description={t('home.unread_messages')}
link={Pages.ticket.list}
/> />
<ItemDashboard <ItemDashboard
@@ -79,6 +82,7 @@ const Home: FC = () => {
color='#0047FF' color='#0047FF'
count={4} count={4}
description={t('home.receip')} description={t('home.receip')}
link={Pages.receipts.index}
/> />
<ItemDashboard <ItemDashboard
@@ -87,6 +91,7 @@ const Home: FC = () => {
color='#FF0000' color='#FF0000'
count={4} count={4}
description={t('home.unread_announcement')} description={t('home.unread_announcement')}
link={Pages.announcement.list}
/> />
</div> </div>
+5 -3
View File
@@ -1,17 +1,19 @@
import { FC, ReactNode } from 'react' import { FC, ReactNode } from 'react'
import { Link } from 'react-router-dom'
type Props = { type Props = {
title: string title: string
icon: ReactNode, icon: ReactNode,
color: string, color: string,
count: number, count: number,
description: string description: string,
link: string
} }
const ItemDashboard: FC<Props> = (props: Props) => { const ItemDashboard: FC<Props> = (props: Props) => {
return ( return (
<div className='p-6 min-w-[40%] xl:min-w-[20%] flex flex-col items-center xl:items-start flex-1 h-[178px] bg-white rounded-3xl'> <Link to={props.link} className='p-6 min-w-[40%] xl:min-w-[20%] flex flex-col items-center xl:items-start flex-1 h-[178px] bg-white rounded-3xl'>
<div className='size-10 rounded-full bg-[#EEF0F7] flex justify-center items-center'> <div className='size-10 rounded-full bg-[#EEF0F7] flex justify-center items-center'>
{props.icon} {props.icon}
</div> </div>
@@ -28,7 +30,7 @@ const ItemDashboard: FC<Props> = (props: Props) => {
</div> </div>
</div> </div>
</div> </div>
</div> </Link>
) )
} }
+27 -7
View File
@@ -5,25 +5,31 @@ import { useTranslation } from 'react-i18next';
import { clx } from '../../helpers/utils'; import { clx } from '../../helpers/utils';
import StatusCircle from '../../components/StatusCircle'; import StatusCircle from '../../components/StatusCircle';
import { useOutsideClick } from '../../hooks/useOutSideClick'; import { useOutsideClick } from '../../hooks/useOutSideClick';
import { useGetNotification } from './hooks/useNotificationData'; import { useGetNotification, useReadAll } from './hooks/useNotificationData';
import { NotificationItemType } from './types/NotificationTypes'; import { NotificationItemType } from './types/NotificationTypes';
import { timeAgo } from '../../config/func'; import { timeAgo } from '../../config/func';
import InfiniteScroll from 'react-infinite-scroll-component'; import InfiniteScroll from 'react-infinite-scroll-component';
import MoonLoader from "react-spinners/MoonLoader" import MoonLoader from "react-spinners/MoonLoader"
import Button from '../../components/Button';
import { toast } from 'react-toastify';
const Notifications: FC = () => { const Notifications: FC = () => {
const { t } = useTranslation('global'); const { t } = useTranslation('global');
const ref = useOutsideClick(() => setShowModal(false)); const ref = useOutsideClick(() => setShowModal(false));
const [activeTab, setActiveTab] = useState<'all' | 'read' | 'unread'>('all'); const [activeTab, setActiveTab] = useState<'all' | 'read' | 'unread'>('all');
const [showModal, setShowModal] = useState<boolean>(false); const [showModal, setShowModal] = useState<boolean>(false);
const { data, fetchNextPage, hasNextPage, isFetching, isLoading } = useGetNotification(); const { data, fetchNextPage, hasNextPage, refetch } = useGetNotification();
const readAll = useReadAll()
const posts = data?.pages.flatMap((page) => page.data?.notifications) || []; const posts = data?.pages.flatMap((page) => page.data?.notifications) || [];
console.log('posts:', posts); const handleAllRead = () => {
console.log('hasNextPage:', hasNextPage); readAll.mutate(undefined, {
console.log('isFetching:', isFetching); onSuccess: () => {
console.log('isLoading:', isLoading); refetch()
toast.success(t('success'))
}
})
}
return ( return (
<div ref={ref}> <div ref={ref}>
@@ -38,6 +44,8 @@ const Notifications: FC = () => {
</div> </div>
</div> </div>
<div className="mt-6 flex h-8 border border-white border-opacity-35 text-xs rounded-lg overflow-hidden"> <div className="mt-6 flex h-8 border border-white border-opacity-35 text-xs rounded-lg overflow-hidden">
<div <div
onClick={() => setActiveTab('all')} onClick={() => setActiveTab('all')}
@@ -68,6 +76,18 @@ const Notifications: FC = () => {
</div> </div>
</div> </div>
<div className='flex mt-4 justify-end'>
<Button
isLoading={readAll.isPending}
onClick={handleAllRead}
className={clx(
'flex-1 border bg-transparent text-xs h-7 rounded-md cursor-pointer text-white border-white border-opacity-70 flex justify-center items-center',
)}
>
{t('notif.all_read')}
</Button>
</div>
<div className="mt-6 flex flex-col gap-4 text-xs overflow-auto"> <div className="mt-6 flex flex-col gap-4 text-xs overflow-auto">
<InfiniteScroll <InfiniteScroll
dataLength={posts.length} dataLength={posts.length}
@@ -1,5 +1,5 @@
import * as api from "../service/NotificationService"; import * as api from "../service/NotificationService";
import { useInfiniteQuery } from "@tanstack/react-query"; import { useInfiniteQuery, useMutation } from "@tanstack/react-query";
export const useGetNotification = () => { export const useGetNotification = () => {
return useInfiniteQuery({ return useInfiniteQuery({
@@ -15,3 +15,9 @@ export const useGetNotification = () => {
}, },
}); });
}; };
export const useReadAll = () => {
return useMutation({
mutationFn: (_) => api.readAll(),
});
};
@@ -4,3 +4,8 @@ export const getNotifications = async (page: number) => {
const { data } = await axios.get(`/notifications?page=${page}`); const { data } = await axios.get(`/notifications?page=${page}`);
return data; return data;
}; };
export const readAll = async () => {
const { data } = await axios.patch(`/notifications/read-all`);
return data;
};
+7 -7
View File
@@ -1,7 +1,7 @@
import { FC, useState } from 'react' import { FC, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import Button from '../../components/Button' import Button from '../../components/Button'
import { Add, Eye, MessageRemove, MessageTick, MessageTime } from 'iconsax-react' import { Add, Eye, MessageRemove, Messages1, MessageTick, MessageTime } from 'iconsax-react'
import Tabs from '../../components/Tabs' import Tabs from '../../components/Tabs'
import Td from '../../components/Td' import Td from '../../components/Td'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
@@ -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'>('PENDING') const [activeTab, setActiveTab] = useState<'ANSWERED' | 'PENDING' | 'CLOSED' | ''>('')
const getTickets = useGetTickets(activeTab) const getTickets = useGetTickets(activeTab)
return ( return (
@@ -40,6 +40,11 @@ const TicketList: FC = () => {
<Tabs <Tabs
active={activeTab} active={activeTab}
items={[ items={[
{
icon: <Messages1 color={activeTab === '' ? 'black' : '#8C90A3'} size={22} />,
label: t('ticket.all'),
value: ''
},
{ {
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'),
@@ -50,11 +55,6 @@ const TicketList: FC = () => {
label: t('ticket.answered'), label: t('ticket.answered'),
value: 'ANSWERED' value: 'ANSWERED'
}, },
// {
// icon: <Message2 color={activeTab === 'wating' ? 'black' : '#8C90A3'} size={22} />,
// label: t('ticket.wait_answered'),
// value: 'wating'
// },
{ {
icon: <MessageRemove color={activeTab === 'CLOSED' ? 'black' : '#8C90A3'} size={22} />, icon: <MessageRemove color={activeTab === 'CLOSED' ? 'black' : '#8C90A3'} size={22} />,
label: t('ticket.closed'), label: t('ticket.closed'),
+5 -1
View File
@@ -2,7 +2,11 @@ import axios from "../../../config/axios";
import { AddMessageTicketType, CreateTicketType } from "../types/TicketTypes"; import { AddMessageTicketType, CreateTicketType } from "../types/TicketTypes";
export const getTickets = async (status: string) => { export const getTickets = async (status: string) => {
const { data } = await axios.get(`/tickets?status=${status}`); let query = ``;
if (status) {
query = `?status=${status}`;
}
const { data } = await axios.get(`/tickets${query}`);
return data; return data;
}; };
+10 -2
View File
@@ -12,6 +12,7 @@ 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' import { ErrorType } from '../../../helpers/types'
import { TickCircle } from 'iconsax-react'
const CardtoCard: FC = () => { const CardtoCard: FC = () => {
@@ -98,11 +99,18 @@ const CardtoCard: FC = () => {
<div className='mt-10 flex justify-end'> <div className='mt-10 flex justify-end'>
<Button <Button
label={t('wallet.submit_slip')}
className='w-[180px]' className='w-[180px]'
onClick={() => formik.handleSubmit()} onClick={() => formik.handleSubmit()}
isLoading={depositTransfer.isPending || upload.isPending} isLoading={depositTransfer.isPending || upload.isPending}
/> >
<div className='flex gap-2 items-center'>
<TickCircle
size={24}
color='white'
/>
<div>{t('wallet.submit_slip')}</div>
</div>
</Button>
</div> </div>
</Fragment> </Fragment>
+14 -4
View File
@@ -7,8 +7,9 @@ import { useGetGetWays, usePayment } from '../hooks/useWalletData'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
import { ErrorType } from '../../../helpers/types' import { ErrorType } from '../../../helpers/types'
import { GatewayItemType } from '../types/WalletTypes' import { GatewayItemType } from '../types/WalletTypes'
import { TickCircle } from 'iconsax-react'
const defaultAmounts = [100000, 200000, 500000, 1000000, 2000000, 5000000, 10000000] const defaultAmounts = [500000, 1000000, 3000000, 5000000, 8000000, 10000000];
const Online: FC = () => { const Online: FC = () => {
@@ -24,7 +25,7 @@ const Online: FC = () => {
toast.error(t('wallet.error_select_price')) toast.error(t('wallet.error_select_price'))
} else { } else {
const amout = desiredAmount === 0 ? amountSelected : desiredAmount const amout = desiredAmount === 0 ? amountSelected : desiredAmount
if (amout < 100000) { if (amout < 500000) {
toast.error(t('wallet.error_min_price')) toast.error(t('wallet.error_min_price'))
return return
} else { } else {
@@ -103,11 +104,20 @@ const Online: FC = () => {
<div className='mt-10 flex justify-end'> <div className='mt-10 flex justify-end'>
<Button <Button
label={t('wallet.pay')}
className='w-[180px]' className='w-[180px]'
onClick={handlePay} onClick={handlePay}
isLoading={payment.isPending} isLoading={payment.isPending}
/> >
<div className='flex gap-2 items-center'>
<TickCircle
size={24}
color='white'
/>
<div>{t('wallet.pay')}</div>
</div>
</Button>
</div> </div>
</div> </div>
</div> </div>
+10 -2
View File
@@ -12,6 +12,7 @@ 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' import { ErrorType } from '../../../helpers/types'
import { TickCircle } from 'iconsax-react'
const CardtoCard: FC = () => { const CardtoCard: FC = () => {
@@ -99,11 +100,18 @@ const CardtoCard: FC = () => {
<div className='mt-10 flex justify-end'> <div className='mt-10 flex justify-end'>
<Button <Button
label={t('wallet.submit_slip')}
className='w-[180px]' className='w-[180px]'
onClick={() => formik.handleSubmit()} onClick={() => formik.handleSubmit()}
isLoading={depositTransfer.isPending || upload.isPending} isLoading={depositTransfer.isPending || upload.isPending}
/> >
<div className='flex gap-2 items-center'>
<TickCircle
size={24}
color='white'
/>
<div>{t('wallet.submit_slip')}</div>
</div>
</Button>
</div> </div>
</Fragment> </Fragment>
+1 -1
View File
@@ -101,7 +101,7 @@ const Header: FC = () => {
isActive isActive
isWithoutLine isWithoutLine
/> />
<div className='flex items-center mt-4 h-8 pl-2 rounded-full bg-[#EEF0F7]'> <div className='flex xl:hidden items-center mt-4 h-8 pl-2 rounded-full bg-[#EEF0F7]'>
<div className='ps-3'>{t('home.balance')}</div> <div className='ps-3'>{t('home.balance')}</div>
<div className='px-3 text-xs'> <div className='px-3 text-xs'>
{NumberFormat(getWalletBalance.data?.data?.balance) + ' ' + t('toman')} {NumberFormat(getWalletBalance.data?.data?.balance) + ' ' + t('toman')}