From 76a68adc1c6e336aff8a3fdf4344a64a180f41a9 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Wed, 22 Jul 2026 15:59:15 +0330 Subject: [PATCH] fix build --- src/pages/customer/service/CustomerService.ts | 4 +- src/pages/receipts/Create.tsx | 861 +++++++------- src/pages/receipts/Detail.tsx | 1043 ++++++++--------- src/pages/ticket/CreateTicket.tsx | 447 ++++--- 4 files changed, 1139 insertions(+), 1216 deletions(-) diff --git a/src/pages/customer/service/CustomerService.ts b/src/pages/customer/service/CustomerService.ts index b7ad634..9bcbf48 100644 --- a/src/pages/customer/service/CustomerService.ts +++ b/src/pages/customer/service/CustomerService.ts @@ -2,9 +2,7 @@ import axios from "../../../config/axios"; import { CreateCustomerType } from "../types/CustomerTypes"; export const getCustomers = async (page: number, limit: number, withoutPaginate?: boolean, search?: string) => { - const { data } = await axios.get( - `/users/customers?page=${page}&limit=${limit}&paginate=${withoutPaginate ? "0" : "1"}&q=${encodeURIComponent(search ?? "")}`, - ); + const { data } = await axios.get(`/users/customers?page=${page}&limit=${limit}&paginate=${withoutPaginate ? "0" : "1"}&q=${encodeURIComponent(search ?? "")}`); return data; }; diff --git a/src/pages/receipts/Create.tsx b/src/pages/receipts/Create.tsx index ee83a97..1871760 100644 --- a/src/pages/receipts/Create.tsx +++ b/src/pages/receipts/Create.tsx @@ -1,480 +1,445 @@ -import { ChangeEvent, FC, Fragment, useState } from 'react' -import { useTranslation } from 'react-i18next' -import Button from '../../components/Button' -import { Add, TickCircle, TickSquare, Trash } from 'iconsax-react' -import Select from '../../components/Select' -import Input from '../../components/Input' -import { CreateReceiptType, ReceiptCreateItemsType } from './types/ReceiptTypes' -import { useFormik } from 'formik' -import * as Yup from 'yup' -import { toast } from '../../components/Toast'; -import { useGetCustomers } from '../customer/hooks/useCustomerData' -import { CustomerItemType } from '../customer/types/CustomerTypes' -import PageLoading from '../../components/PageLoading' -import { useCreateInvoice } from './hooks/useReceiptData' -import { useNavigate } from 'react-router-dom' -import { Pages } from '../../config/Pages' -import { ErrorType } from '../../helpers/types' -import { RecurringPeriodEnum } from './enum/ReceipEnum' -import SwitchComponent from '../../components/Switch' +import { useFormik } from "formik"; +import { Add, TickCircle, TickSquare, Trash } from "iconsax-react"; +import { ChangeEvent, FC, Fragment, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { useNavigate } from "react-router-dom"; +import * as Yup from "yup"; +import Button from "../../components/Button"; +import Input from "../../components/Input"; +import PageLoading from "../../components/PageLoading"; +import Select from "../../components/Select"; +import SwitchComponent from "../../components/Switch"; +import { toast } from "../../components/Toast"; +import { Pages } from "../../config/Pages"; +import { ErrorType } from "../../helpers/types"; +import { useGetCustomers } from "../customer/hooks/useCustomerData"; +import { CustomerItemType } from "../customer/types/CustomerTypes"; +import { RecurringPeriodEnum } from "./enum/ReceipEnum"; +import { useCreateInvoice } from "./hooks/useReceiptData"; +import { CreateReceiptType, ReceiptCreateItemsType } from "./types/ReceiptTypes"; const CreateReceipt: FC = () => { + const navigate = useNavigate(); + const { t } = useTranslation("global"); + const [items, setItems] = useState([]); + const [customer, setCustomer] = useState(); + const [isRecurring, setIsRecurring] = useState(false); + const [type, setType] = useState(RecurringPeriodEnum.WEEKLY); + const [maxRecurringCycles, setMaxRecurringCycles] = useState(0); + const getCustomers = useGetCustomers(1, 50, true); + const createInvoice = useCreateInvoice(); - const navigate = useNavigate() - const { t } = useTranslation('global') - const [items, setItems] = useState([]) - const [customer, setCustomer] = useState() - const [isRecurring, setIsRecurring] = useState(false) - const [type, setType] = useState(RecurringPeriodEnum.WEEKLY) - const [maxRecurringCycles, setMaxRecurringCycles] = useState(0) - const getCustomers = useGetCustomers(1, true) - const createInvoice = useCreateInvoice() - - const formik = useFormik({ - initialValues: { - name: '', - count: '', - unitPrice: '', - discount: '' + const formik = useFormik({ + initialValues: { + name: "", + count: "", + unitPrice: "", + discount: "", + }, + validationSchema: Yup.object({ + name: Yup.string().required(t("errors.required")), + count: Yup.string().required(t("errors.required")), + unitPrice: Yup.string().required(t("errors.required")), + }), + onSubmit: (values) => { + setItems((prev) => [ + ...prev, + { + count: +values.count, + discount: +values.discount, + name: values.name, + unitPrice: +values.unitPrice, }, - validationSchema: Yup.object({ - name: Yup.string().required(t('errors.required')), - count: Yup.string().required(t('errors.required')), - unitPrice: Yup.string().required(t('errors.required')), - }), - onSubmit: (values) => { - setItems((prev) => [...prev, { - count: +values.count, - discount: +values.discount, - name: values.name, - unitPrice: +values.unitPrice - }]) - formik.resetForm() - } - }) + ]); + formik.resetForm(); + }, + }); - const handleChangeCustomer = (e: ChangeEvent) => { - const value = e.target.value - const customer = getCustomers.data?.data?.customers?.find((item: CustomerItemType) => item.id === value) - setCustomer(customer) + const handleChangeCustomer = (e: ChangeEvent) => { + const value = e.target.value; + const customer = getCustomers.data?.data?.customers?.find((item: CustomerItemType) => item.id === value); + setCustomer(customer); + }; + + const handleSubmit = () => { + if (customer) { + const params: CreateReceiptType = { + userId: customer?.id, + items: items, + isRecurring: isRecurring, + recurringPeriod: isRecurring ? +type : undefined, + maxRecurringCycles: isRecurring ? maxRecurringCycles : undefined, + }; + + createInvoice.mutate(params, { + onSuccess: () => { + toast(t("success"), "success"); + navigate(Pages.receipts.index); + }, + onError(error: ErrorType) { + toast(error.response?.data?.error.message[0], "error"); + }, + }); } + }; - const handleSubmit = () => { - if (customer) { - const params: CreateReceiptType = { - userId: customer?.id, - items: items, - isRecurring: isRecurring, - recurringPeriod: isRecurring ? +type : undefined, - maxRecurringCycles: isRecurring ? maxRecurringCycles : undefined - } + const handleRemove = (index: number) => { + setItems((prev) => prev.filter((_, i) => i !== index)); + }; - createInvoice.mutate(params, { - onSuccess: () => { - toast(t('success'), 'success') - navigate(Pages.receipts.index) - }, - onError(error: ErrorType) { - toast(error.response?.data?.error.message[0], 'error') - }, - }) - } - } + return ( +
+ {getCustomers.isPending ? ( + + ) : ( + +
+
{t("receip.add_receip")}
+
+ +
+
- const handleRemove = (index: number) => { - setItems((prev) => prev.filter((_, i) => i !== index)) - } +
+
+
{t("receip.customer_information")}
+
+
+ { - return { - label: item.firstName + ' ' + item.lastName, - value: item.id - } - })} - onChange={handleChangeCustomer} - /> -
-
+ {isRecurring && ( +
+
{t("receip.select_type")}
- { - customer && -
-
-
-
{t('receip.type_person')}
-
{customer.legalUser ? 'حقوقی' : 'حقیقی'}
-
-
-
{t('receip.representativeـname')}
-
{customer.firstName + ' ' + customer.lastName}
-
-
-
{t('receip.company_name')}
-
{customer?.legalUser?.registrationName}
-
-
-
{t('receip.registration_number')}
-
{customer?.legalUser?.registrationCode}
-
-
-
-
-
{t('receip.tel_company')}
-
{customer?.realUser?.phone || customer?.legalUser?.phone}
-
-
-
{t('receip.national_code')}
-
{customer.nationalCode}
-
-
-
{t('receip.postal_code')}
-
{customer?.realUser?.address?.postalCode || customer?.legalUser?.address?.postalCode}
-
-
-
-
-
{t('receip.state')}
-
{customer?.realUser?.address?.city?.province?.name || customer?.legalUser?.address?.city?.province?.name}
-
-
-
{t('receip.city')}
-
{customer?.realUser?.address?.city?.name || customer?.legalUser?.address?.city?.name}
-
-
-
{t('receip.address')}
-
{customer?.realUser?.address?.fullAddress || customer?.legalUser?.address?.fullAddress}
-
-
-
- } +
+ setMaxRecurringCycles(+e.target.value)} + /> +
+
+ )} - { - isRecurring && -
-
- {t('receip.select_type')} -
+
+
{t("receip.receipt_information")}
+
-
- setMaxRecurringCycles(+e.target.value)} - /> -
-
- } +
+
{t("receip.product_name")}
+ +
-
-
{t('receip.receipt_information')}
-
+
+
{t("receip.count")}
+ +
-
-
-
- {t('receip.number')} -
-
- {items.length + 1} -
-
+
+
{t("receip.unit_amount")}
+ formik.setFieldValue("unitPrice", e.target.value)} + seprator + /> +
-
-
- {t('receip.product_name')} -
- -
+
+
{t("receip.discount")}
+ +
-
-
- {t('receip.count')} -
- -
+
+
{t("receip.total_amount")}
+ +
-
-
- {t('receip.unit_amount')} -
- formik.setFieldValue('unitPrice', e.target.value)} - seprator - /> -
+
{ + if (formik.errors.name || formik.errors.count || formik.errors.unitPrice || formik.errors.discount) { + toast(t("receip.error_empty"), "error"); + } else { + formik.handleSubmit(); + } + }} + className="size-10 border border-border rounded-xl flex justify-center items-center" + > + +
+
-
-
- {t('receip.discount')} -
- -
+ {items.map((item, index: number) => { + return ( +
+
+ {index === 0 &&
{t("receip.number")}
} +
{index + 1}
+
+
+ {index === 0 &&
{t("receip.product_name")}
} + +
-
-
- {t('receip.total_amount')} -
- -
+
+ {index === 0 &&
{t("receip.count")}
} + +
-
{ - if (formik.errors.name || formik.errors.count || formik.errors.unitPrice || formik.errors.discount) { - toast(t('receip.error_empty'), 'error') - } else { - formik.handleSubmit() - } - }} className='size-10 border border-border rounded-xl flex justify-center items-center'> - -
+
+ {index === 0 &&
{t("receip.unit_amount")}
} + +
+
+ {index === 0 &&
{t("receip.discount")}
} + +
-
+
+ {index === 0 &&
{t("receip.total_amount")}
} + +
- { - items.map((item, index: number) => { - return ( -
-
- { - index === 0 && -
- {t('receip.number')} -
- } -
- {index + 1} -
-
-
- { - index === 0 && -
- {t('receip.product_name')} -
- } - -
+
handleRemove(index)} + className="size-10 border border-border rounded-xl flex justify-center items-center" + > + +
+
+ ); + })} -
- { - index === 0 && -
- {t('receip.count')} -
- } - -
+
+
+
{t("receip.tax")}
+
+ {( + items.reduce( + (acc, item) => acc + (Number(item.unitPrice) || 0) * (Number(item.count) || 0) - (Number(item.unitPrice) || 0) * (Number(item.count) || 0) * (Number(item.discount) / 100 || 0), + 0, + ) * 0.1 + ).toFixed(1)} +
+
+
+
{t("receip.total")}
+
+ {( + items.reduce( + (acc, item) => acc + (Number(item.unitPrice) || 0) * (Number(item.count) || 0) - (Number(item.unitPrice) || 0) * (Number(item.count) || 0) * (Number(item.discount) / 100 || 0), + 0, + ) * 1.1 + ).toFixed(1)} +
+
+
+
-
- { - index === 0 && -
- {t('receip.unit_amount')} -
- } - -
+
+
{t("ticket.title_hint")}
-
- { - index === 0 && -
- {t('receip.discount')} -
- } - -
+
+
+
+ +
+
سوالات - مشکلاتی که به یک موضوع مربوط میشوند را در یک درخواست پشتیبانی پیگیر باشید و چند درخواست برای یک موضوع باز نکنید.
+
+
+
+ +
+
لطفاً برای بررسی و رفع مشکلات احتمالی صبور باشید بررسی و رفع مشکلات در برخی موارد زمان گیر است.
+
+
+
+ +
+
+ پاسخگویی 24 ساعته تلفنی را تنها از میهن وب هاست می توانید انتظار داشته باشید .بخش پشتیبانی در هر ساعتی حتی در روز های تعطیل آماده پیگیری سریع مشکلات کاربران است. +
+
+
+
+
+
+ )} +
+ ); +}; -
- { - index === 0 && -
- {t('receip.total_amount')} -
- } - -
- -
handleRemove(index)} className='size-10 border border-border rounded-xl flex justify-center items-center'> - -
- - ) - }) - } - - - -
-
-
- {t('receip.tax')} -
-
- {((items.reduce((acc, item) => acc + (Number(item.unitPrice) || 0) * (Number(item.count) || 0) - (Number(item.unitPrice) || 0) * (Number(item.count) || 0) * (Number(item.discount) / 100 || 0), 0)) * 0.10).toFixed(1)} -
-
-
-
- {t('receip.total')} -
-
- {( - items.reduce((acc, item) => acc + (Number(item.unitPrice) || 0) * (Number(item.count) || 0) - (Number(item.unitPrice) || 0) * (Number(item.count) || 0) * (Number(item.discount) / 100 || 0), 0) * 1.10 - ).toFixed(1)} -
-
-
- - - -
-
- {t('ticket.title_hint')} -
- -
-
-
- -
-
- سوالات - مشکلاتی که به یک موضوع مربوط میشوند را در یک درخواست پشتیبانی پیگیر باشید و چند درخواست برای یک موضوع باز نکنید. -
-
-
-
- -
-
- لطفاً برای بررسی و رفع مشکلات احتمالی صبور باشید بررسی و رفع مشکلات در برخی موارد زمان گیر است. -
-
-
-
- -
-
- پاسخگویی 24 ساعته تلفنی را تنها از میهن وب هاست می توانید انتظار داشته باشید .بخش پشتیبانی در هر ساعتی حتی در روز های تعطیل آماده پیگیری سریع مشکلات کاربران است. -
-
-
-
- - - } - - ) -} - -export default CreateReceipt \ No newline at end of file +export default CreateReceipt; diff --git a/src/pages/receipts/Detail.tsx b/src/pages/receipts/Detail.tsx index e28cb03..d5ca56a 100644 --- a/src/pages/receipts/Detail.tsx +++ b/src/pages/receipts/Detail.tsx @@ -1,562 +1,529 @@ -import { ChangeEvent, FC, Fragment, useState, useEffect } from 'react' -import { useTranslation } from 'react-i18next' -import Button from '../../components/Button' -import { Add, TickCircle, TickSquare, Trash } from 'iconsax-react' -import Select from '../../components/Select' -import Input from '../../components/Input' -import { CreateReceiptType, ReceiptCreateItemsType } from './types/ReceiptTypes' -import { useFormik } from 'formik' -import * as Yup from 'yup' -import { toast } from '../../components/Toast'; -import { useGetCustomers } from '../customer/hooks/useCustomerData' -import { CustomerItemType } from '../customer/types/CustomerTypes' -import PageLoading from '../../components/PageLoading' -import { useGetInvoiceById, useUpdateInvoice } from './hooks/useReceiptData' -import { useNavigate, useParams } from 'react-router-dom' -import { Pages } from '../../config/Pages' -import { ErrorType } from '../../helpers/types' -import { RecurringPeriodEnum } from './enum/ReceipEnum' -import SwitchComponent from '../../components/Switch' +import { useFormik } from "formik"; +import { Add, TickCircle, TickSquare, Trash } from "iconsax-react"; +import { ChangeEvent, FC, Fragment, useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { useNavigate, useParams } from "react-router-dom"; +import * as Yup from "yup"; +import Button from "../../components/Button"; +import Input from "../../components/Input"; +import PageLoading from "../../components/PageLoading"; +import Select from "../../components/Select"; +import SwitchComponent from "../../components/Switch"; +import { toast } from "../../components/Toast"; +import { Pages } from "../../config/Pages"; +import { ErrorType } from "../../helpers/types"; +import { useGetCustomers } from "../customer/hooks/useCustomerData"; +import { CustomerItemType } from "../customer/types/CustomerTypes"; +import { RecurringPeriodEnum } from "./enum/ReceipEnum"; +import { useGetInvoiceById, useUpdateInvoice } from "./hooks/useReceiptData"; +import { CreateReceiptType, ReceiptCreateItemsType } from "./types/ReceiptTypes"; // Add interface for invoice item from API interface InvoiceItemType { - id: string; - name: string; - count: number; - unitPrice: number; - discount?: number; - totalPrice: number; - createdAt: string; - updatedAt: string; - subscriptionPlan: null | string; + id: string; + name: string; + count: number; + unitPrice: number; + discount?: number; + totalPrice: number; + createdAt: string; + updatedAt: string; + subscriptionPlan: null | string; } const CreateReceipt: FC = () => { + const navigate = useNavigate(); + const { id } = useParams(); + const { t } = useTranslation("global"); + const { data: invoice, isPending: isLoading } = useGetInvoiceById(id as string); + const updateInvoice = useUpdateInvoice(); + const [items, setItems] = useState([]); + const [customer, setCustomer] = useState(); + const [isRecurring, setIsRecurring] = useState(false); + const [type, setType] = useState(RecurringPeriodEnum.WEEKLY); + const [maxRecurringCycles, setMaxRecurringCycles] = useState(0); + const getCustomers = useGetCustomers(1, 50, true); - const navigate = useNavigate() - const { id } = useParams() - const { t } = useTranslation('global') - const { data: invoice, isPending: isLoading } = useGetInvoiceById(id as string) - const updateInvoice = useUpdateInvoice() - const [items, setItems] = useState([]) - const [customer, setCustomer] = useState() - const [isRecurring, setIsRecurring] = useState(false) - const [type, setType] = useState(RecurringPeriodEnum.WEEKLY) - const [maxRecurringCycles, setMaxRecurringCycles] = useState(0) - const getCustomers = useGetCustomers(1, true) - - const formik = useFormik({ - initialValues: { - name: '', - count: '', - unitPrice: '', - discount: '' + const formik = useFormik({ + initialValues: { + name: "", + count: "", + unitPrice: "", + discount: "", + }, + validationSchema: Yup.object({ + name: Yup.string().required(t("errors.required")), + count: Yup.string().required(t("errors.required")), + unitPrice: Yup.string().required(t("errors.required")), + }), + onSubmit: (values) => { + setItems((prev) => [ + ...prev, + { + count: +values.count, + discount: +values.discount, + name: values.name, + unitPrice: +values.unitPrice, }, - validationSchema: Yup.object({ - name: Yup.string().required(t('errors.required')), - count: Yup.string().required(t('errors.required')), - unitPrice: Yup.string().required(t('errors.required')), - }), - onSubmit: (values) => { - setItems((prev) => [...prev, { - count: +values.count, - discount: +values.discount, - name: values.name, - unitPrice: +values.unitPrice - }]) - formik.resetForm() - } - }) + ]); + formik.resetForm(); + }, + }); - const handleChangeCustomer = (e: ChangeEvent) => { - const value = e.target.value - const customer = getCustomers.data?.data?.customers?.find((item: CustomerItemType) => item.id === value) - setCustomer(customer) + const handleChangeCustomer = (e: ChangeEvent) => { + const value = e.target.value; + const customer = getCustomers.data?.data?.customers?.find((item: CustomerItemType) => item.id === value); + setCustomer(customer); + }; + + const handleSubmit = () => { + if (customer) { + const params: CreateReceiptType = { + userId: customer?.id, + items: items, + isRecurring: isRecurring, + recurringPeriod: isRecurring ? +type : undefined, + maxRecurringCycles: isRecurring ? maxRecurringCycles : undefined, + }; + + updateInvoice.mutate( + { id: id as string, params }, + { + onSuccess: () => { + toast(t("success"), "success"); + navigate(Pages.receipts.index); + }, + onError(error: ErrorType) { + toast(error.response?.data?.error.message[0], "error"); + }, + }, + ); } + }; - const handleSubmit = () => { - if (customer) { - const params: CreateReceiptType = { - userId: customer?.id, - items: items, - isRecurring: isRecurring, - recurringPeriod: isRecurring ? +type : undefined, - maxRecurringCycles: isRecurring ? maxRecurringCycles : undefined - } + const handleRemove = (index: number) => { + setItems((prev) => prev.filter((_, i) => i !== index)); + }; - updateInvoice.mutate({ id: id as string, params }, { - onSuccess: () => { - toast(t('success'), 'success') - navigate(Pages.receipts.index) - }, - onError(error: ErrorType) { - toast(error.response?.data?.error.message[0], 'error') - }, - }) - } + // Prefill form when editing an invoice + useEffect(() => { + // Check if we need to access invoice.data or directly invoice + const invoiceData = invoice?.data?.invoice || invoice; + + if (id && invoiceData) { + console.log("Invoice data to use:", invoiceData); + + // 1. If there's a user, find matching customer + if (invoiceData.user && getCustomers.data?.data?.customers) { + const foundCustomer = getCustomers.data.data.customers.find((item: CustomerItemType) => item.id === invoiceData.user.id); + setCustomer(foundCustomer); + console.log("Found customer:", foundCustomer); + setCustomer(foundCustomer); + } + + // 2. Set items from invoice - directly use the structure from API response + if (invoiceData.items && invoiceData.items.length > 0) { + console.log("Setting items:", invoiceData.items); + // Map API items to the format expected by our component + setItems( + invoiceData.items.map((item: InvoiceItemType) => ({ + name: item.name, + count: item.count, + unitPrice: item.unitPrice, + discount: item.discount || 0, + })), + ); + + // 3. Set formik values from first item + } + + // 4. Set recurring settings + setIsRecurring(Boolean(invoiceData.isRecurring)); + if (typeof invoiceData.recurringPeriod === "number") { + setType(invoiceData.recurringPeriod.toString()); + } + setMaxRecurringCycles(invoiceData.maxRecurringCycles || 0); } + }, [id, invoice, getCustomers.data]); - const handleRemove = (index: number) => { - setItems((prev) => prev.filter((_, i) => i !== index)) + // Add this function to programmatically select the customer in the dropdown + const selectCustomerInDropdown = () => { + if (customer && invoice?.user?.id) { + // Trigger the onChange manually with a synthetic event + const event = { + target: { + value: invoice.user.id, + }, + } as ChangeEvent; + + handleChangeCustomer(event); } + }; - // Prefill form when editing an invoice - useEffect(() => { + // Call this when customer or invoice changes + useEffect(() => { + if (customer && invoice?.user?.id) { + selectCustomerInDropdown(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [customer, invoice]); - // Check if we need to access invoice.data or directly invoice - const invoiceData = invoice?.data?.invoice || invoice; + return ( +
+ {getCustomers.isPending || isLoading ? ( + + ) : ( + +
+
{t("receip.add_receip")}
+
+ +
+
- if (id && invoiceData) { - console.log("Invoice data to use:", invoiceData); +
+
+
{t("receip.customer_information")}
- // 1. If there's a user, find matching customer - if (invoiceData.user && getCustomers.data?.data?.customers) { - const foundCustomer = getCustomers.data.data.customers.find( - (item: CustomerItemType) => item.id === invoiceData.user.id +
+
+ setType(e.target.value as unknown as RecurringPeriodEnum)} + /> + + setMaxRecurringCycles(+e.target.value)} + /> +
+
+ )} + +
+
{t("receip.receipt_information")}
+
+ +
+
+
{t("receip.number")}
+
{items.length + 1}
+
+ +
+
{t("receip.product_name")}
+ +
+ +
+
{t("receip.count")}
+ +
+ +
+
{t("receip.unit_amount")}
+ formik.setFieldValue("unitPrice", e.target.value)} + seprator + /> +
+ +
+
{t("receip.discount")}
+ +
+ +
+
{t("receip.total_amount")}
+ +
+ +
{ + if (formik.errors.name || formik.errors.count || formik.errors.unitPrice || formik.errors.discount) { + toast(t("receip.error_empty"), "error"); + } else { + formik.handleSubmit(); + } + }} + className="size-10 border border-border rounded-xl flex justify-center items-center" + > + +
+
+ + {items.map((item, index: number) => { + return ( +
+
+ {index === 0 &&
{t("receip.number")}
} +
{index + 1}
+
+
+ {index === 0 &&
{t("receip.product_name")}
} + +
+ +
+ {index === 0 &&
{t("receip.count")}
} + +
+ +
+ {index === 0 &&
{t("receip.unit_amount")}
} + +
+ +
+ {index === 0 &&
{t("receip.discount")}
} + +
+ +
+ {index === 0 &&
{t("receip.total_amount")}
} + +
+ +
handleRemove(index)} + className="size-10 border border-border rounded-xl flex justify-center items-center" + > + +
+
); - setCustomer(foundCustomer); - console.log("Found customer:", foundCustomer); - setCustomer(foundCustomer); - } + })} - // 2. Set items from invoice - directly use the structure from API response - if (invoiceData.items && invoiceData.items.length > 0) { - console.log("Setting items:", invoiceData.items); - // Map API items to the format expected by our component - setItems(invoiceData.items.map((item: InvoiceItemType) => ({ - name: item.name, - count: item.count, - unitPrice: item.unitPrice, - discount: item.discount || 0 - }))); +
+
+
{t("receip.tax")}
+
+ {( + items.reduce( + (acc, item) => acc + (Number(item.unitPrice) || 0) * (Number(item.count) || 0) - (Number(item.unitPrice) || 0) * (Number(item.count) || 0) * (Number(item.discount) / 100 || 0), + 0, + ) * 0.1 + ).toFixed(1)} +
+
+
+
{t("receip.total")}
+
+ {( + items.reduce( + (acc, item) => acc + (Number(item.unitPrice) || 0) * (Number(item.count) || 0) - (Number(item.unitPrice) || 0) * (Number(item.count) || 0) * (Number(item.discount) / 100 || 0), + 0, + ) * 1.1 + ).toFixed(1)} +
+
+
+
- // 3. Set formik values from first item +
+
{t("ticket.title_hint")}
- } +
+
+
+ +
+
سوالات - مشکلاتی که به یک موضوع مربوط میشوند را در یک درخواست پشتیبانی پیگیر باشید و چند درخواست برای یک موضوع باز نکنید.
+
+
+
+ +
+
لطفاً برای بررسی و رفع مشکلات احتمالی صبور باشید بررسی و رفع مشکلات در برخی موارد زمان گیر است.
+
+
+
+ +
+
+ پاسخگویی 24 ساعته تلفنی را تنها از میهن وب هاست می توانید انتظار داشته باشید .بخش پشتیبانی در هر ساعتی حتی در روز های تعطیل آماده پیگیری سریع مشکلات کاربران است. +
+
+
+
+
+
+ )} +
+ ); +}; - // 4. Set recurring settings - setIsRecurring(Boolean(invoiceData.isRecurring)); - if (typeof invoiceData.recurringPeriod === 'number') { - setType(invoiceData.recurringPeriod.toString()); - } - setMaxRecurringCycles(invoiceData.maxRecurringCycles || 0); - } - }, [id, invoice, getCustomers.data]); - - // Add this function to programmatically select the customer in the dropdown - const selectCustomerInDropdown = () => { - if (customer && invoice?.user?.id) { - // Trigger the onChange manually with a synthetic event - const event = { - target: { - value: invoice.user.id - } - } as ChangeEvent; - - handleChangeCustomer(event); - } - }; - - // Call this when customer or invoice changes - useEffect(() => { - if (customer && invoice?.user?.id) { - selectCustomerInDropdown(); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [customer, invoice]); - - return ( -
- { - getCustomers.isPending || isLoading ? - - : - -
-
- {t('receip.add_receip')} -
-
- -
-
- -
-
-
- {t('receip.customer_information')} -
- -
-
- setType(e.target.value as unknown as RecurringPeriodEnum)} - /> - - setMaxRecurringCycles(+e.target.value)} - /> -
-
- } - -
-
{t('receip.receipt_information')}
-
- -
-
-
- {t('receip.number')} -
-
- {items.length + 1} -
-
- -
-
- {t('receip.product_name')} -
- -
- -
-
- {t('receip.count')} -
- -
- -
-
- {t('receip.unit_amount')} -
- formik.setFieldValue('unitPrice', e.target.value)} - seprator - /> -
- -
-
- {t('receip.discount')} -
- -
- -
-
- {t('receip.total_amount')} -
- -
- -
{ - if (formik.errors.name || formik.errors.count || formik.errors.unitPrice || formik.errors.discount) { - toast(t('receip.error_empty'), 'error') - } else { - formik.handleSubmit() - } - }} className='size-10 border border-border rounded-xl flex justify-center items-center'> - -
- - -
- - { - items.map((item, index: number) => { - return ( -
-
- { - index === 0 && -
- {t('receip.number')} -
- } -
- {index + 1} -
-
-
- { - index === 0 && -
- {t('receip.product_name')} -
- } - -
- -
- { - index === 0 && -
- {t('receip.count')} -
- } - -
- -
- { - index === 0 && -
- {t('receip.unit_amount')} -
- } - -
- -
- { - index === 0 && -
- {t('receip.discount')} -
- } - -
- -
- { - index === 0 && -
- {t('receip.total_amount')} -
- } - -
- -
handleRemove(index)} className='size-10 border border-border rounded-xl flex justify-center items-center'> - -
-
- ) - }) - } - - - -
-
-
- {t('receip.tax')} -
-
- {(items.reduce((acc, item) => acc + (Number(item.unitPrice) || 0) * (Number(item.count) || 0) - (Number(item.unitPrice) || 0) * (Number(item.count) || 0) * (Number(item.discount) / 100 || 0), 0) * 0.10).toFixed(1)} -
-
-
-
- {t('receip.total')} -
-
- {( - items.reduce((acc, item) => acc + (Number(item.unitPrice) || 0) * (Number(item.count) || 0) - (Number(item.unitPrice) || 0) * (Number(item.count) || 0) * (Number(item.discount) / 100 || 0), 0) * 1.10 - ).toFixed(1)} -
-
-
- -
- -
-
- {t('ticket.title_hint')} -
- -
-
-
- -
-
- سوالات - مشکلاتی که به یک موضوع مربوط میشوند را در یک درخواست پشتیبانی پیگیر باشید و چند درخواست برای یک موضوع باز نکنید. -
-
-
-
- -
-
- لطفاً برای بررسی و رفع مشکلات احتمالی صبور باشید بررسی و رفع مشکلات در برخی موارد زمان گیر است. -
-
-
-
- -
-
- پاسخگویی 24 ساعته تلفنی را تنها از میهن وب هاست می توانید انتظار داشته باشید .بخش پشتیبانی در هر ساعتی حتی در روز های تعطیل آماده پیگیری سریع مشکلات کاربران است. -
-
-
-
-
-
- } -
- ) -} - -export default CreateReceipt +export default CreateReceipt; diff --git a/src/pages/ticket/CreateTicket.tsx b/src/pages/ticket/CreateTicket.tsx index de1ea14..f044161 100644 --- a/src/pages/ticket/CreateTicket.tsx +++ b/src/pages/ticket/CreateTicket.tsx @@ -1,244 +1,237 @@ -import { FC, useState } from 'react' -import { useTranslation } from 'react-i18next' -import Input from '../../components/Input' -import Select from '../../components/Select' -import Textarea from '../../components/Textarea' -import UploadBox from '../../components/UploadBox' -import Button from '../../components/Button' -import { TickCircle, TickSquare } from 'iconsax-react' -import { useCreateTicket, useGetCategories } from './hooks/useTicketData' -import { useGetProfile } from '../profile/hooks/useProfileData' -import PageLoading from '../../components/PageLoading' -import { useFormik } from 'formik' -import * as Yup from 'yup' -import { ErrorType } from '../../helpers/types' -import { useNavigate } from 'react-router-dom' -import { Pages } from '../../config/Pages' -import { CreateTicketAdminType } from './types/TicketTypes' -import { toast } from '../../components/Toast'; -import { useMultiUpload } from '../service/hooks/useServiceData' -import { useGetCustomers } from '../customer/hooks/useCustomerData' -import { CustomerItemType } from '../customer/types/CustomerTypes' +import { useFormik } from "formik"; +import { TickCircle, TickSquare } from "iconsax-react"; +import { FC, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { useNavigate } from "react-router-dom"; +import * as Yup from "yup"; +import Button from "../../components/Button"; +import Input from "../../components/Input"; +import PageLoading from "../../components/PageLoading"; +import Select from "../../components/Select"; +import Textarea from "../../components/Textarea"; +import { toast } from "../../components/Toast"; +import UploadBox from "../../components/UploadBox"; +import { Pages } from "../../config/Pages"; +import { ErrorType } from "../../helpers/types"; +import { useGetCustomers } from "../customer/hooks/useCustomerData"; +import { CustomerItemType } from "../customer/types/CustomerTypes"; +import { useGetProfile } from "../profile/hooks/useProfileData"; +import { useMultiUpload } from "../service/hooks/useServiceData"; +import { useCreateTicket, useGetCategories } from "./hooks/useTicketData"; +import { CreateTicketAdminType } from "./types/TicketTypes"; const CreateTicket: FC = () => { - const { t } = useTranslation('global') - const navigate = useNavigate() - const [files, setFiles] = useState([]) - const getProfile = useGetProfile() - const getCategories = useGetCategories() - const multiUpload = useMultiUpload() - const createTicket = useCreateTicket() - const getCustomers = useGetCustomers(1, true) + const { t } = useTranslation("global"); + const navigate = useNavigate(); + const [files, setFiles] = useState([]); + const getProfile = useGetProfile(); + const getCategories = useGetCategories(); + const multiUpload = useMultiUpload(); + const createTicket = useCreateTicket(); + const getCustomers = useGetCustomers(1, 50, true); + const formik = useFormik({ + initialValues: { + subject: "", + message: "", + categoryId: "", + priority: "LOW", + attachmentUrls: [], + userId: "", + }, + validationSchema: Yup.object({ + subject: Yup.string().required(t("errors.required")), + message: Yup.string().required(t("errors.required")), + categoryId: Yup.string().required(t("errors.required")), + priority: Yup.string().required(t("errors.required")), + }), + onSubmit: async (values) => { + if (files.length > 0) { + const images = new FormData(); + files.forEach((file) => { + images.append("files", file); + }); + await multiUpload.mutateAsync(images, { + onSuccess: async (data) => { + values.attachmentUrls = await data.data.map((item: { url: string }) => item?.url); + }, + onError: (error: ErrorType) => { + toast(error.response?.data?.error?.message[0], "error"); + }, + }); + } else { + delete values.attachmentUrls; + } - const formik = useFormik({ - initialValues: { - subject: '', - message: '', - categoryId: '', - priority: 'LOW', - attachmentUrls: [], - userId: '' + if (values.danakServiceId === "") { + delete values.danakServiceId; + } + + createTicket.mutate(values, { + onSuccess: (data) => { + toast(t("success"), "success"); + formik.resetForm(); + navigate(Pages.ticket.detail + data.data?.ticketId); }, - validationSchema: Yup.object({ - subject: Yup.string().required(t('errors.required')), - message: Yup.string().required(t('errors.required')), - categoryId: Yup.string().required(t('errors.required')), - priority: Yup.string().required(t('errors.required')), - }), - onSubmit: async (values) => { - if (files.length > 0) { - const images = new FormData() - files.forEach(file => { - images.append('files', file) - }) - await multiUpload.mutateAsync(images, { - onSuccess: async (data) => { - values.attachmentUrls = await data.data.map((item: { url: string }) => item?.url) - }, - onError: (error: ErrorType) => { - toast(error.response?.data?.error?.message[0], 'error') - } - }) - } else { - delete values.attachmentUrls - } + onError: (error: ErrorType) => { + toast(error.response?.data?.error?.message[0], "error"); + }, + }); + }, + }); - if (values.danakServiceId === '') { - delete values.danakServiceId - } + return ( +
+
{t("ticket.new_ticket")}
+ {getProfile.isPending || getCategories.isPending ? ( + + ) : ( +
+
+
{t("ticket.submit_your_message")}
- createTicket.mutate(values, { - onSuccess: (data) => { - toast(t('success'), 'success') - formik.resetForm() - navigate(Pages.ticket.detail + data.data?.ticketId) - }, - onError: (error: ErrorType) => { - toast(error.response?.data?.error?.message[0], 'error') - } - }) - } - }) - - - return ( -
-
- {t('ticket.new_ticket')} +
+ + { - return { - label: item.firstName + ' ' + item.lastName, - value: item.id - } - })} - {...formik.getFieldProps('userId')} - /> -
+
+