@appcorp/fusion-storybook 0.4.67 → 0.4.69

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,12 +4,14 @@ import { downloadFromUrl } from "@react-pakistan/util-functions/general/download
4
4
  import { showErrorToast, showSuccessToast, showInfoToast, } from "@appcorp/shadcn/lib/toast-utils";
5
5
  import { getCachedWorkspaceSync } from "../workspace/cache";
6
6
  import converter from "json-2-csv";
7
- import { Timeline } from "../../components/timeline";
8
7
  import { useTranslations } from "next-intl";
9
8
  import { pageLimit } from "./constants";
10
9
  import { ATTENDANCE_API_ROUTES } from "../../constants";
11
10
  import { ATTENDANCE_ACTION_TYPES, useAttendanceContext } from "./context";
12
- import { useRef, useEffect, useCallback } from "react";
11
+ import { useRef, useEffect, useCallback, useState } from "react";
12
+ import { Button } from "@appcorp/shadcn/components/ui/button";
13
+ import { EnhancedInput } from "@appcorp/shadcn/components/enhanced-input";
14
+ import { EnhancedTextarea } from "@appcorp/shadcn/components/enhanced-textarea";
13
15
  const workspace = getCachedWorkspaceSync();
14
16
  const POLL_INTERVAL_MS = 2000;
15
17
  const POLL_TIMEOUT_MS = 300000;
@@ -78,10 +80,53 @@ function formatErrorSummary(t, errors) {
78
80
  lines.push(t("messagesBulkMoreRows", { count: remaining }));
79
81
  return lines.join("\n");
80
82
  }
83
+ function formatAutoPostErrorSummary(t, errors) {
84
+ if (!(errors === null || errors === void 0 ? void 0 : errors.length))
85
+ return "";
86
+ const lines = errors.slice(0, 5).map((e) => t("messagesAutoPostRowError", {
87
+ computerNumber: e.computerNumber,
88
+ error: e.error,
89
+ }));
90
+ const remaining = errors.length - 5;
91
+ if (remaining > 0)
92
+ lines.push(t("messagesAutoPostMoreRows", { count: remaining }));
93
+ return lines.join("\n");
94
+ }
95
+ async function pollAutoPostJob(statusUrl, signal, onProgress) {
96
+ const startTime = Date.now();
97
+ let lastProgressToast = 0;
98
+ while (true) {
99
+ if (signal.aborted)
100
+ throw new Error("Polling cancelled");
101
+ if (Date.now() - startTime > POLL_TIMEOUT_MS) {
102
+ throw new Error("Operation timed out");
103
+ }
104
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
105
+ if (signal.aborted)
106
+ throw new Error("Polling cancelled");
107
+ const res = await fetch(statusUrl, { signal });
108
+ if (!res.ok)
109
+ continue;
110
+ const data = (await res.json());
111
+ if (data.status === "completed" || data.status === "failed") {
112
+ return data;
113
+ }
114
+ if (data.status === "running" && Date.now() - lastProgressToast > 10000) {
115
+ lastProgressToast = Date.now();
116
+ onProgress === null || onProgress === void 0 ? void 0 : onProgress(data.processed, data.total);
117
+ }
118
+ }
119
+ }
81
120
  export const AttendanceMoreActions = () => {
82
121
  const t = useTranslations("attendance");
83
122
  const { dispatch } = useAttendanceContext();
84
123
  const abortRef = useRef(null);
124
+ const [autoPostDate, setAutoPostDate] = useState(new Date().toISOString().split("T")[0]);
125
+ const [absentText, setAbsentText] = useState("");
126
+ const [lateText, setLateText] = useState("");
127
+ const [excusedText, setExcusedText] = useState("");
128
+ const [halfDayText, setHalfDayText] = useState("");
129
+ const [autoPostSubmitting, setAutoPostSubmitting] = useState(false);
85
130
  useEffect(() => {
86
131
  return () => {
87
132
  var _a;
@@ -221,37 +266,171 @@ export const AttendanceMoreActions = () => {
221
266
  }));
222
267
  }
223
268
  }, [dispatch, t]);
224
- const handleBulkCreate = useCallback((files) => handleBulkFlow(files, "POST"), [handleBulkFlow]);
225
- const handleBulkUpdate = useCallback((files) => handleBulkFlow(files, "PUT"), [handleBulkFlow]);
226
- const create = [
227
- {
228
- id: "1",
229
- title: t("downloadEmptyCsvTemplate"),
230
- handleOnClick: async () => {
231
- var _a;
232
- await handleGetAllRecords(((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "", 1);
233
- },
234
- },
235
- { id: "2", title: t("addYourDataToTheCsv") },
236
- {
237
- id: "3",
238
- title: t("uploadTheCompletedCsvToTheSystem"),
239
- },
240
- ];
241
- const update = [
242
- {
243
- id: "1",
244
- title: t("downloadPopulatedCsvTemplate"),
245
- handleOnClick: async () => {
246
- var _a;
247
- await handleGetAllRecords(((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "", 1000);
248
- },
249
- },
250
- { id: "2", title: t("updateYourDataInTheCsv") },
251
- {
252
- id: "3",
253
- title: t("uploadTheCompletedCsvToTheSystem"),
254
- },
255
- ];
256
- return (_jsxs("div", { className: "space-y-4", children: [_jsx(Timeline, { events: create, heading: t("bulkCreate"), handleOnBulkCreate: handleBulkCreate }), _jsx(Timeline, { events: update, heading: t("bulkUpdate"), handleOnBulkCreate: handleBulkUpdate })] }));
269
+ const closeDrawer = useCallback(() => {
270
+ dispatch({
271
+ type: ATTENDANCE_ACTION_TYPES.SET_DRAWER,
272
+ payload: { drawer: null },
273
+ });
274
+ }, [dispatch]);
275
+ const refreshList = useCallback(() => {
276
+ var _a;
277
+ const schoolId = ((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "";
278
+ fetch(`${ATTENDANCE_API_ROUTES.UNIT}?currentPage=1&pageLimit=${pageLimit}&schoolId=${schoolId}`, {
279
+ headers: { "Content-Type": "application/json" },
280
+ })
281
+ .then(async (res) => {
282
+ var _a, _b;
283
+ if (!res.ok)
284
+ return;
285
+ const data = await res.json();
286
+ dispatch({
287
+ type: ATTENDANCE_ACTION_TYPES.SET_ITEMS,
288
+ payload: { items: (_a = data.items) !== null && _a !== void 0 ? _a : [], count: (_b = data.count) !== null && _b !== void 0 ? _b : 0 },
289
+ });
290
+ })
291
+ .catch(() => { });
292
+ }, [dispatch]);
293
+ const handleAutoPost = useCallback(async () => {
294
+ var _a, _b, _c, _d;
295
+ const schoolId = ((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "";
296
+ if (!schoolId) {
297
+ showErrorToast("School ID not found");
298
+ return;
299
+ }
300
+ if (!autoPostDate) {
301
+ showErrorToast(t("validationAutoPostDateRequired"));
302
+ return;
303
+ }
304
+ // Parse text areas into assignment arrays
305
+ const parseNumbers = (text) => text
306
+ .split(",")
307
+ .map((n) => n.trim())
308
+ .filter(Boolean);
309
+ const absentNumbers = parseNumbers(absentText);
310
+ const lateNumbers = parseNumbers(lateText);
311
+ const excusedNumbers = parseNumbers(excusedText);
312
+ const halfDayNumbers = parseNumbers(halfDayText);
313
+ const totalExplicit = absentNumbers.length +
314
+ lateNumbers.length +
315
+ excusedNumbers.length +
316
+ halfDayNumbers.length;
317
+ if (totalExplicit === 0) {
318
+ showErrorToast(t("validationAutoPostAssignmentsRequired"));
319
+ return;
320
+ }
321
+ // Build assignments (first match wins via Set in the API/worker)
322
+ const assignments = [];
323
+ for (const cn of absentNumbers) {
324
+ assignments.push({ computerNumber: cn, status: "ABSENT" });
325
+ }
326
+ for (const cn of lateNumbers) {
327
+ assignments.push({ computerNumber: cn, status: "LATE" });
328
+ }
329
+ for (const cn of excusedNumbers) {
330
+ assignments.push({ computerNumber: cn, status: "EXCUSED" });
331
+ }
332
+ for (const cn of halfDayNumbers) {
333
+ assignments.push({ computerNumber: cn, status: "HALF_DAY" });
334
+ }
335
+ setAutoPostSubmitting(true);
336
+ (_b = abortRef.current) === null || _b === void 0 ? void 0 : _b.abort();
337
+ const controller = new AbortController();
338
+ abortRef.current = controller;
339
+ const { signal } = controller;
340
+ try {
341
+ showInfoToast(t("messagesAutoPostJobQueued", { count: assignments.length }));
342
+ let jobId;
343
+ try {
344
+ const res = await fetch(ATTENDANCE_API_ROUTES.AUTO_POST, {
345
+ method: "POST",
346
+ headers: { "Content-Type": "application/json" },
347
+ body: JSON.stringify({ schoolId, date: autoPostDate, assignments }),
348
+ signal,
349
+ });
350
+ if (!res.ok) {
351
+ const errorData = (await res.json().catch(() => ({})));
352
+ throw new Error(errorData.error || `Auto-post failed with status ${res.status}`);
353
+ }
354
+ const data = (await res.json());
355
+ jobId = data.jobId;
356
+ }
357
+ catch (submitError) {
358
+ showErrorToast(t("messagesAutoPostJobSubmitFailed", {
359
+ error: submitError instanceof Error
360
+ ? submitError.message
361
+ : t("unknownError"),
362
+ }));
363
+ return;
364
+ }
365
+ const status = await pollAutoPostJob(ATTENDANCE_API_ROUTES.AUTO_POST_STATUS(jobId), signal, (processed, total) => {
366
+ showInfoToast(t("messagesAutoPostProgress", { processed, total }));
367
+ });
368
+ if (signal.aborted)
369
+ return;
370
+ if (status.status === "completed") {
371
+ const r = status.results;
372
+ if (r && ((_c = r.errors) === null || _c === void 0 ? void 0 : _c.length) > 0) {
373
+ const summary = formatAutoPostErrorSummary(t, r.errors);
374
+ showSuccessToast(t("messagesAutoPostResults", {
375
+ present: r.present,
376
+ absent: r.absent,
377
+ late: r.late,
378
+ excused: r.excused,
379
+ halfDay: r.halfDay,
380
+ skipped: r.skipped,
381
+ }) +
382
+ "\n" +
383
+ summary);
384
+ }
385
+ else if (r) {
386
+ showSuccessToast(t("messagesAutoPostResults", {
387
+ present: r.present,
388
+ absent: r.absent,
389
+ late: r.late,
390
+ excused: r.excused,
391
+ halfDay: r.halfDay,
392
+ skipped: r.skipped,
393
+ }));
394
+ }
395
+ else {
396
+ showSuccessToast(t("messagesAutoPostSuccess"));
397
+ }
398
+ refreshList();
399
+ closeDrawer();
400
+ }
401
+ else {
402
+ const r = status.results;
403
+ const detail = ((_d = r === null || r === void 0 ? void 0 : r.errors) === null || _d === void 0 ? void 0 : _d.length)
404
+ ? formatAutoPostErrorSummary(t, r.errors)
405
+ : t("unknownError");
406
+ showErrorToast(t("messagesAutoPostFailed") + "\n" + detail);
407
+ }
408
+ }
409
+ catch (error) {
410
+ if (error.message === "Polling cancelled")
411
+ return;
412
+ showErrorToast(t("messagesAutoPostFailedDetail", {
413
+ error: error instanceof Error ? error.message : t("unknownError"),
414
+ }));
415
+ }
416
+ finally {
417
+ setAutoPostSubmitting(false);
418
+ }
419
+ }, [
420
+ t,
421
+ closeDrawer,
422
+ refreshList,
423
+ autoPostDate,
424
+ absentText,
425
+ lateText,
426
+ excusedText,
427
+ halfDayText,
428
+ ]);
429
+ const canAutoPost = autoPostDate.trim() !== "" &&
430
+ (absentText.trim() !== "" ||
431
+ lateText.trim() !== "" ||
432
+ excusedText.trim() !== "" ||
433
+ halfDayText.trim() !== "") &&
434
+ !autoPostSubmitting;
435
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-sm font-semibold", children: t("actionsButtonAutoPost") }), _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: "autoPostAbsent", info: t("formAutoPostAbsentInfo"), label: t("formAutoPostAbsentLabel"), onChange: (e) => setAbsentText(e.target.value), placeholder: t("formAutoPostAbsentPlaceholder"), rows: 6, value: absentText }), _jsx(EnhancedTextarea, { id: "autoPostLate", info: t("formAutoPostLateInfo"), label: t("formAutoPostLateLabel"), onChange: (e) => setLateText(e.target.value), placeholder: t("formAutoPostLatePlaceholder"), rows: 6, value: lateText }), _jsx(EnhancedTextarea, { id: "autoPostExcused", info: t("formAutoPostExcusedInfo"), label: t("formAutoPostExcusedLabel"), onChange: (e) => setExcusedText(e.target.value), placeholder: t("formAutoPostExcusedPlaceholder"), rows: 6, value: excusedText }), _jsx(EnhancedTextarea, { id: "autoPostHalfDay", info: t("formAutoPostHalfDayInfo"), label: t("formAutoPostHalfDayLabel"), onChange: (e) => setHalfDayText(e.target.value), placeholder: t("formAutoPostHalfDayPlaceholder"), rows: 6, value: halfDayText }), _jsx(Button, { disabled: !canAutoPost, onClick: handleAutoPost, children: t("actionsButtonAutoPost") })] }));
257
436
  };
@@ -83,9 +83,16 @@ export const BulkOperationsView = () => {
83
83
  const att = item;
84
84
  return (_jsxs(AccordionItem, { value: att.studentName, className: `mb-2 border-l-4 px-4 ${(_a = ITEM_BORDER_COLOR[att.status]) !== null && _a !== void 0 ? _a : ""}`, children: [_jsx(AccordionTrigger, { className: "py-3 hover:no-underline", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { className: "text-sm font-medium", children: att.studentName }), _jsx(Badge, { variant: (_b = ATTENDANCE_STATUS_VARIANT[att.attendanceStatus]) !== null && _b !== void 0 ? _b : "secondary", children: att.attendanceStatus }), _jsx(Badge, { variant: (_c = ITEM_STATUS_VARIANT[att.status]) !== null && _c !== void 0 ? _c : "secondary", children: t((_d = ITEM_STATUS_I18N[att.status]) !== null && _d !== void 0 ? _d : att.status) })] }) }), _jsx(AccordionContent, { className: "pb-4", children: _jsxs("div", { className: "space-y-3 pl-1", children: [_jsx("p", { className: "text-muted-foreground text-sm", children: att.reason }), _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { className: "bg-muted/50 rounded-md p-2 text-center", children: [_jsx("p", { className: "text-muted-foreground text-xs", children: t("viewItemRecordAction") }), _jsx(Badge, { variant: (_e = RECORD_ACTION_VARIANT[att.recordAction]) !== null && _e !== void 0 ? _e : "secondary", className: "mt-1", children: att.recordAction })] }), _jsxs("div", { className: "bg-muted/50 rounded-md p-2 text-center", children: [_jsx("p", { className: "text-muted-foreground text-xs", children: t("viewItemAttendanceStatus") }), _jsx(Badge, { variant: (_f = ATTENDANCE_STATUS_VARIANT[att.attendanceStatus]) !== null && _f !== void 0 ? _f : "secondary", className: "mt-1", children: att.attendanceStatus })] })] }), att.studentProfileId ? (_jsxs("div", { className: "bg-muted/50 rounded-md p-2", children: [_jsx("p", { className: "text-muted-foreground text-xs", children: "Student Profile ID" }), _jsx("p", { className: "font-mono text-xs break-all", children: att.studentProfileId })] })) : null, att.error ? (_jsxs("div", { className: "bg-destructive/10 rounded-md p-2", children: [_jsx("p", { className: "text-destructive text-xs font-medium", children: "Error" }), _jsx("p", { className: "text-destructive text-xs", children: att.error })] })) : null] }) })] }, att.studentName));
85
85
  })
86
- : sortedItems.map((item) => {
87
- var _a, _b, _c;
88
- const fee = item;
89
- return (_jsxs(AccordionItem, { value: fee.computerNumber, className: `mb-2 border-l-4 px-4 ${(_a = ITEM_BORDER_COLOR[fee.status]) !== null && _a !== void 0 ? _a : ""}`, children: [_jsx(AccordionTrigger, { className: "py-3 hover:no-underline", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("span", { className: "text-sm font-medium", children: [t("viewItemComputerNumber"), " ", fee.computerNumber] }), _jsx(Badge, { variant: (_b = ITEM_STATUS_VARIANT[fee.status]) !== null && _b !== void 0 ? _b : "secondary", children: t((_c = ITEM_STATUS_I18N[fee.status]) !== null && _c !== void 0 ? _c : fee.status) })] }) }), _jsx(AccordionContent, { className: "pb-4", children: _jsxs("div", { className: "space-y-4 pl-1", children: [_jsx("p", { className: "text-muted-foreground text-sm", children: fee.reason }), _jsxs("div", { className: "grid grid-cols-3 gap-3", children: [_jsxs("div", { className: "bg-muted/50 rounded-md p-2 text-center", children: [_jsx("p", { className: "text-muted-foreground text-xs", children: t("viewItemPendingMarkedPaid") }), _jsx("p", { className: "text-sm font-medium", children: fee.pendingMarkedPaid })] }), _jsxs("div", { className: "bg-muted/50 rounded-md p-2 text-center", children: [_jsx("p", { className: "text-muted-foreground text-xs", children: t("viewItemPaidAtUpdated") }), _jsx("p", { className: "text-sm font-medium", children: fee.paidAtUpdated })] }), _jsxs("div", { className: "bg-muted/50 rounded-md p-2 text-center", children: [_jsx("p", { className: "text-muted-foreground text-xs", children: t("viewItemSameDaySkipped") }), _jsx("p", { className: "text-sm font-medium", children: fee.sameDaySkipped })] })] }), fee.fees && fee.fees.length > 0 ? (_jsxs("div", { children: [_jsx("p", { className: "text-muted-foreground mb-2 text-xs font-semibold tracking-wide uppercase", children: t("viewItemFees") }), _jsx("div", { className: "overflow-x-auto rounded-md border", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-muted/50 border-b text-left", children: [_jsx("th", { className: "text-muted-foreground px-3 py-2 text-xs font-medium", children: t("viewItemFeeId") }), _jsx("th", { className: "text-muted-foreground px-3 py-2 text-xs font-medium", children: t("viewItemFeeDueDate") }), _jsx("th", { className: "text-muted-foreground px-3 py-2 text-xs font-medium", children: t("viewItemFeeAmount") }), _jsx("th", { className: "text-muted-foreground px-3 py-2 text-xs font-medium", children: t("viewItemFeeFine") }), _jsx("th", { className: "text-muted-foreground px-3 py-2 text-xs font-medium", children: t("viewItemFeeAction") })] }) }), _jsx("tbody", { children: fee.fees.map((f) => (_jsxs("tr", { className: "border-b last:border-b-0", children: [_jsx("td", { className: "px-3 py-2 font-mono text-xs", children: f.feeId }), _jsx("td", { className: "px-3 py-2", children: f.dueDate }), _jsx("td", { className: "px-3 py-2", children: f.amount }), _jsx("td", { className: "px-3 py-2", children: f.fine }), _jsx("td", { className: "px-3 py-2", children: f.action })] }, f.feeId))) })] }) })] })) : null] }) })] }, fee.computerNumber));
90
- }) }) })] })) : null] }));
86
+ : type === "attendance-auto-post"
87
+ ? sortedItems.map((item) => {
88
+ var _a, _b, _c, _d, _e, _f, _g;
89
+ const att = item;
90
+ const itemKey = (_a = att.studentProfileId) !== null && _a !== void 0 ? _a : att.computerNumber;
91
+ return (_jsxs(AccordionItem, { value: itemKey, className: `mb-2 border-l-4 px-4 ${(_b = ITEM_BORDER_COLOR[att.status]) !== null && _b !== void 0 ? _b : ""}`, children: [_jsx(AccordionTrigger, { className: "py-3 hover:no-underline", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { className: "text-sm font-medium", children: (_c = att.studentName) !== null && _c !== void 0 ? _c : att.computerNumber }), _jsx(Badge, { variant: (_d = ATTENDANCE_STATUS_VARIANT[att.assignedStatus]) !== null && _d !== void 0 ? _d : "secondary", children: att.assignedStatus }), _jsx(Badge, { variant: (_e = ITEM_STATUS_VARIANT[att.status]) !== null && _e !== void 0 ? _e : "secondary", children: t((_f = ITEM_STATUS_I18N[att.status]) !== null && _f !== void 0 ? _f : att.status) })] }) }), _jsx(AccordionContent, { className: "pb-4", children: _jsxs("div", { className: "space-y-3 pl-1", children: [_jsx("p", { className: "text-muted-foreground text-sm", children: att.reason }), _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { className: "bg-muted/50 rounded-md p-2 text-center", children: [_jsx("p", { className: "text-muted-foreground text-xs", children: "Computer Number" }), _jsx("p", { className: "text-sm font-medium", children: att.computerNumber })] }), _jsxs("div", { className: "bg-muted/50 rounded-md p-2 text-center", children: [_jsx("p", { className: "text-muted-foreground text-xs", children: t("viewItemAttendanceStatus") }), _jsx(Badge, { variant: (_g = ATTENDANCE_STATUS_VARIANT[att.assignedStatus]) !== null && _g !== void 0 ? _g : "secondary", className: "mt-1", children: att.assignedStatus })] })] }), att.studentProfileId ? (_jsxs("div", { className: "bg-muted/50 rounded-md p-2", children: [_jsx("p", { className: "text-muted-foreground text-xs", children: "Student Profile ID" }), _jsx("p", { className: "font-mono text-xs break-all", children: att.studentProfileId })] })) : null, att.error ? (_jsxs("div", { className: "bg-destructive/10 rounded-md p-2", children: [_jsx("p", { className: "text-destructive text-xs font-medium", children: "Error" }), _jsx("p", { className: "text-destructive text-xs", children: att.error })] })) : null] }) })] }, itemKey));
92
+ })
93
+ : sortedItems.map((item) => {
94
+ var _a, _b, _c;
95
+ const fee = item;
96
+ return (_jsxs(AccordionItem, { value: fee.computerNumber, className: `mb-2 border-l-4 px-4 ${(_a = ITEM_BORDER_COLOR[fee.status]) !== null && _a !== void 0 ? _a : ""}`, children: [_jsx(AccordionTrigger, { className: "py-3 hover:no-underline", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("span", { className: "text-sm font-medium", children: [t("viewItemComputerNumber"), " ", fee.computerNumber] }), _jsx(Badge, { variant: (_b = ITEM_STATUS_VARIANT[fee.status]) !== null && _b !== void 0 ? _b : "secondary", children: t((_c = ITEM_STATUS_I18N[fee.status]) !== null && _c !== void 0 ? _c : fee.status) })] }) }), _jsx(AccordionContent, { className: "pb-4", children: _jsxs("div", { className: "space-y-4 pl-1", children: [_jsx("p", { className: "text-muted-foreground text-sm", children: fee.reason }), _jsxs("div", { className: "grid grid-cols-3 gap-3", children: [_jsxs("div", { className: "bg-muted/50 rounded-md p-2 text-center", children: [_jsx("p", { className: "text-muted-foreground text-xs", children: t("viewItemPendingMarkedPaid") }), _jsx("p", { className: "text-sm font-medium", children: fee.pendingMarkedPaid })] }), _jsxs("div", { className: "bg-muted/50 rounded-md p-2 text-center", children: [_jsx("p", { className: "text-muted-foreground text-xs", children: t("viewItemPaidAtUpdated") }), _jsx("p", { className: "text-sm font-medium", children: fee.paidAtUpdated })] }), _jsxs("div", { className: "bg-muted/50 rounded-md p-2 text-center", children: [_jsx("p", { className: "text-muted-foreground text-xs", children: t("viewItemSameDaySkipped") }), _jsx("p", { className: "text-sm font-medium", children: fee.sameDaySkipped })] })] }), fee.fees && fee.fees.length > 0 ? (_jsxs("div", { children: [_jsx("p", { className: "text-muted-foreground mb-2 text-xs font-semibold tracking-wide uppercase", children: t("viewItemFees") }), _jsx("div", { className: "overflow-x-auto rounded-md border", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-muted/50 border-b text-left", children: [_jsx("th", { className: "text-muted-foreground px-3 py-2 text-xs font-medium", children: t("viewItemFeeId") }), _jsx("th", { className: "text-muted-foreground px-3 py-2 text-xs font-medium", children: t("viewItemFeeDueDate") }), _jsx("th", { className: "text-muted-foreground px-3 py-2 text-xs font-medium", children: t("viewItemFeeAmount") }), _jsx("th", { className: "text-muted-foreground px-3 py-2 text-xs font-medium", children: t("viewItemFeeFine") }), _jsx("th", { className: "text-muted-foreground px-3 py-2 text-xs font-medium", children: t("viewItemFeeAction") })] }) }), _jsx("tbody", { children: fee.fees.map((f) => (_jsxs("tr", { className: "border-b last:border-b-0", children: [_jsx("td", { className: "px-3 py-2 font-mono text-xs", children: f.feeId }), _jsx("td", { className: "px-3 py-2", children: f.dueDate }), _jsx("td", { className: "px-3 py-2", children: f.amount }), _jsx("td", { className: "px-3 py-2", children: f.fine }), _jsx("td", { className: "px-3 py-2", children: f.action })] }, f.feeId))) })] }) })] })) : null] }) })] }, fee.computerNumber));
97
+ }) }) })] })) : null] }));
91
98
  };
package/constants.d.ts CHANGED
@@ -12,6 +12,8 @@ export declare const ATTENDANCE_API_ROUTES: {
12
12
  readonly UNIT: "/api/v1/attendance";
13
13
  readonly BULK: "/api/v1/attendance/bulk";
14
14
  readonly BULK_STATUS: (jobId: string) => string;
15
+ readonly AUTO_POST: "/api/v1/attendance/auto-post";
16
+ readonly AUTO_POST_STATUS: (jobId: string) => string;
15
17
  };
16
18
  export declare const BULK_OPERATIONS_API_ROUTES: {
17
19
  readonly LIST: "/api/v1/bulk-operations";
package/constants.js CHANGED
@@ -15,6 +15,8 @@ export const ATTENDANCE_API_ROUTES = {
15
15
  UNIT: "/api/v1/attendance",
16
16
  BULK: "/api/v1/attendance/bulk",
17
17
  BULK_STATUS: (jobId) => `/api/v1/attendance/bulk/${jobId}`,
18
+ AUTO_POST: "/api/v1/attendance/auto-post",
19
+ AUTO_POST_STATUS: (jobId) => `/api/v1/attendance/auto-post/${jobId}`,
18
20
  };
19
21
  export const BULK_OPERATIONS_API_ROUTES = {
20
22
  LIST: "/api/v1/bulk-operations",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appcorp/fusion-storybook",
3
- "version": "0.4.67",
3
+ "version": "0.4.69",
4
4
  "scripts": {
5
5
  "build-storybook": "storybook build",
6
6
  "build:next": "next build",