@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
- // Set uploading state
359
- // dispatch({
360
- // type: TEACHER_ACTION_TYPES.SET_INPUT_FIELD,
361
- // payload: { key: "avatarUploading", value: true },
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 = uuidv4();
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
- // dispatch({
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
- // dispatch({
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
- // dispatch({
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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appcorp/fusion-storybook",
3
- "version": "0.2.11",
3
+ "version": "0.2.12",
4
4
  "scripts": {
5
5
  "build-storybook": "storybook build",
6
6
  "build:next": "next build",