@appcorp/fusion-storybook 0.3.44 → 0.3.46

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.
Files changed (106) hide show
  1. package/base-modules/admission/context/use-admission-module.js +4 -1
  2. package/base-modules/admission/form.js +3 -1
  3. package/base-modules/admission/more-actions.js +2 -2
  4. package/base-modules/admission/view.js +1 -1
  5. package/base-modules/attendance/context.js +2 -1
  6. package/base-modules/attendance/form.js +3 -3
  7. package/base-modules/attendance/more-actions.js +1 -1
  8. package/base-modules/attendance/page.js +1 -1
  9. package/base-modules/attendance/view.js +2 -2
  10. package/base-modules/campus/context.js +2 -1
  11. package/base-modules/campus/more-actions.js +2 -1
  12. package/base-modules/class/cache.d.ts +3 -3
  13. package/base-modules/class/cache.js +1 -1
  14. package/base-modules/class/context.js +2 -1
  15. package/base-modules/class/more-actions.js +1 -1
  16. package/base-modules/course/context.js +2 -1
  17. package/base-modules/course/form.js +1 -1
  18. package/base-modules/course/more-actions.js +2 -1
  19. package/base-modules/course/view.js +1 -3
  20. package/base-modules/discount-code/cache.d.ts +3 -3
  21. package/base-modules/discount-code/cache.js +1 -1
  22. package/base-modules/discount-code/context.js +2 -1
  23. package/base-modules/enrollment/context.js +2 -1
  24. package/base-modules/enrollment/form.js +4 -3
  25. package/base-modules/enrollment/more-actions.js +1 -1
  26. package/base-modules/enrollment/page.js +2 -1
  27. package/base-modules/enrollment/view.js +3 -3
  28. package/base-modules/expense/context.js +2 -1
  29. package/base-modules/expense/more-actions.js +1 -1
  30. package/base-modules/expense/page.js +1 -1
  31. package/base-modules/expense/view.js +2 -4
  32. package/base-modules/family/context.js +2 -1
  33. package/base-modules/family/more-actions.js +1 -1
  34. package/base-modules/family-member/context.js +2 -1
  35. package/base-modules/family-member/more-actions.js +2 -2
  36. package/base-modules/family-member/view.js +1 -1
  37. package/base-modules/fee-structure/cache.d.ts +3 -3
  38. package/base-modules/fee-structure/cache.js +1 -1
  39. package/base-modules/fee-structure/context.js +2 -1
  40. package/base-modules/fee-structure/form.js +1 -1
  41. package/base-modules/fee-structure/more-actions.js +1 -1
  42. package/base-modules/push-campaign/cache.d.ts +9 -0
  43. package/base-modules/push-campaign/cache.js +16 -0
  44. package/base-modules/push-campaign/constants.d.ts +24 -0
  45. package/base-modules/push-campaign/constants.js +11 -0
  46. package/base-modules/push-campaign/context/module-base.d.ts +181 -0
  47. package/base-modules/push-campaign/context/module-base.js +45 -0
  48. package/base-modules/push-campaign/context/use-push-campaign-module.d.ts +66 -0
  49. package/base-modules/push-campaign/context/use-push-campaign-module.js +451 -0
  50. package/base-modules/push-campaign/context.d.ts +2 -0
  51. package/base-modules/push-campaign/context.js +3 -0
  52. package/base-modules/push-campaign/filter.d.ts +1 -0
  53. package/base-modules/push-campaign/filter.js +43 -0
  54. package/base-modules/push-campaign/form.d.ts +1 -0
  55. package/base-modules/push-campaign/form.js +21 -0
  56. package/base-modules/push-campaign/page.d.ts +28 -0
  57. package/base-modules/push-campaign/page.js +152 -0
  58. package/base-modules/push-campaign/validate.d.ts +11 -0
  59. package/base-modules/push-campaign/validate.js +11 -0
  60. package/base-modules/push-campaign/view.d.ts +1 -0
  61. package/base-modules/push-campaign/view.js +26 -0
  62. package/base-modules/rbac/context.js +2 -1
  63. package/base-modules/school/cache.js +1 -1
  64. package/base-modules/school/context.js +1 -1
  65. package/base-modules/section/cache.d.ts +3 -3
  66. package/base-modules/section/cache.js +1 -1
  67. package/base-modules/section/context.js +2 -1
  68. package/base-modules/section/more-actions.js +1 -1
  69. package/base-modules/student-fee/context/use-student-fee-module.js +4 -1
  70. package/base-modules/student-fee/form.js +2 -1
  71. package/base-modules/student-fee/more-actions.js +1 -1
  72. package/base-modules/student-fee/page.js +1 -1
  73. package/base-modules/student-fee/single-entry.js +1 -1
  74. package/base-modules/student-fee/view.js +4 -4
  75. package/base-modules/student-profile/cache.d.ts +3 -3
  76. package/base-modules/student-profile/cache.js +1 -1
  77. package/base-modules/student-profile/context/use-student-profile-module.js +4 -1
  78. package/base-modules/student-profile/form.js +1 -1
  79. package/base-modules/student-profile/more-actions.js +1 -1
  80. package/base-modules/student-profile/page.js +1 -1
  81. package/base-modules/student-profile/view.js +1 -1
  82. package/base-modules/subject/cache.d.ts +3 -3
  83. package/base-modules/subject/cache.js +1 -1
  84. package/base-modules/subject/context.js +2 -1
  85. package/base-modules/subject/more-actions.js +1 -1
  86. package/base-modules/teacher/cache.d.ts +3 -3
  87. package/base-modules/teacher/cache.js +1 -1
  88. package/base-modules/teacher/context.js +2 -1
  89. package/base-modules/teacher/more-actions.js +1 -1
  90. package/base-modules/teacher/view.js +1 -1
  91. package/base-modules/user/cache.d.ts +3 -3
  92. package/base-modules/user/cache.js +1 -1
  93. package/base-modules/user/context/use-user-module.js +4 -1
  94. package/base-modules/user/more-actions.js +2 -1
  95. package/base-modules/workspace/cache.js +2 -1
  96. package/base-modules/workspace/context.js +1 -1
  97. package/base-modules/workspace/view.js +1 -1
  98. package/base-modules/workspace-user/context.js +5 -2
  99. package/base-modules/workspace-user/more-actions.js +2 -2
  100. package/constants.d.ts +6 -0
  101. package/constants.js +6 -0
  102. package/package.json +2 -2
  103. package/tsconfig.build.tsbuildinfo +1 -1
  104. package/types/communication.d.ts +28 -0
  105. package/types/enums.d.ts +1 -0
  106. package/types/enums.js +1 -0
@@ -0,0 +1,451 @@
1
+ import { useCallback, useEffect, useMemo, useRef } from "react";
2
+ import { useTranslations } from "next-intl";
3
+ import { useTheme } from "next-themes";
4
+ import { isCreatedOrUpdated } from "@react-pakistan/util-functions/general/is-created-or-updated";
5
+ import { validateForm } from "@react-pakistan/util-functions/general/validate-form";
6
+ import { useModuleEntityV2, } from "@react-pakistan/util-functions/hooks/use-module-entity-v2";
7
+ import { useDebounce } from "@react-pakistan/util-functions/hooks/use-debounce";
8
+ import { generateThemeToast, TOAST_VARIANT, } from "@appcorp/shadcn/lib/toast-utils";
9
+ import { PUSH_CAMPAIGN_API_ROUTES } from "../../../constants";
10
+ import { pushCampaignFormValidation } from "../validate";
11
+ import { getCachedWorkspaceSync } from "../../workspace/cache";
12
+ import { usePushCampaignContext, PUSH_CAMPAIGN_ACTION_TYPES, PUSH_CAMPAIGN_DRAWER, } from "./module-base";
13
+ export const usePushCampaignModule = () => {
14
+ var _a, _b, _c;
15
+ const context = usePushCampaignContext();
16
+ const { dispatch } = context;
17
+ const state = context.state;
18
+ const t = useTranslations("pushCampaign");
19
+ const { theme } = useTheme();
20
+ const workspace = getCachedWorkspaceSync();
21
+ const listFetchNowRef = useRef(null);
22
+ const debouncedQuery = useDebounce(state.searchQuery, 800);
23
+ const listParams = useMemo(() => {
24
+ var _a;
25
+ return (Object.assign(Object.assign(Object.assign({ currentPage: state.currentPage, pageLimit: state.pageLimit, schoolId: ((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "" }, (debouncedQuery ? { searchQuery: debouncedQuery } : {})), (state.filterEnabled !== undefined
26
+ ? { filterEnabled: String(state.filterEnabled) }
27
+ : {})), (state.filterStatus ? { filterStatus: state.filterStatus } : {})));
28
+ }, [
29
+ state.currentPage,
30
+ state.filterEnabled,
31
+ state.filterStatus,
32
+ state.pageLimit,
33
+ debouncedQuery,
34
+ (_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id,
35
+ ]);
36
+ const updateParams = useMemo(() => {
37
+ var _a;
38
+ return ({
39
+ id: state.id || undefined,
40
+ schoolId: state.schoolId || ((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "",
41
+ name: state.name,
42
+ title: state.title,
43
+ body: state.body,
44
+ scheduledAt: state.scheduledAt,
45
+ allStudents: state.allStudents,
46
+ audience: state.audience,
47
+ status: state.status,
48
+ enabled: state.enabled,
49
+ });
50
+ }, [state, (_b = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _b === void 0 ? void 0 : _b.id]);
51
+ const byIdParams = useMemo(() => ({ id: state.id }), [state.id]);
52
+ const deleteParams = useMemo(() => ({ id: state.id }), [state.id]);
53
+ const showToast = useCallback((description, variant) => {
54
+ generateThemeToast({
55
+ description,
56
+ theme: theme,
57
+ variant,
58
+ });
59
+ }, [theme]);
60
+ const resetFormAndCloseDrawer = useCallback(() => {
61
+ dispatch({ type: PUSH_CAMPAIGN_ACTION_TYPES.RESET_FORM });
62
+ dispatch({
63
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_ERRORS,
64
+ payload: { errors: {} },
65
+ });
66
+ dispatch({
67
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
68
+ payload: { disabled: false },
69
+ });
70
+ dispatch({
71
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_DRAWER,
72
+ payload: { drawer: null },
73
+ });
74
+ }, [dispatch]);
75
+ const resetRecordFormState = useCallback(() => {
76
+ dispatch({
77
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_ERRORS,
78
+ payload: { errors: {} },
79
+ });
80
+ dispatch({
81
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
82
+ payload: { disabled: false },
83
+ });
84
+ }, [dispatch]);
85
+ const listCallback = useCallback(({ data, error }) => {
86
+ var _a, _b;
87
+ if (error) {
88
+ showToast(t("messagesFetchFailed"), TOAST_VARIANT.ERROR);
89
+ return;
90
+ }
91
+ if (data) {
92
+ const response = data;
93
+ dispatch({
94
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_ITEMS,
95
+ payload: { items: (_a = response.items) !== null && _a !== void 0 ? _a : [], count: (_b = response.count) !== null && _b !== void 0 ? _b : 0 },
96
+ });
97
+ }
98
+ }, [dispatch, showToast, t]);
99
+ const updateCallback = useCallback(({ data, error }) => {
100
+ var _a;
101
+ if (error) {
102
+ showToast(t("messagesUpdateFailed"), TOAST_VARIANT.ERROR);
103
+ return;
104
+ }
105
+ if (data) {
106
+ const isCreated = isCreatedOrUpdated(data);
107
+ showToast(isCreated ? t("messagesCreateSuccess") : t("messagesUpdateSuccess"), TOAST_VARIANT.SUCCESS);
108
+ resetFormAndCloseDrawer();
109
+ (_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
110
+ }
111
+ }, [resetFormAndCloseDrawer, showToast, t]);
112
+ const byIdCallback = useCallback(({ data, error }) => {
113
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
114
+ if (error) {
115
+ showToast(t("messagesDetailsFetchFailed"), TOAST_VARIANT.ERROR);
116
+ return;
117
+ }
118
+ if (data && typeof data === "object" && "id" in data) {
119
+ const pc = data;
120
+ dispatch({
121
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_FORM_DATA,
122
+ payload: {
123
+ form: {
124
+ id: pc.id,
125
+ name: (_a = pc.name) !== null && _a !== void 0 ? _a : "",
126
+ title: (_b = pc.title) !== null && _b !== void 0 ? _b : "",
127
+ body: (_c = pc.body) !== null && _c !== void 0 ? _c : "",
128
+ schoolId: (_d = pc.schoolId) !== null && _d !== void 0 ? _d : "",
129
+ scheduledAt: (_e = pc.scheduledAt) !== null && _e !== void 0 ? _e : "",
130
+ status: pc.status,
131
+ enabled: typeof pc.enabled === "boolean" ? pc.enabled : true,
132
+ allStudents: typeof pc.allStudents === "boolean" ? pc.allStudents : false,
133
+ successCount: (_f = pc.successCount) !== null && _f !== void 0 ? _f : 0,
134
+ failedCount: (_g = pc.failedCount) !== null && _g !== void 0 ? _g : 0,
135
+ totalCount: (_h = pc.totalCount) !== null && _h !== void 0 ? _h : 0,
136
+ workerJobId: (_j = pc.workerJobId) !== null && _j !== void 0 ? _j : null,
137
+ audience: Array.isArray(pc.audience) ? pc.audience : [],
138
+ },
139
+ },
140
+ });
141
+ }
142
+ }, [dispatch, showToast, t]);
143
+ const deleteCallback = useCallback(({ data, error }) => {
144
+ var _a;
145
+ if (error) {
146
+ showToast(t("messagesDeleteFailed"), TOAST_VARIANT.ERROR);
147
+ return;
148
+ }
149
+ if (data) {
150
+ showToast(t("messagesDeleteSuccess"), TOAST_VARIANT.SUCCESS);
151
+ (_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
152
+ }
153
+ }, [showToast, t]);
154
+ const { byIdFetchNow, byIdLoading, deleteFetchNow, deleteLoading, listFetchNow, listLoading, updateFetchNow, updateLoading, } = useModuleEntityV2({
155
+ byIdCallback,
156
+ byIdParams,
157
+ deleteCallback,
158
+ deleteParams,
159
+ listCallback,
160
+ listParams,
161
+ listUrl: PUSH_CAMPAIGN_API_ROUTES.UNIT,
162
+ searchQuery: debouncedQuery,
163
+ unitByIdUrl: PUSH_CAMPAIGN_API_ROUTES.UNIT,
164
+ unitUrl: PUSH_CAMPAIGN_API_ROUTES.UNIT,
165
+ updateCallback,
166
+ updateParams,
167
+ headers: {
168
+ "Content-Type": "application/json",
169
+ },
170
+ });
171
+ const handleChange = useCallback((field, value) => {
172
+ dispatch({
173
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_ERRORS,
174
+ payload: { errors: {} },
175
+ });
176
+ dispatch({
177
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
178
+ payload: { disabled: false },
179
+ });
180
+ dispatch({
181
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_INPUT_FIELD,
182
+ payload: { key: field, value },
183
+ });
184
+ }, [dispatch]);
185
+ const closeDrawer = useCallback(() => {
186
+ resetFormAndCloseDrawer();
187
+ }, [resetFormAndCloseDrawer]);
188
+ const handleCreate = useCallback(() => {
189
+ dispatch({
190
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_DRAWER,
191
+ payload: { drawer: PUSH_CAMPAIGN_DRAWER.FORM_DRAWER },
192
+ });
193
+ }, [dispatch]);
194
+ const handleView = useCallback((row) => {
195
+ resetRecordFormState();
196
+ byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
197
+ dispatch({
198
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_DRAWER,
199
+ payload: { drawer: PUSH_CAMPAIGN_DRAWER.VIEW_DRAWER },
200
+ });
201
+ }, [byIdFetchNow, dispatch, resetRecordFormState]);
202
+ const handleEdit = useCallback((row) => {
203
+ resetRecordFormState();
204
+ byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
205
+ dispatch({
206
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_DRAWER,
207
+ payload: { drawer: PUSH_CAMPAIGN_DRAWER.FORM_DRAWER },
208
+ });
209
+ }, [byIdFetchNow, dispatch, resetRecordFormState]);
210
+ const handleDelete = useCallback((row) => {
211
+ if (!confirm(t("messagesDeleteConfirmation")))
212
+ return;
213
+ deleteFetchNow === null || deleteFetchNow === void 0 ? void 0 : deleteFetchNow(undefined, {
214
+ body: JSON.stringify({ id: row === null || row === void 0 ? void 0 : row.id }),
215
+ });
216
+ }, [deleteFetchNow, t]);
217
+ const handleLaunch = useCallback(async (row) => {
218
+ var _a, _b;
219
+ const campaignId = row === null || row === void 0 ? void 0 : row.id;
220
+ if (!campaignId)
221
+ return;
222
+ try {
223
+ const res = await fetch(PUSH_CAMPAIGN_API_ROUTES.START, {
224
+ method: "POST",
225
+ headers: { "Content-Type": "application/json" },
226
+ body: JSON.stringify({ id: campaignId }),
227
+ });
228
+ if (res.ok) {
229
+ showToast(t("messagesLaunchSuccess"), TOAST_VARIANT.SUCCESS);
230
+ (_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
231
+ }
232
+ else {
233
+ const err = (await res.json());
234
+ showToast((_b = err === null || err === void 0 ? void 0 : err.error) !== null && _b !== void 0 ? _b : t("messagesLaunchFailed"), TOAST_VARIANT.ERROR);
235
+ }
236
+ }
237
+ catch (_c) {
238
+ showToast(t("messagesLaunchFailed"), TOAST_VARIANT.ERROR);
239
+ }
240
+ }, [showToast, t]);
241
+ const handleAiCheck = useCallback(async () => {
242
+ var _a;
243
+ const title = state.title;
244
+ const body = state.body;
245
+ if (!title || !body) {
246
+ showToast(t("aiCheckMissingFields"), TOAST_VARIANT.ERROR);
247
+ return;
248
+ }
249
+ dispatch({
250
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_INPUT_FIELD,
251
+ payload: { key: "aiCheckLoading", value: true },
252
+ });
253
+ try {
254
+ const res = await fetch(PUSH_CAMPAIGN_API_ROUTES.AI_CHECK, {
255
+ method: "POST",
256
+ headers: { "Content-Type": "application/json" },
257
+ body: JSON.stringify({ title, body }),
258
+ });
259
+ if (!res.ok) {
260
+ const err = (await res.json());
261
+ showToast((_a = err === null || err === void 0 ? void 0 : err.error) !== null && _a !== void 0 ? _a : t("aiCheckFailed"), TOAST_VARIANT.ERROR);
262
+ dispatch({
263
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_INPUT_FIELD,
264
+ payload: { key: "aiCheckLoading", value: false },
265
+ });
266
+ return;
267
+ }
268
+ const result = (await res.json());
269
+ dispatch({
270
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_INPUT_FIELD,
271
+ payload: { key: "aiCheckPassed", value: result.passed },
272
+ });
273
+ dispatch({
274
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_INPUT_FIELD,
275
+ payload: { key: "aiCheckScore", value: result.score },
276
+ });
277
+ dispatch({
278
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_INPUT_FIELD,
279
+ payload: { key: "aiSuggestions", value: result.suggestions },
280
+ });
281
+ if (result.passed && result.improvedTitle && result.improvedBody) {
282
+ dispatch({
283
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_INPUT_FIELD,
284
+ payload: { key: "title", value: result.improvedTitle },
285
+ });
286
+ dispatch({
287
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_INPUT_FIELD,
288
+ payload: { key: "body", value: result.improvedBody },
289
+ });
290
+ }
291
+ }
292
+ catch (_b) {
293
+ showToast(t("aiCheckFailed"), TOAST_VARIANT.ERROR);
294
+ }
295
+ finally {
296
+ dispatch({
297
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_INPUT_FIELD,
298
+ payload: { key: "aiCheckLoading", value: false },
299
+ });
300
+ }
301
+ }, [state.title, state.body, showToast, t, dispatch]);
302
+ const handleFilters = useCallback(() => {
303
+ dispatch({
304
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_DRAWER,
305
+ payload: { drawer: PUSH_CAMPAIGN_DRAWER.FILTER_DRAWER },
306
+ });
307
+ }, [dispatch]);
308
+ const handlePageChange = useCallback((page) => {
309
+ const nextPage = typeof page === "number" ? page : state.currentPage + 1;
310
+ dispatch({
311
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_CURRENT_PAGE,
312
+ payload: { currentPage: nextPage },
313
+ });
314
+ }, [dispatch, state.currentPage]);
315
+ const handlePageLimitChange = useCallback((k, value) => {
316
+ const val = Object.assign({}, value);
317
+ dispatch({
318
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_PAGE_LIMIT,
319
+ payload: { pageLimit: Number(val.option) },
320
+ });
321
+ dispatch({
322
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_CURRENT_PAGE,
323
+ payload: { currentPage: 1 },
324
+ });
325
+ }, [dispatch]);
326
+ const handleSearch = useCallback((query) => {
327
+ dispatch({
328
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_SEARCH_QUERY,
329
+ payload: { searchQuery: query },
330
+ });
331
+ }, [dispatch]);
332
+ const applyFilters = useCallback(() => {
333
+ dispatch({
334
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_CURRENT_PAGE,
335
+ payload: { currentPage: 1 },
336
+ });
337
+ closeDrawer();
338
+ }, [dispatch, closeDrawer]);
339
+ const clearFilters = useCallback(() => {
340
+ dispatch({
341
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_FILTERS,
342
+ payload: {
343
+ filters: {
344
+ filterEnabled: undefined,
345
+ filterStatus: undefined,
346
+ },
347
+ },
348
+ });
349
+ dispatch({
350
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_CURRENT_PAGE,
351
+ payload: { currentPage: 1 },
352
+ });
353
+ }, [dispatch]);
354
+ const handleSubmit = useCallback(() => {
355
+ dispatch({
356
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
357
+ payload: { disabled: true },
358
+ });
359
+ validateForm({
360
+ params: updateParams,
361
+ schema: pushCampaignFormValidation,
362
+ successCallback: () => {
363
+ updateFetchNow(undefined, {
364
+ body: JSON.stringify(updateParams),
365
+ });
366
+ },
367
+ errorCallback: (errors) => {
368
+ dispatch({
369
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_ERRORS,
370
+ payload: { errors },
371
+ });
372
+ dispatch({
373
+ type: PUSH_CAMPAIGN_ACTION_TYPES.SET_DISABLE_SAVE_BUTTON,
374
+ payload: { disabled: false },
375
+ });
376
+ showToast(t("messagesFormErrors"), TOAST_VARIANT.ERROR);
377
+ },
378
+ });
379
+ }, [dispatch, updateParams, t, showToast, updateFetchNow]);
380
+ const headerActions = useMemo(() => [
381
+ {
382
+ enabled: true,
383
+ handleOnClick: handleFilters,
384
+ label: t("actionsButtonFilters"),
385
+ order: 1,
386
+ },
387
+ {
388
+ enabled: true,
389
+ handleOnClick: handleCreate,
390
+ label: t("actionsButtonNewCampaign"),
391
+ order: 2,
392
+ },
393
+ ], [handleCreate, handleFilters, t]);
394
+ const rowActions = useMemo(() => [
395
+ {
396
+ enabled: true,
397
+ handleOnClick: handleView,
398
+ label: t("actionsRowView"),
399
+ order: 1,
400
+ },
401
+ {
402
+ enabled: true,
403
+ handleOnClick: handleEdit,
404
+ label: t("actionsRowEdit"),
405
+ order: 2,
406
+ },
407
+ {
408
+ enabled: true,
409
+ handleOnClick: handleLaunch,
410
+ label: t("actionsRowLaunch"),
411
+ order: 3,
412
+ },
413
+ {
414
+ enabled: true,
415
+ handleOnClick: handleDelete,
416
+ label: t("actionsRowDelete"),
417
+ order: 4,
418
+ },
419
+ ], [t, handleView, handleEdit, handleLaunch, handleDelete]);
420
+ useEffect(() => {
421
+ listFetchNowRef.current = listFetchNow;
422
+ }, [listFetchNow]);
423
+ useEffect(() => {
424
+ var _a, _b;
425
+ if (!((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id))
426
+ return;
427
+ (_b = listFetchNowRef.current) === null || _b === void 0 ? void 0 : _b.call(listFetchNowRef);
428
+ }, [dispatch, listParams, (_c = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _c === void 0 ? void 0 : _c.id, showToast, t]);
429
+ return Object.assign(Object.assign({}, context), { applyFilters,
430
+ byIdLoading,
431
+ clearFilters,
432
+ closeDrawer,
433
+ deleteLoading,
434
+ handleAiCheck,
435
+ handleChange,
436
+ handleCreate,
437
+ handleDelete,
438
+ handleEdit,
439
+ handleFilters,
440
+ handleLaunch,
441
+ handlePageChange,
442
+ handlePageLimitChange,
443
+ handleSearch,
444
+ handleSubmit,
445
+ handleView,
446
+ headerActions,
447
+ listFetchNow,
448
+ listLoading,
449
+ rowActions,
450
+ updateLoading });
451
+ };
@@ -0,0 +1,2 @@
1
+ export { PUSH_CAMPAIGN_DRAWER, PUSH_CAMPAIGN_ACTION_TYPES, pushCampaignModuleConfig, initialPushCampaignState, PushCampaignProvider, pushCampaignReducer, usePushCampaignContext, } from "./context/module-base";
2
+ export { usePushCampaignModule } from "./context/use-push-campaign-module";
@@ -0,0 +1,3 @@
1
+ "use client";
2
+ export { PUSH_CAMPAIGN_DRAWER, PUSH_CAMPAIGN_ACTION_TYPES, pushCampaignModuleConfig, initialPushCampaignState, PushCampaignProvider, pushCampaignReducer, usePushCampaignContext, } from "./context/module-base";
3
+ export { usePushCampaignModule } from "./context/use-push-campaign-module";
@@ -0,0 +1 @@
1
+ export declare const PushCampaignFilter: () => import("react").JSX.Element;
@@ -0,0 +1,43 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { EnhancedCheckbox } from "@appcorp/shadcn/components/enhanced-checkbox";
4
+ import { useEnhancedCombobox } from "@appcorp/shadcn/hooks/use-enhanced-combobox";
5
+ import { useTranslations } from "next-intl";
6
+ import { usePushCampaignModule } from "./context";
7
+ import { STATUS_OPTIONS } from "./constants";
8
+ export const PushCampaignFilter = () => {
9
+ const t = useTranslations("pushCampaign");
10
+ const context = usePushCampaignModule();
11
+ const { filterEnabled, filterStatus } = context.state;
12
+ const { handleChange } = context;
13
+ const statusLabelMap = {
14
+ draft: t("filterOptionDraft"),
15
+ scheduled: t("filterOptionScheduled"),
16
+ running: t("filterOptionRunning"),
17
+ completed: t("filterOptionCompleted"),
18
+ failed: t("filterOptionFailed"),
19
+ paused: t("filterOptionPaused"),
20
+ };
21
+ const { enhancedComboboxElement: statusCombo } = useEnhancedCombobox({
22
+ id: "filterStatus",
23
+ info: t("filterStatusInfo"),
24
+ label: t("filterStatusLabel"),
25
+ onValueChange: (value) => handleChange("filterStatus", value),
26
+ options: STATUS_OPTIONS.map((opt) => ({
27
+ value: opt.value,
28
+ label: statusLabelMap[opt.label] || opt.label,
29
+ })),
30
+ placeholder: "",
31
+ searchEndpoint: "/api/v1/push-campaign",
32
+ formatSearchResult: (item) => {
33
+ var _a, _b;
34
+ return ({
35
+ label: String((_a = item.label) !== null && _a !== void 0 ? _a : ""),
36
+ value: String((_b = item.value) !== null && _b !== void 0 ? _b : ""),
37
+ });
38
+ },
39
+ value: filterStatus !== null && filterStatus !== void 0 ? filterStatus : "",
40
+ emptyText: t("filterOptionAll"),
41
+ });
42
+ return (_jsxs("div", { className: "space-y-4", children: [statusCombo, _jsx(EnhancedCheckbox, { checked: filterEnabled === undefined ? true : filterEnabled, info: t("filterEnabledInfo"), label: t("filterEnabledLabel"), onCheckedChange: (checked) => handleChange("filterEnabled", checked) })] }));
43
+ };
@@ -0,0 +1 @@
1
+ export declare const PushCampaignForm: () => import("react").JSX.Element;
@@ -0,0 +1,21 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { EnhancedInput } from "@appcorp/shadcn/components/enhanced-input";
4
+ import { EnhancedTextarea } from "@appcorp/shadcn/components/enhanced-textarea";
5
+ import { EnhancedCheckbox } from "@appcorp/shadcn/components/enhanced-checkbox";
6
+ import { useTranslations } from "next-intl";
7
+ import { usePushCampaignModule } from "./context";
8
+ import { getTranslatedError } from "../../utils/get-translated-error";
9
+ const getMinScheduleDatetime = () => {
10
+ const d = new Date();
11
+ d.setHours(d.getHours() + 1);
12
+ d.setMinutes(0, 0, 0);
13
+ return d.toISOString().slice(0, 16);
14
+ };
15
+ export const PushCampaignForm = () => {
16
+ const t = useTranslations("pushCampaign");
17
+ const context = usePushCampaignModule();
18
+ const { allStudents, body, errors, enabled, name, scheduledAt, status, title, aiCheckLoading, aiCheckPassed, aiCheckScore, aiSuggestions, } = context.state;
19
+ const { handleAiCheck, handleChange, } = context;
20
+ return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "space-y-4", children: [_jsx(EnhancedInput, { error: getTranslatedError({ errors, key: "name", t }), id: "name", info: t("formNameInfo"), label: t("formNameLabel"), onChange: (e) => handleChange("name", e.target.value), placeholder: t("formNamePlaceholder"), required: true, value: name }), _jsx(EnhancedInput, { error: getTranslatedError({ errors, key: "title", t }), id: "title", info: t("formTitleInfo"), label: t("formTitleLabel"), maxLength: 100, onChange: (e) => handleChange("title", e.target.value), placeholder: t("formTitlePlaceholder"), required: true, value: title }), _jsx(EnhancedTextarea, { error: getTranslatedError({ errors, key: "body", t }), id: "body", info: t("formBodyInfo"), label: t("formBodyLabel"), maxLength: 300, onChange: (e) => handleChange("body", e.target.value), placeholder: t("formBodyPlaceholder"), required: true, rows: 4, value: body }), _jsx(EnhancedInput, { error: getTranslatedError({ errors, key: "scheduledAt", t }), id: "scheduledAt", info: t("formScheduledAtInfo"), label: t("formScheduledAtLabel"), min: getMinScheduleDatetime(), onChange: (e) => handleChange("scheduledAt", e.target.value), required: true, type: "datetime-local", value: scheduledAt })] }), _jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-lg font-semibold", children: t("formSectionAudience") }), _jsx(EnhancedCheckbox, { checked: allStudents, info: t("formAllStudentsInfo"), label: t("formAllStudentsLabel"), onCheckedChange: (checked) => handleChange("allStudents", checked) })] }), _jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-lg font-semibold", children: t("formSectionAiReview") }), _jsxs("div", { className: "flex items-center gap-4", children: [_jsx("button", { className: "rounded bg-primary px-4 py-2 text-primary-foreground disabled:opacity-50", disabled: aiCheckLoading || !title || !body, onClick: handleAiCheck, type: "button", children: aiCheckLoading ? t("aiCheckRunning") : t("aiCheckButton") }), aiCheckScore !== null && (_jsxs("span", { className: "text-sm font-medium", children: [t("aiCheckScore"), ": ", Math.round(aiCheckScore), "/10", aiCheckPassed ? " ✅" : " ❌"] }))] }), aiSuggestions && (_jsx("p", { className: "text-sm text-muted-foreground whitespace-pre-wrap", children: aiSuggestions }))] }), status && (_jsx("div", { className: "space-y-4", children: _jsx(EnhancedInput, { id: "status", label: t("formStatusLabel"), value: status, disabled: true }) })), _jsx(EnhancedCheckbox, { checked: enabled, info: t("formEnabledInfo"), label: t("formEnabledLabel"), onCheckedChange: (checked) => handleChange("enabled", checked) })] }));
21
+ };
@@ -0,0 +1,28 @@
1
+ import { FC } from "react";
2
+ import { USER_ROLE } from "../../type";
3
+ interface Props {
4
+ drawerButtonCancel: string;
5
+ drawerButtonSave: string;
6
+ drawerFilterDescription: string;
7
+ drawerFilterTitle: string;
8
+ drawerFormDescription: string;
9
+ drawerFormTitle: string;
10
+ drawerMoreActionsDescription: string;
11
+ drawerMoreActionsTitle: string;
12
+ drawerViewDescription: string;
13
+ drawerViewTitle: string;
14
+ tableColumnHeaderActions: string;
15
+ tableColumnHeaderAllStudents: string;
16
+ tableColumnHeaderId: string;
17
+ tableColumnHeaderName: string;
18
+ tableColumnHeaderScheduledAt: string;
19
+ tableColumnHeaderStatus: string;
20
+ tableColumnHeaderSuccessCount: string;
21
+ tableColumnHeaderTitle: string;
22
+ tableDescription: string;
23
+ tableSearchPlaceholder: string;
24
+ tableTitle: string;
25
+ userRole: USER_ROLE;
26
+ }
27
+ export declare const PushCampaignPage: FC<Props>;
28
+ export {};