@crimson-education/sdk 0.3.5 → 0.3.6

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.
@@ -14,6 +14,14 @@ export declare const taskKeys: {
14
14
  };
15
15
  export declare function useTasks(missionId: string | null, enabled: boolean): import("@tanstack/react-query").UseQueryResult<Task[], Error>;
16
16
  export declare function useTaskCreators(roadmapId: string | null, enabled?: boolean): import("@tanstack/react-query").UseQueryResult<User[], Error>;
17
+ export declare class ActivityLoader {
18
+ private client;
19
+ private queue;
20
+ private timeout;
21
+ constructor(client: any);
22
+ load(id: string, type: string): Promise<ActionItemActivityBrief[]>;
23
+ private flush;
24
+ }
17
25
  export declare function useTaskActivities(actionItemIds: string[], type?: string, enabled?: boolean): {
18
26
  data: Record<string, ActionItemActivityBrief[]>;
19
27
  isLoading: boolean;
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  });
11
11
  };
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.taskKeys = void 0;
13
+ exports.ActivityLoader = exports.taskKeys = void 0;
14
14
  exports.useTasks = useTasks;
15
15
  exports.useTaskCreators = useTaskCreators;
16
16
  exports.useTaskActivities = useTaskActivities;
@@ -66,72 +66,70 @@ function useTaskCreators(roadmapId, enabled = true) {
66
66
  enabled: !!roadmapId && enabled,
67
67
  });
68
68
  }
69
- function useTaskActivities(actionItemIds, type = "duedate", enabled = true) {
70
- const client = (0, provider_1.useCrimsonClient)();
71
- const queryClient = (0, react_query_1.useQueryClient)();
72
- const STALE_TIME = 5 * 60 * 1000;
73
- // 1. Use useQueries to READ from cache.
74
- // We disable them so they never trigger individual fetches.
75
- // They effectively act as observers of the cache.
76
- const queries = (0, react_query_1.useQueries)({
77
- queries: actionItemIds.map((id) => ({
78
- queryKey: exports.taskKeys.activity(id, type),
79
- // No queryFn needed because we never enable it to fetch
80
- enabled: false,
81
- })),
82
- });
83
- // 2. Manage fetching via side-effect
84
- (0, react_1.useEffect)(() => {
85
- if (!enabled || actionItemIds.length === 0)
86
- return;
87
- const now = Date.now();
88
- const idsToFetch = actionItemIds.filter((id) => {
89
- const state = queryClient.getQueryState(exports.taskKeys.activity(id, type));
90
- // If no data, need fetch
91
- if (!state || !state.data)
92
- return true;
93
- // If data exists but is stale, need fetch
94
- if (state.dataUpdatedAt && (now - state.dataUpdatedAt > STALE_TIME)) {
95
- return true;
69
+ class ActivityLoader {
70
+ constructor(client) {
71
+ this.queue = new Map();
72
+ this.timeout = new Map();
73
+ this.client = client;
74
+ }
75
+ load(id, type) {
76
+ const key = type;
77
+ if (!this.queue.has(key)) {
78
+ this.queue.set(key, []);
79
+ }
80
+ return new Promise((resolve, reject) => {
81
+ this.queue.get(key).push({ id, type, resolve, reject });
82
+ if (!this.timeout.has(key)) {
83
+ const timeout = setTimeout(() => {
84
+ this.timeout.delete(key);
85
+ this.flush(key);
86
+ }, 50);
87
+ this.timeout.set(key, timeout);
96
88
  }
97
- return false;
98
89
  });
99
- if (idsToFetch.length === 0)
100
- return;
101
- // Deduplicate IDs just in case
102
- const uniqueIdsToFetch = [...new Set(idsToFetch)];
103
- // Perform batch fetch
104
- const fetchBatch = () => __awaiter(this, void 0, void 0, function* () {
90
+ }
91
+ flush(key) {
92
+ return __awaiter(this, void 0, void 0, function* () {
93
+ const items = this.queue.get(key);
94
+ this.queue.delete(key);
95
+ if (!items || items.length === 0)
96
+ return;
97
+ const uniqueIds = Array.from(new Set(items.map(i => i.id)));
98
+ const type = items[0].type; // All items in this queue have same type
105
99
  try {
106
- const result = yield client.tasks.getActivities(uniqueIdsToFetch, type);
107
- // Update cache for each ID
108
- // Note: We update ALL requested IDs. If an ID is missing in result,
109
- // it implies no activities, so we set empty array to prevent infinite refetching.
110
- uniqueIdsToFetch.forEach(id => {
111
- const activities = result[id] || [];
112
- queryClient.setQueryData(exports.taskKeys.activity(id, type), activities);
100
+ const result = yield this.client.tasks.getActivities(uniqueIds, type);
101
+ items.forEach(({ id, resolve }) => {
102
+ resolve(result[id] || []);
113
103
  });
114
104
  }
115
105
  catch (error) {
116
- console.error("Failed to batch fetch activities", error);
106
+ items.forEach(({ reject }) => reject(error));
117
107
  }
118
108
  });
119
- fetchBatch();
120
- // We intentionally do not include queryClient deeply in deps if not needed,
121
- // but here it's stable.
122
- // We rely on actionItemIds changing (scroll) or enabled changing to trigger this.
123
- // For periodic polling of staleness, one might need a timer, but for now
124
- // check-on-mount/update is sufficient.
125
- }, [actionItemIds, type, enabled, client, queryClient]); // STALE_TIME constant
126
- const isLoading = queries.some((q) => !q.data && enabled); // If enabled and no data, we are effectively loading
127
- const data = {};
128
- queries.forEach((q, index) => {
129
- // q.data comes from cache
130
- if (q.data) {
131
- data[actionItemIds[index]] = q.data;
109
+ }
110
+ }
111
+ exports.ActivityLoader = ActivityLoader;
112
+ function useTaskActivities(actionItemIds, type = "duedate", enabled = true) {
113
+ const client = (0, provider_1.useCrimsonClient)();
114
+ const loaderRef = (0, react_1.useMemo)(() => new ActivityLoader(client), [client]);
115
+ return (0, react_query_1.useQueries)({
116
+ queries: actionItemIds.map((id) => ({
117
+ queryKey: exports.taskKeys.activity(id, type),
118
+ queryFn: () => loaderRef.load(id, type),
119
+ enabled: enabled,
120
+ staleTime: Infinity, // Cache forever until invalidated
121
+ })),
122
+ combine: (results) => {
123
+ const data = {};
124
+ const isLoading = results.some((r) => r.isLoading);
125
+ results.forEach((r, index) => {
126
+ if (r.data) {
127
+ data[actionItemIds[index]] = r.data;
128
+ }
129
+ });
130
+ return { data, isLoading };
132
131
  }
133
132
  });
134
- return { data, isLoading };
135
133
  }
136
134
  function useAllUserTasks(missionLinkIds, enabled) {
137
135
  const client = (0, provider_1.useCrimsonClient)();
@@ -425,8 +423,12 @@ function useBulkUpdateTasks(options) {
425
423
  queryClient.setQueryData(JSON.parse(keyStr), old);
426
424
  });
427
425
  },
428
- onSettled: () => {
426
+ onSettled: (data, error, variables) => {
429
427
  queryClient.invalidateQueries({ queryKey: exports.taskKeys.all });
428
+ // Invalidate activities for all updated tasks
429
+ variables.ids.forEach(id => {
430
+ queryClient.invalidateQueries({ queryKey: exports.taskKeys.activitiesOfTask(id) });
431
+ });
430
432
  },
431
433
  });
432
434
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crimson-education/sdk",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "description": "Crimson SDK for accessing Crimson App APIs",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",