diff --git a/package.json b/package.json index 308d4587..9df96da4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "app.salona", "private": true, - "version": "2.86.3", + "version": "2.86.4", "type": "module", "scripts": { "dev": "vite --host", diff --git a/src/apps/appointment/pages/modules-list/index.tsx b/src/apps/appointment/pages/modules-list/index.tsx index b8732c30..911c3c75 100644 --- a/src/apps/appointment/pages/modules-list/index.tsx +++ b/src/apps/appointment/pages/modules-list/index.tsx @@ -1,96 +1,78 @@ -import { useGetUserInfo } from '@appointment/services/User'; -import { PageLoading } from '@/components/PageLoading'; -import modulesVector from '@appointment/assets/images/modules.svg'; -import repairVector from '@appointment/assets/images/repair-vector.svg'; -import loyaltyVector from '@appointment/assets/images/loyalty.svg'; -import surveyVector from '@appointment/assets/images/survey.svg'; -import incomeVector from '@appointment/assets/images/income.svg'; -import { AbilityActionEnum } from '@appointment/utils/enums'; -import { CheckCircleIcon, GiftIcon, XCircleIcon } from 'lucide-react'; +import { useGetUserInfo } from "@appointment/services/User"; +import { PageLoading } from "@/components/PageLoading"; +import modulesVector from "@appointment/assets/images/modules.svg"; +import repairVector from "@appointment/assets/images/repair-vector.svg"; +import loyaltyVector from "@appointment/assets/images/loyalty.svg"; +import surveyVector from "@appointment/assets/images/survey.svg"; +import incomeVector from "@appointment/assets/images/income.svg"; +import { AbilityActionEnum } from "@appointment/utils/enums"; +import { CheckCircleIcon, GiftIcon, XCircleIcon } from "lucide-react"; -const modulesObject: Record< - AbilityActionEnum, - { title: string; image: string } -> = { - [AbilityActionEnum.REPAIR_REMINDER]: { - title: 'ماژول ترمیم', - image: repairVector, - }, - [AbilityActionEnum.LOYALTY_SERVICE]: { - title: 'ماژول وفاداری', - image: loyaltyVector, - }, - [AbilityActionEnum.SURVEY_SERVICE]: { - title: 'ماژول نظرسنجی', - image: surveyVector, - }, - [AbilityActionEnum.ACCOUNTANT_SERVICE]: { - title: 'ماژول حسابداری', - image: incomeVector, - }, +const modulesObject: Record = { + [AbilityActionEnum.REPAIR_REMINDER]: { + title: "ماژول ترمیم", + image: repairVector, + }, + [AbilityActionEnum.LOYALTY_SERVICE]: { + title: "ماژول وفاداری", + image: loyaltyVector, + }, + [AbilityActionEnum.SURVEY_SERVICE]: { + title: "ماژول نظرسنجی", + image: surveyVector, + }, + [AbilityActionEnum.ACCOUNTANT_SERVICE]: { + title: "ماژول حسابداری", + image: incomeVector, + }, }; const ModulesList = () => { - const { data: userInfo, isLoading: userInfoLoading } = useGetUserInfo(); + const { data: userInfo, isLoading: userInfoLoading } = useGetUserInfo(); - return ( -
- -
-

- لیست ماژول‌ها -

-
-
- -
- {userInfo?.user_abilities_list.map((ab) => ( -
-
- -
-
-

- {modulesObject[ab.ability_action].title} + return ( +

+ +
+

+ لیست ماژول‌ها

- {ab.remaining_time === 'bonus' ? ( - <> -

- هدیه -

- - - ) : ab.remaining_time === 'Expired' ? ( - <> -

غیر فعال

- - - ) : ( - <> -

- - {ab.remaining_time} - - روز باقی مانده -

- - - )} -
- ))} +
+ +
+ {userInfo?.user_abilities_list.map((ab) => ( +
+
+ +
+
+

{modulesObject[ab.ability_action].title}

+ {ab.remaining_time === "bonus" ? ( + <> +

هدیه

+ + + ) : ab.remaining_time === "Expired" ? ( + <> +

غیر فعال

+ + + ) : ( + <> +

+ {ab.remaining_time} + روز باقی مانده +

+ + + )} +
+
+ ))} +
+
-
-
- ); + ); }; export default ModulesList; diff --git a/src/apps/new-ui/components/AppointmentComponents/CustomerSkleton.tsx b/src/apps/new-ui/components/AppointmentComponents/CustomerSkleton.tsx index 8a92d2f1..8f09f72e 100644 --- a/src/apps/new-ui/components/AppointmentComponents/CustomerSkleton.tsx +++ b/src/apps/new-ui/components/AppointmentComponents/CustomerSkleton.tsx @@ -1,85 +1,85 @@ import { Skeleton } from "@/components/ui/skeleton"; const CustomerSkleton = () => { - return ( -
- {/* ===== Header ===== */} -
-
- - -
- -
- - {/* ===== Date & Time ===== */} -
-
- -
- - -
-
-
- - {/* ===== Cost ===== */} -
- - -
- - {/* ===== Services ===== */} -
- {[1, 2, 3].map((i) => ( -
-
- -
- - -
+ return ( +
+ {/* ===== Header ===== */} +
+
+ + +
+
- -
- ))} -
- {/* ===== Descriptions ===== */} -
-
    - - -
-
- - -
-
+ {/* ===== Date & Time ===== */} +
+
+ +
+ + +
+
+
- {/* ===== Statistics ===== */} -
- -
- {[1, 2, 3, 4].map((i) => ( - - ))} -
-
+ {/* ===== Cost ===== */} +
+ + +
- {/* ===== Bottom Buttons ===== */} - {/*
+ {/* ===== Services ===== */} +
+ {[1, 2, 3].map((i) => ( +
+
+ +
+ + +
+
+ +
+ ))} +
+ + {/* ===== Descriptions ===== */} +
+
    + + +
+
+ + +
+
+ + {/* ===== Statistics ===== */} +
+ +
+ {[1, 2, 3, 4].map((i) => ( + + ))} +
+
+ + {/* ===== Bottom Buttons ===== */} + {/*
{[1, 2, 3, 4].map((i) => ( ))}
*/} -
- ); +
+ ); }; export default CustomerSkleton; diff --git a/src/apps/new-ui/pages/CustomerClub/+components/AddCustomer.tsx b/src/apps/new-ui/pages/CustomerClub/+components/AddCustomer.tsx index 91bf2ca4..14562130 100644 --- a/src/apps/new-ui/pages/CustomerClub/+components/AddCustomer.tsx +++ b/src/apps/new-ui/pages/CustomerClub/+components/AddCustomer.tsx @@ -15,321 +15,293 @@ import { showErrorAlert } from "@/apps/new-ui/components/CustomAlert"; import { Input } from "@/components/ui/input"; interface Contact { - name?: string[]; - tel?: string[]; + name?: string[]; + tel?: string[]; } interface ContactsManager { - select(props: string[], opts?: { multiple?: boolean }): Promise; + select(props: string[], opts?: { multiple?: boolean }): Promise; } const AddCustomerPage = () => { - const [name, setName] = useState(""); - const [phoneNumber, setPhoneNumber] = useState(""); - const [statusTitle, setStatusTitle] = useState(""); - const [birthDate, setBirthDate] = useState(""); - const [sendAskPhotoSMS, setSendAskPhotoSMS] = useState(false); - const [isSelectPhotoOpen, setIsSelectPhotoOpen] = useState(false); - const [profilePicture, setProfilePicture] = useState(addPhoto); - const fileInputRef = useRef(null); - const [isAddStatusOpen, setIsAddStatusOpen] = useState(false); - const [photoFile, setPhotoFile] = useState(null); - const navigate = useNavigate(); + const [name, setName] = useState(""); + const [phoneNumber, setPhoneNumber] = useState(""); + const [statusTitle, setStatusTitle] = useState(""); + const [birthDate, setBirthDate] = useState(""); + const [sendAskPhotoSMS, setSendAskPhotoSMS] = useState(false); + const [isSelectPhotoOpen, setIsSelectPhotoOpen] = useState(false); + const [profilePicture, setProfilePicture] = useState(addPhoto); + const fileInputRef = useRef(null); + const [isAddStatusOpen, setIsAddStatusOpen] = useState(false); + const [photoFile, setPhotoFile] = useState(null); + const navigate = useNavigate(); - const btnEnable = name !== "" && phoneNumber !== ""; + const btnEnable = name !== "" && phoneNumber !== ""; - const addCustomerMutation = useAddSingleCustomer(); + const addCustomerMutation = useAddSingleCustomer(); - const statusList = [ - { id: 1, title: "VIP", icon: general }, - { id: 2, title: "عمومی", icon: family }, - { id: 3, title: "آشنایان", icon: VIP }, - ]; + const statusList = [ + { id: 1, title: "VIP", icon: general }, + { id: 2, title: "عمومی", icon: family }, + { id: 3, title: "آشنایان", icon: VIP }, + ]; - const handleChangePhoto = () => { - fileInputRef.current?.click(); - }; - - const handleFileChange = (e: React.ChangeEvent) => { - const file = e.target.files?.[0]; - if (file) { - const validTypes = ["image/jpeg", "image/jpg", "image/png"]; - if (!validTypes.includes(file.type)) { - showErrorAlert( - "فرمت فایل معتبر نیست. لطفاً یکی از فرمت‌های jpg، jpeg یا png را انتخاب کنید." - ); - e.target.value = ""; // پاک کردن فایل انتخاب شده - return; - } - - const reader = new FileReader(); - reader.onloadend = () => { - const base64 = reader.result as string; - setProfilePicture(base64); - setPhotoFile(file); - }; - reader.readAsDataURL(file); // تبدیل به base64 - } - }; - - const handleDeletePhoto = () => { - setProfilePicture(addPhoto); - }; - - const handleSaveCustomer = async () => { - if (!btnEnable) return; - - const formData = new FormData(); - formData.append("name", name); - formData.append("phone_number", phoneNumber); - formData.append("customer_type", statusTitle || "عمومی"); - formData.append("description", sendAskPhotoSMS ? "true" : "false"); - formData.append("date_of_birth", birthDate || ""); - - if (photoFile) { - formData.append("profile_picture", photoFile); - } - - try { - await addCustomerMutation.mutateAsync(formData); - - navigate(-1); - } catch (err) { - console.error("خطا در ذخیره مشتری:", err); - } - }; - - useEffect(() => { - return () => { - localStorage.removeItem("birthDate"); + const handleChangePhoto = () => { + fileInputRef.current?.click(); }; - }, []); - const handlePickContact = async () => { - try { - const navigatorWithContacts = navigator as typeof navigator & { - contacts?: ContactsManager; - }; + const handleFileChange = (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (file) { + const validTypes = ["image/jpeg", "image/jpg", "image/png"]; + if (!validTypes.includes(file.type)) { + showErrorAlert("فرمت فایل معتبر نیست. لطفاً یکی از فرمت‌های jpg، jpeg یا png را انتخاب کنید."); + e.target.value = ""; // پاک کردن فایل انتخاب شده + return; + } - if (navigatorWithContacts.contacts) { - const props = ["name", "tel"]; - const opts = { multiple: false }; - const contacts = await navigatorWithContacts.contacts.select( - props, - opts - ); - - if (contacts.length > 0) { - const contact = contacts[0]; - setName(contact.name?.[0] || ""); - - const rawNumber = contact.tel?.[0] || ""; - const cleanedNumber = rawNumber.replace(/\D/g, ""); - setPhoneNumber(cleanedNumber); + const reader = new FileReader(); + reader.onloadend = () => { + const base64 = reader.result as string; + setProfilePicture(base64); + setPhotoFile(file); + }; + reader.readAsDataURL(file); // تبدیل به base64 } - } else { - showErrorAlert("این مرورگر از انتخاب مخاطب پشتیبانی نمی‌کند."); - } - } catch (err) { - console.error(err); - } - }; + }; - return ( -
-
-

- افزودن مشتری جدید -

+ const handleDeletePhoto = () => { + setProfilePicture(addPhoto); + }; - {/* =======profile pic========= */} -
setIsSelectPhotoOpen(true)} - className="mt-4 w-24 h-24 rounded-full cursor-pointer" - > - add -
+ const handleSaveCustomer = async () => { + if (!btnEnable) return; - {/* =================== */} -
- add customer -

- افزودن مشتری از مخاطبین -

-
+ const formData = new FormData(); + formData.append("name", name); + formData.append("phone_number", phoneNumber); + formData.append("customer_type", statusTitle || "عمومی"); + formData.append("description", sendAskPhotoSMS ? "true" : "false"); + formData.append("date_of_birth", birthDate || ""); - {/* ==========name=========== */} -
- setName(e.target.value)} - type="text" - required - maxLength={24} - className="w-full rounded-full border-2 border-gray-300 py-2 px-2 text-sm" - placeholder="نام و نام خانوادگی" - /> -
+ if (photoFile) { + formData.append("profile_picture", photoFile); + } - {/* =================phone number=========== */} -
- setPhoneNumber(e.target.value)} - type="number" - dir="ltr" - maxLength={14} - required - className="w-full rounded-full border-2 border-gray-300 py-2 h-[38px] px-2 text-sm text-right" // text-left - placeholder="شماره موبایل" - /> -
-
+ try { + await addCustomerMutation.mutateAsync(formData); - {/* =============status============== */} -
-

دسته‌بندی

-
setIsAddStatusOpen(true)} - className="flex items-center justify-center gap-2 border-2 w-[90px] border-[#A780C3] rounded-full py-2 cursor-pointer" - > - add customer -

افزودن

-
-
+ navigate(-1); + } catch (err) { + console.error("خطا در ذخیره مشتری:", err); + } + }; -
- {statusList.map((status) => ( -
setStatusTitle(status.title)} - > - status -

{status.title}

-
- ))} -
+ useEffect(() => { + return () => { + localStorage.removeItem("birthDate"); + }; + }, []); - {/* ===========birth date=========== */} -
- setBirthDate(newDate)} - /> -
+ const handlePickContact = async () => { + try { + const navigatorWithContacts = navigator as typeof navigator & { + contacts?: ContactsManager; + }; - {/* ==========send sms============ */} -
- setSendAskPhotoSMS(!sendAskPhotoSMS)} - label="ارسال پیامک درخواست تصویر کاربری از مشتری" - /> -
+ if (navigatorWithContacts.contacts) { + const props = ["name", "tel"]; + const opts = { multiple: false }; + const contacts = await navigatorWithContacts.contacts.select(props, opts); - {/* ============buttons=========== */} -
- - -
+ if (contacts.length > 0) { + const contact = contacts[0]; + setName(contact.name?.[0] || ""); - {/* ==========select pic============= */} - {isSelectPhotoOpen && ( -
-
-
setIsSelectPhotoOpen(false)} - className="absolute cursor-pointer bg-[#dedee3] text-[#999999] text-2xl rounded-full px-3.5 py-1 top-2 right-2" - > - + const rawNumber = contact.tel?.[0] || ""; + const cleanedNumber = rawNumber.replace(/\D/g, ""); + setPhoneNumber(cleanedNumber); + } + } else { + showErrorAlert("این مرورگر از انتخاب مخاطب پشتیبانی نمی‌کند."); + } + } catch (err) { + console.error(err); + } + }; + + return ( +
+
+ {/* =======profile pic========= */} +
setIsSelectPhotoOpen(true)} className="mt-4 w-24 h-24 rounded-full cursor-pointer"> + add +
+ + {/* =================== */} +
+ add customer +

افزودن مشتری از مخاطبین

+
+ + {/* ==========name=========== */} +
+ setName(e.target.value)} + type="text" + required + maxLength={24} + className="w-full rounded-full border-2 h-10 border-gray-300 p-4 text-sm" + placeholder="نام و نام خانوادگی" + /> +
+ + {/* =================phone number=========== */} +
+ setPhoneNumber(e.target.value)} + digitsOnly={true} + maxLength={14} + dir="ltr" + required + className="w-full rounded-full border-2 border-gray-300 h-10 p-4 text-sm text-right" + placeholder="شماره موبایل" + /> +
-
-

مدیریت تصویر مشتری

- customer photo - -
- + add customer +

افزودن

+
+
- +
+ {statusList.map((status) => ( +
setStatusTitle(status.title)} + > + status +

{status.title}

+
+ ))} +
- + setBirthDate(newDate)} /> +
+ + {/* ==========send sms============ */} +
+ setSendAskPhotoSMS(!sendAskPhotoSMS)} + label="ارسال پیامک درخواست تصویر کاربری از مشتری" /> -
- -
-
-
- )} - {isAddStatusOpen && ( -
-
-
setIsAddStatusOpen(false)} - className="absolute cursor-pointer bg-[#dedee3] text-[#999999] text-2xl rounded-full p-2 top-2 right-2 " - > - + {/* ============buttons=========== */} +
+ +
- setIsAddStatusOpen(false)} /> -
+ + {/* ==========select pic============= */} + {isSelectPhotoOpen && ( +
+
+
+

مدیریت تصویر مشتری

+ customer photo + +
+ + + + + +
+ + +
+
+
+ )} + + {isAddStatusOpen && ( +
+
+
setIsAddStatusOpen(false)} + className="absolute cursor-pointer bg-[#dedee3] text-[#999999] text-2xl rounded-full p-2 top-2 right-2 " + > + +
+ setIsAddStatusOpen(false)} /> +
+
+ )}
- )} -
- ); + ); }; export default AddCustomerPage; diff --git a/src/apps/new-ui/pages/CustomerClub/+components/CustomerCards.tsx b/src/apps/new-ui/pages/CustomerClub/+components/CustomerCards.tsx index 01f5235d..5af89e8d 100644 --- a/src/apps/new-ui/pages/CustomerClub/+components/CustomerCards.tsx +++ b/src/apps/new-ui/pages/CustomerClub/+components/CustomerCards.tsx @@ -13,187 +13,131 @@ import { useNavigate } from "react-router-dom"; import { appointmentRoutes } from "@/apps/appointment/routes"; type CustomerCardsProps = { - data?: ICustomer[]; - isError?: boolean; - isLoading?: boolean; + data?: ICustomer[]; + isError?: boolean; + isLoading?: boolean; }; -const CustomerCards: React.FC = ({ - data, - isError, - isLoading, -}) => { - const { mutate: deleteCustomer, isPending } = useDeleteCustomer(); - const navigate = useNavigate(); +const CustomerCards: React.FC = ({ data, isError, isLoading }) => { + const { mutate: deleteCustomer, isPending } = useDeleteCustomer(); + const navigate = useNavigate(); - const handleDelete = (id: number) => { - showWarningAlert("آیا از حذف این مشتری مطمئن هستید؟", () => { - deleteCustomer(id); - }); - }; + const handleDelete = (id: number) => { + showWarningAlert("آیا از حذف این مشتری مطمئن هستید؟", () => { + deleteCustomer(id); + }); + }; - return ( -
- {isError ? ( -
- خطا در دریافت مشتری -
- ) : isLoading ? ( - Array(4) - .fill(0) - .map((_, idx) => ( -
-
- -
- - + return ( +
+ {isError ? ( +
+ خطا در دریافت مشتری
-
+ ) : isLoading ? ( + Array(4) + .fill(0) + .map((_, idx) => ( +
+
+ +
+ + +
+
-
- - - - -
-
- )) - ) : data?.length === 0 ? ( -
-

هیچ مشتری وجود ندارد

-
- ) : ( - data?.map((customer) => ( -
-
-
- avatar - status -
+
+ + + + +
+
+ )) + ) : data?.length === 0 ? ( +
+

هیچ مشتری وجود ندارد

+
+ ) : ( + data?.map((customer) => ( +
+
+
+ avatar + status +
-
- {customer.name.length > 11 ? ( -
-
-

- {customer.name} -

+
+ {customer.name.length > 11 ? ( +
+
+

+ {customer.name} +

+
+
+
+
+ ) : ( +

{customer.name}

+ )} +

{customer.phone_number}

+
+
+ +
+ + + + + + messageIcon + + + + phoneIcon + +
-
-
-
- ) : ( -

- {customer.name} -

- )} -

- {customer.phone_number} -

-
-
- -
- - - - - - messageIcon - - - - phoneIcon - -
-
- )) - )} -
- ); + )) + )} +
+ ); }; export default CustomerCards; diff --git a/src/apps/new-ui/pages/CustomerClub/+components/EditCustomer.tsx b/src/apps/new-ui/pages/CustomerClub/+components/EditCustomer.tsx index 075db71f..155f3ee7 100644 --- a/src/apps/new-ui/pages/CustomerClub/+components/EditCustomer.tsx +++ b/src/apps/new-ui/pages/CustomerClub/+components/EditCustomer.tsx @@ -7,10 +7,7 @@ import family from "../../../assets/appointment/status2.svg"; import deleteIcon from "../../../assets/appointment/delete.svg"; import AddStatus from "../../../pages/AddStatus/AddStatus"; import { XIcon } from "lucide-react"; -import { - useGetAllCustomers, - useUpdateCustomer, -} from "@/apps/new-ui/services/Customer"; +import { useGetAllCustomers, useUpdateCustomer } from "@/apps/new-ui/services/Customer"; import SimpleDatePicker from "@/apps/new-ui/components/MobilePicker/MobileScrollDatePicker"; import ToggleButton from "@/apps/new-ui/components/AppointmentComponents/ToggleButton"; import { useNavigate, useParams } from "react-router-dom"; @@ -18,293 +15,274 @@ import { showErrorAlert } from "@/apps/new-ui/components/CustomAlert"; import { Input } from "@/components/ui/input"; const EditCustomer = () => { - const { data: customersData, isPending } = useGetAllCustomers(); - const { id } = useParams(); - const foundCustomer = customersData?.customers.find( - (customer) => customer.id === Number(id) - ); - const navigate = useNavigate(); + const { data: customersData, isPending } = useGetAllCustomers(); + const { id } = useParams(); + const foundCustomer = customersData?.customers.find((customer) => customer.id === Number(id)); + const navigate = useNavigate(); - const [name, setName] = useState(foundCustomer?.name || ""); - const [phoneNumber, setPhoneNumber] = useState( - foundCustomer?.phone_number || "" - ); - const [statusTitle, setStatusTitle] = useState( - foundCustomer?.description || "" - ); - const [birthDate, setBirthDate] = useState( - foundCustomer?.customer_date_of_birth || "" - ); - const [sendAskPhotoSMS, setSendAskPhotoSMS] = useState(false); - const [isSelectPhotoOpen, setIsSelectPhotoOpen] = useState(false); - const [profilePicture, setProfilePicture] = useState( - foundCustomer?.profile_picture - ? `${import.meta.env.VITE_APP_API_URL}/${foundCustomer.profile_picture}` - : addPhoto - ); + const [name, setName] = useState(foundCustomer?.name || ""); + const [phoneNumber, setPhoneNumber] = useState(foundCustomer?.phone_number || ""); + const [statusTitle, setStatusTitle] = useState(foundCustomer?.description || ""); + const [birthDate, setBirthDate] = useState(foundCustomer?.customer_date_of_birth || ""); + const [sendAskPhotoSMS, setSendAskPhotoSMS] = useState(false); + const [isSelectPhotoOpen, setIsSelectPhotoOpen] = useState(false); + const [profilePicture, setProfilePicture] = useState( + foundCustomer?.profile_picture + ? `${import.meta.env.VITE_APP_API_URL}/${foundCustomer.profile_picture}` + : addPhoto + ); - const fileInputRef = useRef(null); - const [isAddStatusOpen, setIsAddStatusOpen] = useState(false); - const [photoFile, setPhotoFile] = useState(null); + const fileInputRef = useRef(null); + const [isAddStatusOpen, setIsAddStatusOpen] = useState(false); + const [photoFile, setPhotoFile] = useState(null); - const btnEnable = name !== "" && phoneNumber !== ""; + const btnEnable = name !== "" && phoneNumber !== ""; - const editCustomerMutation = useUpdateCustomer(); + const editCustomerMutation = useUpdateCustomer(); - const statusList = [ - { id: 1, title: "VIP", icon: general }, - { id: 2, title: "عمومی", icon: family }, - { id: 3, title: "آشنایان", icon: VIP }, - ]; + const statusList = [ + { id: 1, title: "VIP", icon: general }, + { id: 2, title: "عمومی", icon: family }, + { id: 3, title: "آشنایان", icon: VIP }, + ]; - const handleChangePhoto = () => { - fileInputRef.current?.click(); - }; - - const handleFileChange = (e: React.ChangeEvent) => { - const file = e.target.files?.[0]; - if (file) { - const validTypes = ["image/jpeg", "image/jpg", "image/png"]; - if (!validTypes.includes(file.type)) { - showErrorAlert( - "فرمت فایل معتبر نیست. لطفاً یکی از فرمت‌های jpg، jpeg یا png را انتخاب کنید." - ); - e.target.value = ""; // پاک کردن فایل انتخاب شده - return; - } - - const reader = new FileReader(); - reader.onloadend = () => { - const base64 = reader.result as string; - setProfilePicture(base64); - setPhotoFile(file); - }; - reader.readAsDataURL(file); - } - }; - - const handleDeletePhoto = () => { - setProfilePicture(addPhoto); - }; - - const handleSaveCustomer = async () => { - if (!btnEnable || !id) return; - - const formData = new FormData(); - if (name) formData.append("name", name); - if (sendAskPhotoSMS) - formData.append("description", String(sendAskPhotoSMS)); - if (statusTitle) formData.append("customer_type", statusTitle); - if (birthDate) formData.append("date_of_birth", birthDate); - if (photoFile) formData.append("profile_picture", photoFile); - - try { - await editCustomerMutation.mutateAsync({ - customerId: Number(id), - name, - description: String(sendAskPhotoSMS), - customer_type: statusTitle, - date_of_birth: birthDate, - profile_picture: photoFile || undefined, - }); - - navigate("/customers"); - } catch (err) { - console.error("خطا در بروزرسانی مشتری:", err); - } - }; - - useEffect(() => { - return () => { - localStorage.removeItem("birthDate"); + const handleChangePhoto = () => { + fileInputRef.current?.click(); }; - }, []); - return ( -
-
-

- ویرایش اطلاعات مشتری -

+ const handleFileChange = (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (file) { + const validTypes = ["image/jpeg", "image/jpg", "image/png"]; + if (!validTypes.includes(file.type)) { + showErrorAlert("فرمت فایل معتبر نیست. لطفاً یکی از فرمت‌های jpg، jpeg یا png را انتخاب کنید."); + e.target.value = ""; // پاک کردن فایل انتخاب شده + return; + } - {/* =======profile pic========= */} -
setIsSelectPhotoOpen(true)} - className="mt-4 w-24 h-24 rounded-full cursor-pointer" - > - update photo -
+ const reader = new FileReader(); + reader.onloadend = () => { + const base64 = reader.result as string; + setProfilePicture(base64); + setPhotoFile(file); + }; + reader.readAsDataURL(file); + } + }; - {/* ==========name=========== */} -
- setName(e.target.value)} - type="text" - required - maxLength={32} - className="w-full rounded-full border-2 border-gray-300 py-2 px-2 text-sm" - placeholder="نام و نام خانوادگی" - /> -
+ const handleDeletePhoto = () => { + setProfilePicture(addPhoto); + }; - {/* =================phone number=========== */} -
- setPhoneNumber(e.target.value)} - type="number" - dir="ltr" - maxLength={14} - required - disabled - className="w-full rounded-full border-2 border-gray-300 py-2 h-[38px] px-2 text-sm text-right" // text-left - placeholder="شماره موبایل" - /> -
-
+ const handleSaveCustomer = async () => { + if (!btnEnable || !id) return; - {/* =============status============== */} -
-

دسته‌بندی

-
setIsAddStatusOpen(true)} - className="flex items-center justify-center gap-2 border-2 w-[90px] border-[#A780C3] rounded-full py-2 cursor-pointer" - > - add customer -

افزودن

-
-
+ const formData = new FormData(); + if (name) formData.append("name", name); + if (sendAskPhotoSMS) formData.append("description", String(sendAskPhotoSMS)); + if (statusTitle) formData.append("customer_type", statusTitle); + if (birthDate) formData.append("date_of_birth", birthDate); + if (photoFile) formData.append("profile_picture", photoFile); -
- {statusList.map((status) => ( -
setStatusTitle(status.title)} - > - status -

{status.title}

-
- ))} -
+ try { + await editCustomerMutation.mutateAsync({ + customerId: Number(id), + name, + description: String(sendAskPhotoSMS), + customer_type: statusTitle, + date_of_birth: birthDate, + profile_picture: photoFile || undefined, + }); - {/* ===========birth date=========== */} -
- setBirthDate(newDate)} - /> -
+ navigate("/customers"); + } catch (err) { + console.error("خطا در بروزرسانی مشتری:", err); + } + }; - {/* ==========send sms============ */} -
- setSendAskPhotoSMS(!sendAskPhotoSMS)} - label="ارسال پیامک درخواست تصویر کاربری از مشتری" - /> -
+ useEffect(() => { + return () => { + localStorage.removeItem("birthDate"); + }; + }, []); - {/* ============buttons=========== */} -
- - -
+ return ( +
+
+

ویرایش اطلاعات مشتری

- {/* ==========select pic============= */} - {isSelectPhotoOpen && ( -
-
-
setIsSelectPhotoOpen(false)} - className="absolute cursor-pointer bg-[#dedee3] text-[#999999] text-2xl rounded-full p-2 top-2 right-2" - > - + {/* =======profile pic========= */} +
setIsSelectPhotoOpen(true)} className="mt-4 w-24 h-24 rounded-full cursor-pointer"> + update photo +
+ + {/* ==========name=========== */} +
+ setName(e.target.value)} + type="text" + required + maxLength={24} + className="w-full rounded-full border-2 border-gray-300 h-10 p-4 text-sm" + placeholder="نام و نام خانوادگی" + /> +
+ + {/* =================phone number=========== */} +
+ setPhoneNumber(e.target.value)} + type="number" + dir="ltr" + maxLength={14} + required + disabled + className="w-full rounded-full border-2 border-gray-300 p-4 text-sm h-10 text-right" // text-left + placeholder="شماره موبایل" + /> +
-
-

مدیریت تصویر مشتری

- customer photo - -
- + add customer +

افزودن

+
+
- +
+ {statusList.map((status) => ( +
setStatusTitle(status.title)} + > + status +

{status.title}

+
+ ))} +
- + setBirthDate(newDate)} /> +
+ + {/* ==========send sms============ */} +
+ setSendAskPhotoSMS(!sendAskPhotoSMS)} + label="ارسال پیامک درخواست تصویر کاربری از مشتری" /> -
- -
-
-
- )} - {isAddStatusOpen && ( -
-
-
setIsAddStatusOpen(false)} - className="absolute cursor-pointer bg-[#dedee3] text-[#999999] text-2xl rounded-full px-3.5 py-1 top-2 right-2 " - > - + {/* ============buttons=========== */} +
+ +
- setIsAddStatusOpen(false)} /> -
+ + {/* ==========select pic============= */} + {isSelectPhotoOpen && ( +
+
+
setIsSelectPhotoOpen(false)} + className="absolute cursor-pointer bg-[#dedee3] text-[#999999] text-2xl rounded-full p-2 top-2 right-2" + > + +
+ +
+

مدیریت تصویر مشتری

+ customer photo + +
+ + + + + +
+ + +
+
+
+ )} + + {isAddStatusOpen && ( +
+
+
setIsAddStatusOpen(false)} + className="absolute cursor-pointer bg-[#dedee3] text-[#999999] text-2xl rounded-full px-3.5 py-1 top-2 right-2 " + > + +
+ setIsAddStatusOpen(false)} /> +
+
+ )}
- )} -
- ); + ); }; export default EditCustomer; diff --git a/src/apps/new-ui/pages/Profile/index.tsx b/src/apps/new-ui/pages/Profile/index.tsx index 76c882d2..7d276540 100644 --- a/src/apps/new-ui/pages/Profile/index.tsx +++ b/src/apps/new-ui/pages/Profile/index.tsx @@ -148,7 +148,7 @@ const Profile: React.FC = () => { const walletDisplay = useMemo(() => { const amount = userInfo?.current_user?.wallet_balance ?? null; - return amount ? amount.toLocaleString("fa-IR") : ' - '; + return amount ? amount.toLocaleString("fa-IR") : 0; }, [userInfo]); const prevActiveRef = useRef(null); @@ -264,7 +264,7 @@ const Profile: React.FC = () => { onAction={undefined} rightContent={
-

{walletDisplay ?? 0}

+

{walletDisplay}

تومان

} diff --git a/src/apps/new-ui/pages/reserved-appointments/reserve-form/+components/FormComponent.tsx b/src/apps/new-ui/pages/reserved-appointments/reserve-form/+components/FormComponent.tsx index 2cd780c4..bfca1c21 100644 --- a/src/apps/new-ui/pages/reserved-appointments/reserve-form/+components/FormComponent.tsx +++ b/src/apps/new-ui/pages/reserved-appointments/reserve-form/+components/FormComponent.tsx @@ -8,189 +8,163 @@ import { numberOnInputHandler } from "@/utils/fa-to-en-numbers"; import { MOBILE_REGEX_PATTERN } from "@/utils/constants"; import { useLoginEndUserOverCard } from "@/services/Reserve"; import { Textarea } from "@/components/ui/textarea"; -import { useNavigate, useSearchParams } from "react-router-dom"; +import { useNavigate, useSearchParams } from "react-router-dom"; import { IReserveAppointmentDTO } from "@/apps/appointment/utils/types"; import { validateCaptcha } from "react-simple-captcha"; import Captcha from "@/components/Captcha"; import ROUTES_OBJECT from "@/routes/RoutesObject"; -const FormComponent = ({ - onFormSubmit, -}: { - onFormSubmit: (data: IReserveAppointmentDTO) => void; -}) => { - const [searchParams, setSearchParams] = useSearchParams(); - const [captchaValue, setCaptchaValue] = useState(""); - const captchaInputRef = useRef(null); - const { - register, - handleSubmit, - watch, - formState: { errors }, - } = useForm<{ - name: string; - mobile: string; - service: string; - description: string; - }>({ - defaultValues: { - name: "", - mobile: "", - service: "", - description: "", - }, - }); - const navigate=useNavigate() - const { - mutate: loginEndUserOverCard, - isPending: loginEndUserOverCardPending, - } = useLoginEndUserOverCard(); - const onSubmitHandler = handleSubmit((data) => { - if (!captchaValue) { - if (captchaInputRef.current) captchaInputRef.current.focus(); - return toast.error( - "تکمیل کپچا برای جلوگیری از ورود ربات ها ضروری میباشد." - ); - } - const isValidCaptcha = validateCaptcha(captchaValue); - if (!isValidCaptcha) { - setCaptchaValue(""); - return toast.error( - "مقادیر وارد شده برای کپچا اشتباه است. لطفا ورودی های خود را مجددا بررسی نمایید." - ); - } - loginEndUserOverCard( - { - phone_number: data.mobile, - }, - { - onSuccess: (response) => { - if (response.status >= 200 && response.status < 300) { - const prevParams = Object.fromEntries(searchParams); - setSearchParams({ ...prevParams, mobile: data.mobile }); - onFormSubmit({ - ...data, - artist_id: response.data.artist_id, - }); - } +const FormComponent = ({ onFormSubmit }: { onFormSubmit: (data: IReserveAppointmentDTO) => void }) => { + const [searchParams, setSearchParams] = useSearchParams(); + const [captchaValue, setCaptchaValue] = useState(""); + const captchaInputRef = useRef(null); + const { + register, + handleSubmit, + watch, + formState: { errors }, + } = useForm<{ + name: string; + mobile: string; + service: string; + description: string; + }>({ + defaultValues: { + name: "", + mobile: "", + service: "", + description: "", }, - } + }); + const navigate = useNavigate(); + const { mutate: loginEndUserOverCard, isPending: loginEndUserOverCardPending } = useLoginEndUserOverCard(); + const onSubmitHandler = handleSubmit((data) => { + if (!captchaValue) { + if (captchaInputRef.current) captchaInputRef.current.focus(); + return toast.error("تکمیل کپچا برای جلوگیری از ورود ربات ها ضروری میباشد."); + } + const isValidCaptcha = validateCaptcha(captchaValue); + if (!isValidCaptcha) { + setCaptchaValue(""); + return toast.error("مقادیر وارد شده برای کپچا اشتباه است. لطفا ورودی های خود را مجددا بررسی نمایید."); + } + loginEndUserOverCard( + { + phone_number: data.mobile, + }, + { + onSuccess: (response) => { + if (response.status >= 200 && response.status < 300) { + const prevParams = Object.fromEntries(searchParams); + setSearchParams({ ...prevParams, mobile: data.mobile }); + onFormSubmit({ + ...data, + artist_id: response.data.artist_id, + }); + } + }, + } + ); + }); + const btnEnable = watch("name") && watch("mobile") && watch("service"); + + return ( +
+
+ + +
+
+ + +
+
+ + +
+
+