From baa55860d4c14c62f5d73ec3343288e68f53d278 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Sat, 13 Dec 2025 08:44:47 +0330 Subject: [PATCH] score setting --- src/components/Input.tsx | 7 +- src/pages/settings/Setting.tsx | 10 +- .../settings/components/ScoreSetting.tsx | 235 ++++++++++++++++++ src/pages/settings/types/Types.ts | 51 ++-- 4 files changed, 283 insertions(+), 20 deletions(-) create mode 100644 src/pages/settings/components/ScoreSetting.tsx diff --git a/src/components/Input.tsx b/src/components/Input.tsx index da6bc88..8dd6e96 100644 --- a/src/components/Input.tsx +++ b/src/components/Input.tsx @@ -49,13 +49,16 @@ const Input: FC = (props: Props) => { setFormattedValue(formatted); // ارسال مقدار خام به `onChange` والد - props.onChange?.({ + const syntheticEvent = { ...event, target: { ...event.target, + name: event.target.name, value: inputValue, }, - }); + } as React.ChangeEvent; + + props.onChange?.(syntheticEvent); } else { props.onChange?.(event); } diff --git a/src/pages/settings/Setting.tsx b/src/pages/settings/Setting.tsx index 503b92c..6a8cb91 100644 --- a/src/pages/settings/Setting.tsx +++ b/src/pages/settings/Setting.tsx @@ -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: , - label: 'مالی', + icon: , + label: 'تنظیمات امتیاز', value: SettingTabEnum.FINANCIAL, }, { @@ -45,6 +46,9 @@ const Setting: FC = () => { { activeTab === SettingTabEnum.GENERAL && } + { + activeTab === SettingTabEnum.FINANCIAL && + } ) diff --git a/src/pages/settings/components/ScoreSetting.tsx b/src/pages/settings/components/ScoreSetting.tsx new file mode 100644 index 0000000..f039c76 --- /dev/null +++ b/src/pages/settings/components/ScoreSetting.tsx @@ -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({ + 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 ( +
+ {/* بخش امتیاز خرید */} +
+

امتیاز خرید

+ + {/* خط اول */} +
+
+ به ازای هر + +
+
+ تومان خرید مقدار + +
+ امتیاز به مشتری داده میشود. +
+ + {/* خط دوم */} +
+
+ هر + +
+
+ امتیاز معادل + +
+ تومان اعتبار خرید است. +
+
+ + {/* بخش امتیاز ثابت */} +
+

امتیاز ثابت

+ +
+
+ + + +
+ +
+ + + +
+
+
+ +
+ +
+
+ ) +} + +export default ScoreSetting \ No newline at end of file diff --git a/src/pages/settings/types/Types.ts b/src/pages/settings/types/Types.ts index 8037047..fab48d0 100644 --- a/src/pages/settings/types/Types.ts +++ b/src/pages/settings/types/Types.ts @@ -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;