@appcorp/fusion-storybook 0.3.99 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -56,6 +56,7 @@ export declare const STUDENT_FEE_ACTION_TYPES: {
56
56
  studentProfileId: string;
57
57
  filterEnabled: boolean | undefined;
58
58
  filterStatus: PAYMENT_STATUS | "";
59
+ studentFeesSingleEntry: StudentFeeBE[];
59
60
  }>, initialStudentFeeState: {
60
61
  items: StudentFeeBE[];
61
62
  count: number;
@@ -87,6 +88,7 @@ export declare const STUDENT_FEE_ACTION_TYPES: {
87
88
  studentProfileId: string;
88
89
  filterEnabled: boolean | undefined;
89
90
  filterStatus: PAYMENT_STATUS | "";
91
+ studentFeesSingleEntry: StudentFeeBE[];
90
92
  }, StudentFeeProvider: import("react").FC<{
91
93
  children: React.ReactNode;
92
94
  }>, studentFeeReducer: (state: {
@@ -120,6 +122,7 @@ export declare const STUDENT_FEE_ACTION_TYPES: {
120
122
  studentProfileId: string;
121
123
  filterEnabled: boolean | undefined;
122
124
  filterStatus: PAYMENT_STATUS | "";
125
+ studentFeesSingleEntry: StudentFeeBE[];
123
126
  }, action: any) => {
124
127
  items: StudentFeeBE[];
125
128
  count: number;
@@ -151,6 +154,7 @@ export declare const STUDENT_FEE_ACTION_TYPES: {
151
154
  studentProfileId: string;
152
155
  filterEnabled: boolean | undefined;
153
156
  filterStatus: PAYMENT_STATUS | "";
157
+ studentFeesSingleEntry: StudentFeeBE[];
154
158
  }, useStudentFeeContext: () => import("@react-pakistan/util-functions/factory/generic-module-factory").GenericModuleContextWithHandlers<{
155
159
  items: StudentFeeBE[];
156
160
  count: number;
@@ -182,4 +186,5 @@ export declare const STUDENT_FEE_ACTION_TYPES: {
182
186
  studentProfileId: string;
183
187
  filterEnabled: boolean | undefined;
184
188
  filterStatus: PAYMENT_STATUS | "";
189
+ studentFeesSingleEntry: StudentFeeBE[];
185
190
  }>;
@@ -60,6 +60,7 @@ const studentFeeConfig = {
60
60
  // Filters
61
61
  filterEnabled: undefined,
62
62
  filterStatus: "",
63
+ studentFeesSingleEntry: [],
63
64
  },
64
65
  };
65
66
  // ============================================================================
@@ -1,4 +1,4 @@
1
- import { PAYMENT_STATUS, StudentFeeBE, FEE_RISK_LEVEL } from "../../../type";
1
+ import { PAYMENT_STATUS, FEE_RISK_LEVEL } from "../../../type";
2
2
  import { type RowAction, type TableRow } from "@appcorp/shadcn/components/enhanced-table";
3
3
  export declare const useStudentFeeModule: () => {
4
4
  applyFilters: () => void;
@@ -20,13 +20,9 @@ export declare const useStudentFeeModule: () => {
20
20
  handleProceedMonthlyCreation: () => Promise<void>;
21
21
  handleSaveVouchers: () => Promise<void>;
22
22
  handleSearch: (query: string) => void;
23
- handleSingleRecord: (fees: {
24
- studentFees: StudentFeeBE[];
25
- }, amountPaid: string, remarks: string, paidAt?: string) => Promise<void>;
23
+ handleSingleRecord: () => Promise<void>;
26
24
  handleSubmit: () => void;
27
- handleSubmitSingleEntry: (fees: {
28
- studentFees: StudentFeeBE[];
29
- }, amountPaid: string, remarks: string, paidAt?: string) => Promise<void>;
25
+ handleSubmitSingleEntry: () => Promise<void>;
30
26
  handleView: (row?: TableRow) => void;
31
27
  headerActions: {
32
28
  enabled: boolean;
@@ -42,7 +38,7 @@ export declare const useStudentFeeModule: () => {
42
38
  updateLoading: boolean;
43
39
  handleCloseDrawer?: () => void;
44
40
  state: {
45
- items: StudentFeeBE[];
41
+ items: import("../../../types").StudentFeeBE[];
46
42
  count: number;
47
43
  currentPage: number;
48
44
  pageLimit: number;
@@ -72,6 +68,7 @@ export declare const useStudentFeeModule: () => {
72
68
  studentProfileId: string;
73
69
  filterEnabled: boolean | undefined;
74
70
  filterStatus: PAYMENT_STATUS | "";
71
+ studentFeesSingleEntry: import("../../../types").StudentFeeBE[];
75
72
  };
76
73
  dispatch: React.Dispatch<any>;
77
74
  };
@@ -513,8 +513,11 @@ export const useStudentFeeModule = () => {
513
513
  },
514
514
  });
515
515
  }, [dispatch, updateParams, t, showToast, updateFetchNow]);
516
- const handleSubmitSingleEntry = useCallback(async (fees, amountPaid, remarks, paidAt) => {
516
+ const handleSubmitSingleEntry = useCallback(async () => {
517
517
  var _a;
518
+ const schoolId = (_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id;
519
+ if (!schoolId)
520
+ return;
518
521
  dispatch({
519
522
  type: STUDENT_FEE_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
520
523
  payload: { disabled: true },
@@ -524,11 +527,11 @@ export const useStudentFeeModule = () => {
524
527
  method: API_METHODS.POST,
525
528
  headers: { "Content-Type": "application/json" },
526
529
  body: JSON.stringify({
527
- studentFees: fees.studentFees,
528
- amountPaid: Number(amountPaid),
529
- paidAt: paidAt || null,
530
- remarks,
531
- schoolId: ((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "",
530
+ studentFees: state.studentFeesSingleEntry.map((f) => (Object.assign(Object.assign({}, f), { status: state.status }))),
531
+ amountPaid: Number(state.amountPaid) || 0,
532
+ paidAt: state.paidAt || null,
533
+ remarks: state.remarks || "",
534
+ schoolId,
532
535
  }),
533
536
  });
534
537
  if (!res.ok) {
@@ -556,6 +559,11 @@ export const useStudentFeeModule = () => {
556
559
  (_d = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _d === void 0 ? void 0 : _d.id,
557
560
  resetFormAndCloseDrawer,
558
561
  listFetchNow,
562
+ state.studentFeesSingleEntry,
563
+ state.amountPaid,
564
+ state.paidAt,
565
+ state.remarks,
566
+ state.status,
559
567
  ]);
560
568
  // ============================================================================
561
569
  // 1.4.6 HEADER & ROW ACTIONS
@@ -9,6 +9,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
9
9
  import { useEffect, useMemo, useRef, useState } from "react";
10
10
  import { STUDENT_FEE_ACTION_TYPES, useStudentFeeModule } from "./context";
11
11
  import { useTranslations } from "next-intl";
12
+ import { useEnhancedCombobox } from "@appcorp/shadcn/hooks/use-enhanced-combobox";
12
13
  import { EnhancedTextarea } from "@appcorp/shadcn/components/enhanced-textarea";
13
14
  import { EnhancedInput } from "@appcorp/shadcn/components/enhanced-input";
14
15
  import { getCachedWorkspaceSync } from "../workspace/cache";
@@ -16,24 +17,16 @@ import { useDebounce } from "@react-pakistan/util-functions/hooks/use-debounce";
16
17
  import { useFetch } from "@react-pakistan/util-functions/hooks/use-fetch";
17
18
  import { STUDENT_FEE_API_ROUTES } from "../../constants";
18
19
  import { API_METHODS } from "@react-pakistan/util-functions/constants/api-methods";
19
- import { DISCOUNT_TYPE } from "../../types";
20
+ import { DISCOUNT_TYPE, PAYMENT_STATUS } from "../../types";
21
+ import { PAYMENT_STATUS_OPTIONS } from "./constants";
20
22
  import { Loader2 } from "lucide-react";
21
23
  export const StudentFeeSingle = () => {
22
24
  var _a, _b, _c, _d, _e, _f, _g, _h;
23
- const { dispatch } = useStudentFeeModule();
24
- // const { state } = useStudentFeeModule();
25
+ const { dispatch, handleChange, state } = useStudentFeeModule();
25
26
  const workspace = getCachedWorkspaceSync();
26
27
  const currency = (_b = (_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.currency) !== null && _b !== void 0 ? _b : "";
27
28
  const t = useTranslations("studentFee");
28
- // const [amountPaid, setAmountPaid] = useState("");
29
- // const [remarks, setRemarks] = useState("");
30
29
  const [computerNumber, setComputerNumber] = useState("");
31
- const [amountPaid, setAmountPaid] = useState("");
32
- const [paidAt, setPaidAt] = useState(() => {
33
- const d = new Date();
34
- return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
35
- });
36
- const [remarks, setRemarks] = useState("");
37
30
  const debouncedComputerNumber = useDebounce(computerNumber, 800);
38
31
  const { fetchNow: fetchByComputerNumber, data: feeByComputerNumber, loading: fetchingByCN, } = useFetch(STUDENT_FEE_API_ROUTES.BY_COMPUTER_NUMBER, {
39
32
  method: API_METHODS.GET,
@@ -53,6 +46,41 @@ export const StudentFeeSingle = () => {
53
46
  },
54
47
  });
55
48
  }, [debouncedComputerNumber, (_c = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _c === void 0 ? void 0 : _c.id]);
49
+ const accumulatedAmount = useMemo(() => {
50
+ var _a;
51
+ if (!((_a = feeByComputerNumber === null || feeByComputerNumber === void 0 ? void 0 : feeByComputerNumber.items) === null || _a === void 0 ? void 0 : _a.length))
52
+ return 0;
53
+ return feeByComputerNumber.items.reduce((sum, f) => { var _a; return sum + ((_a = f.amount) !== null && _a !== void 0 ? _a : 0); }, 0);
54
+ }, [feeByComputerNumber]);
55
+ useEffect(() => {
56
+ var _a;
57
+ if (!((_a = feeByComputerNumber === null || feeByComputerNumber === void 0 ? void 0 : feeByComputerNumber.items) === null || _a === void 0 ? void 0 : _a.length))
58
+ return;
59
+ const total = accumulatedAmount + 0;
60
+ dispatch({
61
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
62
+ payload: {
63
+ key: "studentFeesSingleEntry",
64
+ value: feeByComputerNumber.items,
65
+ },
66
+ });
67
+ dispatch({
68
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
69
+ payload: { key: "amountPaid", value: total },
70
+ });
71
+ dispatch({
72
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
73
+ payload: { key: "paidAt", value: state.paidAt },
74
+ });
75
+ dispatch({
76
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
77
+ payload: { key: "remarks", value: "" },
78
+ });
79
+ dispatch({
80
+ type: STUDENT_FEE_ACTION_TYPES.SET_INPUT_FIELD,
81
+ payload: { key: "status", value: PAYMENT_STATUS.PENDING },
82
+ });
83
+ }, [feeByComputerNumber, dispatch, accumulatedAmount, state.paidAt]);
56
84
  const isStale = computerNumber !== debouncedComputerNumber;
57
85
  const hasData = !!feeByComputerNumber &&
58
86
  !!debouncedComputerNumber &&
@@ -84,38 +112,47 @@ export const StudentFeeSingle = () => {
84
112
  const discountCodeLabel = (fee === null || fee === void 0 ? void 0 : fee.discountCode)
85
113
  ? `${fee.discountCode.code} - ${fee.discountCode.discountValue}${fee.discountCode.discountType === DISCOUNT_TYPE.PERCENTAGE ? "%" : currency}`
86
114
  : (fee === null || fee === void 0 ? void 0 : fee.discountCodeId) || "";
87
- const statusDisplay = (fee === null || fee === void 0 ? void 0 : fee.status)
88
- ? paymentStatusLabelMap[fee.status] || fee.status
89
- : "";
90
115
  const formatDisplayDate = (rawDate) => {
91
116
  if (!rawDate)
92
117
  return "";
93
118
  const d = new Date(rawDate);
94
119
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
95
120
  };
96
- const accumulatedAmount = useMemo(() => {
97
- var _a;
98
- if (!((_a = response === null || response === void 0 ? void 0 : response.studentFees) === null || _a === void 0 ? void 0 : _a.length))
99
- return 0;
100
- return response.studentFees.reduce((sum, f) => { var _a; return sum + ((_a = f.amount) !== null && _a !== void 0 ? _a : 0); }, 0);
101
- }, [response]);
102
121
  // const accumulatedFine = useMemo(() => {
103
122
  // if (!response?.studentFees?.length) return 0;
104
123
  // return response.studentFees.reduce((sum, f) => sum + (f.fine ?? 0), 0);
105
124
  // }, [response]);
106
125
  const accumulatedFine = 0;
107
126
  const handleUpdateAmountPaid = (value) => {
108
- const amountPaid = parseFloat(value);
109
- if (isNaN(amountPaid))
127
+ const parsed = parseFloat(value);
128
+ if (isNaN(parsed))
110
129
  return;
111
- setAmountPaid(value);
130
+ handleChange("amountPaid", parsed);
112
131
  };
113
- useEffect(() => {
114
- (async () => {
115
- setAmountPaid(String((accumulatedAmount !== null && accumulatedAmount !== void 0 ? accumulatedAmount : 0) + (accumulatedFine !== null && accumulatedFine !== void 0 ? accumulatedFine : 0)));
116
- })();
117
- }, [fee, accumulatedFine, accumulatedAmount, setAmountPaid]);
118
- return (_jsxs("div", { className: "grid grid-cols-1 gap-4", children: [_jsx(EnhancedInput, { id: "computerNumber", info: t("formComputerNumberInfo"), label: t("formComputerNumberLabel"), onChange: (e) => setComputerNumber(e.target.value), placeholder: t("formComputerNumberPlaceholder"), type: "number", required: true, value: computerNumber }), fetchingByCN && debouncedComputerNumber ? (_jsx("div", { className: "flex items-center justify-center py-4", children: _jsx(Loader2, { className: "text-muted-foreground h-5 w-5 animate-spin" }) })) : null, fee && profile ? (_jsxs(_Fragment, { children: [_jsx(EnhancedInput, { readOnly: true, id: "studentProfileId-readonly", label: t("formStudentLabel"), value: studentName }), _jsx(EnhancedInput, { readOnly: true, id: "feeStructureId-readonly", label: t("formFeeStructureLabel"), value: feeStructureName }), _jsx(EnhancedInput, { readOnly: true, id: "discountCodeId-readonly", label: t("formDiscountCodeLabel"), value: discountCodeLabel }), _jsx(EnhancedInput, { readOnly: true, id: "discountAmount-readonly", label: t("formDiscountAmountLabel"), value: (_h = fee === null || fee === void 0 ? void 0 : fee.discountAmount) !== null && _h !== void 0 ? _h : 0, type: "number", step: "0.01" }), _jsx(EnhancedInput, { readOnly: true, id: "accumulatedFine-readonly", info: t("formAccumulatedFineInfo"), label: t("formAccumulatedFineLabel"), value: accumulatedFine, type: "number", step: "0.01" }), _jsx(EnhancedInput, { readOnly: true, id: "amount-readonly", info: t("formTotalAmountInfo"), label: t("formTotalAmountLabel"), value: accumulatedAmount + (accumulatedFine !== null && accumulatedFine !== void 0 ? accumulatedFine : 0), type: "number", step: "0.01" }), _jsx(EnhancedInput, { id: "amountPaid", info: t("formAmountPaidInfo"), label: t("formAmountPaidLabel"), value: accumulatedAmount + (accumulatedFine !== null && accumulatedFine !== void 0 ? accumulatedFine : 0) - fee.amountPaid || "0", onChange: (e) => handleUpdateAmountPaid(e.target.value), type: "number", step: "0.01" }), _jsx(EnhancedInput, { readOnly: true, id: "amountDue-readonly", info: t("formAmountDueInfo"), label: t("formAmountDueLabel"), value: (accumulatedAmount !== null && accumulatedAmount !== void 0 ? accumulatedAmount : 0) +
132
+ const { enhancedComboboxElement: statusCombo } = useEnhancedCombobox({
133
+ emptyText: t("formNoStatusEmpty"),
134
+ id: "status",
135
+ info: t("formStatusInfo"),
136
+ label: t("formStatusLabel"),
137
+ onValueChange: (value) => handleChange("status", value),
138
+ options: PAYMENT_STATUS_OPTIONS.map((opt) => ({
139
+ value: opt.value,
140
+ label: paymentStatusLabelMap[opt.value] || opt.label,
141
+ })),
142
+ placeholder: t("formStatusPlaceholder"),
143
+ required: true,
144
+ searchEndpoint: STUDENT_FEE_API_ROUTES.UNIT,
145
+ searchPlaceholder: t("formSearchStatusPlaceholder"),
146
+ formatSearchResult: (item) => {
147
+ var _a, _b;
148
+ return ({
149
+ label: String((_a = item.label) !== null && _a !== void 0 ? _a : ""),
150
+ value: String((_b = item.value) !== null && _b !== void 0 ? _b : ""),
151
+ });
152
+ },
153
+ value: state.status,
154
+ });
155
+ return (_jsxs("div", { className: "grid grid-cols-1 gap-4", children: [_jsx(EnhancedInput, { id: "computerNumber", info: t("formComputerNumberInfo"), label: t("formComputerNumberLabel"), onChange: (e) => setComputerNumber(e.target.value), placeholder: t("formComputerNumberPlaceholder"), type: "number", required: true, value: computerNumber }), fetchingByCN && debouncedComputerNumber ? (_jsx("div", { className: "flex items-center justify-center py-4", children: _jsx(Loader2, { className: "text-muted-foreground h-5 w-5 animate-spin" }) })) : null, fee && profile ? (_jsxs(_Fragment, { children: [_jsx(EnhancedInput, { readOnly: true, id: "studentProfileId-readonly", label: t("formStudentLabel"), value: studentName }), _jsx(EnhancedInput, { readOnly: true, id: "feeStructureId-readonly", label: t("formFeeStructureLabel"), value: feeStructureName }), _jsx(EnhancedInput, { readOnly: true, id: "discountCodeId-readonly", label: t("formDiscountCodeLabel"), value: discountCodeLabel }), _jsx(EnhancedInput, { readOnly: true, id: "discountAmount-readonly", label: t("formDiscountAmountLabel"), value: (_h = fee === null || fee === void 0 ? void 0 : fee.discountAmount) !== null && _h !== void 0 ? _h : 0, type: "number", step: "0.01" }), _jsx(EnhancedInput, { readOnly: true, id: "accumulatedFine-readonly", info: t("formAccumulatedFineInfo"), label: t("formAccumulatedFineLabel"), value: accumulatedFine, type: "number", step: "0.01" }), _jsx(EnhancedInput, { readOnly: true, id: "amount-readonly", info: t("formTotalAmountInfo"), label: t("formTotalAmountLabel"), value: accumulatedAmount + (accumulatedFine !== null && accumulatedFine !== void 0 ? accumulatedFine : 0), type: "number", step: "0.01" }), _jsx(EnhancedInput, { id: "amountPaid", info: t("formAmountPaidInfo"), label: t("formAmountPaidLabel"), value: state.amountPaid || 0, onChange: (e) => handleUpdateAmountPaid(e.target.value), type: "number", step: "0.01" }), _jsx(EnhancedInput, { readOnly: true, id: "amountDue-readonly", info: t("formAmountDueInfo"), label: t("formAmountDueLabel"), value: (accumulatedAmount !== null && accumulatedAmount !== void 0 ? accumulatedAmount : 0) +
119
156
  (accumulatedFine !== null && accumulatedFine !== void 0 ? accumulatedFine : 0) -
120
- parseFloat(amountPaid || "0"), type: "number", step: "0.01" }), _jsx(EnhancedInput, { readOnly: true, id: "dueDate-readonly", label: t("formDueDateLabel"), value: formatDisplayDate(fee === null || fee === void 0 ? void 0 : fee.dueDate), type: "date" }), _jsx(EnhancedInput, { id: "paidAt", info: t("formPaidAtInfo"), label: t("formPaidAtLabel"), onChange: (e) => setPaidAt(e.target.value), onClick: (e) => { var _a, _b; return (_b = (_a = e.currentTarget).showPicker) === null || _b === void 0 ? void 0 : _b.call(_a); }, type: "date", value: paidAt || "" }), _jsx(EnhancedInput, { readOnly: true, id: "status-readonly", label: t("formStatusLabel"), value: statusDisplay }), _jsx(EnhancedTextarea, { id: "remarks-readonly", label: t("formRemarksLabel"), value: remarks || "", onChange: (e) => setRemarks(e.target.value) })] })) : null] }));
157
+ Number(state.amountPaid || 0), type: "number", step: "0.01" }), _jsx(EnhancedInput, { readOnly: true, id: "dueDate-readonly", label: t("formDueDateLabel"), value: formatDisplayDate(fee === null || fee === void 0 ? void 0 : fee.dueDate), type: "date" }), _jsx(EnhancedInput, { id: "paidAt", info: t("formPaidAtInfo"), label: t("formPaidAtLabel"), onChange: (e) => handleChange("paidAt", e.target.value), onClick: (e) => { var _a, _b; return (_b = (_a = e.currentTarget).showPicker) === null || _b === void 0 ? void 0 : _b.call(_a); }, type: "date", value: state.paidAt || "" }), statusCombo, _jsx(EnhancedTextarea, { id: "remarks", label: t("formRemarksLabel"), value: state.remarks || "", onChange: (e) => handleChange("remarks", e.target.value) })] })) : null] }));
121
158
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appcorp/fusion-storybook",
3
- "version": "0.3.99",
3
+ "version": "0.4.0",
4
4
  "scripts": {
5
5
  "build-storybook": "storybook build",
6
6
  "build:next": "next build",