@appcorp/fusion-storybook 0.2.24 → 0.2.26

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.
@@ -10,13 +10,17 @@ import { CSVS } from "../../constants";
10
10
  import { teacherFormValidation } from "./validate";
11
11
  import { TEACHER_API_ROUTES } from "./constants";
12
12
  import { invalidateTeachersCache } from "./cache";
13
- import { useTeacherContext, TEACHER_ACTION_TYPES } from "./context";
13
+ import { TEACHER_ACTION_TYPES, useTeacherModule } from "./context";
14
14
  import { useRef, useEffect, useCallback } from "react";
15
15
  const workspace = getCachedWorkspaceSync();
16
16
  const POLL_INTERVAL_MS = 2000;
17
17
  const POLL_TIMEOUT_MS = 300000;
18
18
  const handleGetAllRecords = async (schoolId) => {
19
- const response = await fetch(`${TEACHER_API_ROUTES.UNIT}?pageLimit=1000&currentPage=1&schoolId=${schoolId}`);
19
+ const response = await fetch(`${TEACHER_API_ROUTES.UNIT}?pageLimit=1000&currentPage=1&schoolId=${schoolId}`, {
20
+ headers: {
21
+ "x-api-token": process.env.NEXT_PUBLIC_API_TOKEN,
22
+ },
23
+ });
20
24
  const result = await response.json();
21
25
  const csv = await converter.json2csv(result.items || [], {});
22
26
  const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
@@ -27,11 +31,14 @@ async function submitBulkJob(csvData, method, signal) {
27
31
  const schoolId = ((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "";
28
32
  if (!schoolId)
29
33
  throw new Error("School ID not found");
34
+ const apiKey = process.env.NEXT_PUBLIC_API_TOKEN;
35
+ if (!apiKey)
36
+ throw new Error("API key not configured");
30
37
  const res = await fetch(TEACHER_API_ROUTES.BULK, {
31
38
  method,
32
39
  headers: {
33
40
  "Content-Type": "application/json",
34
- "x-api-token": process.env.NEXT_PUBLIC_API_KEY,
41
+ "x-api-token": apiKey,
35
42
  },
36
43
  body: JSON.stringify({ schoolId, csvData }),
37
44
  signal,
@@ -55,9 +62,12 @@ async function pollBulkJob(jobId, signal, onProgress) {
55
62
  await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
56
63
  if (signal.aborted)
57
64
  throw new Error("Polling cancelled");
65
+ const apiKey = process.env.NEXT_PUBLIC_API_TOKEN;
66
+ if (!apiKey)
67
+ throw new Error("API key not configured");
58
68
  const res = await fetch(TEACHER_API_ROUTES.BULK_STATUS(jobId), {
59
69
  headers: {
60
- "x-api-token": process.env.NEXT_PUBLIC_API_KEY,
70
+ "x-api-token": apiKey,
61
71
  },
62
72
  signal,
63
73
  });
@@ -68,8 +78,7 @@ async function pollBulkJob(jobId, signal, onProgress) {
68
78
  return data;
69
79
  }
70
80
  // Show progress toast every 10 seconds while running
71
- if (data.status === "running" &&
72
- Date.now() - lastProgressToast > 10000) {
81
+ if (data.status === "running" && Date.now() - lastProgressToast > 10000) {
73
82
  lastProgressToast = Date.now();
74
83
  onProgress === null || onProgress === void 0 ? void 0 : onProgress(data.processed, data.total);
75
84
  }
@@ -86,7 +95,7 @@ function formatErrorSummary(errors) {
86
95
  }
87
96
  export const TeacherMoreActions = () => {
88
97
  const t = useTranslations("teacher");
89
- const { dispatch } = useTeacherContext();
98
+ const { dispatch, listFetchNow } = useTeacherModule();
90
99
  const abortRef = useRef(null);
91
100
  // Abort any in-flight polling on unmount
92
101
  useEffect(() => {
@@ -95,14 +104,14 @@ export const TeacherMoreActions = () => {
95
104
  (_a = abortRef.current) === null || _a === void 0 ? void 0 : _a.abort();
96
105
  };
97
106
  }, []);
98
- const closeDrawer = () => {
99
- dispatch({
100
- type: TEACHER_ACTION_TYPES.SET_DRAWER,
101
- payload: { drawer: null },
102
- });
103
- };
104
107
  const handleBulkFlow = useCallback(async (files, method) => {
105
108
  var _a, _b, _c;
109
+ const closeDrawer = () => {
110
+ dispatch({
111
+ type: TEACHER_ACTION_TYPES.SET_DRAWER,
112
+ payload: { drawer: null },
113
+ });
114
+ };
106
115
  // Cancel previous in-flight request
107
116
  (_a = abortRef.current) === null || _a === void 0 ? void 0 : _a.abort();
108
117
  const controller = new AbortController();
@@ -139,7 +148,14 @@ export const TeacherMoreActions = () => {
139
148
  }
140
149
  try {
141
150
  showInfoToast(`Bulk ${label} job queued (${records.length} records). Processing...`);
142
- const jobId = await submitBulkJob(text, method, signal);
151
+ let jobId;
152
+ try {
153
+ jobId = await submitBulkJob(text, method, signal);
154
+ }
155
+ catch (submitError) {
156
+ showErrorToast(`Failed to submit ${label} job: ${submitError instanceof Error ? submitError.message : "Unknown error"}`);
157
+ return;
158
+ }
143
159
  const status = await pollBulkJob(jobId, signal, (processed, total) => {
144
160
  showInfoToast(`Processing ${processed}/${total} teachers...`);
145
161
  });
@@ -158,6 +174,7 @@ export const TeacherMoreActions = () => {
158
174
  showSuccessToast("Bulk operation completed successfully");
159
175
  }
160
176
  invalidateTeachersCache();
177
+ listFetchNow();
161
178
  closeDrawer();
162
179
  }
163
180
  else {
@@ -173,7 +190,7 @@ export const TeacherMoreActions = () => {
173
190
  return;
174
191
  showErrorToast(`Bulk ${label} failed: ${error instanceof Error ? error.message : "Unknown error"}`);
175
192
  }
176
- }, [closeDrawer]);
193
+ }, [dispatch, listFetchNow]);
177
194
  const handleBulkCreate = useCallback((files) => handleBulkFlow(files, "POST"), [handleBulkFlow]);
178
195
  const handleBulkUpdate = useCallback((files) => handleBulkFlow(files, "PUT"), [handleBulkFlow]);
179
196
  const create = [
@@ -9,7 +9,14 @@ export const Timeline = ({ heading, events, handleOnBulkCreate, }) => {
9
9
  // EnhancedDropzone calls onChange synchronously during render.
10
10
  queueMicrotask(() => setFiles(f));
11
11
  }, []);
12
+ const handleUploadClick = useCallback(() => {
13
+ if (files.length > 0) {
14
+ handleOnBulkCreate === null || handleOnBulkCreate === void 0 ? void 0 : handleOnBulkCreate(files);
15
+ // Clear files after upload to allow resubmission
16
+ queueMicrotask(() => setFiles([]));
17
+ }
18
+ }, [files, handleOnBulkCreate]);
12
19
  return (_jsxs("div", { className: "space-y-6", children: [_jsx("h2", { className: "text-foreground text-xl font-semibold", children: heading }), _jsxs("div", { className: "space-y-4", children: [events.map((event) => (_jsxs("div", { className: "flex items-start gap-2", children: [_jsx("div", { className: "z-10 flex h-6 w-6 items-center justify-center", children: _jsx("div", { className: "bg-muted-foreground h-3 w-3 rounded-full" }) }), _jsxs("div", { className: "min-w-0 flex-1 pb-1", children: [_jsx("div", { onClick: event.handleOnClick, className: `text-muted-foreground text-sm ${event.handleOnClick ? "cursor-pointer underline" : ""}`, children: event.title }), event.description && (_jsx("div", { className: "text-foreground mt-1 text-sm", children: event.description }))] })] }, event.id))), _jsx(EnhancedDropzone, { className: "", label: "Upload CSV", id: "timeline-dropzone", info: "Drag and drop your CSV file here, or click to select.", error: "", accept: { "text/csv": [".csv"] }, maxFiles: 1, onChange: handleDropzoneChange, onRemoveRemote: () => {
13
20
  // Handle remote file removal if needed
14
- } }), _jsx(Button, { disabled: files.length === 0, onClick: () => handleOnBulkCreate === null || handleOnBulkCreate === void 0 ? void 0 : handleOnBulkCreate(files), children: "Upload and Process CSV" })] })] }));
21
+ } }), _jsx(Button, { disabled: files.length === 0, onClick: handleUploadClick, children: "Upload and Process CSV" })] })] }));
15
22
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appcorp/fusion-storybook",
3
- "version": "0.2.24",
3
+ "version": "0.2.26",
4
4
  "scripts": {
5
5
  "build-storybook": "storybook build",
6
6
  "build:next": "next build",