request create product + category learning
This commit is contained in:
@@ -200,5 +200,7 @@ export const Pages = {
|
||||
withdrawalRequests: "/sellers/withdrawal-requests",
|
||||
announcement: "/sellers/announcement",
|
||||
requestCreateProduct: "/sellers/request-create-product",
|
||||
learningCategory: "/sellers/learning-category",
|
||||
learning: "/sellers/learning",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,8 +1,104 @@
|
||||
import { type FC } from 'react'
|
||||
import { type FC, useState } from 'react'
|
||||
import { useGetLearningCategory } from './hooks/useSellerData'
|
||||
import { type LearningCategory } from './types/Types'
|
||||
import PageLoading from '../../components/PageLoading'
|
||||
import Error from '../../components/Error'
|
||||
import Td from '../../components/Td'
|
||||
import Button from '@/components/Button'
|
||||
import CategoryLearningTableRow from './components/CategoryLearningTableRow'
|
||||
import CreateUpdateCategoryModal from './components/CreateUpdateCategoryModal'
|
||||
|
||||
const CategoryLearning: FC = () => {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false)
|
||||
const [selectedCategory, setSelectedCategory] = useState<LearningCategory | undefined>()
|
||||
|
||||
const { data: categoriesData, isLoading, error, refetch } = useGetLearningCategory()
|
||||
|
||||
const handleModalClose = () => {
|
||||
setIsModalOpen(false)
|
||||
setSelectedCategory(undefined)
|
||||
}
|
||||
|
||||
const handleModalSuccess = () => {
|
||||
refetch()
|
||||
}
|
||||
|
||||
const handleEditCategory = (category: LearningCategory) => {
|
||||
setSelectedCategory(category)
|
||||
setIsModalOpen(true)
|
||||
}
|
||||
|
||||
const handleCreateCategory = () => {
|
||||
setSelectedCategory(undefined)
|
||||
setIsModalOpen(true)
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex justify-center items-center min-h-[400px]">
|
||||
<PageLoading />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="flex justify-center items-center min-h-[400px]">
|
||||
<Error errorText="خطا در بارگذاری دستهبندیهای یادگیری" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const categories = categoriesData?.results?.learningCategory || []
|
||||
|
||||
const CategoryLearning = () => {
|
||||
return (
|
||||
<div>CategoryLearning</div>
|
||||
<div>
|
||||
<div className='flex justify-end mt-5'>
|
||||
<Button
|
||||
label="ایجاد دستهبندی جدید"
|
||||
onClick={handleCreateCategory}
|
||||
className="w-auto"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='relative overflow-x-auto rounded-3xl mt-5 w-full'>
|
||||
<table className='w-full text-sm'>
|
||||
<thead className='thead'>
|
||||
<tr>
|
||||
<Td text={'عنوان'} />
|
||||
<Td text={'تاریخ ایجاد'} />
|
||||
<Td text={'تاریخ بروزرسانی'} />
|
||||
<Td text={'وضعیت'} />
|
||||
<Td text={'عملیات'} />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{categories.length === 0 ? (
|
||||
<tr className='tr'>
|
||||
<td colSpan={5} className="text-center py-8 text-gray-500">
|
||||
هیچ دستهبندی یادگیری یافت نشد
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
categories.map((category: LearningCategory) => (
|
||||
<CategoryLearningTableRow
|
||||
key={category._id}
|
||||
category={category}
|
||||
onEdit={handleEditCategory}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<CreateUpdateCategoryModal
|
||||
open={isModalOpen}
|
||||
close={handleModalClose}
|
||||
onSuccess={handleModalSuccess}
|
||||
category={selectedCategory}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import { type FC } from 'react'
|
||||
import Td from '../../../components/Td'
|
||||
import { Calendar, Edit } from 'iconsax-react'
|
||||
import StatusWithText from '../../../components/StatusWithText'
|
||||
import type { LearningCategory } from '../types/Types'
|
||||
|
||||
interface Props {
|
||||
category: LearningCategory
|
||||
onEdit: (category: LearningCategory) => void
|
||||
}
|
||||
|
||||
const CategoryLearningTableRow: FC<Props> = ({ category, onEdit }) => {
|
||||
const formatDate = (dateString: string) => {
|
||||
return new Date(dateString).toLocaleDateString('fa-IR', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<tr className='tr'>
|
||||
<Td text="">
|
||||
<div className="max-w-xs">
|
||||
<div className="font-medium text-gray-900 truncate">
|
||||
{category.title}
|
||||
</div>
|
||||
</div>
|
||||
</Td>
|
||||
<Td text="">
|
||||
<div className="flex items-center gap-2">
|
||||
<Calendar size={16} color="#8C90A3" />
|
||||
<span className="text-gray-600 text-sm">
|
||||
{formatDate(category.createdAt)}
|
||||
</span>
|
||||
</div>
|
||||
</Td>
|
||||
<Td text="">
|
||||
<div className="flex items-center gap-2">
|
||||
<Calendar size={16} color="#8C90A3" />
|
||||
<span className="text-gray-600 text-sm">
|
||||
{formatDate(category.updatedAt)}
|
||||
</span>
|
||||
</div>
|
||||
</Td>
|
||||
<Td text="">
|
||||
<StatusWithText
|
||||
variant={category.deleted ? 'error' : 'success'}
|
||||
text={category.deleted ? 'غیرفعال' : 'فعال'}
|
||||
/>
|
||||
</Td>
|
||||
<Td text="">
|
||||
<div className="flex gap-2">
|
||||
<Edit onClick={() => onEdit(category)} color="#8C90A3" size={16} />
|
||||
</div>
|
||||
</Td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
export default CategoryLearningTableRow
|
||||
@@ -0,0 +1,111 @@
|
||||
import { type FC, useEffect } from 'react'
|
||||
import DefaulModal from '@/components/DefaulModal'
|
||||
import Input from '@/components/Input'
|
||||
import Button from '@/components/Button'
|
||||
import { useCreateLearningCategory, useUpdateLearningCategory } from '../hooks/useSellerData'
|
||||
import { type LearningCategory, type CreateCategoryLearning } from '../types/Types'
|
||||
import { useFormik } from 'formik'
|
||||
import * as Yup from 'yup'
|
||||
import { toast } from 'react-toastify'
|
||||
import { extractErrorMessage } from '@/helpers/utils'
|
||||
|
||||
interface Props {
|
||||
open: boolean
|
||||
close: () => void
|
||||
onSuccess?: () => void
|
||||
category?: LearningCategory
|
||||
}
|
||||
|
||||
const CreateUpdateCategoryModal: FC<Props> = ({ open, close, onSuccess, category }) => {
|
||||
const isEdit = !!category
|
||||
const createMutation = useCreateLearningCategory()
|
||||
const updateMutation = useUpdateLearningCategory()
|
||||
|
||||
const formik = useFormik<CreateCategoryLearning>({
|
||||
initialValues: {
|
||||
title: category?.title || ''
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
title: Yup.string().required('عنوان دستهبندی الزامی است')
|
||||
}),
|
||||
onSubmit: (values) => {
|
||||
if (isEdit && category) {
|
||||
// Update category
|
||||
updateMutation.mutate({
|
||||
id: category._id,
|
||||
params: values
|
||||
}, {
|
||||
onSuccess: () => {
|
||||
toast.success('دستهبندی با موفقیت بروزرسانی شد')
|
||||
close()
|
||||
onSuccess?.()
|
||||
formik.resetForm()
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(extractErrorMessage(error))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// Create category
|
||||
createMutation.mutate(values, {
|
||||
onSuccess: () => {
|
||||
toast.success('دستهبندی جدید با موفقیت ایجاد شد')
|
||||
close()
|
||||
onSuccess?.()
|
||||
formik.resetForm()
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(extractErrorMessage(error))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
formik.resetForm()
|
||||
formik.setValues({
|
||||
title: category?.title || ''
|
||||
})
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [open, category])
|
||||
|
||||
return (
|
||||
<DefaulModal
|
||||
open={open}
|
||||
close={close}
|
||||
isHeader={true}
|
||||
title_header={isEdit ? "ویرایش دستهبندی یادگیری" : "ایجاد دستهبندی یادگیری جدید"}
|
||||
width={500}
|
||||
>
|
||||
<div className="space-y-6 mt-4 w-[450px]">
|
||||
<Input
|
||||
label="عنوان دستهبندی"
|
||||
placeholder="عنوان دستهبندی را وارد کنید"
|
||||
{...formik.getFieldProps('title')}
|
||||
error_text={formik.touched.title && formik.errors.title ? formik.errors.title : ''}
|
||||
/>
|
||||
|
||||
<div className="flex gap-3 pt-4">
|
||||
<Button
|
||||
label="لغو"
|
||||
variant="outline"
|
||||
onClick={close}
|
||||
className="flex-1"
|
||||
/>
|
||||
<Button
|
||||
label={isEdit ? "بروزرسانی" : "ایجاد"}
|
||||
onClick={() => formik.handleSubmit()}
|
||||
isLoading={createMutation.isPending || updateMutation.isPending}
|
||||
disabled={!formik.isValid || createMutation.isPending || updateMutation.isPending}
|
||||
className="flex-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</DefaulModal>
|
||||
)
|
||||
}
|
||||
|
||||
export default CreateUpdateCategoryModal
|
||||
@@ -1,8 +1,6 @@
|
||||
import { type FC } from 'react'
|
||||
import DefaulModal from '@/components/DefaulModal'
|
||||
import { type ProductRequest } from '../types/Types'
|
||||
import StatusWithText from '@/components/StatusWithText'
|
||||
import { Calendar, User as UserIcon, Shop, Tag, Box, MessageSquare, Location, Money } from 'iconsax-react'
|
||||
|
||||
interface Props {
|
||||
open: boolean
|
||||
@@ -13,31 +11,6 @@ interface Props {
|
||||
const ProductRequestDetailModal: FC<Props> = ({ open, close, request }) => {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
const formatDate = (dateString: string) => {
|
||||
if (!dateString) return '-'
|
||||
return new Date(dateString).toLocaleDateString('fa-IR')
|
||||
}
|
||||
|
||||
return (
|
||||
<DefaulModal
|
||||
open={open}
|
||||
@@ -47,203 +20,10 @@ const ProductRequestDetailModal: FC<Props> = ({ open, close, request }) => {
|
||||
width={800}
|
||||
>
|
||||
<div className="space-y-6 mt-4">
|
||||
{/* وضعیت درخواست */}
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-lg font-semibold text-gray-900">وضعیت درخواست</h3>
|
||||
<StatusWithText
|
||||
variant={getStatusVariant(request.requestStatus)}
|
||||
text={getStatusText(request.requestStatus)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* اطلاعات فروشنده */}
|
||||
<div className="bg-gray-50 rounded-lg p-4">
|
||||
<h4 className="text-md font-medium text-gray-900 mb-3 flex items-center gap-2">
|
||||
<UserIcon size={20} color="#374151" />
|
||||
اطلاعات فروشنده
|
||||
</h4>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<UserIcon size={16} color="#6B7280" />
|
||||
<span className="text-sm text-gray-600">نام:</span>
|
||||
<span className="text-sm font-medium">{request.seller?.fullName || '-'}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Shop size={16} color="#6B7280" />
|
||||
<span className="text-sm text-gray-600">فروشگاه:</span>
|
||||
<span className="text-sm font-medium">{request.shop?.shopName || '-'}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Location size={16} color="#6B7280" />
|
||||
<span className="text-sm text-gray-600">آدرس:</span>
|
||||
<span className="text-sm font-medium">{request.shop?.address?.province?.name || '-'}، {request.shop?.address?.city?.name || '-'}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Tag size={16} color="#6B7280" />
|
||||
<span className="text-sm text-gray-600">کد فروشگاه:</span>
|
||||
<span className="text-sm font-medium">{request.shop?.shopCode || '-'}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* اطلاعات محصول */}
|
||||
<div className="bg-blue-50 rounded-lg p-4">
|
||||
<h4 className="text-md font-medium text-gray-900 mb-3 flex items-center gap-2">
|
||||
<Box size={20} color="#1E40AF" />
|
||||
اطلاعات محصول
|
||||
</h4>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Box size={16} color="#6B7280" />
|
||||
<span className="text-sm text-gray-600">نام محصول:</span>
|
||||
<span className="text-sm font-medium">{request.productName}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Tag size={16} color="#6B7280" />
|
||||
<span className="text-sm text-gray-600">برند:</span>
|
||||
<span className="text-sm font-medium">{request.brand?.title_fa || '-'}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<MessageSquare size={16} color="#6B7280" />
|
||||
<span className="text-sm text-gray-600">دستهبندی:</span>
|
||||
<span className="text-sm font-medium">{request.category?.title_fa || '-'}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Tag size={16} color="#6B7280" />
|
||||
<span className="text-sm text-gray-600">منبع:</span>
|
||||
<span className="text-sm font-medium">{request.source || '-'}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* توضیحات */}
|
||||
<div className="bg-green-50 rounded-lg p-4">
|
||||
<h4 className="text-md font-medium text-gray-900 mb-3">توضیحات</h4>
|
||||
<p className="text-sm text-gray-700 leading-relaxed">{String(request.description || 'توضیحاتی وارد نشده')}</p>
|
||||
</div>
|
||||
|
||||
{/* ابعاد و وزن */}
|
||||
<div className="bg-yellow-50 rounded-lg p-4">
|
||||
<h4 className="text-md font-medium text-gray-900 mb-3 flex items-center gap-2">
|
||||
<Box size={20} color="#92400E" />
|
||||
ابعاد و وزن
|
||||
</h4>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
<div className="text-center">
|
||||
<div className="text-lg font-semibold text-gray-900">{request.dimensions?.package_weight || 0}</div>
|
||||
<div className="text-xs text-gray-600">وزن (گرم)</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-lg font-semibold text-gray-900">{request.dimensions?.package_length || 0}</div>
|
||||
<div className="text-xs text-gray-600">طول (سانتیمتر)</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-lg font-semibold text-gray-900">{request.dimensions?.package_width || 0}</div>
|
||||
<div className="text-xs text-gray-600">عرض (سانتیمتر)</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-lg font-semibold text-gray-900">{request.dimensions?.package_height || 0}</div>
|
||||
<div className="text-xs text-gray-600">ارتفاع (سانتیمتر)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* مزایا و معایب */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="bg-green-50 rounded-lg p-4">
|
||||
<h4 className="text-md font-medium text-green-900 mb-3">مزایا</h4>
|
||||
{request.advantages && request.advantages.length > 0 ? (
|
||||
<ul className="space-y-1">
|
||||
{request.advantages.map((advantage, index) => (
|
||||
<li key={index} className="text-sm text-green-800 flex items-center gap-2">
|
||||
<span className="w-1.5 h-1.5 bg-green-600 rounded-full"></span>
|
||||
{String(advantage)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<p className="text-sm text-gray-600">مزایایی وارد نشده</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="bg-red-50 rounded-lg p-4">
|
||||
<h4 className="text-md font-medium text-red-900 mb-3">معایب</h4>
|
||||
{request.disAdvantages && request.disAdvantages.length > 0 ? (
|
||||
<ul className="space-y-1">
|
||||
{request.disAdvantages.map((disadvantage, index) => (
|
||||
<li key={index} className="text-sm text-red-800 flex items-center gap-2">
|
||||
<span className="w-1.5 h-1.5 bg-red-600 rounded-full"></span>
|
||||
{String(disadvantage)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<p className="text-sm text-gray-600">معایبی وارد نشده</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* خدمات درخواست شده */}
|
||||
<div className="bg-purple-50 rounded-lg p-4">
|
||||
<h4 className="text-md font-medium text-gray-900 mb-3">خدمات درخواست شده</h4>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={request.requestPhotography}
|
||||
readOnly
|
||||
className="rounded border-gray-300"
|
||||
/>
|
||||
<span className="text-sm">📸 عکاسی محصول</span>
|
||||
{request.requestPhotosCount && (
|
||||
<span className="text-xs text-gray-600">({request.requestPhotosCount} عکس)</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={request.expertReview}
|
||||
readOnly
|
||||
className="rounded border-gray-300"
|
||||
/>
|
||||
<span className="text-sm">👨💼 بررسی تخصصی</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={request.unboxingVideo}
|
||||
readOnly
|
||||
className="rounded border-gray-300"
|
||||
/>
|
||||
<span className="text-sm">📦 ویدیو باز کردن بسته</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* اطلاعات پرداخت */}
|
||||
{request.payment && (
|
||||
<div className="bg-indigo-50 rounded-lg p-4">
|
||||
<h4 className="text-md font-medium text-gray-900 mb-3 flex items-center gap-2">
|
||||
<Money size={20} color="#312E81" />
|
||||
اطلاعات پرداخت
|
||||
</h4>
|
||||
<div className="text-sm text-gray-700">
|
||||
<pre className="whitespace-pre-wrap">{String(JSON.stringify(request.payment, null, 2))}</pre>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* تاریخ ایجاد */}
|
||||
<div className="flex items-center justify-between text-sm text-gray-600 border-t pt-4">
|
||||
<span>تاریخ ایجاد:</span>
|
||||
<div className="flex items-center gap-1">
|
||||
<Calendar size={16} color="#6B7280" />
|
||||
<span>{formatDate(request._id ? new Date().toISOString() : '')}</span>
|
||||
</div>
|
||||
</div>
|
||||
<p>در حال حاضر این modal در حال توسعه است.</p>
|
||||
</div>
|
||||
</DefaulModal>
|
||||
)
|
||||
}
|
||||
|
||||
export default ProductRequestDetailModal
|
||||
export default ProductRequestDetailModal
|
||||
@@ -1,5 +1,9 @@
|
||||
import * as api from "../service/SellerService";
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import type {
|
||||
CreateCategoryLearning,
|
||||
CreateLearningType,
|
||||
} from "../types/Types";
|
||||
|
||||
export const useGetSellers = (page: number = 1, enabled: boolean = true) => {
|
||||
return useQuery({
|
||||
@@ -66,3 +70,48 @@ export const useGetRequestCreateProduct = (page: number = 1) => {
|
||||
queryFn: () => api.getRequestCreateProduct(page),
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetLearningCategory = () => {
|
||||
return useQuery({
|
||||
queryKey: ["learning-category"],
|
||||
queryFn: () => api.getLearningCategory(),
|
||||
});
|
||||
};
|
||||
|
||||
export const useCreateLearningCategory = () => {
|
||||
return useMutation({
|
||||
mutationFn: api.createLearningCategory,
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateLearningCategory = () => {
|
||||
return useMutation({
|
||||
mutationFn: ({
|
||||
id,
|
||||
params,
|
||||
}: {
|
||||
id: string;
|
||||
params: CreateCategoryLearning;
|
||||
}) => api.updateLearningCategory(id, params),
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetLearning = () => {
|
||||
return useQuery({
|
||||
queryKey: ["learning"],
|
||||
queryFn: () => api.getLearning(),
|
||||
});
|
||||
};
|
||||
|
||||
export const useCreateLearning = () => {
|
||||
return useMutation({
|
||||
mutationFn: api.createLearning,
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateLearning = () => {
|
||||
return useMutation({
|
||||
mutationFn: ({ id, params }: { id: string; params: CreateLearningType }) =>
|
||||
api.updateLearning(id, params),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -7,6 +7,9 @@ import type {
|
||||
NotificationsResponse,
|
||||
CreateAnnouncementSpecificSeller,
|
||||
GetRequestCreateProductResponse,
|
||||
CreateCategoryLearning,
|
||||
GetLearningCategoryResponse,
|
||||
CreateLearningType,
|
||||
} from "../types/Types";
|
||||
|
||||
export const getSellers = async (
|
||||
@@ -87,3 +90,46 @@ export const getRequestCreateProduct = async (
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getLearningCategory = async (): Promise<
|
||||
GetLearningCategoryResponse
|
||||
> => {
|
||||
const { data } = await axios.get(`/learning/category`);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const createLearningCategory = async (
|
||||
params: CreateCategoryLearning
|
||||
) => {
|
||||
const { data } = await axios.post(`/admin/learning/category`, params);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const updateLearningCategory = async (
|
||||
id: string,
|
||||
params: CreateCategoryLearning
|
||||
) => {
|
||||
const { data } = await axios.patch(
|
||||
`/admin/learning/category/${id}/update`,
|
||||
params
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getLearning = async () => {
|
||||
const { data } = await axios.get(`/learning`);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const createLearning = async (params: CreateLearningType) => {
|
||||
const { data } = await axios.post(`/admin/learning`, params);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const updateLearning = async (
|
||||
id: string,
|
||||
params: CreateLearningType
|
||||
) => {
|
||||
const { data } = await axios.patch(`/admin/learning/${id}/update`, params);
|
||||
return data;
|
||||
};
|
||||
|
||||
@@ -217,6 +217,22 @@ export interface CreateCategoryLearning {
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface LearningCategory {
|
||||
_id: string;
|
||||
title: string;
|
||||
deleted: boolean;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface GetLearningCategoryResponse {
|
||||
status: number;
|
||||
success: boolean;
|
||||
results: {
|
||||
learningCategory: LearningCategory[];
|
||||
};
|
||||
}
|
||||
|
||||
// Product Request Types
|
||||
export interface City {
|
||||
_id: number;
|
||||
@@ -318,3 +334,11 @@ export interface GetRequestCreateProductResponse {
|
||||
pager: Pager;
|
||||
};
|
||||
}
|
||||
|
||||
export interface CreateLearningType {
|
||||
title: string;
|
||||
description: string;
|
||||
videoUrl: string;
|
||||
cover: string;
|
||||
category: string;
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ import WholeSaleRequest from '@/pages/seller/WholeSaleRequest'
|
||||
import WithdrawalRequestPage from '@/pages/seller/WithdrawalRequest'
|
||||
import Annoncement from '@/pages/seller/Annoncement'
|
||||
import RequestCreateProduct from '@/pages/seller/RequestCreateProduct'
|
||||
import CategoryLearning from '@/pages/seller/CategoryLearning'
|
||||
const MainRouter: FC = () => {
|
||||
|
||||
const { hasSubMenu } = useSharedStore()
|
||||
@@ -167,6 +168,8 @@ const MainRouter: FC = () => {
|
||||
<Route path={Pages.sellers.withdrawalRequests} element={<WithdrawalRequestPage />} />
|
||||
<Route path={Pages.sellers.announcement} element={<Annoncement />} />
|
||||
<Route path={Pages.sellers.requestCreateProduct} element={<RequestCreateProduct />} />
|
||||
<Route path={Pages.sellers.learningCategory} element={<CategoryLearning />} />
|
||||
{/* <Route path={Pages.sellers.learning} element={<Learning />} /> */}
|
||||
</Routes>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -528,13 +528,13 @@ const SellersSubMenu: FC = () => {
|
||||
/>
|
||||
<SubMenuItem
|
||||
title={'آموزش ها'}
|
||||
isActive={isActive('trainings')}
|
||||
link="/sellers/trainings"
|
||||
isActive={isActive('learning')}
|
||||
link={Pages.sellers.learning}
|
||||
/>
|
||||
<SubMenuItem
|
||||
title={'دسته بندی آموزش ها'}
|
||||
isActive={isActive('training-categories')}
|
||||
link="/sellers/training-categories"
|
||||
isActive={isActive('category')}
|
||||
link={Pages.sellers.learningCategory}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user