This commit is contained in:
@@ -1,267 +1,245 @@
|
||||
import Button from '@/components/Button'
|
||||
import ColorPicker from '@/components/ColorPicker'
|
||||
import Input from '@/components/Input'
|
||||
import Textarea from '@/components/Textarea'
|
||||
import UploadBox from '@/components/UploadBox'
|
||||
import DefaulModal from '@/components/DefaulModal'
|
||||
import LocationPicker from './components/LocationPicker'
|
||||
import LocationInput from './components/LocationInput'
|
||||
import { TickCircle } from 'iconsax-react'
|
||||
import { type FC, useEffect, useState } from 'react'
|
||||
import { useGetRestaurant, useUpdateRestaurant } from './hooks/useSettingData'
|
||||
import { useSingleUpload } from '../uploader/hooks/useUploaderData'
|
||||
import type { UpdateRestaurantType } from './types/Types'
|
||||
import type { ErrorType } from '@/helpers/types'
|
||||
import { useFormik } from 'formik'
|
||||
import * as yup from 'yup'
|
||||
import { toast } from 'react-toastify'
|
||||
import { extractErrorMessage } from '@/config/func'
|
||||
import ServiceAreaPicker from './components/ServiceAreaPicker'
|
||||
import Button from "@/components/Button";
|
||||
import ColorPicker from "@/components/ColorPicker";
|
||||
import DefaulModal from "@/components/DefaulModal";
|
||||
import Input from "@/components/Input";
|
||||
import Textarea from "@/components/Textarea";
|
||||
import UploadBox from "@/components/UploadBox";
|
||||
import { extractErrorMessage } from "@/config/func";
|
||||
import type { ErrorType } from "@/helpers/types";
|
||||
import { useFormik } from "formik";
|
||||
import { TickCircle } from "iconsax-react";
|
||||
import { type FC, useEffect, useState } from "react";
|
||||
import { toast } from "react-toastify";
|
||||
import * as yup from "yup";
|
||||
import { useSingleUpload } from "../uploader/hooks/useUploaderData";
|
||||
import LocationInput from "./components/LocationInput";
|
||||
import LocationPicker from "./components/LocationPicker";
|
||||
import ServiceAreaPicker from "./components/ServiceAreaPicker";
|
||||
import { useGetRestaurant, useUpdateRestaurant } from "./hooks/useSettingData";
|
||||
import type { UpdateRestaurantType } from "./types/Types";
|
||||
|
||||
const validationSchema = yup.object({
|
||||
name: yup.string().required('نام فروشگاه الزامی است'),
|
||||
menuColor: yup.string().required('رنگ منو الزامی است'),
|
||||
phone: yup.string().required('شماره تماس الزامی است'),
|
||||
instagram: yup.string().url('لینک اینستاگرام معتبر نیست').nullable(),
|
||||
address: yup.string().required('آدرس الزامی است'),
|
||||
latitude: yup.number().required('انتخاب موقعیت روی نقشه الزامی است'),
|
||||
longitude: yup.number().required('انتخاب موقعیت روی نقشه الزامی است'),
|
||||
description: yup.string().nullable(),
|
||||
})
|
||||
name: yup.string().required("نام فروشگاه الزامی است"),
|
||||
menuColor: yup.string().required("رنگ منو الزامی است"),
|
||||
phone: yup.string().required("شماره تماس الزامی است"),
|
||||
instagram: yup.string().url("لینک اینستاگرام معتبر نیست").nullable(),
|
||||
address: yup.string().required("آدرس الزامی است"),
|
||||
latitude: yup.number().required("انتخاب موقعیت روی نقشه الزامی است"),
|
||||
longitude: yup.number().required("انتخاب موقعیت روی نقشه الزامی است"),
|
||||
description: yup.string().nullable(),
|
||||
establishedYear: yup
|
||||
.string()
|
||||
.nullable()
|
||||
.matches(/^$|^\d{4}$/, "سال تاسیس باید ۴ رقم باشد"),
|
||||
});
|
||||
|
||||
const GeneralSettings: FC = () => {
|
||||
const { data: restaurant, refetch } = useGetRestaurant()
|
||||
const { mutate: updateRestaurant, isPending } = useUpdateRestaurant()
|
||||
const { mutate: singleUpload, isPending: isUploading } = useSingleUpload()
|
||||
const [isLocationModalOpen, setIsLocationModalOpen] = useState(false)
|
||||
const [logoFile, setLogoFile] = useState<File[]>([])
|
||||
const { data: restaurant, refetch } = useGetRestaurant();
|
||||
const { mutate: updateRestaurant, isPending } = useUpdateRestaurant();
|
||||
const { mutate: singleUpload, isPending: isUploading } = useSingleUpload();
|
||||
const [isLocationModalOpen, setIsLocationModalOpen] = useState(false);
|
||||
const [logoFile, setLogoFile] = useState<File[]>([]);
|
||||
|
||||
const formik = useFormik<UpdateRestaurantType>({
|
||||
initialValues: {
|
||||
name: '',
|
||||
menuColor: '#000000',
|
||||
phone: '',
|
||||
instagram: '',
|
||||
address: '',
|
||||
latitude: 0,
|
||||
longitude: 0,
|
||||
description: '',
|
||||
logo: '',
|
||||
serviceArea: undefined,
|
||||
},
|
||||
validationSchema,
|
||||
onSubmit: (values) => {
|
||||
const submitSettings = (logoUrl?: string) => {
|
||||
const settingsData: UpdateRestaurantType = {
|
||||
...values,
|
||||
logo: logoUrl || values.logo || ''
|
||||
}
|
||||
const formik = useFormik<UpdateRestaurantType>({
|
||||
initialValues: {
|
||||
name: "",
|
||||
menuColor: "#000000",
|
||||
phone: "",
|
||||
instagram: "",
|
||||
address: "",
|
||||
latitude: 0,
|
||||
longitude: 0,
|
||||
description: "",
|
||||
logo: "",
|
||||
serviceArea: undefined,
|
||||
establishedYear: "",
|
||||
},
|
||||
validationSchema,
|
||||
onSubmit: (values) => {
|
||||
const submitSettings = (logoUrl?: string) => {
|
||||
const settingsData: UpdateRestaurantType = {
|
||||
...values,
|
||||
logo: logoUrl || values.logo || "",
|
||||
};
|
||||
|
||||
updateRestaurant(settingsData, {
|
||||
onSuccess: () => {
|
||||
toast.success('تنظیمات با موفقیت ذخیره شد')
|
||||
refetch()
|
||||
setLogoFile([])
|
||||
},
|
||||
onError: (error: unknown) => {
|
||||
toast.error('خطا در ذخیره تنظیمات')
|
||||
console.error(error)
|
||||
},
|
||||
})
|
||||
}
|
||||
updateRestaurant(settingsData, {
|
||||
onSuccess: () => {
|
||||
toast.success("تنظیمات با موفقیت ذخیره شد");
|
||||
refetch();
|
||||
setLogoFile([]);
|
||||
},
|
||||
onError: (error: unknown) => {
|
||||
toast.error("خطا در ذخیره تنظیمات");
|
||||
console.error(error);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
if (logoFile.length > 0) {
|
||||
singleUpload(logoFile[0], {
|
||||
onSuccess: (response) => {
|
||||
const logoUrl = response?.data?.url || ''
|
||||
submitSettings(logoUrl)
|
||||
},
|
||||
onError: (error: ErrorType) => {
|
||||
toast.error(extractErrorMessage(error, 'خطا در آپلود لوگو'))
|
||||
},
|
||||
})
|
||||
} else {
|
||||
submitSettings()
|
||||
}
|
||||
},
|
||||
enableReinitialize: true,
|
||||
})
|
||||
if (logoFile.length > 0) {
|
||||
singleUpload(logoFile[0], {
|
||||
onSuccess: (response) => {
|
||||
const logoUrl = response?.data?.url || "";
|
||||
submitSettings(logoUrl);
|
||||
},
|
||||
onError: (error: ErrorType) => {
|
||||
toast.error(extractErrorMessage(error, "خطا در آپلود لوگو"));
|
||||
},
|
||||
});
|
||||
} else {
|
||||
submitSettings();
|
||||
}
|
||||
},
|
||||
enableReinitialize: true,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (restaurant?.data) {
|
||||
const restaurantData = restaurant.data
|
||||
formik.setValues({
|
||||
name: restaurantData.name || '',
|
||||
menuColor: restaurantData.menuColor || '#000000',
|
||||
phone: restaurantData.phone || '',
|
||||
instagram: restaurantData.instagram || '',
|
||||
address: restaurantData.address || '',
|
||||
latitude: restaurantData.latitude || 0,
|
||||
longitude: restaurantData.longitude || 0,
|
||||
description: restaurantData.description || '',
|
||||
logo: restaurantData.logo || '',
|
||||
serviceArea: restaurantData.serviceArea || undefined,
|
||||
})
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [restaurant])
|
||||
|
||||
const handleLocationSelect = (lat: number, lng: number) => {
|
||||
formik.setFieldValue('latitude', lat)
|
||||
formik.setFieldValue('longitude', lng)
|
||||
setIsLocationModalOpen(false)
|
||||
useEffect(() => {
|
||||
if (restaurant?.data) {
|
||||
const restaurantData = restaurant.data;
|
||||
formik.setValues({
|
||||
name: restaurantData.name || "",
|
||||
menuColor: restaurantData.menuColor || "#000000",
|
||||
phone: restaurantData.phone || "",
|
||||
instagram: restaurantData.instagram || "",
|
||||
address: restaurantData.address || "",
|
||||
latitude: restaurantData.latitude || 0,
|
||||
longitude: restaurantData.longitude || 0,
|
||||
description: restaurantData.description || "",
|
||||
logo: restaurantData.logo || "",
|
||||
serviceArea: restaurantData.serviceArea || undefined,
|
||||
establishedYear: restaurantData.establishedYear?.toString() || "",
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [restaurant]);
|
||||
|
||||
const handleLocationSelect = (lat: number, lng: number) => {
|
||||
formik.setFieldValue("latitude", lat);
|
||||
formik.setFieldValue("longitude", lng);
|
||||
setIsLocationModalOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='bg-white rounded-4xl p-8'>
|
||||
<div className='text-lg font-light'>
|
||||
تنظیمات عمومی
|
||||
</div>
|
||||
return (
|
||||
<>
|
||||
<div className="bg-white rounded-4xl p-8">
|
||||
<div className="text-lg font-light">تنظیمات عمومی</div>
|
||||
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<div className='mt-8 rowTwoInput'>
|
||||
<Input
|
||||
label='نام فروشگاه'
|
||||
name='name'
|
||||
value={formik.values.name}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error_text={formik.touched.name && formik.errors.name ? formik.errors.name : undefined}
|
||||
/>
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<div className="mt-8 rowTwoInput">
|
||||
<Input
|
||||
label="نام فروشگاه"
|
||||
name="name"
|
||||
value={formik.values.name}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error_text={formik.touched.name && formik.errors.name ? formik.errors.name : undefined}
|
||||
/>
|
||||
|
||||
<ColorPicker
|
||||
label='رنگ منو'
|
||||
value={formik.values.menuColor}
|
||||
onChange={(value) => formik.setFieldValue('menuColor', value)}
|
||||
error_text={formik.touched.menuColor && formik.errors.menuColor ? formik.errors.menuColor : undefined}
|
||||
/>
|
||||
</div>
|
||||
<ColorPicker
|
||||
label="رنگ منو"
|
||||
value={formik.values.menuColor}
|
||||
onChange={(value) => formik.setFieldValue("menuColor", value)}
|
||||
error_text={formik.touched.menuColor && formik.errors.menuColor ? formik.errors.menuColor : undefined}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-8'>
|
||||
<UploadBox
|
||||
label='لوگو'
|
||||
onChange={(files) => setLogoFile(files)}
|
||||
isReset={logoFile.length === 0 && !formik.values.logo}
|
||||
/>
|
||||
<div className="mt-8">
|
||||
<UploadBox label="لوگو" onChange={(files) => setLogoFile(files)} isReset={logoFile.length === 0 && !formik.values.logo} />
|
||||
|
||||
{
|
||||
formik.values.logo && (
|
||||
<div className='mt-3'>
|
||||
<img src={formik.values.logo} alt='logo' className='w-20 h-20 rounded-full' />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
{formik.values.logo && (
|
||||
<div className="mt-3">
|
||||
<img src={formik.values.logo} alt="logo" className="w-20 h-20 rounded-full" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className='mt-8 rowTwoInput'>
|
||||
<Input
|
||||
label='شماره تماس'
|
||||
name='phone'
|
||||
value={formik.values.phone}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error_text={formik.touched.phone && formik.errors.phone ? formik.errors.phone : undefined}
|
||||
/>
|
||||
<div className="mt-8 rowTwoInput">
|
||||
<Input
|
||||
label="شماره تماس"
|
||||
name="phone"
|
||||
value={formik.values.phone}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error_text={formik.touched.phone && formik.errors.phone ? formik.errors.phone : undefined}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label='اینستاگرام'
|
||||
name='instagram'
|
||||
value={formik.values.instagram}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error_text={formik.touched.instagram && formik.errors.instagram ? formik.errors.instagram : undefined}
|
||||
placeholder='https://instagram.com/...'
|
||||
/>
|
||||
</div>
|
||||
<Input
|
||||
label="اینستاگرام"
|
||||
name="instagram"
|
||||
value={formik.values.instagram}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error_text={formik.touched.instagram && formik.errors.instagram ? formik.errors.instagram : undefined}
|
||||
placeholder="https://instagram.com/..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-8'>
|
||||
<Textarea
|
||||
label='آدرس'
|
||||
name='address'
|
||||
value={formik.values.address}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error_text={formik.touched.address && formik.errors.address ? formik.errors.address : undefined}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-8 rowTwoInput">
|
||||
<Input
|
||||
label="سال تاسیس"
|
||||
name="establishedYear"
|
||||
type="number"
|
||||
value={formik.values.establishedYear}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error_text={formik.touched.establishedYear && formik.errors.establishedYear ? formik.errors.establishedYear : undefined}
|
||||
placeholder="مثال: 1400"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<LocationInput
|
||||
label='موقعیت روی نقشه'
|
||||
latitude={formik.values.latitude}
|
||||
longitude={formik.values.longitude}
|
||||
onClick={() => setIsLocationModalOpen(true)}
|
||||
error_text={
|
||||
(formik.touched.latitude || formik.touched.longitude) && (formik.errors.latitude || formik.errors.longitude)
|
||||
? formik.errors.latitude || formik.errors.longitude
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
<div className="mt-8">
|
||||
<Textarea
|
||||
label="آدرس"
|
||||
name="address"
|
||||
value={formik.values.address}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error_text={formik.touched.address && formik.errors.address ? formik.errors.address : undefined}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-8'>
|
||||
<Textarea
|
||||
label='توضیحات'
|
||||
name='description'
|
||||
value={formik.values.description || ''}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error_text={formik.touched.description && formik.errors.description ? formik.errors.description : undefined}
|
||||
/>
|
||||
</div>
|
||||
<LocationInput
|
||||
label="موقعیت روی نقشه"
|
||||
latitude={formik.values.latitude}
|
||||
longitude={formik.values.longitude}
|
||||
onClick={() => setIsLocationModalOpen(true)}
|
||||
error_text={(formik.touched.latitude || formik.touched.longitude) && (formik.errors.latitude || formik.errors.longitude) ? formik.errors.latitude || formik.errors.longitude : undefined}
|
||||
/>
|
||||
|
||||
<div className='mt-8'>
|
||||
<ServiceAreaPicker
|
||||
initialPolygon={formik.values.serviceArea}
|
||||
onPolygonSelect={(polygon) => formik.setFieldValue('serviceArea', polygon)}
|
||||
/>
|
||||
</div>
|
||||
{/* </div> */}
|
||||
<div className="mt-8">
|
||||
<Textarea
|
||||
label="توضیحات"
|
||||
name="description"
|
||||
value={formik.values.description || ""}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error_text={formik.touched.description && formik.errors.description ? formik.errors.description : undefined}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-8 flex justify-end'>
|
||||
<Button
|
||||
type='submit'
|
||||
className='w-fit px-6'
|
||||
isloading={isPending || isUploading}
|
||||
disabled={isPending || isUploading}
|
||||
>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<TickCircle
|
||||
size={20}
|
||||
color='#fff'
|
||||
/>
|
||||
<span>ذخیره</span>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</form >
|
||||
</div >
|
||||
<div className="mt-8">
|
||||
<ServiceAreaPicker initialPolygon={formik.values.serviceArea} onPolygonSelect={(polygon) => formik.setFieldValue("serviceArea", polygon)} />
|
||||
</div>
|
||||
{/* </div> */}
|
||||
|
||||
<div className="mt-8 flex justify-end">
|
||||
<Button type="submit" className="w-fit px-6" isloading={isPending || isUploading} disabled={isPending || isUploading}>
|
||||
<div className="flex gap-2 items-center">
|
||||
<TickCircle size={20} color="#fff" />
|
||||
<span>ذخیره</span>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<DefaulModal open={isLocationModalOpen} close={() => setIsLocationModalOpen(false)} isHeader={true} title_header="انتخاب موقعیت روی نقشه" width={800}>
|
||||
<div className="p-4">
|
||||
<LocationPicker initialPosition={formik.values.latitude && formik.values.longitude ? [formik.values.latitude, formik.values.longitude] : undefined} onLocationSelect={handleLocationSelect} />
|
||||
<div className="mt-4 text-xs text-gray-600 text-center">روی نقشه کلیک کنید تا موقعیت را انتخاب کنید</div>
|
||||
</div>
|
||||
</DefaulModal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
<DefaulModal
|
||||
open={isLocationModalOpen}
|
||||
close={() => setIsLocationModalOpen(false)}
|
||||
isHeader={true}
|
||||
title_header='انتخاب موقعیت روی نقشه'
|
||||
width={800}
|
||||
>
|
||||
<div className='p-4'>
|
||||
<LocationPicker
|
||||
initialPosition={
|
||||
formik.values.latitude && formik.values.longitude
|
||||
? [formik.values.latitude, formik.values.longitude]
|
||||
: undefined
|
||||
}
|
||||
onLocationSelect={handleLocationSelect}
|
||||
/>
|
||||
<div className='mt-4 text-xs text-gray-600 text-center'>
|
||||
روی نقشه کلیک کنید تا موقعیت را انتخاب کنید
|
||||
</div>
|
||||
</div>
|
||||
</DefaulModal>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default GeneralSettings
|
||||
export default GeneralSettings;
|
||||
|
||||
@@ -17,6 +17,7 @@ export type UpdateRestaurantType = {
|
||||
latitude?: number;
|
||||
longitude?: number;
|
||||
description?: string;
|
||||
establishedYear?: string;
|
||||
serviceArea?: GeoJSONPolygon;
|
||||
score?: {
|
||||
purchaseAmount: string;
|
||||
|
||||
Reference in New Issue
Block a user