banner mobile
This commit is contained in:
@@ -9,6 +9,7 @@ type Props = {
|
|||||||
isMultiple?: boolean,
|
isMultiple?: boolean,
|
||||||
onChange?: (file: File[]) => void;
|
onChange?: (file: File[]) => void;
|
||||||
isReset?: boolean;
|
isReset?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UploadBox: FC<Props> = (props: Props) => {
|
const UploadBox: FC<Props> = (props: Props) => {
|
||||||
@@ -17,6 +18,9 @@ const UploadBox: FC<Props> = (props: Props) => {
|
|||||||
const [files, setFiles] = useState<File[]>([])
|
const [files, setFiles] = useState<File[]>([])
|
||||||
|
|
||||||
const onDrop = useCallback((acceptedFiles: File[]) => {
|
const onDrop = useCallback((acceptedFiles: File[]) => {
|
||||||
|
if (props.disabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (props.isMultiple) {
|
if (props.isMultiple) {
|
||||||
const array = [...files]
|
const array = [...files]
|
||||||
array.push(acceptedFiles[0])
|
array.push(acceptedFiles[0])
|
||||||
@@ -31,8 +35,8 @@ const UploadBox: FC<Props> = (props: Props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [files])
|
}, [files, props.disabled, props.isMultiple, props.onChange])
|
||||||
const { getRootProps, getInputProps } = useDropzone({ onDrop })
|
const { getRootProps, getInputProps } = useDropzone({ onDrop, disabled: props.disabled })
|
||||||
|
|
||||||
const handleRemove = (index: number) => {
|
const handleRemove = (index: number) => {
|
||||||
const array = [...files]
|
const array = [...files]
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { useState, type FC } from 'react'
|
import { useState, type FC } from 'react'
|
||||||
import PageTitle from '../../components/PageTitle'
|
import PageTitle from '@/components/PageTitle'
|
||||||
import { useDeleteBanner, useGetBanners, useUpdateBanner } from './hooks/useSettingData'
|
import PageLoading from '@/components/PageLoading'
|
||||||
import { type BannerItem, type UpdateBannerType } from './types/Types'
|
import Error from '@/components/Error'
|
||||||
import PageLoading from '../../components/PageLoading'
|
import Td from '@/components/Td'
|
||||||
import Error from '../../components/Error'
|
import Button from '@/components/Button'
|
||||||
import Td from '../../components/Td'
|
import TrashWithConfrim from '@/components/TrashWithConfrim'
|
||||||
|
import Switch from '@/components/Switch'
|
||||||
|
import { useDeleteBanner, useGetBanners, useUpdateBanner } from '@/pages/setting/hooks/useSettingData'
|
||||||
|
import { type BannerItem, type UpdateBannerType } from '@/pages/setting/types/Types'
|
||||||
import { Calendar, Add, Edit, Eye } from 'iconsax-react'
|
import { Calendar, Add, Edit, Eye } from 'iconsax-react'
|
||||||
import Button from '../../components/Button'
|
|
||||||
import TrashWithConfrim from '../../components/TrashWithConfrim'
|
|
||||||
import Switch from '../../components/Switch'
|
|
||||||
import CreateBannerModal from './components/CreateBannerModal'
|
import CreateBannerModal from './components/CreateBannerModal'
|
||||||
import EditBannerModal from './components/EditBannerModal'
|
import EditBannerModal from './components/EditBannerModal'
|
||||||
|
|
||||||
@@ -55,7 +55,8 @@ const Banners: FC = () => {
|
|||||||
title: banner.title,
|
title: banner.title,
|
||||||
linkUrl: banner.linkUrl,
|
linkUrl: banner.linkUrl,
|
||||||
isActive: !banner.isActive,
|
isActive: !banner.isActive,
|
||||||
order: banner.order
|
order: banner.order,
|
||||||
|
displayLocation: banner.displayLocation
|
||||||
}
|
}
|
||||||
|
|
||||||
updateBanner.mutate({ id: banner._id, params: updateData })
|
updateBanner.mutate({ id: banner._id, params: updateData })
|
||||||
@@ -87,6 +88,7 @@ const Banners: FC = () => {
|
|||||||
<Td text={'عنوان'} />
|
<Td text={'عنوان'} />
|
||||||
<Td text={'متن جایگزین'} />
|
<Td text={'متن جایگزین'} />
|
||||||
<Td text={'لینک'} />
|
<Td text={'لینک'} />
|
||||||
|
<Td text={'محل نمایش'} />
|
||||||
<Td text={'ترتیب'} />
|
<Td text={'ترتیب'} />
|
||||||
<Td text={'وضعیت'} />
|
<Td text={'وضعیت'} />
|
||||||
<Td text={'تاریخ ایجاد'} />
|
<Td text={'تاریخ ایجاد'} />
|
||||||
@@ -96,7 +98,7 @@ const Banners: FC = () => {
|
|||||||
<tbody>
|
<tbody>
|
||||||
{banners.length === 0 ? (
|
{banners.length === 0 ? (
|
||||||
<tr className='tr'>
|
<tr className='tr'>
|
||||||
<td colSpan={8} className="text-center py-8 text-gray-500">
|
<td colSpan={9} className="text-center py-8 text-gray-500">
|
||||||
هیچ بنری یافت نشد
|
هیچ بنری یافت نشد
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -137,6 +139,11 @@ const Banners: FC = () => {
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</Td>
|
</Td>
|
||||||
|
<Td text="">
|
||||||
|
<span className="capitalize">
|
||||||
|
{banner.displayLocation === 'desktop' ? 'دسکتاپ' : 'موبایل'}
|
||||||
|
</span>
|
||||||
|
</Td>
|
||||||
<Td text={banner.order.toString()} />
|
<Td text={banner.order.toString()} />
|
||||||
<Td text="">
|
<Td text="">
|
||||||
<Switch
|
<Switch
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { type FC } from 'react'
|
import { type FC } from 'react'
|
||||||
import Button from '../../../components/Button'
|
import Button from '@/components/Button'
|
||||||
import Input from '../../../components/Input'
|
import Input from '@/components/Input'
|
||||||
import DefaulModal from '../../../components/DefaulModal'
|
import DefaulModal from '@/components/DefaulModal'
|
||||||
import { useCreateBanner } from '../hooks/useSettingData'
|
import UploadBox from '@/components/UploadBox'
|
||||||
import { useUploadSingle } from '../../../pages/uploader/hooks/useUploaderData'
|
import Switch from '@/components/Switch'
|
||||||
import { type CreateBannerType } from '../types/Types'
|
import Select, { type ItemsSelectType } from '@/components/Select'
|
||||||
|
import { useCreateBanner } from '@/pages/setting/hooks/useSettingData'
|
||||||
|
import { useUploadSingle } from '@/pages/uploader/hooks/useUploaderData'
|
||||||
|
import { type CreateBannerType } from '@/pages/setting/types/Types'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
import { extractErrorMessage } from '@/helpers/utils'
|
import { extractErrorMessage } from '@/helpers/utils'
|
||||||
import UploadBox from '../../../components/UploadBox'
|
|
||||||
import Switch from '../../../components/Switch'
|
|
||||||
|
|
||||||
interface CreateBannerModalProps {
|
interface CreateBannerModalProps {
|
||||||
isOpen: boolean
|
isOpen: boolean
|
||||||
@@ -17,14 +18,24 @@ interface CreateBannerModalProps {
|
|||||||
onSuccess: () => void
|
onSuccess: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CreateBannerFormState = Omit<CreateBannerType, 'displayLocation'> & {
|
||||||
|
displayLocation: '' | 'desktop' | 'mobile'
|
||||||
|
}
|
||||||
|
|
||||||
|
const displayLocationOptions: ItemsSelectType[] = [
|
||||||
|
{ value: 'desktop', label: 'دسکتاپ' },
|
||||||
|
{ value: 'mobile', label: 'موبایل' }
|
||||||
|
]
|
||||||
|
|
||||||
const CreateBannerModal: FC<CreateBannerModalProps> = ({ isOpen, onClose }) => {
|
const CreateBannerModal: FC<CreateBannerModalProps> = ({ isOpen, onClose }) => {
|
||||||
const [formData, setFormData] = useState<CreateBannerType>({
|
const [formData, setFormData] = useState<CreateBannerFormState>({
|
||||||
imageUrl: '',
|
imageUrl: '',
|
||||||
altText: '',
|
altText: '',
|
||||||
title: '',
|
title: '',
|
||||||
linkUrl: '',
|
linkUrl: '',
|
||||||
isActive: true,
|
isActive: true,
|
||||||
order: 1,
|
order: 1,
|
||||||
|
displayLocation: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
const [imageFile, setImageFile] = useState<File[]>([])
|
const [imageFile, setImageFile] = useState<File[]>([])
|
||||||
@@ -40,6 +51,11 @@ const CreateBannerModal: FC<CreateBannerModalProps> = ({ isOpen, onClose }) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!formData.displayLocation) {
|
||||||
|
toast.error('لطفا محل نمایش بنر را مشخص کنید')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (imageFile.length === 0) {
|
if (imageFile.length === 0) {
|
||||||
toast.error('لطفا تصویر بنر را انتخاب کنید')
|
toast.error('لطفا تصویر بنر را انتخاب کنید')
|
||||||
return
|
return
|
||||||
@@ -68,6 +84,7 @@ const CreateBannerModal: FC<CreateBannerModalProps> = ({ isOpen, onClose }) => {
|
|||||||
linkUrl: formData.linkUrl,
|
linkUrl: formData.linkUrl,
|
||||||
isActive: formData.isActive,
|
isActive: formData.isActive,
|
||||||
order: formData.order,
|
order: formData.order,
|
||||||
|
displayLocation: formData.displayLocation,
|
||||||
}, {
|
}, {
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
toast.error(extractErrorMessage(error))
|
toast.error(extractErrorMessage(error))
|
||||||
@@ -89,6 +106,7 @@ const CreateBannerModal: FC<CreateBannerModalProps> = ({ isOpen, onClose }) => {
|
|||||||
linkUrl: '',
|
linkUrl: '',
|
||||||
isActive: true,
|
isActive: true,
|
||||||
order: 1,
|
order: 1,
|
||||||
|
displayLocation: '',
|
||||||
})
|
})
|
||||||
setImageFile([])
|
setImageFile([])
|
||||||
onClose()
|
onClose()
|
||||||
@@ -97,12 +115,25 @@ const CreateBannerModal: FC<CreateBannerModalProps> = ({ isOpen, onClose }) => {
|
|||||||
return (
|
return (
|
||||||
<DefaulModal open={isOpen} close={handleClose} isHeader={true} title_header="افزودن بنر جدید">
|
<DefaulModal open={isOpen} close={handleClose} isHeader={true} title_header="افزودن بنر جدید">
|
||||||
<form onSubmit={handleSubmit} className="w-[500px] mt-4 space-y-6">
|
<form onSubmit={handleSubmit} className="w-[500px] mt-4 space-y-6">
|
||||||
|
{/* محل نمایش */}
|
||||||
|
<div>
|
||||||
|
<Select
|
||||||
|
label='محل نمایش'
|
||||||
|
placeholder='انتخاب محل نمایش'
|
||||||
|
items={displayLocationOptions}
|
||||||
|
value={formData.displayLocation}
|
||||||
|
onChange={(e) => setFormData(prev => ({ ...prev, displayLocation: e.target.value as CreateBannerFormState['displayLocation'] }))}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* تصویر بنر */}
|
{/* تصویر بنر */}
|
||||||
<div>
|
<div>
|
||||||
<UploadBox
|
<UploadBox
|
||||||
label='تصویر بنر'
|
label='تصویر بنر'
|
||||||
isMultiple={false}
|
isMultiple={false}
|
||||||
onChange={(files) => setImageFile(files)}
|
onChange={(files) => setImageFile(files)}
|
||||||
|
disabled={!formData.displayLocation}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import { type FC } from 'react'
|
import { type FC } from 'react'
|
||||||
import Button from '../../../components/Button'
|
import Button from '@/components/Button'
|
||||||
import Input from '../../../components/Input'
|
import Input from '@/components/Input'
|
||||||
import DefaulModal from '../../../components/DefaulModal'
|
import DefaulModal from '@/components/DefaulModal'
|
||||||
import { useUpdateBanner } from '../hooks/useSettingData'
|
import UploadBox from '@/components/UploadBox'
|
||||||
import { useUploadSingle } from '../../../pages/uploader/hooks/useUploaderData'
|
import Switch from '@/components/Switch'
|
||||||
import { type BannerItem, type UpdateBannerType } from '../types/Types'
|
import Select, { type ItemsSelectType } from '@/components/Select'
|
||||||
|
import { useUpdateBanner } from '@/pages/setting/hooks/useSettingData'
|
||||||
|
import { useUploadSingle } from '@/pages/uploader/hooks/useUploaderData'
|
||||||
|
import { type BannerItem, type UpdateBannerType } from '@/pages/setting/types/Types'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
import { extractErrorMessage } from '@/helpers/utils'
|
import { extractErrorMessage } from '@/helpers/utils'
|
||||||
import UploadBox from '../../../components/UploadBox'
|
|
||||||
import Switch from '../../../components/Switch'
|
|
||||||
|
|
||||||
interface EditBannerModalProps {
|
interface EditBannerModalProps {
|
||||||
banner: BannerItem
|
banner: BannerItem
|
||||||
@@ -18,6 +19,11 @@ interface EditBannerModalProps {
|
|||||||
onSuccess: () => void
|
onSuccess: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const displayLocationOptions: ItemsSelectType[] = [
|
||||||
|
{ value: 'desktop', label: 'دسکتاپ' },
|
||||||
|
{ value: 'mobile', label: 'موبایل' }
|
||||||
|
]
|
||||||
|
|
||||||
const EditBannerModal: FC<EditBannerModalProps> = ({ banner, isOpen, onClose, onSuccess }) => {
|
const EditBannerModal: FC<EditBannerModalProps> = ({ banner, isOpen, onClose, onSuccess }) => {
|
||||||
const [formData, setFormData] = useState<UpdateBannerType>({
|
const [formData, setFormData] = useState<UpdateBannerType>({
|
||||||
imageUrl: '',
|
imageUrl: '',
|
||||||
@@ -26,6 +32,7 @@ const EditBannerModal: FC<EditBannerModalProps> = ({ banner, isOpen, onClose, on
|
|||||||
linkUrl: '',
|
linkUrl: '',
|
||||||
isActive: true,
|
isActive: true,
|
||||||
order: 1,
|
order: 1,
|
||||||
|
displayLocation: 'desktop',
|
||||||
})
|
})
|
||||||
|
|
||||||
const [imageFile, setImageFile] = useState<File[]>([])
|
const [imageFile, setImageFile] = useState<File[]>([])
|
||||||
@@ -42,6 +49,7 @@ const EditBannerModal: FC<EditBannerModalProps> = ({ banner, isOpen, onClose, on
|
|||||||
linkUrl: banner.linkUrl,
|
linkUrl: banner.linkUrl,
|
||||||
isActive: banner.isActive,
|
isActive: banner.isActive,
|
||||||
order: banner.order,
|
order: banner.order,
|
||||||
|
displayLocation: banner.displayLocation,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, [banner])
|
}, [banner])
|
||||||
@@ -59,6 +67,11 @@ const EditBannerModal: FC<EditBannerModalProps> = ({ banner, isOpen, onClose, on
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!formData.displayLocation) {
|
||||||
|
toast.error('لطفا محل نمایش بنر را مشخص کنید')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let finalImageUrl = formData.imageUrl
|
let finalImageUrl = formData.imageUrl
|
||||||
|
|
||||||
@@ -83,6 +96,7 @@ const EditBannerModal: FC<EditBannerModalProps> = ({ banner, isOpen, onClose, on
|
|||||||
linkUrl: formData.linkUrl,
|
linkUrl: formData.linkUrl,
|
||||||
isActive: formData.isActive,
|
isActive: formData.isActive,
|
||||||
order: formData.order,
|
order: formData.order,
|
||||||
|
displayLocation: formData.displayLocation,
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
@@ -106,6 +120,7 @@ const EditBannerModal: FC<EditBannerModalProps> = ({ banner, isOpen, onClose, on
|
|||||||
linkUrl: '',
|
linkUrl: '',
|
||||||
isActive: true,
|
isActive: true,
|
||||||
order: 1,
|
order: 1,
|
||||||
|
displayLocation: 'desktop',
|
||||||
})
|
})
|
||||||
setImageFile([])
|
setImageFile([])
|
||||||
onClose()
|
onClose()
|
||||||
@@ -114,6 +129,17 @@ const EditBannerModal: FC<EditBannerModalProps> = ({ banner, isOpen, onClose, on
|
|||||||
return (
|
return (
|
||||||
<DefaulModal open={isOpen} close={handleClose} isHeader={true} title_header="ویرایش بنر">
|
<DefaulModal open={isOpen} close={handleClose} isHeader={true} title_header="ویرایش بنر">
|
||||||
<form onSubmit={handleSubmit} className="w-[500px] mt-4 space-y-6">
|
<form onSubmit={handleSubmit} className="w-[500px] mt-4 space-y-6">
|
||||||
|
{/* محل نمایش */}
|
||||||
|
<div>
|
||||||
|
<Select
|
||||||
|
label='محل نمایش'
|
||||||
|
items={displayLocationOptions}
|
||||||
|
value={formData.displayLocation}
|
||||||
|
onChange={(e) => setFormData(prev => ({ ...prev, displayLocation: e.target.value as UpdateBannerType['displayLocation'] }))}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* تصویر بنر */}
|
{/* تصویر بنر */}
|
||||||
<div>
|
<div>
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
|
|||||||
@@ -220,6 +220,7 @@ export interface BannerItem {
|
|||||||
linkUrl: string;
|
linkUrl: string;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
order: number;
|
order: number;
|
||||||
|
displayLocation: "desktop" | "mobile";
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
}
|
}
|
||||||
@@ -241,6 +242,7 @@ export interface CreateBannerType {
|
|||||||
linkUrl: string;
|
linkUrl: string;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
order: number;
|
order: number;
|
||||||
|
displayLocation: "desktop" | "mobile";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateBannerType {
|
export interface UpdateBannerType {
|
||||||
@@ -250,6 +252,7 @@ export interface UpdateBannerType {
|
|||||||
linkUrl: string;
|
linkUrl: string;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
order: number;
|
order: number;
|
||||||
|
displayLocation: "desktop" | "mobile";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SliderItem {
|
export interface SliderItem {
|
||||||
|
|||||||
Reference in New Issue
Block a user