request list + structure
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
import { type FC } from 'react'
|
||||
import Stats from './components/Stats'
|
||||
import Services from './components/Services'
|
||||
import Orders from './components/Orders'
|
||||
import NewOrderImage from '@/assets/images/new_order.png'
|
||||
import { t } from '@/locale'
|
||||
import Button from '@/components/Button'
|
||||
import { AddSquare, MessageQuestion } from 'iconsax-react'
|
||||
import { COLORS } from '@/constants/colors'
|
||||
import SupportImage from '@/assets/images/support1.png'
|
||||
|
||||
const Home: FC = () => {
|
||||
return (
|
||||
<div className='flex gap-6'>
|
||||
<div className='flex-1'>
|
||||
<Stats />
|
||||
<Services />
|
||||
<Orders />
|
||||
</div>
|
||||
<div className='min-w-[267px] mt-5'>
|
||||
<div className='bg-white rounded-3xl p-6'>
|
||||
<img src={NewOrderImage} className='w-[98px] mx-auto' />
|
||||
<h4 className='mt-4 text-center font-medium'>
|
||||
{t('home.submitNewOrder')}
|
||||
</h4>
|
||||
<Button
|
||||
className='mt-2.5'>
|
||||
<div className='flex gap-1'>
|
||||
<AddSquare size={20} color='#292D32' />
|
||||
<div className=''>{t('home.submitNewOrderButton')}</div>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className='mt-7 bg-white rounded-3xl p-6 relative'>
|
||||
<h4>
|
||||
{t('home.specialSolution')}
|
||||
</h4>
|
||||
<p className='mt-2 text-[#7B7E8B] text-xs'>
|
||||
{t('home.specialSolutionDescription')}
|
||||
</p>
|
||||
|
||||
<div className='mt-2 flex flex-col gap-2'>
|
||||
<div className='flex gap-2 items-center text-xs'>
|
||||
<div className='size-1.5 rounded-full bg-primary'></div>
|
||||
<div>{t('home.specialSolutionFeature1')}</div>
|
||||
</div>
|
||||
<div className='flex gap-2 items-center text-xs'>
|
||||
<div className='size-1.5 rounded-full bg-primary'></div>
|
||||
<div>{t('home.specialSolutionFeature2')}</div>
|
||||
</div>
|
||||
<div className='flex gap-2 items-center text-xs'>
|
||||
<div className='size-1.5 rounded-full bg-primary'></div>
|
||||
<div>{t('home.specialSolutionFeature3')}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
label={t('home.freeConsultation')}
|
||||
className='mt-12'
|
||||
/>
|
||||
|
||||
<div className='mt-2.5 bg-primary/11 py-6 px-4 rounded-[13px]'>
|
||||
<div className='flex justify-between items-center'>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<MessageQuestion size={20} color={COLORS.primary} />
|
||||
<div className='text-xs font-light'>{t('home.contactUs')}</div>
|
||||
</div>
|
||||
<div>{t('home.phoneNumber')}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<img src={SupportImage} className='w-[50px] absolute bottom-[159px] left-2' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Home
|
||||
@@ -0,0 +1,106 @@
|
||||
import { type FC } from 'react';
|
||||
import { Eye } from 'iconsax-react';
|
||||
import StatusCircle from '@/components/StatusCircle';
|
||||
import { type Order, type OrderStatus } from './types/OrderTypes';
|
||||
|
||||
// کامپوننت رندر شماره سفارش
|
||||
export const OrderNumberRenderer: FC<{ order: Order }> = ({ order }) => {
|
||||
return (
|
||||
<span className="text-sm font-medium text-gray-900">
|
||||
{order.number}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
// کامپوننت رندر عنوان سفارش
|
||||
export const OrderTitleRenderer: FC<{ order: Order }> = ({ order }) => {
|
||||
return (
|
||||
<span className="text-sm font-medium text-gray-900">
|
||||
{order.title}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
// کامپوننت رندر تاریخ
|
||||
export const OrderDateRenderer: FC<{ order: Order }> = ({ order }) => {
|
||||
return (
|
||||
<div className="text-xs text-gray-500">
|
||||
<div className="font-medium">
|
||||
({order.creationDate.gregorian})
|
||||
</div>
|
||||
<div>
|
||||
{order.creationDate.persian}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// کامپوننت رندر وضعیت سفارش
|
||||
export const OrderStatusRenderer: FC<{ order: Order }> = ({ order }) => {
|
||||
const getStatusConfig = (status: OrderStatus) => {
|
||||
switch (status) {
|
||||
case 'در حال طراحی':
|
||||
return {
|
||||
color: 'text-blue-600',
|
||||
bgColor: 'bg-blue-50'
|
||||
};
|
||||
case 'تهیه متریال':
|
||||
return {
|
||||
color: 'text-gray-600',
|
||||
bgColor: 'bg-gray-50'
|
||||
};
|
||||
case 'در حال چاپ':
|
||||
return {
|
||||
color: 'text-orange-600',
|
||||
bgColor: 'bg-orange-50'
|
||||
};
|
||||
case 'تکمیل شده':
|
||||
return {
|
||||
color: 'text-green-600',
|
||||
bgColor: 'bg-green-50'
|
||||
};
|
||||
default:
|
||||
return {
|
||||
color: 'text-gray-600',
|
||||
bgColor: 'bg-gray-50'
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const config = getStatusConfig(order.status);
|
||||
|
||||
return (
|
||||
<span className={`text-sm font-medium ${config.color}`}>
|
||||
{order.status}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
// کامپوننت رندر پیامها
|
||||
export const OrderMessagesRenderer: FC<{ order: Order }> = ({ order }) => {
|
||||
const hasUnreadMessages = order.unreadMessages > 0;
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<StatusCircle color={hasUnreadMessages ? '#EF4444' : '#3B82F6'} />
|
||||
<span className="text-xs text-gray-500">
|
||||
{order.unreadMessages} پیام خوانده نشده
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// کامپوننت رندر آیکون مشاهده
|
||||
export const OrderViewRenderer: FC<{ order: Order }> = ({ order }) => {
|
||||
return (
|
||||
<button
|
||||
className="p-1 hover:bg-gray-100 rounded-full transition-colors"
|
||||
onClick={() => {
|
||||
// اینجا میتوانید منطق مشاهده جزئیات را اضافه کنید
|
||||
console.log('View order:', order.id);
|
||||
}}
|
||||
>
|
||||
<Eye color='black' size={16} />
|
||||
</button>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
import Table from '@/components/Table'
|
||||
import { type FC } from 'react'
|
||||
import { type ColumnType } from '@/components/types/TableTypes'
|
||||
import { type Order } from './types/OrderTypes'
|
||||
import { ordersData } from './data/ordersData'
|
||||
import {
|
||||
OrderNumberRenderer,
|
||||
OrderTitleRenderer,
|
||||
OrderDateRenderer,
|
||||
OrderStatusRenderer,
|
||||
OrderMessagesRenderer,
|
||||
OrderViewRenderer
|
||||
} from './OrderTableComponents'
|
||||
|
||||
const Orders: FC = () => {
|
||||
const columns: ColumnType<Order>[] = [
|
||||
{
|
||||
title: 'شماره',
|
||||
key: 'number',
|
||||
render: (order) => <OrderNumberRenderer order={order} />
|
||||
},
|
||||
{
|
||||
title: 'عنوان سفارش',
|
||||
key: 'title',
|
||||
render: (order) => <OrderTitleRenderer order={order} />
|
||||
},
|
||||
{
|
||||
title: 'تاریخ ایجاد',
|
||||
key: 'creationDate',
|
||||
render: (order) => <OrderDateRenderer order={order} />
|
||||
},
|
||||
{
|
||||
title: 'وضعیت سفارش',
|
||||
key: 'status',
|
||||
render: (order) => <OrderStatusRenderer order={order} />
|
||||
},
|
||||
{
|
||||
title: 'پیام ها',
|
||||
key: 'unreadMessages',
|
||||
render: (order) => <OrderMessagesRenderer order={order} />
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
key: 'actions',
|
||||
render: (order) => <OrderViewRenderer order={order} />,
|
||||
width: '60px'
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<div className='mt-6 bg-white p-6 rounded-3xl'>
|
||||
<h4 className='text-lg font-light'>
|
||||
سفارش های در حال انجام
|
||||
</h4>
|
||||
|
||||
<Table<Order>
|
||||
columns={columns}
|
||||
data={ordersData}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Orders
|
||||
@@ -0,0 +1,13 @@
|
||||
import { type FC } from 'react'
|
||||
|
||||
const ServiceItem: FC = () => {
|
||||
return (
|
||||
<div>
|
||||
<div className='size-20 rounded-full bg-gray-200 border-[3px] border-primary'>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ServiceItem
|
||||
@@ -0,0 +1,44 @@
|
||||
import { t } from '@/locale'
|
||||
import { type FC } from 'react'
|
||||
import { Swiper, SwiperSlide } from 'swiper/react'
|
||||
import ServiceItem from './ServiceItem'
|
||||
|
||||
|
||||
const Services: FC = () => {
|
||||
return (
|
||||
<div className='mt-6 bg-white p-6 rounded-3xl'>
|
||||
<h4 className='text-lg font-light'>
|
||||
{t('home.services')}
|
||||
</h4>
|
||||
|
||||
<div className='mt-6'>
|
||||
<Swiper
|
||||
spaceBetween={16}
|
||||
slidesPerView={'auto'}
|
||||
className='h-full'
|
||||
breakpoints={{
|
||||
640: {
|
||||
spaceBetween: 24,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<SwiperSlide className='!w-auto'>
|
||||
<ServiceItem />
|
||||
</SwiperSlide>
|
||||
<SwiperSlide className='!w-auto'>
|
||||
<ServiceItem />
|
||||
</SwiperSlide>
|
||||
<SwiperSlide className='!w-auto'>
|
||||
<ServiceItem />
|
||||
</SwiperSlide>
|
||||
<SwiperSlide className='!w-auto'>
|
||||
<ServiceItem />
|
||||
</SwiperSlide>
|
||||
</Swiper>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Services
|
||||
@@ -0,0 +1,34 @@
|
||||
import { COLORS } from '@/constants/colors'
|
||||
import { ArrowLeft } from 'iconsax-react'
|
||||
import { type FC, type ReactNode } from 'react'
|
||||
|
||||
type Props = {
|
||||
icon: ReactNode,
|
||||
count: number,
|
||||
description: string
|
||||
}
|
||||
|
||||
const StatCard: FC<Props> = (props) => {
|
||||
const { icon, count, description } = props
|
||||
return (
|
||||
<div className='flex-1 bg-white rounded-3xl p-6'>
|
||||
<div className='flex justify-between items-center'>
|
||||
{icon}
|
||||
|
||||
<div className='size-8 bg-[#FFF1D7] rounded-full flex justify-center items-center'>
|
||||
<ArrowLeft size={16} color={COLORS.primary} className='rotate-45' />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='mt-2 text-2xl font-semibold'>
|
||||
{count}
|
||||
</div>
|
||||
|
||||
<div className='mt-2 text-sm'>
|
||||
{description}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default StatCard
|
||||
@@ -0,0 +1,53 @@
|
||||
import GridWrapper from '@/components/GridWrapper'
|
||||
import { COLORS } from '@/constants/colors'
|
||||
import { t } from '@/locale'
|
||||
import { BoxTick, BoxTime, ReceiptText, TruckTick } from 'iconsax-react'
|
||||
import { type FC } from 'react'
|
||||
import StatCard from './StatCard'
|
||||
|
||||
const Stats: FC = () => {
|
||||
return (
|
||||
<GridWrapper
|
||||
desktop={4}
|
||||
mobile={2}
|
||||
gapDesktop={24}
|
||||
gapMobile={12}
|
||||
className='mt-5'
|
||||
>
|
||||
<StatCard
|
||||
count={2}
|
||||
description={t('home.requestCount')}
|
||||
icon={<BoxTime
|
||||
size={27}
|
||||
color={COLORS.primary}
|
||||
/>}
|
||||
/>
|
||||
<StatCard
|
||||
count={2}
|
||||
description={t('home.factureCount')}
|
||||
icon={<ReceiptText
|
||||
size={27}
|
||||
color={COLORS.primary}
|
||||
/>}
|
||||
/>
|
||||
<StatCard
|
||||
count={10}
|
||||
description={t('home.orderCount')}
|
||||
icon={<BoxTick
|
||||
size={27}
|
||||
color={COLORS.primary}
|
||||
/>}
|
||||
/>
|
||||
<StatCard
|
||||
count={20}
|
||||
description={t('home.orderDoneCount')}
|
||||
icon={<TruckTick
|
||||
size={27}
|
||||
color={COLORS.primary}
|
||||
/>}
|
||||
/>
|
||||
</GridWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
export default Stats
|
||||
@@ -0,0 +1,37 @@
|
||||
import { type Order } from '../types/OrderTypes';
|
||||
|
||||
export const ordersData: Order[] = [
|
||||
{
|
||||
id: 1,
|
||||
number: '123455',
|
||||
title: 'کارت ویزیت',
|
||||
creationDate: {
|
||||
gregorian: '2024-11-01',
|
||||
persian: '1403/09/01'
|
||||
},
|
||||
status: 'در حال طراحی',
|
||||
unreadMessages: 2
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
number: '123455',
|
||||
title: 'شاپینگ بگ',
|
||||
creationDate: {
|
||||
gregorian: '2024-11-01',
|
||||
persian: '1403/09/01'
|
||||
},
|
||||
status: 'تهیه متریال',
|
||||
unreadMessages: 0
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
number: '123455',
|
||||
title: 'کارت ویزیت',
|
||||
creationDate: {
|
||||
gregorian: '2024-11-01',
|
||||
persian: '1403/09/01'
|
||||
},
|
||||
status: 'در حال چاپ',
|
||||
unreadMessages: 2
|
||||
}
|
||||
];
|
||||
@@ -0,0 +1,22 @@
|
||||
import { type RowDataType } from '@/components/types/TableTypes';
|
||||
|
||||
export interface Order extends RowDataType {
|
||||
id: string | number;
|
||||
number: string;
|
||||
title: string;
|
||||
creationDate: {
|
||||
gregorian: string;
|
||||
persian: string;
|
||||
};
|
||||
status: OrderStatus;
|
||||
unreadMessages: number;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export type OrderStatus = 'در حال طراحی' | 'تهیه متریال' | 'در حال چاپ' | 'تکمیل شده';
|
||||
|
||||
export interface OrderStatusConfig {
|
||||
status: OrderStatus;
|
||||
color: string;
|
||||
textColor: string;
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
import Tabs from '@/components/Tabs'
|
||||
import { useState, type FC } from 'react'
|
||||
import { ProformaInvoiceStatusEnum } from './enum/InvoiceEnum'
|
||||
import Filters from '@/components/Filters'
|
||||
import Table from '@/components/Table'
|
||||
|
||||
const ProformaInvoice: FC = () => {
|
||||
|
||||
const [activeTab, setactiveTab] = useState<ProformaInvoiceStatusEnum>(ProformaInvoiceStatusEnum.ALL)
|
||||
|
||||
return (
|
||||
<div className='mt-5'>
|
||||
<h1>
|
||||
پیش فاکتورها
|
||||
</h1>
|
||||
<div className='mt-8'>
|
||||
<Tabs
|
||||
items={[
|
||||
{ label: 'همه', value: 'all' },
|
||||
{ label: 'تایید نشده', value: 'not_confirmed' },
|
||||
{ label: 'تایید شده', value: 'confirmed' },
|
||||
]}
|
||||
activeTab={activeTab}
|
||||
onTabChange={(tab) => setactiveTab(tab as ProformaInvoiceStatusEnum)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-8'>
|
||||
<Filters
|
||||
fields={[
|
||||
{
|
||||
type: 'input',
|
||||
name: 'search',
|
||||
placeholder: 'جستجو',
|
||||
},
|
||||
{
|
||||
type: 'date',
|
||||
name: 'date',
|
||||
placeholder: 'تاریخ',
|
||||
},
|
||||
]}
|
||||
onChange={() => { }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-8'>
|
||||
<Table
|
||||
columns={[
|
||||
{
|
||||
key: 'id',
|
||||
title: 'شماره',
|
||||
},
|
||||
{
|
||||
key: 'service',
|
||||
title: 'خدمت',
|
||||
},
|
||||
{
|
||||
key: 'issueDate',
|
||||
title: 'تاریخ صدور',
|
||||
},
|
||||
{
|
||||
key: 'lastConfirmDate',
|
||||
title: 'آخرین مهلت تایید',
|
||||
},
|
||||
{
|
||||
key: 'total',
|
||||
title: 'مجموع',
|
||||
},
|
||||
{
|
||||
key: 'confirmStatus',
|
||||
title: 'وضعیت تایید',
|
||||
},
|
||||
{
|
||||
key: 'paymentStatus',
|
||||
title: 'وضعیت پرداخت',
|
||||
}
|
||||
]}
|
||||
data={[
|
||||
{
|
||||
id: 1,
|
||||
service: 'خدمت 1',
|
||||
issueDate: '2021-01-01',
|
||||
lastConfirmDate: '2021-01-01',
|
||||
total: 100000,
|
||||
confirmStatus: 'تایید شده',
|
||||
paymentStatus: 'پرداخت شده',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
service: 'خدمت 2',
|
||||
issueDate: '2021-01-01',
|
||||
lastConfirmDate: '2021-01-01',
|
||||
total: 100000,
|
||||
confirmStatus: 'تایید شده',
|
||||
paymentStatus: 'پرداخت شده',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ProformaInvoice
|
||||
@@ -0,0 +1,5 @@
|
||||
export const enum ProformaInvoiceStatusEnum {
|
||||
ALL = 'all',
|
||||
NOT_CONFIRMED = 'not_confirmed',
|
||||
CONFIRMED = 'confirmed',
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
import { Notification } from 'iconsax-react';
|
||||
import { type FC, useState } from 'react';
|
||||
import XIcon from '../../assets/images/close-circle.svg';
|
||||
import { clx } from '../../helpers/utils';
|
||||
import StatusCircle from '@/components/StatusCircle';
|
||||
import { useOutsideClick } from '@/hooks/useOutSideClick';
|
||||
import { type NotificationItemType, NotificationTypeEnum } from './types/NotificationTypes';
|
||||
import Button from '@/components/Button';
|
||||
import { t } from '@/locale';
|
||||
|
||||
const Notifications: FC = () => {
|
||||
const ref = useOutsideClick(() => setShowModal(false));
|
||||
const [activeTab, setActiveTab] = useState<'read' | 'unread'>('unread');
|
||||
const [showModal, setShowModal] = useState<boolean>(false);
|
||||
const posts: NotificationItemType[] = [];
|
||||
// const getDashboard = useGetNotification('all')
|
||||
|
||||
const handleAllRead = () => {
|
||||
// TODO: Implement read all functionality
|
||||
}
|
||||
|
||||
const handleRedirect = (type: NotificationTypeEnum) => {
|
||||
switch (type) {
|
||||
case NotificationTypeEnum.USER_LOGIN:
|
||||
break;
|
||||
case NotificationTypeEnum.ANNOUNCEMENT:
|
||||
// navigate(Pages.announcement.list)
|
||||
break;
|
||||
case NotificationTypeEnum.WALLET_CHARGE:
|
||||
// navigate(Pages.transactions)
|
||||
break;
|
||||
case NotificationTypeEnum.WALLET_DEDUCTION:
|
||||
// navigate(Pages.transactions)
|
||||
break;
|
||||
case NotificationTypeEnum.BILL_INVOICE_REMINDER:
|
||||
// navigate(Pages.receipts.index)
|
||||
break;
|
||||
case NotificationTypeEnum.BILL_INVOICE:
|
||||
// navigate(Pages.receipts.index)
|
||||
break;
|
||||
case NotificationTypeEnum.CREATE_INVOICE:
|
||||
// navigate(Pages.receipts.index)
|
||||
break;
|
||||
case NotificationTypeEnum.CREATE_SERVICE:
|
||||
// navigate(Pages.services.other)
|
||||
break;
|
||||
case NotificationTypeEnum.UNBLOCK_SERVICE:
|
||||
// navigate(Pages.services.other)
|
||||
break;
|
||||
case NotificationTypeEnum.BLOCK_SERVICE:
|
||||
// navigate(Pages.services.other)
|
||||
break;
|
||||
case NotificationTypeEnum.ANSWER_TICKET:
|
||||
// navigate(Pages.ticket.list)
|
||||
break;
|
||||
case NotificationTypeEnum.CREATE_TICKET:
|
||||
// navigate(Pages.ticket.list)
|
||||
break;
|
||||
default:
|
||||
break
|
||||
}
|
||||
setShowModal(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref={ref}>
|
||||
<div onClick={() => setShowModal(!showModal)} className='relative cursor-pointer'>
|
||||
<Notification size={18} color="black" />
|
||||
<div className="absolute top-0 right-0 -mt-1 -mr-1 rounded-full bg-red-500 text-white text-[8px] size-3 flex pt-0.5 pl-[1px] justify-center items-center">
|
||||
{/* {getDashboard.data?.pages?.[0]?.data?.notificationCount || 0} */}
|
||||
2
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{showModal && (
|
||||
<div id='notificationsContainer' className="xl:h-[calc(100%-110px)] h-[70%] p-6 z-50 xl:w-[300px] w-full xl:left-7 left-0 xl:top-[90px] top-0 overflow-y-auto xl:rounded-3xl rounded-b-3xl rounded-t-none fixed modalGlass3 ">
|
||||
<div className="flex justify-between items-center">
|
||||
<div>{t('notif.natification')}</div>
|
||||
<div className="size-7 rounded-full bg-white bg-opacity-35 flex justify-center items-center">
|
||||
<img src={XIcon} alt="close" className="w-4 h-4" onClick={() => setShowModal(false)} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div className="mt-6 flex h-8 border border-white border-opacity-35 text-xs rounded-lg overflow-hidden">
|
||||
<div
|
||||
onClick={() => setActiveTab('unread')}
|
||||
className={clx(
|
||||
'flex-1 border-l cursor-pointer text-white border-white border-opacity-70 bg-transparent flex justify-center items-center',
|
||||
activeTab === 'unread' ? 'bg-white bg-opacity-70 text-black' : ''
|
||||
)}
|
||||
>
|
||||
خوانده نشده
|
||||
</div>
|
||||
<div
|
||||
onClick={() => setActiveTab('read')}
|
||||
className={clx(
|
||||
'flex-1 cursor-pointer text-white border-white bg-transparent flex justify-center items-center',
|
||||
activeTab === 'read' ? 'bg-white bg-opacity-70 text-black' : ''
|
||||
)}
|
||||
>
|
||||
خوانده شده
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex mt-4 justify-end'>
|
||||
<Button
|
||||
isLoading={false}
|
||||
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">
|
||||
{
|
||||
posts.map((item: NotificationItemType) => (
|
||||
<div onClick={() => handleRedirect(item.type)} className="bg-white cursor-pointer h-fit gap-4 items-start rounded-xl bg-opacity-60 p-3 mb-4 flex" key={item.id}>
|
||||
{
|
||||
!item.isRead &&
|
||||
<div className="mt-1">
|
||||
<StatusCircle color="#00BA4B" />
|
||||
</div>
|
||||
}
|
||||
<div>
|
||||
<div className="truncate max-w-[200px]">{item.message}</div>
|
||||
<div className="mt-2 flex gap-2 text-[10px] text-description">
|
||||
<div>{/* timeAgo(item.createdAt) */}</div>
|
||||
<div className="flex gap-1 items-center">
|
||||
<StatusCircle color="#8C90A3" />
|
||||
<div>{item.title}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Notifications;
|
||||
@@ -0,0 +1,22 @@
|
||||
import * as api from "../service/NotificationService";
|
||||
import { useInfiniteQuery, useMutation } from "@tanstack/react-query";
|
||||
|
||||
export const useGetNotification = (status: "all" | "read" | "unread") => {
|
||||
return useInfiniteQuery({
|
||||
queryKey: ["notifications", status],
|
||||
queryFn: ({ pageParam = 1 }) => api.getNotifications(pageParam, status), // فراخوانی API برای گرفتن دادهها
|
||||
initialPageParam: 1, // صفحه اول به طور پیشفرض
|
||||
getNextPageParam: (lastPage) => {
|
||||
const currentPage = lastPage.data?.pager.page;
|
||||
const totalPages = lastPage.data?.pager.totalPages;
|
||||
|
||||
return currentPage < totalPages ? currentPage + 1 : undefined;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useReadAll = () => {
|
||||
return useMutation({
|
||||
mutationFn: () => api.readAll(),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
import axios from "../../../config/axios";
|
||||
|
||||
export const getNotifications = async (
|
||||
page: number,
|
||||
status: "all" | "read" | "unread"
|
||||
) => {
|
||||
let query = ``;
|
||||
if (status !== "all") {
|
||||
query = `&isRead=${status === "read" ? 1 : 0}`;
|
||||
}
|
||||
const { data } = await axios.get(`/notifications?page=${page}${query}`);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const readAll = async () => {
|
||||
const { data } = await axios.patch(`/notifications/read-all`);
|
||||
return data;
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
export type NotificationItemType = {
|
||||
id: string;
|
||||
title: string;
|
||||
message: string;
|
||||
createdAt: string;
|
||||
isRead: boolean;
|
||||
type: NotificationTypeEnum;
|
||||
};
|
||||
|
||||
export const NotificationTypeEnum = {
|
||||
USER_LOGIN: "USER_LOGIN",
|
||||
ANNOUNCEMENT: "ANNOUNCEMENT",
|
||||
|
||||
// Finance category
|
||||
WALLET_CHARGE: "WALLET_CHARGE",
|
||||
WALLET_DEDUCTION: "WALLET_DEDUCTION",
|
||||
|
||||
//Invoice
|
||||
BILL_INVOICE_REMINDER: "BILL_INVOICE_REMINDER",
|
||||
BILL_INVOICE: "BILL_INVOICE",
|
||||
CREATE_INVOICE: "CREATE_INVOICE",
|
||||
|
||||
// Service category
|
||||
CREATE_SERVICE: "CREATE_SERVICE",
|
||||
UNBLOCK_SERVICE: "UNBLOCK_SERVICE",
|
||||
BLOCK_SERVICE: "BLOCK_SERVICE",
|
||||
|
||||
// Support category
|
||||
ANSWER_TICKET: "ANSWER_TICKET",
|
||||
CREATE_TICKET: "CREATE_TICKET",
|
||||
} as const;
|
||||
|
||||
export type NotificationTypeEnum = typeof NotificationTypeEnum[keyof typeof NotificationTypeEnum];
|
||||
@@ -0,0 +1,118 @@
|
||||
import Tabs from '@/components/Tabs'
|
||||
import { useState, type FC } from 'react'
|
||||
import { TabMyOrdersEnum } from './enum/OrderEnum'
|
||||
import Filters from '@/components/Filters'
|
||||
import Button from '@/components/Button'
|
||||
import { AddSquare } from 'iconsax-react'
|
||||
import Table from '@/components/Table'
|
||||
|
||||
const MyOrders: FC = () => {
|
||||
|
||||
const [activeTab, setActiveTab] = useState<TabMyOrdersEnum>(TabMyOrdersEnum.ALL)
|
||||
return (
|
||||
<div className='mt-5'>
|
||||
<h1>
|
||||
سفارشات من
|
||||
</h1>
|
||||
|
||||
<div className='mt-10'>
|
||||
<Tabs
|
||||
items={[
|
||||
{ label: 'همه', value: TabMyOrdersEnum.ALL },
|
||||
{ label: 'در حال انجام', value: TabMyOrdersEnum.IN_PROGRESS },
|
||||
{ label: 'تایید شده', value: TabMyOrdersEnum.CONFIRMED },
|
||||
{ label: 'تحویل داده شده', value: TabMyOrdersEnum.DELIVERED },
|
||||
{ label: 'کنسل شده', value: TabMyOrdersEnum.CANCELLED },
|
||||
]}
|
||||
activeTab={activeTab}
|
||||
onTabChange={(tab) => setActiveTab(tab as TabMyOrdersEnum)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-16 flex justify-between items-center'>
|
||||
<Filters
|
||||
fields={[
|
||||
{ type: 'input', name: 'search', placeholder: 'جستجو' },
|
||||
{ type: 'date', name: 'date', placeholder: 'تاریخ' },
|
||||
{
|
||||
type: 'select', name: 'status', placeholder: 'وضعیت', options: [
|
||||
{ label: 'همه', value: 'all' },
|
||||
{ label: 'در حال انجام', value: 'in_progress' },
|
||||
{ label: 'تایید شده', value: 'confirmed' },
|
||||
{ label: 'تحویل داده شده', value: 'delivered' },
|
||||
{ label: 'کنسل شده', value: 'cancelled' },
|
||||
]
|
||||
},
|
||||
]}
|
||||
onChange={() => { }}
|
||||
/>
|
||||
|
||||
<Button
|
||||
className='w-fit px-5'
|
||||
>
|
||||
<div className='flex items-center gap-2'>
|
||||
<AddSquare
|
||||
size={16}
|
||||
color='#000000'
|
||||
/>
|
||||
<span>
|
||||
سفارش جدید
|
||||
</span>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className='mt-10'>
|
||||
<Table
|
||||
columns={[
|
||||
{
|
||||
key: 'id',
|
||||
title: 'شماره',
|
||||
},
|
||||
{
|
||||
key: 'title',
|
||||
title: 'عنوان',
|
||||
},
|
||||
{
|
||||
key: 'createdAt',
|
||||
title: 'زمان ثبت سفارش',
|
||||
},
|
||||
{
|
||||
key: 'designer',
|
||||
title: 'طراح',
|
||||
},
|
||||
{
|
||||
key: 'type',
|
||||
title: 'نوع سفارش',
|
||||
},
|
||||
{
|
||||
key: 'itemsCount',
|
||||
title: 'تعداد اقلام',
|
||||
},
|
||||
{
|
||||
key: 'status',
|
||||
title: 'وضعیت سفارش',
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
title: '',
|
||||
}
|
||||
]}
|
||||
data={[
|
||||
{
|
||||
id: 1,
|
||||
title: 'سفارش 1',
|
||||
createdAt: '2021-01-01',
|
||||
designer: 'طراح 1',
|
||||
type: 'نوع 1',
|
||||
itemsCount: 10,
|
||||
status: 'در حال انجام',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default MyOrders
|
||||
@@ -0,0 +1,73 @@
|
||||
import Button from '@/components/Button'
|
||||
import Input from '@/components/Input'
|
||||
import Select from '@/components/Select'
|
||||
import UploadBox from '@/components/UploadBox'
|
||||
import VoiceRecorder from '@/components/VoiceRecorder'
|
||||
import { COLORS } from '@/constants/colors'
|
||||
import { AddSquare } from 'iconsax-react'
|
||||
import { type FC } from 'react'
|
||||
|
||||
const NewOrder: FC = () => {
|
||||
return (
|
||||
<div className='mt-5'>
|
||||
<h1 className='text-lg font-light'>
|
||||
سفارش جدید
|
||||
</h1>
|
||||
|
||||
<div className='bg-white rounded-3xl p-6 mt-8'>
|
||||
<div className='font-light'>اطلاعات سفارش</div>
|
||||
|
||||
<div className='mt-6'>
|
||||
<Select
|
||||
items={[]}
|
||||
label='محصول'
|
||||
placeholder='انتخاب محصول'
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-6 rowTwoInput'>
|
||||
<Select
|
||||
items={[]}
|
||||
label='تعداد'
|
||||
placeholder='انتخاب'
|
||||
/>
|
||||
|
||||
<Input
|
||||
label='انتخاب دلخواه'
|
||||
placeholder='100'
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-6'>
|
||||
<VoiceRecorder
|
||||
label='پیام صوتی'
|
||||
onRecordingComplete={(blob) => {
|
||||
console.log('ضبط صدا تکمیل شد:', blob)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-6'>
|
||||
<UploadBox
|
||||
label='فایل های ضبط شده'
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-6 flex justify-end'>
|
||||
<Button
|
||||
className='bg-transparent border border-primary text-primary w-fit px-6'
|
||||
>
|
||||
<div className='flex gap-1'>
|
||||
<AddSquare color={COLORS.primary} size={20} />
|
||||
<div>
|
||||
اضافه کردن
|
||||
</div>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default NewOrder
|
||||
@@ -0,0 +1,154 @@
|
||||
import { type FC, useState } from 'react'
|
||||
import { Microphone, Paperclip2, Receipt1 } from 'iconsax-react'
|
||||
import Button from '@/components/Button'
|
||||
import UploadBox from '@/components/UploadBox'
|
||||
import Input from '@/components/Input'
|
||||
|
||||
const OrderDetail: FC = () => {
|
||||
const [message, setMessage] = useState('')
|
||||
const [files, setFiles] = useState<File[]>([])
|
||||
|
||||
const orderData = {
|
||||
orderId: '۱۲۲۴۵',
|
||||
title: 'شاپینگ بک',
|
||||
designer: 'عباس حسینی',
|
||||
quantity: '۱۰۰',
|
||||
estimatedDate: '۱۴۰۵/۰۶/۰۶/۱۳',
|
||||
description: 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ، و با استفاده از طراحان گرافیک است، چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است، و برای شرایط فعلی تکنولوژی مورد نیاز، و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد، کتابهای زیادی در شصت و سه درصد گذشته حال و آینده، شناخت فراوان جامعه و متخصصان را می طلبد، تا با نرم افزارها شناخت بیشتری را برای طراحان رایانه ای علی الخصوص طراحان خلاق...'
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
console.log('Submit:', { message, files })
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full min-h-screen bg-[#eceef6] p-6">
|
||||
{/* Header Section */}
|
||||
<div className="flex items-start justify-between mb-6">
|
||||
|
||||
|
||||
<div className="text-sm text-[#8C90A3]">
|
||||
سفارش #{orderData.orderId}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Order Information Section */}
|
||||
<div className="bg-white rounded-2xl p-6 mb-6">
|
||||
<div className='flex justify-between items-center'>
|
||||
<h2 className="text-lg font-light mb-6">اطلاعات سفارش</h2>
|
||||
|
||||
<a href="#" className="flex items-center gap-2 text-[#0037FF] text-sm">
|
||||
<Receipt1 size={20} color="#3B82F6" />
|
||||
<span>پیش فاکتور</span>
|
||||
</a>
|
||||
</div>
|
||||
<div className="flex items-center gap-6">
|
||||
{/* Product Image */}
|
||||
<div className='size-[86px] rounded-lg bg-gray-200'>
|
||||
</div>
|
||||
|
||||
{/* Order Details */}
|
||||
<div className="flex-1 flex gap-20 pr-10">
|
||||
<div className='flex items-center gap-2'>
|
||||
<div className="text-xs text-desc">عنوان:</div>
|
||||
<div className="text-sm font-medium text-black">{orderData.title}</div>
|
||||
</div>
|
||||
<div className='flex items-center gap-2'>
|
||||
<div className="text-xs text-desc">نام طرح:</div>
|
||||
<div className="text-sm font-medium text-black">{orderData.designer}</div>
|
||||
</div>
|
||||
<div className='flex items-center gap-2'>
|
||||
<div className="text-xs text-desc">تعداد:</div>
|
||||
<div className="text-sm font-medium text-black">{orderData.quantity}</div>
|
||||
</div>
|
||||
<div className='flex items-center gap-2'>
|
||||
<div className="text-xs text-desc">تخمین زمان:</div>
|
||||
<div className="text-sm font-medium text-black">{orderData.estimatedDate}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Order Description */}
|
||||
<div className="mt-6 pt-6 border-t border-dashed border-desc">
|
||||
<div className="text-sm font-medium mb-2 text-desc">شرح سفارش:</div>
|
||||
<p className="text-sm font-light text-black leading-6">
|
||||
{orderData.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom Section - White Card */}
|
||||
<div className="bg-white rounded-2xl p-6">
|
||||
{/* Designer Name */}
|
||||
<div className="mt-6">
|
||||
<Input
|
||||
label="نام طراح"
|
||||
placeholder="عباس حسینی"
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='bg-[#F5F7FC] rounded-4xl rounded-tr-none mt-6 p-6 max-w-[55%]'>
|
||||
<div className='text-sm font-light text-black leading-6'>
|
||||
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ، و با استفاده از طراحان گرافیک است، چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است، و برای شرایط فعلی تکنولوژی مورد نیاز، و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد، کتابهای زیادی در شصت و سه درصد گذشته حال و آینده، شناخت فراوان جامعه و متخصصان را می طلبد،
|
||||
</div>
|
||||
|
||||
<div className='flex justify-between mt-3'>
|
||||
<div className='flex items-center gap-1.5 text-[#0047FF]'>
|
||||
<Paperclip2 size={20} color="#0047FF" />
|
||||
<div className='text-xs'>loremipsum.pdf</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex justify-end'>'
|
||||
<div className='bg-[#F5F7FC] rounded-4xl rounded-tl-none mt-6 p-6 max-w-[55%]'>
|
||||
<div className='flex gap-1 text-sm mb-2'>
|
||||
<div className='font-bold'>طراح : </div>
|
||||
<div>عباس حسینی</div>
|
||||
</div>
|
||||
<div className='text-sm font-light text-black leading-6'>
|
||||
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ، و با استفاده از طراحان گرافیک است، چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است، و برای شرایط فعلی تکنولوژی مورد نیاز، و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد، کتابهای زیادی در شصت و سه درصد گذشته حال و آینده، شناخت فراوان جامعه و متخصصان را می طلبد،
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div className="mt-6">
|
||||
<div className="text-sm mb-2 text-black">پیام شما</div>
|
||||
<div className="relative">
|
||||
<textarea
|
||||
value={message}
|
||||
onChange={(e) => setMessage(e.target.value)}
|
||||
className="w-full h-40 bg-white border border-[#f5f7fc] rounded-xl p-4 text-sm resize-none outline-none"
|
||||
placeholder=""
|
||||
/>
|
||||
<button className="absolute left-4 bottom-4 bg-[#FFF1D7] size-8 rounded-lg flex items-center justify-center">
|
||||
<Microphone size={20} color="black" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="mt-6">
|
||||
<UploadBox
|
||||
label="فایل های ضمیمه"
|
||||
isMultiple={true}
|
||||
onChange={setFiles}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex mt-10 justify-end">
|
||||
<Button
|
||||
label="ارسال"
|
||||
onClick={handleSubmit}
|
||||
className='w-[150px]'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default OrderDetail
|
||||
@@ -0,0 +1,7 @@
|
||||
export const enum TabMyOrdersEnum {
|
||||
ALL = "all",
|
||||
IN_PROGRESS = "in_progress",
|
||||
CONFIRMED = "confirmed",
|
||||
DELIVERED = "delivered",
|
||||
CANCELLED = "cancelled",
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import axios from "@/config/axios";
|
||||
|
||||
export interface ProfileData {
|
||||
user: {
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
email: string;
|
||||
profilePic?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const useGetProfile = () => {
|
||||
return useQuery({
|
||||
queryKey: ["profile"],
|
||||
queryFn: async (): Promise<{ data: ProfileData }> => {
|
||||
const response = await axios.get("/profile");
|
||||
return response.data;
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,102 @@
|
||||
import Filters from '@/components/Filters'
|
||||
import Table from '@/components/Table'
|
||||
import { type FC } from 'react'
|
||||
|
||||
const RequestList: FC = () => {
|
||||
return (
|
||||
<div className='mt-5'>
|
||||
<h1 className='text-lg font-light'>درخواست ها</h1>
|
||||
|
||||
<div className='mt-8'>
|
||||
<Filters
|
||||
fields={[
|
||||
{
|
||||
name: 'search',
|
||||
type: 'input',
|
||||
placeholder: 'جستجو',
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
type: 'select',
|
||||
placeholder: 'وضعیت',
|
||||
options: [
|
||||
{
|
||||
label: 'درحال انتظار',
|
||||
value: 'pending',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'date',
|
||||
type: 'date',
|
||||
placeholder: 'تاریخ',
|
||||
}
|
||||
]}
|
||||
onChange={() => { }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-8'>
|
||||
<Table
|
||||
columns={[
|
||||
{
|
||||
key: 'id',
|
||||
title: 'شماره',
|
||||
},
|
||||
{
|
||||
key: 'customer',
|
||||
title: 'مشتری',
|
||||
},
|
||||
{
|
||||
key: 'creationDate',
|
||||
title: 'تاریخ ایجاد درخواست',
|
||||
},
|
||||
{
|
||||
key: 'lastApprovalDate',
|
||||
title: 'آخرین مهلت تایید',
|
||||
},
|
||||
{
|
||||
key: 'itemCount',
|
||||
title: 'تعداد اقلام',
|
||||
},
|
||||
{
|
||||
key: 'status',
|
||||
title: 'وضعیت',
|
||||
render: (item) => {
|
||||
return (
|
||||
<div className='h-6 w-fit flex items-center bg-[#FFEDCA] text-[#FF7B00] rounded-full px-2.5 text-xs'>
|
||||
{item.status}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
title: '',
|
||||
},
|
||||
]}
|
||||
data={[
|
||||
{
|
||||
id: 1,
|
||||
customer: 'مشتری 1',
|
||||
creationDate: '2024-01-01',
|
||||
lastApprovalDate: '2024-01-01',
|
||||
itemCount: 10,
|
||||
status: 'درحال انتظار',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
customer: 'مشتری 2',
|
||||
creationDate: '2024-01-01',
|
||||
lastApprovalDate: '2024-01-01',
|
||||
itemCount: 10,
|
||||
status: 'تایید شده',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default RequestList
|
||||
@@ -0,0 +1,16 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import axios from "@/config/axios";
|
||||
|
||||
export interface WalletBalanceData {
|
||||
balance: number;
|
||||
}
|
||||
|
||||
export const useGetWalletBalance = () => {
|
||||
return useQuery({
|
||||
queryKey: ["wallet-balance"],
|
||||
queryFn: async (): Promise<{ data: WalletBalanceData }> => {
|
||||
const response = await axios.get("/wallet/balance");
|
||||
return response.data;
|
||||
},
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user