score setting

This commit is contained in:
hamid zarghami
2025-12-13 08:44:47 +03:30
parent 610a82c1d5
commit baa55860d4
4 changed files with 283 additions and 20 deletions
+5 -2
View File
@@ -49,13 +49,16 @@ const Input: FC<Props> = (props: Props) => {
setFormattedValue(formatted);
// ارسال مقدار خام به `onChange` والد
props.onChange?.({
const syntheticEvent = {
...event,
target: {
...event.target,
name: event.target.name,
value: inputValue,
},
});
} as React.ChangeEvent<HTMLInputElement>;
props.onChange?.(syntheticEvent);
} else {
props.onChange?.(event);
}
+7 -3
View File
@@ -1,8 +1,9 @@
import Tabs from '@/components/Tabs'
import { Card, KeySquare, Setting4, TruckFast } from 'iconsax-react'
import { KeySquare, Money2, Setting4, TruckFast } from 'iconsax-react'
import { useState, type FC } from 'react'
import { SettingTabEnum } from './enum/Enum'
import GeneralSettings from './GeneralSettings'
import ScoreSetting from './components/ScoreSetting'
const Setting: FC = () => {
@@ -26,8 +27,8 @@ const Setting: FC = () => {
value: SettingTabEnum.PASSWORD,
},
{
icon: <Card color={activeTab === SettingTabEnum.FINANCIAL ? 'black' : '#8C90A3'} size={24} />,
label: 'مالی',
icon: <Money2 color={activeTab === SettingTabEnum.FINANCIAL ? 'black' : '#8C90A3'} size={24} />,
label: 'تنظیمات امتیاز',
value: SettingTabEnum.FINANCIAL,
},
{
@@ -45,6 +46,9 @@ const Setting: FC = () => {
{
activeTab === SettingTabEnum.GENERAL && <GeneralSettings />
}
{
activeTab === SettingTabEnum.FINANCIAL && <ScoreSetting />
}
</div>
</div>
)
@@ -0,0 +1,235 @@
import { useEffect, useState, type FC } from 'react'
import { useGetRestaurant, useUpdateRestaurant } from '../hooks/useSettingData'
import type { UpdateRestaurantType } from '../types/Types'
import { useFormik } from 'formik'
import * as Yup from 'yup'
import Input from '@/components/Input'
import Button from '@/components/Button'
import { toast } from 'react-toastify'
interface FlatFormValues {
purchaseAmount: string
purchaseScore: string
scoreAmount: string
scoreCredit: string
birthdayScore: string
registerScore: string
marriageDateScore: string
referrerScore: string
}
const ScoreSetting: FC = () => {
const { data: restaurant } = useGetRestaurant()
const { mutate: updateRestaurant, isPending } = useUpdateRestaurant()
const [isInitialized, setIsInitialized] = useState(false)
const formik = useFormik<FlatFormValues>({
initialValues: {
purchaseAmount: '',
purchaseScore: '',
scoreAmount: '',
scoreCredit: '',
birthdayScore: '',
registerScore: '',
marriageDateScore: '',
referrerScore: '',
},
validationSchema: Yup.object().shape({
purchaseAmount: Yup.string().required('مبلغ خرید الزامی است'),
purchaseScore: Yup.string().required('امتیاز خرید الزامی است'),
scoreAmount: Yup.string().required('مبلغ امتیاز الزامی است'),
scoreCredit: Yup.string().required('مبلغ اعتبار الزامی است'),
birthdayScore: Yup.string().required('امتیاز تولد الزامی است'),
registerScore: Yup.string().required('امتیاز ثبت نام الزامی است'),
marriageDateScore: Yup.string().required('امتیاز سالگرد ازدواج الزامی است'),
referrerScore: Yup.string().required('امتیاز معرف الزامی است'),
}),
validateOnMount: false,
onSubmit: (values) => {
const payload: UpdateRestaurantType = {
score: {
purchaseAmount: values.purchaseAmount,
purchaseScore: values.purchaseScore,
scoreAmount: values.scoreAmount,
scoreCredit: values.scoreCredit,
birthdayScore: values.birthdayScore,
registerScore: values.registerScore,
marriageDateScore: values.marriageDateScore,
referrerScore: values.referrerScore,
},
}
updateRestaurant(payload, {
onSuccess: () => {
toast.success('تنظیمات امتیاز با موفقیت به‌روزرسانی شد')
},
onError: () => {
toast.error('خطا در به‌روزرسانی تنظیمات امتیاز')
},
})
},
})
const getFieldError = (fieldName: string): string | undefined => {
const meta = formik.getFieldMeta(fieldName)
return meta.touched && meta.error ? meta.error : undefined
}
useEffect(() => {
if (restaurant?.data?.score && !isInitialized) {
const scorePrice = restaurant.data.score
formik.setValues({
purchaseAmount: scorePrice.purchaseAmount != null ? String(scorePrice.purchaseAmount) : '',
purchaseScore: scorePrice.purchaseScore != null ? String(scorePrice.purchaseScore) : '',
scoreAmount: scorePrice.scoreAmount != null ? String(scorePrice.scoreAmount) : '',
scoreCredit: scorePrice.scoreCredit != null ? String(scorePrice.scoreCredit) : '',
birthdayScore: scorePrice.birthdayScore != null ? String(scorePrice.birthdayScore) : '',
registerScore: scorePrice.registerScore != null ? String(scorePrice.registerScore) : '',
marriageDateScore: scorePrice.marriageDateScore != null ? String(scorePrice.marriageDateScore) : '',
referrerScore: scorePrice.referrerScore != null ? String(scorePrice.referrerScore) : '',
}, false)
formik.setTouched({}, false)
setIsInitialized(true)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [restaurant, isInitialized])
return (
<form onSubmit={formik.handleSubmit} className='bg-white rounded-2xl p-6'>
{/* بخش امتیاز خرید */}
<div className='mb-8'>
<h2 className='text-base font-medium mb-6 text-right'>امتیاز خرید</h2>
{/* خط اول */}
<div className='flex items-center gap-3 mb-4'>
<div className='flex items-center gap-2'>
<span className='text-sm text-gray-700 whitespace-nowrap'>به ازای هر</span>
<Input
name='purchaseAmount'
value={formik.values.purchaseAmount}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error_text={getFieldError('purchaseAmount')}
placeholder='0'
seprator
className='w-[200px]'
/>
</div>
<div className='flex items-center gap-2'>
<span className='text-sm text-gray-700 whitespace-nowrap'>تومان خرید مقدار</span>
<Input
name='purchaseScore'
value={formik.values.purchaseScore}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error_text={getFieldError('purchaseScore')}
placeholder='0'
seprator
className='w-[200px]'
/>
</div>
<span className='text-sm text-gray-700 whitespace-nowrap'>امتیاز به مشتری داده میشود.</span>
</div>
{/* خط دوم */}
<div className='flex items-center gap-3'>
<div className='flex items-center gap-2'>
<span className='text-sm text-gray-700 whitespace-nowrap'>هر</span>
<Input
name='scoreAmount'
value={formik.values.scoreAmount}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error_text={getFieldError('scoreAmount')}
placeholder='0'
seprator
className='w-[200px]'
/>
</div>
<div className='flex items-center gap-2'>
<span className='text-sm text-gray-700 whitespace-nowrap'>امتیاز معادل</span>
<Input
name='scoreCredit'
value={formik.values.scoreCredit}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error_text={getFieldError('scoreCredit')}
placeholder='0'
seprator
className='w-[200px]'
/>
</div>
<span className='text-sm text-gray-700 whitespace-nowrap'>تومان اعتبار خرید است.</span>
</div>
</div>
{/* بخش امتیاز ثابت */}
<div className='mb-8'>
<h2 className='text-base font-medium mb-6 text-right'>امتیاز ثابت</h2>
<div className='grid grid-cols-1 md:grid-cols-2 gap-6 gap-x-8'>
<div className='space-y-4'>
<Input
label='امتیاز ثبت نام'
name='registerScore'
value={formik.values.registerScore}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error_text={getFieldError('registerScore')}
placeholder='0'
seprator
/>
<Input
label='امتیاز تاریخ تولد'
name='birthdayScore'
value={formik.values.birthdayScore}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error_text={getFieldError('birthdayScore')}
placeholder='0'
seprator
/>
</div>
<div className='space-y-4'>
<Input
label='امتیاز تاریخ ازدواج'
name='marriageDateScore'
value={formik.values.marriageDateScore}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error_text={getFieldError('marriageDateScore')}
placeholder='0'
seprator
/>
<Input
label='امتیاز دعوت'
name='referrerScore'
value={formik.values.referrerScore}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error_text={getFieldError('referrerScore')}
placeholder='0'
seprator
/>
</div>
</div>
</div>
<div className='flex justify-end'>
<Button
type='submit'
isloading={isPending}
className='w-full md:w-48'
>
ذخیره تغییرات
</Button>
</div>
</form>
)
}
export default ScoreSetting
+36 -15
View File
@@ -8,16 +8,26 @@ export type GeoJSONPolygon = {
};
export type UpdateRestaurantType = {
name: string;
menuColor: string;
phone: string;
instagram: string;
address: string;
name?: string;
menuColor?: string;
phone?: string;
instagram?: string;
address?: string;
logo?: string;
latitude: number;
longitude: number;
description: string;
latitude?: number;
longitude?: number;
description?: string;
serviceArea?: GeoJSONPolygon;
score?: {
purchaseAmount: string;
purchaseScore: string;
scoreAmount: string;
scoreCredit: string;
birthdayScore: string;
registerScore: string;
marriageDateScore: string;
referrerScore: string;
};
};
export type Restaurant = {
@@ -27,25 +37,36 @@ export type Restaurant = {
deletedAt: string | null;
name: string;
slug: string;
logo: string;
address: string;
menuColor: string;
latitude: number;
longitude: number;
logo: string | null;
address: string | null;
menuColor: string | null;
latitude: number | null;
longitude: number | null;
serviceArea: GeoJSONPolygon;
isActive: boolean;
establishedYear: number | null;
phoneNumber: string | null;
phone: string;
instagram: string;
instagram: string | null;
telegram: string | null;
whatsapp: string | null;
description: string;
description: string | null;
seoTitle: string | null;
seoDescription: string | null;
tagNames: unknown | null;
images: unknown | null;
vat: number;
domain: string;
score: {
scoreAmount: string;
scoreCredit: string;
birthdayScore: string;
purchaseScore: string;
referrerScore: string;
registerScore: string;
purchaseAmount: string;
marriageDateScore: string;
};
};
export type GetRestaurantResponse = IResponse<Restaurant>;