From 467ca9e5df102c8caff4dd226a1092d6302589c5 Mon Sep 17 00:00:00 2001 From: Areos Chen Date: Sat, 6 Apr 2024 01:36:40 +1030 Subject: [PATCH] imp: bonus & deduction for payslip --- src/configs/i18n/scriptEn.ts | 9 ++ src/configs/schema/payslipSchema.ts | 8 +- src/configs/zustore/payslipStore.ts | 58 ++++++++ src/lib/time.ts | 2 +- src/pageComponents/modals/mPayslip/Bonus.tsx | 125 +++++++++++++++++ .../modals/mPayslip/Deduction.tsx | 130 ++++++++++++++++++ .../modals/mPayslip/FormContent.tsx | 13 +- .../modals/mPayslip/WorkCard.tsx | 8 +- .../payslip/template1/BDFooter.tsx | 47 +++++++ .../payslip/template1/BDHeader.tsx | 23 ++++ .../pdfTemplates/payslip/template1/BDRows.tsx | 46 +++++++ .../payslip/template1/BillTitle.tsx | 77 ++++++----- .../{TableFooter.tsx => PayFooter.tsx} | 4 +- .../payslip/template1/PayHeader.tsx | 14 +- .../payslip/template1/PayRows.tsx | 44 ++++-- .../payslip/template1/TableHeader.tsx | 29 ---- .../payslip/template1/TableRows.tsx | 67 --------- .../payslip/template1/template.tsx | 63 +++++---- 18 files changed, 584 insertions(+), 183 deletions(-) create mode 100644 src/pageComponents/modals/mPayslip/Bonus.tsx create mode 100644 src/pageComponents/modals/mPayslip/Deduction.tsx create mode 100644 src/pageComponents/pdfTemplates/payslip/template1/BDFooter.tsx create mode 100644 src/pageComponents/pdfTemplates/payslip/template1/BDHeader.tsx create mode 100644 src/pageComponents/pdfTemplates/payslip/template1/BDRows.tsx rename src/pageComponents/pdfTemplates/payslip/template1/{TableFooter.tsx => PayFooter.tsx} (96%) delete mode 100644 src/pageComponents/pdfTemplates/payslip/template1/TableHeader.tsx delete mode 100644 src/pageComponents/pdfTemplates/payslip/template1/TableRows.tsx diff --git a/src/configs/i18n/scriptEn.ts b/src/configs/i18n/scriptEn.ts index 6305a10..9318035 100644 --- a/src/configs/i18n/scriptEn.ts +++ b/src/configs/i18n/scriptEn.ts @@ -76,6 +76,8 @@ const en = { }, btn: { addDate: "Add Date", + addNewBonus: "Add New Bonus", + addNewDeduction: "Add New Deduction", append: "Append", addClient: "Register New Client", addStuff: "Register New Staff", @@ -119,12 +121,14 @@ const en = { addr: "Addr", address: "Address", addrJob: "Job Address", + amount: "Amount", assignStaff: "Assign Staff", assignedStaff: "Assigned Staff", aud: "AUD", balance: "Balance", billTo: "Bill To", bld: "BLD", + bonus: "Bonus", bsb: "BSB", break: "Break", bank: "Bank Account", @@ -138,9 +142,11 @@ const en = { completed: "Completed", companyInfo: "Company Info", confirmedWU: "Confirmed Work Units", + confirmedWL: "Confirmed Work Logs", country: "Country", date: "Date", datePicker: "Date Picker", + deduction: "Deduction", defaultUnit: "Default Unit", defaultPrice: "Default Price", deposit: "Deposit", @@ -171,6 +177,7 @@ const en = { manager: "Manager", menu: "Menu", name: "Name", + note: "Note", netto: "Netto", newIssueDate: "New Issue Date", none: "None", @@ -194,6 +201,8 @@ const en = { paymentTo: "Payment To", payDate: "Paid Date", payslip: "Payslip", + payPeriod: "Pay Period", + payTo: "Pay To", pending: "Pending", period: "Work Period", pc: "Poscode", diff --git a/src/configs/schema/payslipSchema.ts b/src/configs/schema/payslipSchema.ts index 310665d..bd7427d 100644 --- a/src/configs/schema/payslipSchema.ts +++ b/src/configs/schema/payslipSchema.ts @@ -13,18 +13,16 @@ const payslipSchema = z.object({ }); const bonusSchema = z.object({ - bsid: z.string().default(""), fk_psid: z.string().default(""), fk_uid: z.string().default(""), - bs_note: z.string().trim().nullable().default(""), + note: z.string().trim().nullable().default(""), amount: z.number().default(0), }); const deductionSchema = z.object({ - did: z.string().default(""), fk_psid: z.string().default(""), fk_uid: z.string().default(""), - bs_note: z.string().trim().nullable().default(""), + note: z.string().trim().nullable().default(""), amount: z.number().default(0), }); @@ -34,3 +32,5 @@ const payslipsSchema = payslipSchema.extend({ }); export type Tpayslips = z.infer; +export type Tbonus = z.infer; +export type Tdedcution = z.infer; diff --git a/src/configs/zustore/payslipStore.ts b/src/configs/zustore/payslipStore.ts index e17705a..7a0647f 100644 --- a/src/configs/zustore/payslipStore.ts +++ b/src/configs/zustore/payslipStore.ts @@ -2,26 +2,84 @@ import { useStore } from "zustand"; import { createStore } from "zustand/vanilla"; import { DateRange } from "react-day-picker"; import { TwlTableRow } from "../schema/workSchema"; +import { Tbonus, Tdedcution } from "../schema/payslipSchema"; type Tstate = { dayRange: DateRange; staffWL: TwlTableRow[]; + bonus: Partial[]; + dedcution: Partial[]; }; type Taction = { setDayRange: (range: DateRange | undefined) => void; setStaffWL: (worklogs: TwlTableRow[]) => void; + /* bonus */ + setBonusAmount: (index: number, amount: number) => void; + setBonusNote: (index: number, note: string) => void; + appendBonus: (bonus: Partial) => void; + removeBonus: (index: number) => void; + /* deduction */ + setDeductionAmount: (index: number, amount: number) => void; + setDeductionNote: (index: number, note: string) => void; + appendDeduction: (dedcution: Partial) => void; + removeDeduction: (index: number) => void; }; export const payslipStore = createStore((set) => ({ dayRange: { from: undefined, to: undefined }, staffWL: [], + bonus: [], + dedcution: [], setDayRange: (range: DateRange | undefined) => set({ dayRange: range }), setStaffWL: (worklogs: TwlTableRow[]) => set((state) => ({ ...state, staffWL: worklogs, })), + /* bonus */ + setBonusAmount: (index: number, amount: number) => + set((state) => { + const newBonus = [...state.bonus]; + newBonus[index] = { ...newBonus[index], amount }; + return { ...state, bonus: newBonus }; + }), + setBonusNote: (index: number, note: string) => + set((state) => { + const newBonus = [...state.bonus]; + newBonus[index] = { ...newBonus[index], note }; + return { ...state, bonus: newBonus }; + }), + appendBonus: (bonus: Partial) => + set((state) => ({ ...state, bonus: [...state.bonus, bonus] })), + removeBonus: (index: number) => + set((state) => { + const newBonus = state.bonus.filter((_, i) => i !== index); + return { ...state, bonus: newBonus }; + }), + /* deduction */ + setDeductionAmount: (index: number, amount: number) => + set((state) => { + const newDeduction = [...state.dedcution]; + newDeduction[index] = { ...newDeduction[index], amount }; + return { ...state, dedcution: newDeduction }; + }), + setDeductionNote: (index: number, note: string) => + set((state) => { + const newDeduction = [...state.dedcution]; + newDeduction[index] = { ...newDeduction[index], note }; + return { ...state, dedcution: newDeduction }; + }), + appendDeduction: (dedcution: Partial) => + set((state) => ({ + ...state, + dedcution: [...state.dedcution, dedcution], + })), + removeDeduction: (index: number) => + set((state) => { + const newDeduction = state.dedcution.filter((_, i) => i !== index); + return { ...state, dedcution: newDeduction }; + }), })); export const usePayslipStore = (selector: (state: Tstate & Taction) => T) => diff --git a/src/lib/time.ts b/src/lib/time.ts index 37e500a..e954844 100644 --- a/src/lib/time.ts +++ b/src/lib/time.ts @@ -19,7 +19,7 @@ export const auToISO = (date: string) => { * @returns yyy-MM-dd is used for datepicker */ export const dateFormat = ( - date: Date | string | null, + date: Date | string | null | undefined, form: "au" | "iso" = "iso" ) => { if (date instanceof Date) { diff --git a/src/pageComponents/modals/mPayslip/Bonus.tsx b/src/pageComponents/modals/mPayslip/Bonus.tsx new file mode 100644 index 0000000..c4572ad --- /dev/null +++ b/src/pageComponents/modals/mPayslip/Bonus.tsx @@ -0,0 +1,125 @@ +import type { FC } from "react"; +import { useState } from "react"; +import Card from "@/components/card"; +import { Button } from "@/components/ui/button"; +import { useTranslation } from "react-i18next"; +import { usePayslipStore } from "@/configs/zustore"; +import { XBtn } from "@/components/btns"; + +const Bonus: FC = () => { + const [t] = useTranslation(); + const bonus = usePayslipStore((state) => state.bonus); + const removeBonus = usePayslipStore((state) => state.removeBonus); + const appendBonus = usePayslipStore((state) => state.appendBonus); + const setBonusAmount = usePayslipStore((state) => state.setBonusAmount); + const setBonusNote = usePayslipStore((state) => state.setBonusNote); + const [amount, setAmount] = useState(0); + const [note, setNote] = useState(""); + let timeoutID: NodeJS.Timeout | null = null; + + const handleAddBonus = () => { + appendBonus({ amount: 0, note: "" }); + }; + + const AddBtn = () => { + return ( +
+ +
+ ); + }; + + const bonusList = bonus.map((b, i) => { + return ( +
+ {/* x btn */} +
+ { + removeBonus(i); + }} + /> +
+ +
+ + { + setAmount(parseInt(e.target.value)); + timeoutID && clearTimeout(timeoutID); + timeoutID = setTimeout(() => { + setBonusAmount(i, parseInt(e.target.value)); + }, 1500); + }} + onBlur={() => { + if (timeoutID) { + clearTimeout(timeoutID); + setBonusAmount(i, amount); + } + }} + className="outline-none h-9 block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6 pl-2" + /> +
+
+ +