This commit is contained in:
hamid zarghami
2025-10-15 14:43:02 +03:30
parent 05b555e07e
commit 75f2f0ab17
23 changed files with 299 additions and 101 deletions
View File
+2
View File
@@ -15,6 +15,7 @@ type Props = {
className?: string; className?: string;
label: string, label: string,
readOnly?: boolean; readOnly?: boolean;
minDate?: Date;
}; };
const DatePickerComponent: FC<Props> = (props: Props) => { const DatePickerComponent: FC<Props> = (props: Props) => {
@@ -63,6 +64,7 @@ const DatePickerComponent: FC<Props> = (props: Props) => {
calendarPosition="bottom-right" calendarPosition="bottom-right"
className={props.className} className={props.className}
readOnly={props.readOnly} readOnly={props.readOnly}
minDate={props.minDate}
/> />
{props.error_text && props.error_text !== '' && ( {props.error_text && props.error_text !== '' && (
<div className="text-xs text-right text-red-600 mt-2 mr-2 font-medium"> <div className="text-xs text-right text-red-600 mt-2 mr-2 font-medium">
+6 -2
View File
@@ -3,11 +3,15 @@ import { useLocation } from 'react-router-dom'
import TitleLine from './TitleLine' import TitleLine from './TitleLine'
import { getPageTitle } from '../config/PageTitles' import { getPageTitle } from '../config/PageTitles'
const PageTitle: FC = () => { type Props = {
title1?: string
}
const PageTitle: FC<Props> = ({ title1 }) => {
const location = useLocation() const location = useLocation()
const title = getPageTitle(location.pathname) const title = getPageTitle(location.pathname)
return <TitleLine title={title} /> return <TitleLine title={title1 || title} />
} }
export default PageTitle export default PageTitle
+2 -2
View File
@@ -171,7 +171,7 @@ export const Pages = {
orders: { orders: {
native: "/orders/native", native: "/orders/native",
sellers: "/orders/seller", sellers: "/orders/seller",
admin: "/orders/native", admin: "/orders/native?status=Admin",
completed: "/orders/native?status=Completed", completed: "/orders/native?status=Completed",
cancelled: "/orders/native?status=Cancelled", cancelled: "/orders/native?status=Cancelled",
pending: "/orders/native?status=Pending", pending: "/orders/native?status=Pending",
@@ -204,7 +204,7 @@ export const Pages = {
withdrawalRequests: "/sellers/withdrawal-requests", withdrawalRequests: "/sellers/withdrawal-requests",
announcement: "/sellers/announcement", announcement: "/sellers/announcement",
requestCreateProduct: "/sellers/request-create-product", requestCreateProduct: "/sellers/request-create-product",
learningCategory: "/sellers/learning-category", learningCategory: "/sellers/category",
learning: "/sellers/learning", learning: "/sellers/learning",
learningCreate: "/sellers/learning/create", learningCreate: "/sellers/learning/create",
learningUpdate: "/sellers/learning/update/", learningUpdate: "/sellers/learning/update/",
+1
View File
@@ -214,6 +214,7 @@ const CreateCoupon: FC = () => {
placeholder='انتخاب تاریخ' placeholder='انتخاب تاریخ'
onChange={(date) => formik.setFieldValue('expirationDate', date)} onChange={(date) => formik.setFieldValue('expirationDate', date)}
error_text={formik.touched.expirationDate && formik.errors.expirationDate ? formik.errors.expirationDate : ''} error_text={formik.touched.expirationDate && formik.errors.expirationDate ? formik.errors.expirationDate : ''}
minDate={new Date()}
/> />
<Textarea <Textarea
+2 -1
View File
@@ -15,6 +15,7 @@ import { useUploadMultiple, useUploadSingle } from '../uploader/hooks/useUploade
import UploadBoxDraggble from '@/components/UploadBoxDraggble' import UploadBoxDraggble from '@/components/UploadBoxDraggble'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
import { extractErrorMessage } from '@/helpers/utils' import { extractErrorMessage } from '@/helpers/utils'
import { Pages } from '@/config/Pages'
const Create: FC = () => { const Create: FC = () => {
const navigate = useNavigate() const navigate = useNavigate()
@@ -64,7 +65,7 @@ const Create: FC = () => {
createBrandMutation.mutate(submitData, { createBrandMutation.mutate(submitData, {
onSuccess: () => { onSuccess: () => {
toast.success('برند با موفقیت ایجاد شد') toast.success('برند با موفقیت ایجاد شد')
navigate('/brands') navigate(Pages.products.brands.list)
}, },
onError: (error) => { onError: (error) => {
toast.error(extractErrorMessage(error)) toast.error(extractErrorMessage(error))
+2 -1
View File
@@ -15,6 +15,7 @@ import { useUploadMultiple, useUploadSingle } from '../uploader/hooks/useUploade
import UploadBoxDraggble from '@/components/UploadBoxDraggble' import UploadBoxDraggble from '@/components/UploadBoxDraggble'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
import { extractErrorMessage } from '@/helpers/utils' import { extractErrorMessage } from '@/helpers/utils'
import { Pages } from '@/config/Pages'
const UpdateBrand: FC = () => { const UpdateBrand: FC = () => {
const navigate = useNavigate() const navigate = useNavigate()
@@ -66,7 +67,7 @@ const UpdateBrand: FC = () => {
updateBrandMutation.mutate({ id: id!, params: submitData }, { updateBrandMutation.mutate({ id: id!, params: submitData }, {
onSuccess: () => { onSuccess: () => {
toast.success('برند با موفقیت ویرایش شد') toast.success('برند با موفقیت ویرایش شد')
navigate('/brands') navigate(Pages.products.brands.list)
}, },
onError: (error) => { onError: (error) => {
toast.error(extractErrorMessage(error)) toast.error(extractErrorMessage(error))
+9 -18
View File
@@ -2,7 +2,7 @@
import { type FC, useState } from 'react' import { type FC, useState } from 'react'
import PageTitle from '../../components/PageTitle' import PageTitle from '../../components/PageTitle'
import Button from '../../components/Button' import Button from '../../components/Button'
import { TickCircle, ArrowLeft } from 'iconsax-react' import { TickCircle } from 'iconsax-react'
import SwitchComponent from '../../components/Switch' import SwitchComponent from '../../components/Switch'
import Input from '../../components/Input' import Input from '../../components/Input'
import Textarea from '../../components/Textarea' import Textarea from '../../components/Textarea'
@@ -16,6 +16,7 @@ import { useCreateCategory, useGetCategories, useSingleUpload } from './hooks/us
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
import { Pages } from '../../config/Pages' import { Pages } from '../../config/Pages'
import { extractErrorMessage } from '@/helpers/utils'
const CreateCategory: FC = () => { const CreateCategory: FC = () => {
@@ -36,7 +37,7 @@ const CreateCategory: FC = () => {
icon: '', icon: '',
imageUrl: '', imageUrl: '',
description: '', description: '',
parent: '', parent: undefined,
theme: '', theme: '',
}, },
validationSchema: Yup.object({ validationSchema: Yup.object({
@@ -67,14 +68,15 @@ const CreateCategory: FC = () => {
onSuccess: () => { onSuccess: () => {
navigate(Pages.category.list) navigate(Pages.category.list)
}, },
onError: (error) => {
toast.error(extractErrorMessage(error))
}
}) })
}, },
}) })
// تبدیل داده‌های API به فرمت مورد نیاز
const categoriesData: CategoryTreeNode[] = getCategories.data?.results?.data || [] const categoriesData: CategoryTreeNode[] = getCategories.data?.results?.data || []
// فیلتر کردن دسته‌ها بر اساس جستجو
const filteredCategories = categoriesData.filter(cat => const filteredCategories = categoriesData.filter(cat =>
cat.title_fa.toLowerCase().includes(searchTerm.toLowerCase()) || cat.title_fa.toLowerCase().includes(searchTerm.toLowerCase()) ||
cat.title_en.toLowerCase().includes(searchTerm.toLowerCase()) cat.title_en.toLowerCase().includes(searchTerm.toLowerCase())
@@ -87,21 +89,11 @@ const CreateCategory: FC = () => {
return ( return (
<div className='mt-4'> <div className='mt-4'>
<PageTitle /> <PageTitle />
<div className='flex justify-between items-center'> <div className='flex justify-end'>
<div className='flex items-center gap-3'>
<button
onClick={() => navigate(-1)}
className='p-2 hover:bg-gray-100 rounded-lg transition-colors'
>
<ArrowLeft size={20} />
</button>
<h1 className=''>ساخت دسته جدید</h1>
</div>
<div>
<Button <Button
className='px-6' className='px-6 w-fit'
onClick={() => formik.handleSubmit()} onClick={() => formik.handleSubmit()}
isLoading={createCategoryMutation.isPending} isLoading={createCategoryMutation.isPending || singleUpload.isPending}
disabled={!formik.isValid || createCategoryMutation.isPending} disabled={!formik.isValid || createCategoryMutation.isPending}
> >
<div className='flex gap-2 items-center'> <div className='flex gap-2 items-center'>
@@ -110,7 +102,6 @@ const CreateCategory: FC = () => {
</div> </div>
</Button> </Button>
</div> </div>
</div>
<div className='flex gap-6 xl:mt-8 mt-6'> <div className='flex gap-6 xl:mt-8 mt-6'>
{/* اطلاعات اصلی */} {/* اطلاعات اصلی */}
+11 -21
View File
@@ -1,7 +1,7 @@
import { type FC, useState, useEffect } from 'react' import { type FC, useState, useEffect } from 'react'
import PageTitle from '../../components/PageTitle' import PageTitle from '../../components/PageTitle'
import Button from '../../components/Button' import Button from '../../components/Button'
import { TickCircle, ArrowLeft } from 'iconsax-react' import { TickCircle } from 'iconsax-react'
import SwitchComponent from '../../components/Switch' import SwitchComponent from '../../components/Switch'
import Input from '../../components/Input' import Input from '../../components/Input'
import Textarea from '../../components/Textarea' import Textarea from '../../components/Textarea'
@@ -15,6 +15,7 @@ import { useUpdateCategory, useGetCategories, useGetCategoryById, useSingleUploa
import { useNavigate, useParams } from 'react-router-dom' import { useNavigate, useParams } from 'react-router-dom'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
import { Pages } from '../../config/Pages' import { Pages } from '../../config/Pages'
import { extractErrorMessage } from '@/helpers/utils'
const UpdateCategory: FC = () => { const UpdateCategory: FC = () => {
const navigate = useNavigate() const navigate = useNavigate()
@@ -39,14 +40,14 @@ const UpdateCategory: FC = () => {
icon: '', icon: '',
imageUrl: '', imageUrl: '',
description: '', description: '',
parent: null, parent: undefined,
theme: '', theme: '',
}, },
validationSchema: Yup.object({ validationSchema: Yup.object({
title_fa: Yup.string().required('عنوان فارسی دسته الزامی است'), title_fa: Yup.string().required('عنوان فارسی دسته الزامی است'),
title_en: Yup.string().required('عنوان انگلیسی دسته الزامی است'), title_en: Yup.string().required('عنوان انگلیسی دسته الزامی است'),
description: Yup.string().required('توضیحات دسته الزامی است'), description: Yup.string().required('توضیحات دسته الزامی است'),
parent: Yup.string().nullable().optional(), parent: Yup.string().optional(),
theme: Yup.string().optional(), theme: Yup.string().optional(),
}), }),
onSubmit: async (values) => { onSubmit: async (values) => {
@@ -71,8 +72,8 @@ const UpdateCategory: FC = () => {
toast.success('دسته با موفقیت ویرایش شد') toast.success('دسته با موفقیت ویرایش شد')
navigate(Pages.category.list) navigate(Pages.category.list)
}, },
onError: () => { onError: (error) => {
toast.error('خطا در ویرایش دسته') toast.error(extractErrorMessage(error))
}, },
} }
) )
@@ -89,7 +90,7 @@ const UpdateCategory: FC = () => {
icon: categoryData.icon || '', icon: categoryData.icon || '',
imageUrl: categoryData.imageUrl || '', imageUrl: categoryData.imageUrl || '',
description: categoryData.description || '', description: categoryData.description || '',
parent: categoryData.parent, parent: categoryData.parent || undefined,
theme: categoryData.theme || '', theme: categoryData.theme || '',
}) })
setIsActive(!categoryData.deleted) setIsActive(!categoryData.deleted)
@@ -138,22 +139,12 @@ const UpdateCategory: FC = () => {
return ( return (
<div className='mt-4'> <div className='mt-4'>
<PageTitle /> <PageTitle title1='ویرایش دسته' />
<div className='flex justify-between items-center'> <div className='flex justify-end'>
<div className='flex items-center gap-3'>
<button
onClick={() => navigate(-1)}
className='p-2 hover:bg-gray-100 rounded-lg transition-colors'
>
<ArrowLeft size={20} />
</button>
<h1 className=''>ویرایش دسته</h1>
</div>
<div>
<Button <Button
className='px-6' className='px-6 w-fit'
onClick={() => formik.handleSubmit()} onClick={() => formik.handleSubmit()}
isLoading={updateCategoryMutation.isPending} isLoading={updateCategoryMutation.isPending || singleUpload.isPending}
disabled={!formik.isValid || updateCategoryMutation.isPending} disabled={!formik.isValid || updateCategoryMutation.isPending}
> >
<div className='flex gap-2 items-center'> <div className='flex gap-2 items-center'>
@@ -162,7 +153,6 @@ const UpdateCategory: FC = () => {
</div> </div>
</Button> </Button>
</div> </div>
</div>
<div className='flex gap-6 xl:mt-8 mt-6'> <div className='flex gap-6 xl:mt-8 mt-6'>
{/* اطلاعات اصلی */} {/* اطلاعات اصلی */}
+1 -1
View File
@@ -4,7 +4,7 @@ export type CategoryType = {
icon: string; icon: string;
imageUrl: string; imageUrl: string;
description: string; description: string;
parent: string | null; parent?: string;
theme?: string; theme?: string;
}; };
+1 -2
View File
@@ -31,7 +31,7 @@ const Native: FC = () => {
const status = searchParams.get('status') || '' const status = searchParams.get('status') || ''
const [currentPage, setCurrentPage] = useState(1) const [currentPage, setCurrentPage] = useState(1)
const { data, isLoading, error } = useGetNativeOrders(currentPage, status) const { data, isLoading, error } = useGetNativeOrders(currentPage, status === 'Admin' ? undefined : status)
const orders = data?.results?.orders || [] const orders = data?.results?.orders || []
const pager = data?.results?.pager ? { const pager = data?.results?.pager ? {
@@ -107,7 +107,6 @@ const Native: FC = () => {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<PageTitle /> <PageTitle />
<h1 className="text-2xl font-bold">{getStatusLabel(status)}</h1>
<div className='relative overflow-x-auto rounded-3xl bg-white shadow-sm'> <div className='relative overflow-x-auto rounded-3xl bg-white shadow-sm'>
<table className='w-full text-sm'> <table className='w-full text-sm'>
@@ -155,7 +155,7 @@ const CreateVariant: FC = () => {
onSubmit={handleSubmit} onSubmit={handleSubmit}
> >
{({ setFieldValue }) => ( {({ setFieldValue }) => (
<Form className="space-y-4"> <Form className="space-y-4 w-[500px] mt-4">
{/* انتخاب variant */} {/* انتخاب variant */}
<div> <div>
<label className="text-sm font-medium text-gray-700 mb-1 block"> <label className="text-sm font-medium text-gray-700 mb-1 block">
@@ -142,7 +142,7 @@ const UpdateVariant: FC<UpdateVariantProps> = ({ variant, onUpdate }) => {
onSubmit={handleSubmit} onSubmit={handleSubmit}
> >
{({ setFieldValue }) => ( {({ setFieldValue }) => (
<Form className="space-y-4"> <Form className="space-y-4 w-[500px] mt-4">
{/* اطلاعات قیمت و موجودی */} {/* اطلاعات قیمت و موجودی */}
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
<div> <div>
@@ -7,6 +7,8 @@ import { TickCircle } from 'iconsax-react';
import { useFormik } from 'formik'; import { useFormik } from 'formik';
import * as Yup from 'yup'; import * as Yup from 'yup';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import type { ErrorType } from '@/helpers/types';
import { extractErrorMessage } from '@/helpers/utils';
const CreateReportCategoryModal: FC<{ isOpen: boolean; onClose: () => void }> = ({ isOpen, onClose }) => { const CreateReportCategoryModal: FC<{ isOpen: boolean; onClose: () => void }> = ({ isOpen, onClose }) => {
const createReportCategoryMutation = useCreateReportCategory(); const createReportCategoryMutation = useCreateReportCategory();
@@ -25,8 +27,8 @@ const CreateReportCategoryModal: FC<{ isOpen: boolean; onClose: () => void }> =
onClose(); onClose();
formik.resetForm(); formik.resetForm();
}, },
onError: () => { onError: (error: ErrorType) => {
toast.error('خطا در ایجاد دسته‌بندی گزارش'); toast.error(extractErrorMessage(error));
} }
}); });
}, },
@@ -45,7 +47,7 @@ const CreateReportCategoryModal: FC<{ isOpen: boolean; onClose: () => void }> =
title_header="افزودن دسته‌بندی گزارش" title_header="افزودن دسته‌بندی گزارش"
width={500} width={500}
> >
<div className='mt-4'> <div className='mt-4 w-[400px]'>
<form onSubmit={formik.handleSubmit} className='space-y-6'> <form onSubmit={formik.handleSubmit} className='space-y-6'>
<Input <Input
label='عنوان دسته‌بندی' label='عنوان دسته‌بندی'
@@ -1,6 +1,8 @@
import { type FC } from 'react' import { type FC } from 'react'
import DefaulModal from '@/components/DefaulModal' import DefaulModal from '@/components/DefaulModal'
import { type ProductRequest } from '../types/Types' import { type ProductRequest } from '../types/Types'
import StatusWithText from '@/components/StatusWithText'
import { User, Shop, Box, Map, Global, Archive, TickCircle, CloseCircle, Video, Camera } from 'iconsax-react'
interface Props { interface Props {
open: boolean open: boolean
@@ -11,16 +13,231 @@ interface Props {
const ProductRequestDetailModal: FC<Props> = ({ open, close, request }) => { const ProductRequestDetailModal: FC<Props> = ({ open, close, request }) => {
if (!request) return null if (!request) return null
const getStatusVariant = (status: string) => {
switch (status) {
case 'Approved': return 'success';
case 'Rejected': return 'error';
case 'Pending': return 'warning';
case 'Draft': return 'warning';
default: return 'warning';
}
};
const getStatusText = (status: string) => {
switch (status) {
case 'Approved': return 'تایید شده';
case 'Rejected': return 'رد شده';
case 'Pending': return 'در انتظار';
case 'Draft': return 'پیش‌نویس';
default: return status;
}
};
return ( return (
<DefaulModal <DefaulModal
open={open} open={open}
close={close} close={close}
isHeader={true} isHeader={true}
title_header="جزئیات درخواست ایجاد محصول" title_header="جزئیات درخواست ایجاد محصول"
width={800} width={900}
> >
<div className="space-y-6 mt-4"> <div className="space-y-6 mt-4 max-h-[70vh] overflow-y-auto">
<p>در حال حاضر این modal در حال توسعه است.</p> {/* اطلاعات فروشنده */}
<div className="bg-gray-50 rounded-lg p-4">
<h3 className="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
<User size={20} color="#6B7280" />
اطلاعات فروشنده
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<span className="text-sm text-gray-600">نام فروشنده:</span>
<p className="font-medium">{request.seller?.fullName || '-'}</p>
</div>
<div>
<span className="text-sm text-gray-600">شناسه فروشنده:</span>
<p className="font-medium font-mono text-sm">{request.seller?._id || '-'}</p>
</div>
</div>
</div>
{/* اطلاعات فروشگاه */}
<div className="bg-blue-50 rounded-lg p-4">
<h3 className="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
<Shop size={20} color="#3B82F6" />
اطلاعات فروشگاه
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<span className="text-sm text-gray-600">نام فروشگاه:</span>
<p className="font-medium">{request.shop?.shopName || '-'}</p>
</div>
<div>
<span className="text-sm text-gray-600">کد فروشگاه:</span>
<p className="font-medium">{request.shop?.shopCode || '-'}</p>
</div>
{request.shop?.address && (
<>
<div className="md:col-span-2">
<span className="text-sm text-gray-600 flex items-center gap-1">
<Map size={16} />
آدرس:
</span>
<p className="font-medium">{request.shop.address.address}</p>
<p className="text-sm text-gray-500 mt-1">
{request.shop.address.city?.name}، {request.shop.address.province?.name}
</p>
{request.shop.address.postalCode && (
<p className="text-sm text-gray-500">
کد پستی: {request.shop.address.postalCode}
</p>
)}
</div>
</>
)}
</div>
</div>
{/* اطلاعات محصول */}
<div className="bg-green-50 rounded-lg p-4">
<h3 className="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
<Box size={20} color="#10B981" />
اطلاعات محصول
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<span className="text-sm text-gray-600">نام محصول:</span>
<p className="font-medium">{request.productName}</p>
</div>
<div>
<span className="text-sm text-gray-600">برند:</span>
<p className="font-medium">{request.brand?.title_fa} ({request.brand?.title_en})</p>
</div>
<div>
<span className="text-sm text-gray-600">دستهبندی:</span>
<p className="font-medium">{request.category?.title_fa}</p>
</div>
<div>
<span className="text-sm text-gray-600 flex items-center gap-1">
<Global size={16} />
منبع:
</span>
<p className="font-medium">{request.source}</p>
</div>
<div className="md:col-span-2">
<span className="text-sm text-gray-600">توضیحات:</span>
<p className="font-medium mt-1 p-3 bg-white rounded border">{request.description}</p>
</div>
</div>
</div>
{/* ابعاد محصول */}
{request.dimensions && (
<div className="bg-purple-50 rounded-lg p-4">
<h3 className="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
<Archive size={20} color="#8B5CF6" />
ابعاد و وزن محصول
</h3>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div>
<span className="text-sm text-gray-600">وزن بسته (گرم):</span>
<p className="font-medium">{request.dimensions.package_weight}</p>
</div>
<div>
<span className="text-sm text-gray-600">ارتفاع (سانتیمتر):</span>
<p className="font-medium">{request.dimensions.package_height}</p>
</div>
<div>
<span className="text-sm text-gray-600">طول (سانتیمتر):</span>
<p className="font-medium">{request.dimensions.package_length}</p>
</div>
<div>
<span className="text-sm text-gray-600">عرض (سانتیمتر):</span>
<p className="font-medium">{request.dimensions.package_width}</p>
</div>
</div>
</div>
)}
{/* مزایا و معایب */}
{(request.advantages?.length > 0 || request.disAdvantages?.length > 0) && (
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{request.advantages && request.advantages.length > 0 && (
<div className="bg-green-50 rounded-lg p-4">
<h3 className="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
<TickCircle size={20} color="#10B981" />
مزایا
</h3>
<ul className="space-y-2">
{request.advantages.map((advantage, index) => (
<li key={index} className="flex items-start gap-2">
<TickCircle size={16} color="#10B981" className="mt-0.5 flex-shrink-0" />
<span className="text-sm">{advantage}</span>
</li>
))}
</ul>
</div>
)}
{request.disAdvantages && request.disAdvantages.length > 0 && (
<div className="bg-red-50 rounded-lg p-4">
<h3 className="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
<CloseCircle size={20} color="#EF4444" />
معایب
</h3>
<ul className="space-y-2">
{request.disAdvantages.map((disadvantage, index) => (
<li key={index} className="flex items-start gap-2">
<CloseCircle size={16} color="#EF4444" className="mt-0.5 flex-shrink-0" />
<span className="text-sm">{disadvantage}</span>
</li>
))}
</ul>
</div>
)}
</div>
)}
{/* خدمات درخواست شده */}
<div className="bg-yellow-50 rounded-lg p-4">
<h3 className="text-lg font-semibold text-gray-800 mb-3">خدمات درخواست شده</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className={`p-3 rounded-lg border-2 ${request.requestPhotography ? 'border-green-200 bg-green-100' : 'border-gray-200 bg-gray-100'}`}>
<div className="flex items-center gap-2 mb-2">
<Camera size={18} color={request.requestPhotography ? "#10B981" : "#6B7280"} />
<span className="font-medium">عکاسی محصول</span>
</div>
{request.requestPhotography && request.requestPhotosCount && (
<p className="text-sm text-gray-600">تعداد عکس: {request.requestPhotosCount}</p>
)}
</div>
<div className={`p-3 rounded-lg border-2 ${request.expertReview ? 'border-green-200 bg-green-100' : 'border-gray-200 bg-gray-100'}`}>
<div className="flex items-center gap-2 mb-2">
<User size={18} color={request.expertReview ? "#10B981" : "#6B7280"} />
<span className="font-medium">بررسی تخصصی</span>
</div>
</div>
<div className={`p-3 rounded-lg border-2 ${request.unboxingVideo ? 'border-green-200 bg-green-100' : 'border-gray-200 bg-gray-100'}`}>
<div className="flex items-center gap-2 mb-2">
<Video size={18} color={request.unboxingVideo ? "#10B981" : "#6B7280"} />
<span className="font-medium">ویدیو باز کردن بسته</span>
</div>
</div>
</div>
</div>
{/* وضعیت درخواست */}
<div className="bg-gray-50 rounded-lg p-4">
<div>
<span className="text-sm text-gray-600 mb-2 block">وضعیت درخواست:</span>
<StatusWithText
variant={getStatusVariant(request.requestStatus)}
text={getStatusText(request.requestStatus)}
/>
</div>
</div>
</div> </div>
</DefaulModal> </DefaulModal>
) )
@@ -83,7 +83,7 @@ const WholesaleRequestTableRow: FC<Props> = ({ request, onApprove }) => {
</div> </div>
</Td> </Td>
<Td text=""> <Td text="">
{request.status === 'Pending' && ( {request.status === 'Pending' ? (
<Button <Button
variant="primary" variant="primary"
size="sm" size="sm"
@@ -95,6 +95,8 @@ const WholesaleRequestTableRow: FC<Props> = ({ request, onApprove }) => {
تایید تایید
</div> </div>
</Button> </Button>
) : (
<span className="text-gray-400 text-sm">{request.status}</span>
)} )}
</Td> </Td>
</tr> </tr>
-7
View File
@@ -63,13 +63,6 @@ const TicketsList: FC = () => {
return ( return (
<div> <div>
<PageTitle /> <PageTitle />
<div className='flex justify-end mt-5'>
<Button
label='افزودن تیکت'
onClick={() => navigate(`${Pages.ticket.create}`)}
className='w-fit'
/>
</div>
<div className='relative overflow-x-auto rounded-3xl mt-5 w-full'> <div className='relative overflow-x-auto rounded-3xl mt-5 w-full'>
<table className='w-full text-sm'> <table className='w-full text-sm'>
<thead className='thead'> <thead className='thead'>
+8 -8
View File
@@ -118,7 +118,7 @@ const SideBar: FC = () => {
icon={<Element3 variant={isActive('products') ? 'Bold' : 'Outline'} color={isActive('products') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />} icon={<Element3 variant={isActive('products') ? 'Bold' : 'Outline'} color={isActive('products') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="محصولات" title="محصولات"
isActive={isActive('products')} isActive={isActive('products')}
link="/products" link={Pages.products.list}
activeName='products' activeName='products'
/> />
@@ -172,7 +172,7 @@ const SideBar: FC = () => {
icon={<People variant={isActive('sellers') ? 'Bold' : 'Outline'} color={isActive('sellers') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />} icon={<People variant={isActive('sellers') ? 'Bold' : 'Outline'} color={isActive('sellers') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="فروشندگان" title="فروشندگان"
isActive={isActive('sellers')} isActive={isActive('sellers')}
link="/sellers" link={Pages.sellers.list}
activeName='sellers' activeName='sellers'
/> />
@@ -190,7 +190,7 @@ const SideBar: FC = () => {
icon={<Profile variant={isActive('admin') ? 'Bold' : 'Outline'} color={isActive('admin') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />} icon={<Profile variant={isActive('admin') ? 'Bold' : 'Outline'} color={isActive('admin') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="ادمین ها" title="ادمین ها"
isActive={isActive('admin')} isActive={isActive('admin')}
link="/admin" link={Pages.admin.list}
activeName='admin' activeName='admin'
/> />
@@ -199,7 +199,7 @@ const SideBar: FC = () => {
icon={<Messages3 variant={isActive('tickets') ? 'Bold' : 'Outline'} color={isActive('tickets') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />} icon={<Messages3 variant={isActive('tickets') ? 'Bold' : 'Outline'} color={isActive('tickets') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="تیکت ها" title="تیکت ها"
isActive={isActive('tickets')} isActive={isActive('tickets')}
link="/tickets" link={Pages.ticket.list}
activeName='tickets' activeName='tickets'
/> />
@@ -208,7 +208,7 @@ const SideBar: FC = () => {
icon={<Chart variant={isActive('reports') ? 'Bold' : 'Outline'} color={isActive('reports') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />} icon={<Chart variant={isActive('reports') ? 'Bold' : 'Outline'} color={isActive('reports') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="گزارش ها" title="گزارش ها"
isActive={isActive('reports')} isActive={isActive('reports')}
link="/reports" link={Pages.report.product}
activeName='reports' activeName='reports'
/> />
@@ -217,7 +217,7 @@ const SideBar: FC = () => {
icon={<SmsTracking variant={isActive('chat') ? 'Bold' : 'Outline'} color={isActive('chat') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />} icon={<SmsTracking variant={isActive('chat') ? 'Bold' : 'Outline'} color={isActive('chat') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="گفت و گو" title="گفت و گو"
isActive={isActive('chat')} isActive={isActive('chat')}
link="/chat" link={Pages.messages.list}
activeName='chat' activeName='chat'
/> />
@@ -244,7 +244,7 @@ const SideBar: FC = () => {
icon={<DocumentText variant={isActive('pages') ? 'Bold' : 'Outline'} color={isActive('pages') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />} icon={<DocumentText variant={isActive('pages') ? 'Bold' : 'Outline'} color={isActive('pages') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="مدیریت صفحات" title="مدیریت صفحات"
isActive={isActive('pages')} isActive={isActive('pages')}
link="/pages" link={Pages.pages.aboutUs}
activeName='pages' activeName='pages'
/> />
@@ -253,7 +253,7 @@ const SideBar: FC = () => {
icon={<Briefcase variant={isActive('jobs') ? 'Bold' : 'Outline'} color={isActive('jobs') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />} icon={<Briefcase variant={isActive('jobs') ? 'Bold' : 'Outline'} color={isActive('jobs') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
title="مشاغل" title="مشاغل"
isActive={isActive('jobs')} isActive={isActive('jobs')}
link="/jobs" link={Pages.jobs.list}
activeName='jobs' activeName='jobs'
/> />
</div> </div>
+2 -2
View File
@@ -36,11 +36,11 @@ const BlogSubMenu: FC = () => {
isActive={isActive('create')} isActive={isActive('create')}
link={Pages.blog.category} link={Pages.blog.category}
/> />
<SubMenuItem {/* <SubMenuItem
title={'نظرات'} title={'نظرات'}
isActive={isActive('comments')} isActive={isActive('comments')}
link={Pages.blog.comments} link={Pages.blog.comments}
/> /> */}
</div> </div>
</div> </div>
+1 -1
View File
@@ -29,7 +29,7 @@ const OrdersSubMenu: FC = () => {
/> />
<SubMenuItem <SubMenuItem
title={'لیست سفارشات (مدیر)'} title={'لیست سفارشات (مدیر)'}
isActive={isActive('/native')} isActive={isActive('Admin')}
link={Pages.orders.admin} link={Pages.orders.admin}
/> />
<SubMenuItem <SubMenuItem
-5
View File
@@ -24,11 +24,6 @@ const ReportsSubMenu: FC = () => {
</div> </div>
<div className='flex flex-col mt-10 gap-4'> <div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={'گزارش فروش'}
isActive={isActive('sales')}
link="/reports/sales"
/>
<SubMenuItem <SubMenuItem
title={'گزارش محصولات'} title={'گزارش محصولات'}
isActive={isActive('products')} isActive={isActive('products')}
+1 -1
View File
@@ -31,7 +31,7 @@ const SellersSubMenu: FC = () => {
/> />
<SubMenuItem <SubMenuItem
title={'کیف پول فروشندگان'} title={'کیف پول فروشندگان'}
isActive={isActive('wallet')} isActive={isActive('withdrawal')}
link={Pages.sellers.withdrawalRequests} link={Pages.sellers.withdrawalRequests}
/> />
<SubMenuItem <SubMenuItem
+2 -2
View File
@@ -29,7 +29,7 @@ const UsersSubMenu: FC = () => {
isActive={isActive('list')} isActive={isActive('list')}
link={Pages.admin.list} link={Pages.admin.list}
/> />
<SubMenuItem {/* <SubMenuItem
title={'تعریف نقش'} title={'تعریف نقش'}
isActive={isActive('roles')} isActive={isActive('roles')}
link={Pages.admin.roleList} link={Pages.admin.roleList}
@@ -38,7 +38,7 @@ const UsersSubMenu: FC = () => {
title={'تعریف گروه کاربری'} title={'تعریف گروه کاربری'}
isActive={isActive('groups')} isActive={isActive('groups')}
link={Pages.admin.groupList} link={Pages.admin.groupList}
/> /> */}
</div> </div>
</div> </div>
) )