@appcorp/fusion-storybook 0.2.11 → 0.2.12
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,6 @@ import { teacherFormValidation } from "./validate";
|
|
|
32
32
|
import { getCachedTeachers, invalidateTeachersCache } from "./cache";
|
|
33
33
|
import { getCachedWorkspaceSync } from "../workspace/cache";
|
|
34
34
|
import { processAvatarFile } from "./avatar-upload";
|
|
35
|
-
import { v4 as uuidv4 } from "uuid";
|
|
36
35
|
// ============================================================================
|
|
37
36
|
// 1.1 DRAWER TYPES
|
|
38
37
|
// ============================================================================
|
|
@@ -107,6 +106,8 @@ export const useTeacherModule = () => {
|
|
|
107
106
|
const schoolId = ((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "";
|
|
108
107
|
const listFetchNowRef = useRef(null);
|
|
109
108
|
const debouncedQuery = useDebounce(state.searchQuery, 800);
|
|
109
|
+
const uploadInProgressRef = useRef(false);
|
|
110
|
+
const lastUploadRef = useRef(null);
|
|
110
111
|
// ============================================================================
|
|
111
112
|
// 1.4.2 API PARAMETERS
|
|
112
113
|
// ============================================================================
|
|
@@ -355,30 +356,30 @@ export const useTeacherModule = () => {
|
|
|
355
356
|
}, [dispatch]);
|
|
356
357
|
const handleAvatarUpload = useCallback(async (file) => {
|
|
357
358
|
try {
|
|
358
|
-
//
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
//
|
|
362
|
-
|
|
359
|
+
// Prevent duplicate concurrent uploads
|
|
360
|
+
const sig = `${file.name}-${file.size}-${file.lastModified}`;
|
|
361
|
+
const now = Date.now();
|
|
362
|
+
// If same file uploaded within last 5s, ignore
|
|
363
|
+
if (lastUploadRef.current &&
|
|
364
|
+
lastUploadRef.current.sig === sig &&
|
|
365
|
+
now - lastUploadRef.current.ts < 5000)
|
|
366
|
+
return;
|
|
367
|
+
if (uploadInProgressRef.current)
|
|
368
|
+
return;
|
|
369
|
+
uploadInProgressRef.current = true;
|
|
370
|
+
lastUploadRef.current = { sig, ts: now };
|
|
363
371
|
// Process avatar file (validate, convert to WebP)
|
|
364
372
|
const result = await processAvatarFile(file);
|
|
365
373
|
if ("type" in result) {
|
|
366
374
|
// Error result
|
|
367
375
|
const error = result;
|
|
368
376
|
showToast(error.message, TOAST_VARIANT.ERROR);
|
|
369
|
-
// dispatch({
|
|
370
|
-
// type: TEACHER_ACTION_TYPES.SET_INPUT_FIELD,
|
|
371
|
-
// payload: { key: "avatarUploading", value: false },
|
|
372
|
-
// });
|
|
373
377
|
return;
|
|
374
378
|
}
|
|
375
|
-
const teacherId =
|
|
379
|
+
const teacherId = state.id;
|
|
376
380
|
if (!teacherId) {
|
|
377
381
|
showToast("Please save the teacher record first before uploading an avatar", TOAST_VARIANT.ERROR);
|
|
378
|
-
|
|
379
|
-
// type: TEACHER_ACTION_TYPES.SET_INPUT_FIELD,
|
|
380
|
-
// payload: { key: "avatarUploading", value: false },
|
|
381
|
-
// });
|
|
382
|
+
uploadInProgressRef.current = false;
|
|
382
383
|
return;
|
|
383
384
|
}
|
|
384
385
|
// Upload to S3 via teacher-avatar endpoint
|
|
@@ -399,15 +400,11 @@ export const useTeacherModule = () => {
|
|
|
399
400
|
const errorData = await response.json().catch(() => ({}));
|
|
400
401
|
const errorMessage = errorData.error || `Upload failed with status ${response.status}`;
|
|
401
402
|
showToast(errorMessage, TOAST_VARIANT.ERROR);
|
|
402
|
-
|
|
403
|
-
// type: TEACHER_ACTION_TYPES.SET_INPUT_FIELD,
|
|
404
|
-
// payload: { key: "avatarUploading", value: false },
|
|
405
|
-
// });
|
|
403
|
+
uploadInProgressRef.current = false;
|
|
406
404
|
return;
|
|
407
405
|
}
|
|
408
406
|
const data = await response.json();
|
|
409
407
|
const avatarUrl = data.url;
|
|
410
|
-
// Update avatar field with presigned URL
|
|
411
408
|
dispatch({
|
|
412
409
|
type: TEACHER_ACTION_TYPES.SET_INPUT_FIELD,
|
|
413
410
|
payload: { key: "avatar", value: avatarUrl },
|
|
@@ -421,12 +418,9 @@ export const useTeacherModule = () => {
|
|
|
421
418
|
showToast(errorMessage, TOAST_VARIANT.ERROR);
|
|
422
419
|
}
|
|
423
420
|
finally {
|
|
424
|
-
|
|
425
|
-
// type: TEACHER_ACTION_TYPES.SET_INPUT_FIELD,
|
|
426
|
-
// payload: { key: "avatarUploading", value: false },
|
|
427
|
-
// });
|
|
421
|
+
uploadInProgressRef.current = false;
|
|
428
422
|
}
|
|
429
|
-
}, [dispatch, showToast, workspace === null || workspace === void 0 ? void 0 : workspace.id]);
|
|
423
|
+
}, [dispatch, showToast, state.id, workspace === null || workspace === void 0 ? void 0 : workspace.id]);
|
|
430
424
|
const applyFilters = useCallback(() => {
|
|
431
425
|
dispatch({
|
|
432
426
|
type: TEACHER_ACTION_TYPES.SET_CURRENT_PAGE,
|