From 8eabcf419e7b43ed5fa3ced16901bd17c70881bf Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Tue, 17 Feb 2026 09:21:57 +0330 Subject: [PATCH] create bill water --- .env | 4 +- src/assets/images/logo.svg | 132 +++++--------- src/config/Pages.ts | 6 + src/pages/bill/Create.tsx | 192 ++++++++++++++++++++ src/pages/bill/hooks/useBillData.ts | 8 + src/pages/bill/service/Service.ts | 7 + src/pages/bill/types/Types.ts | 8 + src/pages/company/hooks/useCompanyData.ts | 13 +- src/pages/company/service/CompanyService.ts | 6 +- src/router/Main.tsx | 3 + src/shared/components/CompanySubMenu.tsx | 1 + src/shared/components/ReceiptSubMenu.tsx | 18 ++ 12 files changed, 300 insertions(+), 98 deletions(-) create mode 100644 src/pages/bill/Create.tsx create mode 100644 src/pages/bill/hooks/useBillData.ts create mode 100644 src/pages/bill/service/Service.ts create mode 100644 src/pages/bill/types/Types.ts diff --git a/.env b/.env index 2948e68..96e69df 100644 --- a/.env +++ b/.env @@ -1,7 +1,7 @@ VITE_TOKEN_NAME = 'dsc_token' VITE_REFRESH_TOKEN_NAME = 'dsc_refresh_token' -# VITE_BASE_URL = 'http://192.168.82.158:4000' -VITE_BASE_URL = 'https://api-dzone.danakcorp.com' +VITE_BASE_URL = 'http://172.28.231.88:4000' +# VITE_BASE_URL = 'https://api-dzone.danakcorp.com' # VITE_DANAK_BASE_URL ='http://192.168.1.113:4000' VITE_DANAK_BASE_URL ='https://api.danakcorp.com' VITE_SERVICE_ID = '7e3c2f08-b7e7-4402-ae5f-fea99cff56bd' diff --git a/src/assets/images/logo.svg b/src/assets/images/logo.svg index 200db25..87e1176 100644 --- a/src/assets/images/logo.svg +++ b/src/assets/images/logo.svg @@ -1,91 +1,41 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + Z + Z O N E + \ No newline at end of file diff --git a/src/config/Pages.ts b/src/config/Pages.ts index 88848e8..be50433 100644 --- a/src/config/Pages.ts +++ b/src/config/Pages.ts @@ -122,4 +122,10 @@ export const Pages = { list: "/company/list", detail: "/company/detail/", }, + bill: { + createBillWater: "/bill/water/create", + createBillCharge: "/bill/charge/create", + ListBillWater: "/bill/water/list", + ListBillCharge: "/bill/charge/list", + }, }; diff --git a/src/pages/bill/Create.tsx b/src/pages/bill/Create.tsx new file mode 100644 index 0000000..f4fee04 --- /dev/null +++ b/src/pages/bill/Create.tsx @@ -0,0 +1,192 @@ +import { FC, useEffect, useRef } from 'react' +import { useGetAllCompanies } from '../company/hooks/useCompanyData' +import { useFormik } from 'formik' +import * as Yup from 'yup' +import { CreateBillType } from './types/Types' +import { useCreateBill } from './hooks/useBillData' +import Button from '../../components/Button' +import Input from '../../components/Input' +import { TickCircle } from 'iconsax-react' +import { toast } from 'react-toastify' +import { ErrorType } from '../../helpers/types' +import { Pages } from '../../config/Pages' +import { useNavigate } from 'react-router-dom' +import { CompanyItemType } from '../company/types/CompanyTypes' +import PageLoading from '../../components/PageLoading' + +const CreateBill: FC = () => { + const navigate = useNavigate() + const getCompanies = useGetAllCompanies() + const createBill = useCreateBill() + + const companies: CompanyItemType[] = getCompanies.data?.data?.companies ?? [] + + const formik = useFormik({ + initialValues: { + waterRate: 0, + dueDays: 0, + values: [], + }, + enableReinitialize: true, + validationSchema: Yup.object({ + waterRate: Yup.number().min(0, 'نرخ آب باید عدد مثبت باشد').required('نرخ آب الزامی است'), + dueDays: Yup.number().min(0, 'تعداد روز مهلت باید عدد مثبت باشد').required('تعداد روز مهلت الزامی است'), + values: Yup.array() + .of( + Yup.object({ + companyId: Yup.string().required(), + waterUsage: Yup.number().min(0, 'مصرف آب باید عدد مثبت باشد').required('مصرف آب الزامی است'), + }) + ) + .min(1, 'حداقل یک شرکت باید مصرف داشته باشد') + .required('اطلاعات مصرف شرکت‌ها الزامی است'), + }), + onSubmit: async (values) => { + const filteredValues = values.values.filter((v) => v.companyId && (v.waterUsage ?? 0) >= 0) + if (filteredValues.length === 0) { + toast.error('حداقل یک شرکت با مصرف معتبر وارد کنید') + return + } + await createBill.mutateAsync( + { ...values, values: filteredValues }, + { + onSuccess: () => { + toast.success('قبض آب با موفقیت ثبت شد') + navigate(Pages.company.list) + }, + onError: (error: ErrorType) => { + toast.error(error.response?.data?.error?.message?.[0] ?? 'خطا در ثبت قبض') + }, + } + ) + }, + }) + + const initializedRef = useRef(false) + useEffect(() => { + if (companies.length > 0 && !initializedRef.current) { + initializedRef.current = true + formik.setFieldValue( + 'values', + companies.map((c) => ({ companyId: c.id, waterUsage: 0 })) + ) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [companies]) + + if (getCompanies.isLoading) { + return + } + + if (companies.length === 0 && !getCompanies.isLoading) { + return ( +
+ شرکتی ثبت نشده است. ابتدا شرکت اضافه کنید. +
+ ) + } + + const setWaterUsage = (companyId: string, waterUsage: number) => { + const next = formik.values.values.map((v) => + v.companyId === companyId ? { ...v, waterUsage } : v + ) + formik.setFieldValue('values', next) + } + + return ( +
+
+
افزودن قبض آب
+ +
+ +
+
اطلاعات قبض
+ +
+ + +
+ +
+
+ مصرف آب به تفکیک شرکت +

مصرف آب هر شرکت را در ردیف مربوطه وارد کنید.

+
+ +
+ + + + + + + + + + {companies.map((company, index) => { + const value = formik.values.values.find((v) => v.companyId === company.id) + const usage = value?.waterUsage ?? 0 + return ( + + + + + + ) + })} + +
ردیفنام شرکتمصرف آب
{index + 1}{company.name} + setWaterUsage(company.id, Number(e.target.value) || 0)} + error_text={ + Array.isArray(formik.errors.values) && + formik.errors.values[index] && + (formik.errors.values[index] as { waterUsage?: string })?.waterUsage + ? (formik.errors.values[index] as { waterUsage: string }).waterUsage + : '' + } + className="!mb-0" + /> +
+
+ + {formik.touched.values && typeof formik.errors.values === 'string' && ( +
{formik.errors.values}
+ )} +
+
+
+ ) +} + +export default CreateBill diff --git a/src/pages/bill/hooks/useBillData.ts b/src/pages/bill/hooks/useBillData.ts new file mode 100644 index 0000000..c7c7ff6 --- /dev/null +++ b/src/pages/bill/hooks/useBillData.ts @@ -0,0 +1,8 @@ +import { useMutation } from "@tanstack/react-query"; +import * as api from "../service/Service"; + +export const useCreateBill = () => { + return useMutation({ + mutationFn: api.createBill, + }); +}; diff --git a/src/pages/bill/service/Service.ts b/src/pages/bill/service/Service.ts new file mode 100644 index 0000000..6cf002d --- /dev/null +++ b/src/pages/bill/service/Service.ts @@ -0,0 +1,7 @@ +import axios from "../../../config/axios"; +import { CreateBillType } from "../types/Types"; + +export const createBill = async (params: CreateBillType) => { + const { data } = await axios.post("/bills/water", params); + return data; +}; diff --git a/src/pages/bill/types/Types.ts b/src/pages/bill/types/Types.ts new file mode 100644 index 0000000..9f748be --- /dev/null +++ b/src/pages/bill/types/Types.ts @@ -0,0 +1,8 @@ +export type CreateBillType = { + waterRate: number; + dueDays: number; + values: { + companyId: string; + waterUsage: number; + }[]; +}; diff --git a/src/pages/company/hooks/useCompanyData.ts b/src/pages/company/hooks/useCompanyData.ts index e9ee3f0..c4c579f 100644 --- a/src/pages/company/hooks/useCompanyData.ts +++ b/src/pages/company/hooks/useCompanyData.ts @@ -50,10 +50,17 @@ export const useCreateCompany = () => { }); }; -export const useGetCompanies = (page: number) => { +export const useGetCompanies = (page: number, perPage?: number) => { return useQuery({ - queryKey: ["companies", page], - queryFn: () => api.getCompanies(page), + queryKey: ["companies", page, perPage], + queryFn: () => api.getCompanies(page, perPage), + }); +}; + +export const useGetAllCompanies = () => { + return useQuery({ + queryKey: ["companies", "all"], + queryFn: () => api.getCompanies(1, 1000), }); }; diff --git a/src/pages/company/service/CompanyService.ts b/src/pages/company/service/CompanyService.ts index af2f457..83a19fa 100644 --- a/src/pages/company/service/CompanyService.ts +++ b/src/pages/company/service/CompanyService.ts @@ -47,8 +47,10 @@ export const createCompany = async (params: CreateCompanyType) => { return data; }; -export const getCompanies = async (page: number) => { - const { data } = await axios.get(`/companies/list?page=${page}`); +export const getCompanies = async (page: number, perPage?: number) => { + let query = `?page=${page}`; + if (perPage) query += `&perPage=${perPage}`; + const { data } = await axios.get(`/companies/list${query}`); return data; }; diff --git a/src/router/Main.tsx b/src/router/Main.tsx index 1f6f23b..76c34a9 100644 --- a/src/router/Main.tsx +++ b/src/router/Main.tsx @@ -55,6 +55,7 @@ import RequestDetail from '../pages/requests/Detail' import SliderList from '../pages/slider/List' import UpdateSlider from '../pages/slider/Update' import CreateSlider from '../pages/slider/Create' +import CreateBill from '../pages/bill/Create' const MainRouter: FC = () => { const { hasSubMenu } = useSharedStore() @@ -123,6 +124,8 @@ const MainRouter: FC = () => { } /> } /> } /> + + } /> diff --git a/src/shared/components/CompanySubMenu.tsx b/src/shared/components/CompanySubMenu.tsx index c322c0f..df62560 100644 --- a/src/shared/components/CompanySubMenu.tsx +++ b/src/shared/components/CompanySubMenu.tsx @@ -41,6 +41,7 @@ const CompanySubMenu: FC = () => { isActive={isActive('industries')} link={Pages.company.industries} /> + diff --git a/src/shared/components/ReceiptSubMenu.tsx b/src/shared/components/ReceiptSubMenu.tsx index d86c205..40bdff4 100644 --- a/src/shared/components/ReceiptSubMenu.tsx +++ b/src/shared/components/ReceiptSubMenu.tsx @@ -38,6 +38,24 @@ const ReceiptSubMenu: FC = () => { isActive={isActive('create')} link={Pages.receipts.create} /> + + + + + + {/* */} )