From 6fdbd2766053f2d63cbe0d429b6084e9b7b76654 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Tue, 17 Feb 2026 12:25:15 +0330 Subject: [PATCH] import with excel --- src/pages/bill/Create.tsx | 97 +++++++++++++++++++++++++---- src/pages/bill/hooks/useBillData.ts | 6 ++ src/pages/bill/service/Service.ts | 13 +++- src/pages/bill/types/Types.ts | 6 ++ 4 files changed, 108 insertions(+), 14 deletions(-) diff --git a/src/pages/bill/Create.tsx b/src/pages/bill/Create.tsx index 6fc9adb..7b888eb 100644 --- a/src/pages/bill/Create.tsx +++ b/src/pages/bill/Create.tsx @@ -1,12 +1,13 @@ -import { FC, useEffect, useRef } from 'react' +import { FC, useCallback, useEffect, useRef, useState } from 'react' import { useGetAllCompanies } from '../company/hooks/useCompanyData' import { useFormik } from 'formik' import * as Yup from 'yup' +import { useDropzone } from 'react-dropzone' import { CreateBillType } from './types/Types' -import { useCreateBill } from './hooks/useBillData' +import { useCreateBill, useCreateBillWithExcel } from './hooks/useBillData' import Button from '../../components/Button' import Input from '../../components/Input' -import { TickCircle } from 'iconsax-react' +import { DocumentUpload, TickCircle } from 'iconsax-react' import { toast } from 'react-toastify' import { ErrorType } from '../../helpers/types' import { Pages } from '../../config/Pages' @@ -18,6 +19,21 @@ const CreateBill: FC = () => { const navigate = useNavigate() const getCompanies = useGetAllCompanies() const createBill = useCreateBill() + const createBillWithExcel = useCreateBillWithExcel() + const [excelFile, setExcelFile] = useState(null) + + const onDropExcel = useCallback((acceptedFiles: File[]) => { + setExcelFile(acceptedFiles[0] ?? null) + }, []) + const { getRootProps, getInputProps } = useDropzone({ + onDrop: onDropExcel, + accept: { + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'], + 'application/vnd.ms-excel': ['.xls'], + }, + maxFiles: 1, + multiple: false, + }) const companies: CompanyItemType[] = getCompanies.data?.data?.companies ?? [] @@ -96,20 +112,75 @@ const CreateBill: FC = () => { formik.setFieldValue('values', next) } + const handleSubmitExcel = () => { + const waterRate = Number(formik.values.waterRate) + const dueDays = Number(formik.values.dueDays) + if (waterRate < 0 || dueDays < 0) { + toast.error('نرخ آب و تعداد روز مهلت را وارد کنید') + return + } + if (!excelFile) { + toast.error('فایل اکسل را انتخاب کنید') + return + } + createBillWithExcel.mutate( + { waterRate, dueDays, file: excelFile }, + { + onSuccess: () => { + toast.success('قبض آب با موفقیت از طریق اکسل ثبت شد') + navigate(Pages.bill.list) + }, + onError: (error: ErrorType) => { + toast.error(error.response?.data?.error?.message?.[0] ?? 'خطا در ثبت قبض با اکسل') + }, + } + ) + } + return (
-
+
افزودن قبض آب
- +
+ +
+ + فایل اکسل +
+ {excelFile ? ( + + {excelFile.name} + + ) : ( + کلیک یا فایل را اینجا رها کنید + )} +
- +
diff --git a/src/pages/bill/hooks/useBillData.ts b/src/pages/bill/hooks/useBillData.ts index 42d531c..1f0dca0 100644 --- a/src/pages/bill/hooks/useBillData.ts +++ b/src/pages/bill/hooks/useBillData.ts @@ -13,6 +13,12 @@ export const useCreateCharge = () => { }); }; +export const useCreateBillWithExcel = () => { + return useMutation({ + mutationFn: api.createBillWithExcel, + }); +}; + export const useGetBills = (page: number = 1) => { return useQuery({ queryKey: ["bills", page], diff --git a/src/pages/bill/service/Service.ts b/src/pages/bill/service/Service.ts index e986ae9..127d0fa 100644 --- a/src/pages/bill/service/Service.ts +++ b/src/pages/bill/service/Service.ts @@ -1,5 +1,5 @@ import axios from "../../../config/axios"; -import { CreateBillType, CreateBillChargeType } from "../types/Types"; +import { CreateBillType, CreateBillChargeType, CreateBillWithExcelType } from "../types/Types"; export const createBill = async (params: CreateBillType) => { const { data } = await axios.post("/bills/water", params); @@ -15,3 +15,14 @@ export const getBills = async (page: number = 1) => { const { data } = await axios.get(`/bills?page=${page}`); return data; }; + +export const createBillWithExcel = async (params: CreateBillWithExcelType) => { + const formData = new FormData(); + formData.append("waterRate", String(params.waterRate)); + formData.append("dueDays", String(params.dueDays)); + formData.append("file", params.file); + const { data } = await axios.post("/bills/water/excel", formData, { + headers: { "Content-Type": "multipart/form-data" }, + }); + return data; +}; diff --git a/src/pages/bill/types/Types.ts b/src/pages/bill/types/Types.ts index 41ba09c..d4d2488 100644 --- a/src/pages/bill/types/Types.ts +++ b/src/pages/bill/types/Types.ts @@ -12,6 +12,12 @@ export type CreateBillChargeType = { dueDays: number; }; +export type CreateBillWithExcelType = { + waterRate: number; + dueDays: number; + file: File; +}; + export type BillItemType = { id: string; createdAt: string;