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;
|
||||
}
|
||||
Reference in New Issue
Block a user