@appcorp/fusion-storybook 0.3.74 → 0.3.76

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.
@@ -4,8 +4,8 @@ export declare const STUDENT_FEE_DRAWER: {
4
4
  readonly FORM_DRAWER: string;
5
5
  readonly MORE_ACTIONS_DRAWER: string;
6
6
  readonly VIEW_DRAWER: string;
7
- readonly SINGLE_ENTRY_DRAWER: "SINGLE_ENTRY_DRAWER";
8
- readonly CREATE_MONTHLY_DRAWER: "CREATE_MONTHLY_DRAWER";
7
+ readonly MISC_DRAWER_1: string;
8
+ readonly MISC_DRAWER_2: string;
9
9
  };
10
10
  export interface StudentFeesListResponse {
11
11
  items: StudentFeeBE[];
@@ -11,8 +11,8 @@ export const STUDENT_FEE_DRAWER = {
11
11
  FORM_DRAWER: DRAWER_TYPES.FORM_DRAWER,
12
12
  MORE_ACTIONS_DRAWER: DRAWER_TYPES.MORE_ACTIONS_DRAWER,
13
13
  VIEW_DRAWER: DRAWER_TYPES.VIEW_DRAWER,
14
- SINGLE_ENTRY_DRAWER: "SINGLE_ENTRY_DRAWER",
15
- CREATE_MONTHLY_DRAWER: "CREATE_MONTHLY_DRAWER",
14
+ MISC_DRAWER_1: DRAWER_TYPES.MISC_DRAWER_1,
15
+ MISC_DRAWER_2: DRAWER_TYPES.MISC_DRAWER_2,
16
16
  };
17
17
  const studentFeeConfig = {
18
18
  name: "StudentFee",
@@ -460,7 +460,7 @@ export const useStudentFeeModule = () => {
460
460
  resetRecordFormState();
461
461
  dispatch({
462
462
  type: STUDENT_FEE_ACTION_TYPES.SET_DRAWER,
463
- payload: { drawer: STUDENT_FEE_DRAWER.SINGLE_ENTRY_DRAWER },
463
+ payload: { drawer: STUDENT_FEE_DRAWER.MISC_DRAWER_1 },
464
464
  });
465
465
  }, [dispatch, resetRecordFormState]);
466
466
  const handleCreateMonthly = useCallback(() => {
@@ -471,7 +471,7 @@ export const useStudentFeeModule = () => {
471
471
  });
472
472
  dispatch({
473
473
  type: STUDENT_FEE_ACTION_TYPES.SET_DRAWER,
474
- payload: { drawer: STUDENT_FEE_DRAWER.CREATE_MONTHLY_DRAWER },
474
+ payload: { drawer: STUDENT_FEE_DRAWER.MISC_DRAWER_2 },
475
475
  });
476
476
  }, [dispatch, resetRecordFormState]);
477
477
  const handleView = useCallback((row) => {
@@ -10,6 +10,6 @@ export const StudentFeeCreateMonthly = () => {
10
10
  const { closeDrawer, handleProceedMonthlyCreation, state, updateLoading } = useStudentFeeModule();
11
11
  const t = useTranslations("studentFee");
12
12
  const { disableSaveButton, drawer, errors } = state;
13
- const isOpen = drawer === STUDENT_FEE_DRAWER.CREATE_MONTHLY_DRAWER;
13
+ const isOpen = drawer === STUDENT_FEE_DRAWER.MISC_DRAWER_1;
14
14
  return (_jsx(DrawerGeneric, { filterDrawer: null, filterDrawerHeader: null, filterDrawerFooter: null, formDrawer: isOpen ? _jsx(StudentFeeMonthlyForm, {}) : null, formDrawerHeader: isOpen ? (_jsx(EnhancedDrawerHeader, { title: t("drawerCreateMonthlyTitle"), description: t("drawerCreateMonthlyDescription") })) : null, formDrawerFooter: isOpen ? (_jsx(EnhancedDrawerFooter, { applyFilters: () => { }, clearFilters: () => { }, closeDrawer: closeDrawer, disableSaveButton: disableSaveButton, drawerType: DRAWER_FOOTER_COMPONENT_TYPE.FORM_DRAWER, errors: errors, handleSubmit: handleProceedMonthlyCreation, updateLoading: updateLoading })) : null, viewDrawer: null, viewDrawerHeader: null, viewDrawerFooter: null, moreActionsDrawer: null, moreActionsDrawerHeader: null, moreActionsDrawerFooter: null, onOpenChange: (open) => !open && closeDrawer(), open: isOpen }));
15
15
  };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * StudentFee Filter
3
+ *
4
+ * Filter UI for the student-fee list. Supports filterEnabled (radio) and
5
+ * filterStatus (payment status combobox).
6
+ */
7
+ import React from "react";
8
+ export declare const StudentFeeMonthly: () => React.JSX.Element;
@@ -0,0 +1,33 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * StudentFee Filter
5
+ *
6
+ * Filter UI for the student-fee list. Supports filterEnabled (radio) and
7
+ * filterStatus (payment status combobox).
8
+ */
9
+ import { useCallback, useState } from "react";
10
+ import { STUDENT_FEE_ACTION_TYPES, useStudentFeeModule } from "./context";
11
+ import { useTranslations } from "next-intl";
12
+ import { EnhancedCheckbox } from "@appcorp/shadcn/components/enhanced-checkbox";
13
+ const CHECKBOX_KEYS = [
14
+ "formMonthlyCheckStudentProfile",
15
+ "formMonthlyCheckFeeStructure",
16
+ "formMonthlyCheckGmail",
17
+ "formMonthlyCheckReady",
18
+ ];
19
+ export const StudentFeeMonthly = () => {
20
+ const t = useTranslations("studentFee");
21
+ const { dispatch } = useStudentFeeModule();
22
+ const [checked, setChecked] = useState(Object.fromEntries(CHECKBOX_KEYS.map((key) => [key, false])));
23
+ // const allChecked = CHECKBOX_KEYS.every((key) => checked[key]);
24
+ const handleCheckChange = useCallback((key, value) => {
25
+ const next = Object.assign(Object.assign({}, checked), { [key]: value });
26
+ setChecked(next);
27
+ dispatch({
28
+ type: STUDENT_FEE_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
29
+ payload: { disabled: !CHECKBOX_KEYS.every((k) => next[k]) },
30
+ });
31
+ }, [checked, dispatch]);
32
+ return (_jsxs("div", { className: "grid grid-cols-1 gap-4", children: [_jsx("p", { className: "text-foreground text-sm", children: t("formMonthlyWarningMessage") }), _jsx("div", { className: "flex flex-col gap-3", children: CHECKBOX_KEYS.map((key) => (_jsx(EnhancedCheckbox, { checked: checked[key], id: key, label: t(key), onCheckedChange: (value) => handleCheckChange(key, value) }, key))) })] }));
33
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * StudentFee Filter
3
+ *
4
+ * Filter UI for the student-fee list. Supports filterEnabled (radio) and
5
+ * filterStatus (payment status combobox).
6
+ */
7
+ import React from "react";
8
+ export declare const StudentFeeSingle: () => React.JSX.Element;
@@ -0,0 +1,122 @@
1
+ "use client";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * StudentFee Filter
5
+ *
6
+ * Filter UI for the student-fee list. Supports filterEnabled (radio) and
7
+ * filterStatus (payment status combobox).
8
+ */
9
+ import { useEffect, useMemo, useRef, useState } from "react";
10
+ import { STUDENT_FEE_ACTION_TYPES, useStudentFeeModule } from "./context";
11
+ import { useTranslations } from "next-intl";
12
+ import { EnhancedTextarea } from "@appcorp/shadcn/components/enhanced-textarea";
13
+ import { EnhancedInput } from "@appcorp/shadcn/components/enhanced-input";
14
+ import { getCachedWorkspaceSync } from "../workspace/cache";
15
+ import { useDebounce } from "@react-pakistan/util-functions/hooks/use-debounce";
16
+ import { useFetch } from "@react-pakistan/util-functions/hooks/use-fetch";
17
+ import { STUDENT_FEE_API_ROUTES } from "@/constants";
18
+ import { API_METHODS } from "@react-pakistan/util-functions/constants/api-methods";
19
+ import { DISCOUNT_TYPE } from "../../types";
20
+ import { Loader2 } from "lucide-react";
21
+ export const StudentFeeSingle = () => {
22
+ var _a, _b, _c, _d, _e, _f, _g, _h;
23
+ const { dispatch } = useStudentFeeModule();
24
+ // const { state } = useStudentFeeModule();
25
+ const workspace = getCachedWorkspaceSync();
26
+ 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
+ const t = useTranslations("studentFee");
28
+ // const [amountPaid, setAmountPaid] = useState("");
29
+ // const [remarks, setRemarks] = useState("");
30
+ 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
+ const debouncedComputerNumber = useDebounce(computerNumber, 800);
38
+ const { fetchNow: fetchByComputerNumber, data: feeByComputerNumber, loading: fetchingByCN, } = useFetch(STUDENT_FEE_API_ROUTES.BY_COMPUTER_NUMBER, {
39
+ method: API_METHODS.GET,
40
+ });
41
+ const fetchByCNRef = useRef(fetchByComputerNumber);
42
+ useEffect(() => {
43
+ fetchByCNRef.current = fetchByComputerNumber;
44
+ }, [fetchByComputerNumber]);
45
+ useEffect(() => {
46
+ var _a;
47
+ if (!debouncedComputerNumber)
48
+ return;
49
+ fetchByCNRef.current(undefined, {
50
+ params: {
51
+ computerNumber: debouncedComputerNumber,
52
+ schoolId: (_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id,
53
+ },
54
+ });
55
+ }, [debouncedComputerNumber, (_c = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _c === void 0 ? void 0 : _c.id]);
56
+ const isStale = computerNumber !== debouncedComputerNumber;
57
+ const hasData = !!feeByComputerNumber &&
58
+ !!debouncedComputerNumber &&
59
+ !isStale &&
60
+ !fetchingByCN;
61
+ const response = hasData
62
+ ? feeByComputerNumber
63
+ : null;
64
+ const profile = (_d = response === null || response === void 0 ? void 0 : response.studentProfile) !== null && _d !== void 0 ? _d : null;
65
+ const fee = (_f = (_e = response === null || response === void 0 ? void 0 : response.studentFees) === null || _e === void 0 ? void 0 : _e[0]) !== null && _f !== void 0 ? _f : null;
66
+ useEffect(() => {
67
+ dispatch({
68
+ type: STUDENT_FEE_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
69
+ payload: { disabled: false },
70
+ });
71
+ }, [fee, dispatch]);
72
+ const paymentStatusLabelMap = {
73
+ PENDING: t("formOptionPending"),
74
+ PARTIAL: t("formOptionPartial"),
75
+ PAID: t("formOptionPaid"),
76
+ OVERDUE: t("formOptionOverdue"),
77
+ CANCELLED: t("formOptionCancelled"),
78
+ REFUNDED: t("formOptionRefunded"),
79
+ };
80
+ const studentName = profile
81
+ ? `${profile.firstName} ${profile.lastName}`.trim() || profile.id
82
+ : "";
83
+ const feeStructureName = ((_g = fee === null || fee === void 0 ? void 0 : fee.feeStructure) === null || _g === void 0 ? void 0 : _g.name) || (fee === null || fee === void 0 ? void 0 : fee.feeStructureId) || "";
84
+ const discountCodeLabel = (fee === null || fee === void 0 ? void 0 : fee.discountCode)
85
+ ? `${fee.discountCode.code} - ${fee.discountCode.discountValue}${fee.discountCode.discountType === DISCOUNT_TYPE.PERCENTAGE ? "%" : currency}`
86
+ : (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
+ const formatDisplayDate = (rawDate) => {
91
+ if (!rawDate)
92
+ return "";
93
+ const d = new Date(rawDate);
94
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
95
+ };
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
+ const accumulatedFine = useMemo(() => {
103
+ var _a;
104
+ if (!((_a = response === null || response === void 0 ? void 0 : response.studentFees) === null || _a === void 0 ? void 0 : _a.length))
105
+ return 0;
106
+ return response.studentFees.reduce((sum, f) => { var _a; return sum + ((_a = f.fine) !== null && _a !== void 0 ? _a : 0); }, 0);
107
+ }, [response]);
108
+ const handleUpdateAmountPaid = (value) => {
109
+ const amountPaid = parseFloat(value);
110
+ if (isNaN(amountPaid))
111
+ return;
112
+ setAmountPaid(value);
113
+ };
114
+ useEffect(() => {
115
+ (async () => {
116
+ setAmountPaid(String((accumulatedAmount !== null && accumulatedAmount !== void 0 ? accumulatedAmount : 0) + (accumulatedFine !== null && accumulatedFine !== void 0 ? accumulatedFine : 0)));
117
+ })();
118
+ }, [fee, accumulatedFine, accumulatedAmount, setAmountPaid]);
119
+ 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) +
120
+ (accumulatedFine !== null && accumulatedFine !== void 0 ? accumulatedFine : 0) -
121
+ 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] }));
122
+ };
@@ -23,11 +23,13 @@ import { StudentFeeFilter } from "./filter";
23
23
  import { StudentFeeForm } from "./form";
24
24
  import { StudentFeeMoreActions } from "./more-actions";
25
25
  import { StudentFeeView } from "./view";
26
- import { StudentFeeSingleEntry } from "./single-entry";
27
- import { StudentFeeCreateMonthly } from "./monthly-create";
26
+ // import { StudentFeeSingleEntry } from "./single-entry";
27
+ // import { StudentFeeCreateMonthly } from "./monthly-create";
28
28
  import { resolveRbacPermissions } from "../../utils/resolve-rbac-permissions";
29
29
  import { RbacNoAccess } from "../../components/rbac-no-access";
30
30
  import { formatStudentName, formatAmount, formatAmountPaid, formatAmountDue, } from "./constants";
31
+ import { StudentFeeMonthly } from "./msic-1";
32
+ import { StudentFeeSingle } from "./msic-2";
31
33
  // ============================================================================
32
34
  // TABLE COLUMN CONFIGURATION (static — formatters imported from constants)
33
35
  // ============================================================================
@@ -75,8 +77,8 @@ const createComponentInstances = () => ({
75
77
  form: _jsx(StudentFeeForm, {}),
76
78
  moreActions: _jsx(StudentFeeMoreActions, {}),
77
79
  view: _jsx(StudentFeeView, {}),
78
- misc1: _jsx(StudentFeeSingleEntry, {}),
79
- misc2: _jsx(StudentFeeCreateMonthly, {}),
80
+ misc1: _jsx(StudentFeeMonthly, {}),
81
+ misc2: _jsx(StudentFeeSingle, {}),
80
82
  });
81
83
  const createStudentFeeConfig = ({ dispatch, drawerButtonCancel, drawerButtonSave, drawerFilterDescription, drawerFilterTitle, drawerFormDescription, drawerFormTitle, drawerMisc1Description, drawerMisc1Title, drawerMisc2Description, drawerMisc2Title, drawerMoreActionsDescription, drawerMoreActionsTitle, drawerViewDescription, drawerViewTitle, tableColumnHeaderActions, tableColumnHeaderAmount, tableColumnHeaderAmountDue, tableColumnHeaderAmountPaid, tableColumnHeaderDueDate, tableColumnHeaderFeeStructure, tableColumnHeaderId, tableColumnHeaderRemarks, tableColumnHeaderStatus, tableColumnHeaderStudent, tableDescription, tableSearchPlaceholder, tableTitle, }) => {
82
84
  const components = createComponentInstances();
@@ -20,7 +20,7 @@ export const StudentFeeSingleEntry = () => {
20
20
  const [remarks, setRemarks] = useState("");
21
21
  const t = useTranslations("studentFee");
22
22
  const { disableSaveButton, drawer, errors } = state;
23
- const isOpen = drawer === STUDENT_FEE_DRAWER.SINGLE_ENTRY_DRAWER;
23
+ const isOpen = drawer === STUDENT_FEE_DRAWER.MISC_DRAWER_2;
24
24
  const { fetchNow: fetchByComputerNumber, data: feeByComputerNumber, loading: fetchingByCN, } = useFetch(STUDENT_FEE_API_ROUTES.BY_COMPUTER_NUMBER, {
25
25
  method: API_METHODS.GET,
26
26
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appcorp/fusion-storybook",
3
- "version": "0.3.74",
3
+ "version": "0.3.76",
4
4
  "scripts": {
5
5
  "build-storybook": "storybook build",
6
6
  "build:next": "next build",