@appcorp/fusion-storybook 0.4.15 → 0.4.17

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.
@@ -32,7 +32,7 @@ export declare const useAdmissionModule: () => {
32
32
  listLoading: boolean;
33
33
  rowActions: RowAction[];
34
34
  updateLoading: boolean;
35
- uploadAdmissionDocuments: (files: File[]) => Promise<string[]>;
35
+ uploadAdmissionDocuments: (files: File[], registrationCode: string) => Promise<string[]>;
36
36
  state: {
37
37
  items: AdmissionBE[];
38
38
  count: number;
@@ -16,6 +16,8 @@ import { admissionFormValidation } from "../validate";
16
16
  import { getCachedWorkspaceSync } from "../../workspace/cache";
17
17
  import { downloadAdmissionFormPDF, } from "../../../utils/admission-pdf";
18
18
  import { fileToBase64 } from "../../../utils/file-to-base64";
19
+ import { compressPdf, DocumentTooLargeError, isPdfFile, MAX_DOCUMENT_SIZE_BYTES, } from "../../../utils/compress-pdf";
20
+ import { wakeStorageServer } from "../../../utils/wake-storage";
19
21
  import { normalizeIdNumber } from "../../../utils/id-number";
20
22
  import { toE164Phone } from "../../../utils/to-e164-phone";
21
23
  import { formatPhoneDisplay } from "@react-pakistan/util-functions/general/format-phone-display";
@@ -293,13 +295,19 @@ export const useAdmissionModule = () => {
293
295
  (_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
294
296
  }
295
297
  }, [showToast, t]);
296
- const uploadAdmissionDocuments = useCallback(async (files) => {
298
+ const uploadAdmissionDocuments = useCallback(async (files, registrationCode) => {
297
299
  var _a;
298
300
  const schoolId = (_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id;
299
301
  if (!schoolId) {
300
302
  throw new Error("School context is not available");
301
303
  }
302
- const payload = await Promise.all(files.map(async (file) => ({
304
+ const prepared = await Promise.all(files.map(async (file) => isPdfFile(file) ? await compressPdf(file) : file));
305
+ for (const file of prepared) {
306
+ if (file.size > MAX_DOCUMENT_SIZE_BYTES) {
307
+ throw new DocumentTooLargeError(file.name, file.size);
308
+ }
309
+ }
310
+ const payload = await Promise.all(prepared.map(async (file) => ({
303
311
  fileName: file.name,
304
312
  contentType: file.type || "application/octet-stream",
305
313
  fileBase64: await fileToBase64(file),
@@ -310,7 +318,7 @@ export const useAdmissionModule = () => {
310
318
  headers: {
311
319
  "Content-Type": "application/json",
312
320
  },
313
- body: JSON.stringify({ schoolId, files: payload }),
321
+ body: JSON.stringify({ schoolId, registrationCode, files: payload }),
314
322
  });
315
323
  if (error || !(data === null || data === void 0 ? void 0 : data.urls)) {
316
324
  throw new Error("Upload failed");
@@ -355,11 +363,12 @@ export const useAdmissionModule = () => {
355
363
  resetFormAndCloseDrawer();
356
364
  }, [resetFormAndCloseDrawer]);
357
365
  const handleCreate = useCallback(() => {
366
+ wakeStorageServer();
358
367
  dispatch({
359
368
  type: ADMISSION_ACTION_TYPES.SET_DRAWER,
360
369
  payload: { drawer: ADMISSION_DRAWER.FORM_DRAWER },
361
370
  });
362
- }, [dispatch]);
371
+ }, [dispatch, wakeStorageServer]);
363
372
  const handleView = useCallback((row) => {
364
373
  byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
365
374
  dispatch({
@@ -368,12 +377,13 @@ export const useAdmissionModule = () => {
368
377
  });
369
378
  }, [dispatch, byIdFetchNow]);
370
379
  const handleEdit = useCallback((row) => {
380
+ wakeStorageServer();
371
381
  byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
372
382
  dispatch({
373
383
  type: ADMISSION_ACTION_TYPES.SET_DRAWER,
374
384
  payload: { drawer: ADMISSION_DRAWER.FORM_DRAWER },
375
385
  });
376
- }, [dispatch, byIdFetchNow]);
386
+ }, [dispatch, byIdFetchNow, wakeStorageServer]);
377
387
  const handleDelete = useCallback((row) => {
378
388
  if (!confirm(t("messagesDeleteConfirmation")))
379
389
  return;
@@ -638,7 +648,7 @@ export const useAdmissionModule = () => {
638
648
  const merged = state.documentsFiles.length
639
649
  ? [
640
650
  ...(state.documents || []),
641
- ...(await uploadAdmissionDocuments(state.documentsFiles)),
651
+ ...(await uploadAdmissionDocuments(state.documentsFiles, updateParams.registrationCode)),
642
652
  ]
643
653
  : state.documents || [];
644
654
  dispatch({
@@ -699,12 +709,14 @@ export const useAdmissionModule = () => {
699
709
  }),
700
710
  });
701
711
  }
702
- catch (_b) {
712
+ catch (error) {
703
713
  dispatch({
704
714
  type: ADMISSION_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
705
715
  payload: { disabled: false },
706
716
  });
707
- showToast(t("messagesDocumentsUploadFailed"), TOAST_VARIANT.ERROR);
717
+ showToast(t(error instanceof DocumentTooLargeError
718
+ ? "messagesDocumentTooLarge"
719
+ : "messagesDocumentsUploadFailed"), TOAST_VARIANT.ERROR);
708
720
  }
709
721
  },
710
722
  errorCallback: (errors) => {
@@ -0,0 +1,13 @@
1
+ interface BuildAutoPostPayloadInput {
2
+ schoolId: string;
3
+ computerNumbers: string[];
4
+ paidAt: string;
5
+ skipFine: boolean;
6
+ }
7
+ export declare function buildAutoPostPayload(input: BuildAutoPostPayloadInput): {
8
+ skipFine?: boolean | undefined;
9
+ schoolId: string;
10
+ computerNumbers: string[];
11
+ paidAt: string;
12
+ };
13
+ export {};
@@ -0,0 +1,3 @@
1
+ export function buildAutoPostPayload(input) {
2
+ return Object.assign({ schoolId: input.schoolId, computerNumbers: input.computerNumbers, paidAt: input.paidAt }, (input.skipFine ? { skipFine: true } : {}));
3
+ }
@@ -22,6 +22,12 @@ import { DISCOUNT_TYPE, PAYMENT_STATUS } from "../../types";
22
22
  import { PAYMENT_STATUS_OPTIONS } from "./constants";
23
23
  import { Loader2 } from "lucide-react";
24
24
  import { DATE_FORMATS, formatDate, } from "@react-pakistan/util-functions/general/format-date";
25
+ function toLocalDateString(date) {
26
+ const year = date.getFullYear();
27
+ const month = String(date.getMonth() + 1).padStart(2, "0");
28
+ const day = String(date.getDate()).padStart(2, "0");
29
+ return `${year}-${month}-${day}`;
30
+ }
25
31
  export const StudentFeeSingle = () => {
26
32
  var _a, _b, _c, _d, _e, _f, _g, _h;
27
33
  const { dispatch, handleChange, state } = useStudentFeeModule();
@@ -40,13 +46,14 @@ export const StudentFeeSingle = () => {
40
46
  var _a;
41
47
  if (!debouncedComputerNumber)
42
48
  return;
49
+ // When the chosen payment date differs from today, ask the API to recompute
50
+ // the fines as of that back-dated (or future) payment date.
51
+ const today = toLocalDateString(new Date());
52
+ const useAsOf = state.paidAt && state.paidAt !== today;
43
53
  fetchByCNRef.current(undefined, {
44
- params: {
45
- computerNumber: debouncedComputerNumber,
46
- schoolId: (_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id,
47
- },
54
+ params: Object.assign({ computerNumber: debouncedComputerNumber, schoolId: (_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id }, (useAsOf ? { asOf: state.paidAt } : {})),
48
55
  });
49
- }, [debouncedComputerNumber, (_c = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _c === void 0 ? void 0 : _c.id]);
56
+ }, [debouncedComputerNumber, (_c = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _c === void 0 ? void 0 : _c.id, state.paidAt]);
50
57
  const accumulatedAmount = useMemo(() => {
51
58
  var _a;
52
59
  if (!((_a = feeByComputerNumber === null || feeByComputerNumber === void 0 ? void 0 : feeByComputerNumber.studentFees) === null || _a === void 0 ? void 0 : _a.length))
@@ -4,12 +4,14 @@ import { showErrorToast, showSuccessToast, showInfoToast, } from "@appcorp/shadc
4
4
  import { getCachedWorkspaceSync } from "../workspace/cache";
5
5
  import { useTranslations } from "next-intl";
6
6
  import { STUDENT_FEE_API_ROUTES } from "../../constants";
7
+ import { buildAutoPostPayload } from "./auto-post-payload";
7
8
  import { STUDENT_FEE_ACTION_TYPES, useStudentFeeModule } from "./context";
8
9
  import { useRef, useEffect, useCallback, useState } from "react";
9
10
  import { Button } from "@appcorp/shadcn/components/ui/button";
10
11
  import { Separator } from "@appcorp/shadcn/components/ui/separator";
11
12
  import { EnhancedInput } from "@appcorp/shadcn/components/enhanced-input";
12
13
  import { EnhancedTextarea } from "@appcorp/shadcn/components/enhanced-textarea";
14
+ import { EnhancedCheckbox } from "@appcorp/shadcn/components/enhanced-checkbox";
13
15
  const workspace = getCachedWorkspaceSync();
14
16
  const POLL_INTERVAL_MS = 2000;
15
17
  const POLL_TIMEOUT_MS = 300000;
@@ -61,6 +63,7 @@ export const StudentFeeMoreActions = () => {
61
63
  const abortRef = useRef(null);
62
64
  const [autoPostDate, setAutoPostDate] = useState("");
63
65
  const [computerNumbersText, setComputerNumbersText] = useState("");
66
+ const [skipFine, setSkipFine] = useState(false);
64
67
  const [submitting, setSubmitting] = useState(false);
65
68
  useEffect(() => {
66
69
  return () => {
@@ -127,11 +130,12 @@ export const StudentFeeMoreActions = () => {
127
130
  headers: {
128
131
  "Content-Type": "application/json",
129
132
  },
130
- body: JSON.stringify({
133
+ body: JSON.stringify(buildAutoPostPayload({
131
134
  schoolId,
132
135
  computerNumbers: uniqueNumbers,
133
136
  paidAt: autoPostDate,
134
- }),
137
+ skipFine,
138
+ })),
135
139
  signal,
136
140
  });
137
141
  if (!res.ok) {
@@ -187,9 +191,9 @@ export const StudentFeeMoreActions = () => {
187
191
  finally {
188
192
  setSubmitting(false);
189
193
  }
190
- }, [t, dispatch, closeDrawer, refreshList, computerNumbersText, autoPostDate]);
194
+ }, [t, dispatch, closeDrawer, refreshList, computerNumbersText, autoPostDate, skipFine]);
191
195
  const canSubmit = autoPostDate.trim() !== "" &&
192
196
  computerNumbersText.trim() !== "" &&
193
197
  !submitting;
194
- return (_jsxs("div", { className: "space-y-4", children: [_jsx(Button, { disabled: new Date().getDate() !== 1, onClick: handleCreateMonthly, children: t("actionsButtonCreateMonthly") }), _jsx(Button, { onClick: handleCreateSingleEntry, children: t("actionsButtonSingleEntry") }), _jsx(Separator, {}), _jsxs("div", { className: "space-y-4", children: [_jsx(EnhancedInput, { id: "autoPostDate", info: t("formAutoPostDateInfo"), label: t("formAutoPostDateLabel"), onChange: (e) => setAutoPostDate(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: autoPostDate }), _jsx(EnhancedTextarea, { id: "autoPostComputerNumbers", info: t("formAutoPostComputerNumbersInfo"), label: t("formAutoPostComputerNumbersLabel"), onChange: (e) => setComputerNumbersText(e.target.value), placeholder: t("formAutoPostComputerNumbersPlaceholder"), rows: 8, value: computerNumbersText }), _jsx(Button, { disabled: !canSubmit, onClick: handleAutoPost, children: t("actionsButtonAutoPost") })] })] }));
198
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx(Button, { disabled: new Date().getDate() !== 1, onClick: handleCreateMonthly, children: t("actionsButtonCreateMonthly") }), _jsx(Button, { onClick: handleCreateSingleEntry, children: t("actionsButtonSingleEntry") }), _jsx(Separator, {}), _jsxs("div", { className: "space-y-4", children: [_jsx(EnhancedInput, { id: "autoPostDate", info: t("formAutoPostDateInfo"), label: t("formAutoPostDateLabel"), onChange: (e) => setAutoPostDate(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: autoPostDate }), _jsx(EnhancedTextarea, { id: "autoPostComputerNumbers", info: t("formAutoPostComputerNumbersInfo"), label: t("formAutoPostComputerNumbersLabel"), onChange: (e) => setComputerNumbersText(e.target.value), placeholder: t("formAutoPostComputerNumbersPlaceholder"), rows: 8, value: computerNumbersText }), _jsx(EnhancedCheckbox, { id: "autoPostSkipFine", checked: skipFine, info: t("formSkipFineInfo"), label: t("formSkipFineLabel"), onCheckedChange: (checked) => setSkipFine(!!checked) }), _jsx(Button, { disabled: !canSubmit, onClick: handleAutoPost, children: t("actionsButtonAutoPost") })] })] }));
195
199
  };
package/constants.d.ts CHANGED
@@ -21,6 +21,7 @@ export declare const ADMISSION_API_ROUTES: {
21
21
  export declare const DOCUMENT_UPLOAD_API_ROUTES: {
22
22
  readonly UNIT: "/api/v1/document-upload";
23
23
  };
24
+ export declare const STORAGE_WAKE_URL = "https://storage.edupilotpro.com/";
24
25
  export declare const CAMPUS_API_ROUTES: Record<string, string>;
25
26
  export declare const CLASS_API_ROUTES: {
26
27
  readonly UNIT: "/api/v1/class";
package/constants.js CHANGED
@@ -24,6 +24,7 @@ export const ADMISSION_API_ROUTES = {
24
24
  export const DOCUMENT_UPLOAD_API_ROUTES = {
25
25
  UNIT: "/api/v1/document-upload",
26
26
  };
27
+ export const STORAGE_WAKE_URL = "https://storage.edupilotpro.com/";
27
28
  export const CAMPUS_API_ROUTES = {
28
29
  UNIT: "/api/v1/campus",
29
30
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appcorp/fusion-storybook",
3
- "version": "0.4.15",
3
+ "version": "0.4.17",
4
4
  "scripts": {
5
5
  "build-storybook": "storybook build",
6
6
  "build:next": "next build",
@@ -42,6 +42,7 @@
42
42
  "@commitlint/cli": "^20.5.0",
43
43
  "@commitlint/config-conventional": "^20.5.0",
44
44
  "@playwright/test": "^1.59.1",
45
+ "@quicktoolsone/pdf-compress": "^2.0.0",
45
46
  "@radix-ui/react-avatar": "^1",
46
47
  "@radix-ui/react-checkbox": "^1",
47
48
  "@radix-ui/react-dialog": "^1",
@@ -106,6 +107,7 @@
106
107
  "ts-jest": "^29.4.9",
107
108
  "tw-animate-css": "^1.4.0",
108
109
  "typescript": "^5",
110
+ "undici": "^8.10.0",
109
111
  "uuid": "^13.0.0",
110
112
  "vaul": "^1.1.2",
111
113
  "vite": "^8.0.5",