placementt-core 1.20.196 → 11.0.533
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.
- package/.eslintrc.js +40 -40
- package/.gitattributes +2 -2
- package/lib/config.d.ts +0 -1
- package/lib/constants.d.ts +5 -2
- package/lib/constants.js +130 -136
- package/lib/constants.js.map +1 -1
- package/lib/features/analytics/useAnalytics.d.ts +0 -1
- package/lib/features/analytics/useAnalytics.js +3 -4
- package/lib/features/analytics/useAnalytics.js.map +1 -1
- package/lib/features/config.d.ts +133 -133
- package/lib/features/config.js +35 -35
- package/lib/features/contacts/contacts.d.ts +75 -75
- package/lib/features/contacts/contacts.js +105 -105
- package/lib/features/contacts/contactsSlice.d.ts +5 -5
- package/lib/features/contacts/useContacts.js +1 -2
- package/lib/features/contacts/useContacts.js.map +1 -1
- package/lib/features/downtime/useDowntime.d.ts +11 -11
- package/lib/features/downtime/useDowntime.js +22 -22
- package/lib/features/dropdown/useDropdown.d.ts +2 -3
- package/lib/features/dropdown/useDropdown.js +1 -2
- package/lib/features/dropdown/useDropdown.js.map +1 -1
- package/lib/features/global/downtime/useDowntime.d.ts +0 -1
- package/lib/features/global/downtime/useDowntime.js +3 -2
- package/lib/features/global/downtime/useDowntime.js.map +1 -1
- package/lib/features/global/users/useUserFunctions.d.ts +0 -1
- package/lib/features/global/users/useUserFunctions.js +6 -7
- package/lib/features/global/users/useUserFunctions.js.map +1 -1
- package/lib/features/placements/studentPlacements/activePlacement.d.ts +1 -1
- package/lib/features/placements/studentPlacements/activePlacement.js +1 -1
- package/lib/features/placements/studentPlacements/activePlacement.js.map +1 -1
- package/lib/features/placements/studentPlacements/completedStudentPlacementsSlice.d.ts +4 -5
- package/lib/features/placements/studentPlacements/completedStudentPlacementsSlice.js +1 -4
- package/lib/features/placements/studentPlacements/completedStudentPlacementsSlice.js.map +1 -1
- package/lib/features/placements/studentPlacements/studentPlacementsSlice.d.ts +63 -63
- package/lib/features/placements/studentPlacements/studentPlacementsSlice.js +81 -81
- package/lib/features/placements/studentPlacements/upcomingStudentPlacementsSlice.d.ts +4 -4
- package/lib/features/placements/studentPlacements/upcomingStudentPlacementsSlice.js +1 -1
- package/lib/features/placements/studentPlacements/upcomingStudentPlacementsSlice.js.map +1 -1
- package/lib/features/placements/studentPlacements/useStudentPlacements.d.ts +0 -1
- package/lib/features/placements/studentPlacements/useStudentPlacements.js +1 -2
- package/lib/features/placements/studentPlacements/useStudentPlacements.js.map +1 -1
- package/lib/features/providerPlacements/providerPlacementsSlice.d.ts +19 -19
- package/lib/features/providerPlacements/providerPlacementsSlice.js +24 -24
- package/lib/features/referrals/useReferrals.d.ts +0 -1
- package/lib/features/referrals/useReferrals.js +1 -2
- package/lib/features/referrals/useReferrals.js.map +1 -1
- package/lib/features/studentPlacements/studentPlacementsSlice.d.ts +62 -62
- package/lib/features/studentPlacements/studentPlacementsSlice.js +87 -87
- package/lib/features/studentPlacements/useStudentPlacements.d.ts +6 -6
- package/lib/features/studentPlacements/useStudentPlacements.js +18 -18
- package/lib/features/updates/useUpdates.js +1 -2
- package/lib/features/updates/useUpdates.js.map +1 -1
- package/lib/features/userSlice.d.ts +26 -26
- package/lib/features/userSlice.js +23 -23
- package/lib/features/users/useUserFunctions.d.ts +25 -25
- package/lib/features/users/useUserFunctions.js +124 -124
- package/lib/features/users/userSlice.d.ts +46 -46
- package/lib/features/users/userSlice.js +48 -48
- package/lib/firebase/firebase.d.ts +1 -1
- package/lib/firebase/firebase.js +9 -4
- package/lib/firebase/firebase.js.map +1 -1
- package/lib/firebase/firebaseConfig.js +3 -0
- package/lib/firebase/firebaseConfig.js.map +1 -1
- package/lib/firebase/firebaseQuery.js +3 -0
- package/lib/firebase/firebaseQuery.js.map +1 -1
- package/lib/firebase/persistence.js +2 -2
- package/lib/firebase/persistence.js.map +1 -1
- package/lib/firebase/readDatabase.d.ts +9 -6
- package/lib/firebase/readDatabase.js +16 -6
- package/lib/firebase/readDatabase.js.map +1 -1
- package/lib/firebase/util.d.ts +3 -4
- package/lib/firebase/util.js +49 -4
- package/lib/firebase/util.js.map +1 -1
- package/lib/firebase/writeDatabase.d.ts +3 -3
- package/lib/firebase/writeDatabase.js +7 -1
- package/lib/firebase/writeDatabase.js.map +1 -1
- package/lib/hooks.d.ts +384 -23
- package/lib/hooks.js +1342 -223
- package/lib/hooks.js.map +1 -1
- package/lib/images/GatsbyBenchmarks.d.ts +0 -1
- package/lib/images/GatsbyBenchmarks.js +1 -1
- package/lib/images/GatsbyBenchmarks.js.map +1 -1
- package/lib/reduxHooks.d.ts +11 -20
- package/lib/reduxHooks.js +28 -18
- package/lib/reduxHooks.js.map +1 -1
- package/lib/tasksAndTips.d.ts +25 -5
- package/lib/tasksAndTips.js +346 -48
- package/lib/tasksAndTips.js.map +1 -1
- package/lib/typeDefinitions.d.ts +478 -53
- package/lib/util.d.ts +1 -0
- package/lib/util.js +78 -6
- package/lib/util.js.map +1 -1
- package/package.json +52 -49
- package/src/DatabaseDefinitions.ts +18 -18
- package/src/apiCalls.ts +128 -128
- package/src/config.ts +50 -50
- package/src/constants.ts +708 -707
- package/src/databaseTypes.ts +42 -42
- package/src/features/analytics/useAnalytics.tsx +55 -55
- package/src/features/contacts/contactsSlice.ts +147 -147
- package/src/features/contacts/useContacts.tsx +73 -73
- package/src/features/dropdown/useDropdown.tsx +52 -52
- package/src/features/global/downtime/useDowntime.tsx +19 -18
- package/src/features/global/users/useUserFunctions.tsx +132 -132
- package/src/features/jobs/jobsSlice.ts +65 -65
- package/src/features/placements/studentPlacements/activePlacement.ts +63 -63
- package/src/features/placements/studentPlacements/completedStudentPlacementsSlice.ts +94 -97
- package/src/features/placements/studentPlacements/upcomingStudentPlacementsSlice.ts +108 -108
- package/src/features/placements/studentPlacements/useStudentPlacements.tsx +33 -33
- package/src/features/placements/types.ts +10 -10
- package/src/features/referrals/useReferrals.tsx +56 -56
- package/src/features/updates/useUpdates.tsx +36 -36
- package/src/firebase/firebase.tsx +142 -138
- package/src/firebase/firebaseConfig.tsx +45 -42
- package/src/firebase/firebaseQuery.tsx +143 -140
- package/src/firebase/persistence.ts +84 -84
- package/src/firebase/readDatabase.tsx +208 -197
- package/src/firebase/util.tsx +352 -308
- package/src/firebase/writeDatabase.tsx +75 -68
- package/src/hooks.tsx +3395 -1943
- package/src/images/GatsbyBenchmarks.tsx +711 -711
- package/src/images/LogFuturePlacement.jsx +64 -64
- package/src/images/LogPreviousPlacement.jsx +228 -228
- package/src/images/gatsby_benchmarks.svg +466 -466
- package/src/images/log_future_placement.svg +114 -114
- package/src/images/log_previous_placement.svg +199 -199
- package/src/index.ts +34 -34
- package/src/readDatabase.tsx +3 -3
- package/src/reduxHooks.ts +183 -170
- package/src/tasksAndTips.ts +744 -410
- package/src/tutorialTips.ts +58 -58
- package/src/typeDefinitions.ts +899 -503
- package/src/util.ts +132 -47
- package/tsconfig.dev.json +5 -5
- package/tsconfig.json +21 -21
package/src/tasksAndTips.ts
CHANGED
|
@@ -1,410 +1,744 @@
|
|
|
1
|
-
import {arrayUnion, where} from "firebase/firestore";
|
|
2
|
-
import FirebaseQuery from "./firebase/firebaseQuery";
|
|
3
|
-
import {CohortData, InstituteData, ProviderData, UserData} from "./typeDefinitions";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
callback:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
const
|
|
276
|
-
if (
|
|
277
|
-
return {
|
|
278
|
-
dismissible: false,
|
|
279
|
-
severity: "
|
|
280
|
-
title: `${
|
|
281
|
-
message: `Your cohort '${cohort.name}' has
|
|
282
|
-
link: `/institutes/cohorts/${cohort.id}/
|
|
283
|
-
buttonTitle: "
|
|
284
|
-
} as TaskQueryReturnObject;
|
|
285
|
-
}
|
|
286
|
-
return;
|
|
287
|
-
}));
|
|
288
|
-
return items.filter((v) => v);
|
|
289
|
-
},
|
|
290
|
-
},
|
|
291
|
-
|
|
292
|
-
callback: async (user, _, cohorts) => {
|
|
293
|
-
if (!
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
return;
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
};
|
|
1
|
+
import {arrayUnion, orderBy, where} from "firebase/firestore";
|
|
2
|
+
import FirebaseQuery from "./firebase/firebaseQuery";
|
|
3
|
+
import {CohortData, InstituteData, ProviderData, StudentPlacementData, UserData} from "./typeDefinitions";
|
|
4
|
+
import {getAccess} from "./firebase/util";
|
|
5
|
+
import { convertDate } from "./firebase/util";
|
|
6
|
+
|
|
7
|
+
const firebaseQuery = new FirebaseQuery;
|
|
8
|
+
|
|
9
|
+
type InstituteTipNames = "createCohort"|"uploadStaff"|"assignStaffRoles"|"uploadPlacements"|"allowExternalPlacementUpload"|"uploadStaffGuidance"|"uploadStudentGuidance"
|
|
10
|
+
type ProviderTipNames = string
|
|
11
|
+
type StudentTipNames = string
|
|
12
|
+
|
|
13
|
+
export type InstituteTaskNames = "missingParentEmail"|"verifyInsurance"|"verifyRiskAssessment"|"verifyDbsCheck"|"inactiveStudents"|"uploadStudents"|"inactiveStaff"|"requiredStage"|"approveExternalPlacement"|"overdueStage"
|
|
14
|
+
export type StudentTaskNames = "completeOnboarding"
|
|
15
|
+
export type ProviderTaskNames = "applicationRequireReview"|"requestedVisiblePlacementListings"|"requestedVisibleAddresses"|"completeStudentDocs"|"reviewOnboarding"|"completeListing"|"completeAddress"|"registrationRequests"|"placementStarting"|"completeFeedback"|"setUpFeedback"
|
|
16
|
+
|
|
17
|
+
// IF UPDATING LOGIC WITHIN THIS FILE, PLACEMENTT-BACKEND LOGIC MUST ALSO BE CHANGED ACCORDINGLY
|
|
18
|
+
|
|
19
|
+
export type TaskQueryReturnObject = {
|
|
20
|
+
itemName?: InstituteTaskNames|InstituteTipNames|StudentTipNames|ProviderTipNames,
|
|
21
|
+
title?: string,
|
|
22
|
+
message?: string,
|
|
23
|
+
link?: string,
|
|
24
|
+
buttonTitle?: string,
|
|
25
|
+
dismissible?: boolean,
|
|
26
|
+
severity?: "error"|"warning"|"success"|"primary"|"info"
|
|
27
|
+
}|undefined;
|
|
28
|
+
/*
|
|
29
|
+
type TasksObject = {
|
|
30
|
+
[key in TaskNames]: {
|
|
31
|
+
callback: (user: UserData) => Promise<TaskQueryReturnObject>,
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
*/
|
|
35
|
+
type InstituteTipsObject = {
|
|
36
|
+
[key in InstituteTipNames]: {
|
|
37
|
+
callback: (user: UserData, organisation?:InstituteData|ProviderData) => Promise<TaskQueryReturnObject|TaskQueryReturnObject[]>,
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
type ProviderTipsObject = {
|
|
41
|
+
[key in ProviderTipNames]: {
|
|
42
|
+
callback: (user: UserData, organisation?:InstituteData|ProviderData) => Promise<TaskQueryReturnObject|TaskQueryReturnObject[]>,
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
type StudentTipsObject = {
|
|
46
|
+
[key in StudentTipNames]: {
|
|
47
|
+
callback: (user: UserData, organisation?:InstituteData|ProviderData) => Promise<TaskQueryReturnObject|TaskQueryReturnObject[]>,
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export type InstituteTaskObject = {
|
|
52
|
+
[key in InstituteTaskNames]: {
|
|
53
|
+
callback: (user: UserData, organisation:InstituteData|ProviderData, cohort: CohortData|[string, CohortData][]) => Promise<TaskQueryReturnObject|TaskQueryReturnObject[]>,
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export type StudentTaskObject = {
|
|
58
|
+
[key in StudentTaskNames]: {
|
|
59
|
+
callback: (user: UserData) => Promise<TaskQueryReturnObject|TaskQueryReturnObject[]>,
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
export type ProviderTaskObject = {
|
|
63
|
+
[key in ProviderTaskNames]: {
|
|
64
|
+
callback: (user: UserData) => Promise<TaskQueryReturnObject|TaskQueryReturnObject[]>,
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
const providerTips:ProviderTipsObject = {}
|
|
68
|
+
const studentTips:StudentTipsObject = {}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
const instituteTips:InstituteTipsObject = {
|
|
72
|
+
createCohort: {
|
|
73
|
+
callback: async (user) => {
|
|
74
|
+
if (!getAccess(user, "createCohorts")) return;
|
|
75
|
+
const cohorts = await firebaseQuery.getCount("cohorts", [where("product", "==", user.product), where("oId", "==", user.oId)])
|
|
76
|
+
if (cohorts === 0) {
|
|
77
|
+
return {
|
|
78
|
+
title: "Create a cohort",
|
|
79
|
+
message: "Create a cohort to manage your students, process their placements and track their progress",
|
|
80
|
+
link: "/institutes/cohorts/new",
|
|
81
|
+
buttonTitle: "Create cohort",
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return;
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
uploadStaff: {
|
|
88
|
+
callback: async (user) => {
|
|
89
|
+
const returnObj: TaskQueryReturnObject = {
|
|
90
|
+
link: "",
|
|
91
|
+
dismissible: true,
|
|
92
|
+
};
|
|
93
|
+
if ((await firebaseQuery.getCount(["users"], [where("oId", "==", user.oId), where("userType", "==", "Staff")])) == 1) {
|
|
94
|
+
return {
|
|
95
|
+
...returnObj,
|
|
96
|
+
title: "Upload staff",
|
|
97
|
+
message: "Upload staff to help manage your students",
|
|
98
|
+
link: "/institutes/cohorts/staff/all",
|
|
99
|
+
buttonTitle: "Upload staff",
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return;
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
assignStaffRoles: {
|
|
106
|
+
callback: async () => {
|
|
107
|
+
return undefined;
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
uploadPlacements: {
|
|
111
|
+
callback: async (user) => {
|
|
112
|
+
const returnObj: TaskQueryReturnObject = {
|
|
113
|
+
link: "",
|
|
114
|
+
dismissible: true,
|
|
115
|
+
};
|
|
116
|
+
if (await firebaseQuery.getCount(["placementListings"], where(`savedBy.${user.oId}.exists`, "==", true)) === 0) {
|
|
117
|
+
return {
|
|
118
|
+
...returnObj,
|
|
119
|
+
title: "List placements",
|
|
120
|
+
message: "You can list placements to students, to give them places to contact. Check out the 'Placements' tab to list opportunitites.",
|
|
121
|
+
link: "/institutes/placements",
|
|
122
|
+
buttonTitle: "Add placements",
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return;
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
allowExternalPlacementUpload: {
|
|
129
|
+
callback: async (user, organisation) => {
|
|
130
|
+
if (user.product !== "institutes") return;
|
|
131
|
+
if ((organisation as InstituteData).externalProviderUploads) return;
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
dismissible: true,
|
|
135
|
+
title: "Allow external uploads",
|
|
136
|
+
message: "Get a link to share with businesses, allowing them to list their own opportunities to your students.",
|
|
137
|
+
link: "/institutes/placements",
|
|
138
|
+
buttonTitle: "View placements",
|
|
139
|
+
};
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
uploadStaffGuidance: {
|
|
143
|
+
callback: async (user, organisation) => {
|
|
144
|
+
if (user.product !== "institutes") return;
|
|
145
|
+
const returnObj: TaskQueryReturnObject = {
|
|
146
|
+
link: "",
|
|
147
|
+
dismissible: true,
|
|
148
|
+
};
|
|
149
|
+
const guidanceTips:TaskQueryReturnObject[] = [];
|
|
150
|
+
if (!Object.keys((organisation as InstituteData).staffGuidance || {}).length) {
|
|
151
|
+
guidanceTips.push({
|
|
152
|
+
...returnObj,
|
|
153
|
+
title: "Upload staff guidance",
|
|
154
|
+
message: "Upload guidance documents to support your staff in coordinating work experience.",
|
|
155
|
+
buttonTitle: "Staff guidance",
|
|
156
|
+
link: `/${user.product}/setup/guidance`,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
return guidanceTips;
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
uploadStudentGuidance: {
|
|
163
|
+
callback: async (user, organisation) => {
|
|
164
|
+
if (user.product !== "institutes") return;
|
|
165
|
+
const returnObj: TaskQueryReturnObject = {
|
|
166
|
+
link: "",
|
|
167
|
+
dismissible: true,
|
|
168
|
+
};
|
|
169
|
+
const guidanceTips:TaskQueryReturnObject[] = [];
|
|
170
|
+
if (!Object.keys((organisation as InstituteData).studentsGuidance || {}).length) {
|
|
171
|
+
guidanceTips.push({
|
|
172
|
+
...returnObj,
|
|
173
|
+
title: "Upload student guidance",
|
|
174
|
+
message: "Upload guidance documents to support your staff in preparing for their placements.",
|
|
175
|
+
buttonTitle: "Student guidance",
|
|
176
|
+
link: `/${user.product}/setup/guidance`,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
return guidanceTips;
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
// Accept a cohort to any task
|
|
184
|
+
|
|
185
|
+
const instituteTasks:InstituteTaskObject = {
|
|
186
|
+
requiredStage: {
|
|
187
|
+
callback: async (user, _, cohorts) => {
|
|
188
|
+
if (!getAccess(user, "signOffPlacements")) return;
|
|
189
|
+
|
|
190
|
+
if (!Array.isArray(cohorts)) {
|
|
191
|
+
const placementCount = (await firebaseQuery.getCount(["placements"], [where("oId", "==", user.oId), where("cohort", "==", cohorts.id), where("reqUserType", "==", user.userType)]));
|
|
192
|
+
if (placementCount > 0) {
|
|
193
|
+
return {
|
|
194
|
+
dismissible: false,
|
|
195
|
+
severity: "primary",
|
|
196
|
+
title: `${placementCount} placements require your attention.`,
|
|
197
|
+
message: `Your cohort '${cohorts.name}' has placements for your to review. Click to view these placements.`,
|
|
198
|
+
link: `/institutes/cohorts/${cohorts.id}/placements?id=upcoming&reqUserType=${user.userType}`,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const items = await Promise.all(cohorts.map(async ([id, cohort]) => {
|
|
205
|
+
const placementCount = (await firebaseQuery.getCount(["placements"], [where("oId", "==", user.oId), where("cohort", "==", id), where("reqUserType", "==", user.userType)]));
|
|
206
|
+
if (placementCount > 0) {
|
|
207
|
+
return {
|
|
208
|
+
dismissible: false,
|
|
209
|
+
severity: "primary",
|
|
210
|
+
title: `${placementCount} placements in '${cohort.name}' require your attention.`,
|
|
211
|
+
message: `Your cohort '${cohort.name}' has placements for your to review. Click to view these placements.`,
|
|
212
|
+
link: `/institutes/cohorts/${id}/placements?id=upcoming&reqUserType=${user.userType}`,
|
|
213
|
+
buttonTitle: "Review placements",
|
|
214
|
+
} as TaskQueryReturnObject;
|
|
215
|
+
}
|
|
216
|
+
return;
|
|
217
|
+
}));
|
|
218
|
+
return items.filter((v) => v);
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
verifyInsurance: {
|
|
222
|
+
callback: async (user, _, cohorts) => {
|
|
223
|
+
if (!getAccess(user, "verifyInsurance")) return;
|
|
224
|
+
|
|
225
|
+
if (!Array.isArray(cohorts)) {
|
|
226
|
+
const placementCount = (await firebaseQuery.getCount(["placements"], [where("oId", "==", user.oId), where("cohort", "==", cohorts.id), where("insurance", "==", "awaitingReview")]));
|
|
227
|
+
if (placementCount > 0) {
|
|
228
|
+
return {
|
|
229
|
+
dismissible: false,
|
|
230
|
+
severity: "primary",
|
|
231
|
+
title: `${placementCount} placements have insurance that require review.`,
|
|
232
|
+
message: `Your cohort '${cohorts.name}' has employer's liability insurance documents that require review`,
|
|
233
|
+
link: `/institutes/cohorts/${cohorts.id}/placements?id=upcoming&insurance=awaitingReview`,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const items = await Promise.all(cohorts.map(async ([id, cohort]) => {
|
|
240
|
+
const placementCount = (await firebaseQuery.getCount(["placements"], [where("oId", "==", user.oId), where("cohort", "==", id), where("insurance", "==", "awaitingReview")]));
|
|
241
|
+
if (placementCount > 0) {
|
|
242
|
+
return {
|
|
243
|
+
dismissible: false,
|
|
244
|
+
severity: "primary",
|
|
245
|
+
title: `${placementCount} placements in '${cohort.name}' have insurance that require review.`,
|
|
246
|
+
message: `Your cohort '${cohort.name}' has employer's liability insurance documents that require review`,
|
|
247
|
+
link: `/institutes/cohorts/${cohort.id}/placements?id=upcoming&insurance=awaitingReview`,
|
|
248
|
+
buttonTitle: "Review placements",
|
|
249
|
+
} as TaskQueryReturnObject;
|
|
250
|
+
}
|
|
251
|
+
return;
|
|
252
|
+
}));
|
|
253
|
+
return items.filter((v) => v);
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
verifyDbsCheck: {
|
|
257
|
+
callback: async (user, _, cohorts) => {
|
|
258
|
+
if (!getAccess(user, "verifyDbsChecks")) return;
|
|
259
|
+
|
|
260
|
+
if (!Array.isArray(cohorts)) {
|
|
261
|
+
const placementCount = (await firebaseQuery.getCount(["placements"], [where("oId", "==", user.oId), where("cohort", "==", cohorts.id), where("dbsCheck", "==", "awaitingReview")]));
|
|
262
|
+
if (placementCount > 0) {
|
|
263
|
+
return {
|
|
264
|
+
dismissible: false,
|
|
265
|
+
severity: "primary",
|
|
266
|
+
title: `${placementCount} placements have DBS checks that require review.`,
|
|
267
|
+
message: `Your cohort '${cohorts.name}' has DBS checks that require review`,
|
|
268
|
+
link: `/institutes/cohorts/${cohorts.id}/placements?id=upcoming&dbsCheck=awaitingReview`,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const items = await Promise.all(cohorts.map(async ([id, cohort]) => {
|
|
275
|
+
const placementCount = (await firebaseQuery.getCount(["placements"], [where("oId", "==", user.oId), where("cohort", "==", id), where("dbsCheck", "==", "awaitingReview")]));
|
|
276
|
+
if (placementCount > 0) {
|
|
277
|
+
return {
|
|
278
|
+
dismissible: false,
|
|
279
|
+
severity: "primary",
|
|
280
|
+
title: `${placementCount} placements in '${cohort.name}' have DBS checks that require review.`,
|
|
281
|
+
message: `Your cohort '${cohort.name}' has DBS checks that require review`,
|
|
282
|
+
link: `/institutes/cohorts/${cohort.id}/placements?id=upcoming&dbsCheck=awaitingReview`,
|
|
283
|
+
buttonTitle: "Review placements",
|
|
284
|
+
} as TaskQueryReturnObject;
|
|
285
|
+
}
|
|
286
|
+
return;
|
|
287
|
+
}));
|
|
288
|
+
return items.filter((v) => v);
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
verifyRiskAssessment: {
|
|
292
|
+
callback: async (user, _, cohorts) => {
|
|
293
|
+
if (!getAccess(user, "verifyRiskAssessments")) return;
|
|
294
|
+
|
|
295
|
+
if (!Array.isArray(cohorts)) {
|
|
296
|
+
const placementCount = (await firebaseQuery.getCount(["placements"], [where("oId", "==", user.oId), where("cohort", "==", cohorts.id), where("riskAssessment", "==", "awaitingReview")]));
|
|
297
|
+
if (placementCount > 0) {
|
|
298
|
+
return {
|
|
299
|
+
dismissible: false,
|
|
300
|
+
severity: "primary",
|
|
301
|
+
title: `${placementCount} placements have risk assessments that require review.`,
|
|
302
|
+
message: `Your cohort '${cohorts.name}' has risk assessents that require review`,
|
|
303
|
+
link: `/institutes/cohorts/${cohorts.id}/placements?id=upcoming&riskAssessment=awaitingReview`,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const items = await Promise.all(cohorts.map(async ([id, cohort]) => {
|
|
310
|
+
const placementCount = (await firebaseQuery.getCount(["placements"], [where("oId", "==", user.oId), where("cohort", "==", id), where("riskAssessment", "==", "awaitingReview")]));
|
|
311
|
+
if (placementCount > 0) {
|
|
312
|
+
return {
|
|
313
|
+
dismissible: false,
|
|
314
|
+
severity: "primary",
|
|
315
|
+
title: `${placementCount} placements in '${cohort.name}' have risk assessments that require review.`,
|
|
316
|
+
message: `Your cohort '${cohort.name}' has risk assessments that require review`,
|
|
317
|
+
link: `/institutes/cohorts/${cohort.id}/placements?id=upcoming&riskAssessment=awaitingReview`,
|
|
318
|
+
buttonTitle: "Review placements",
|
|
319
|
+
} as TaskQueryReturnObject;
|
|
320
|
+
}
|
|
321
|
+
return;
|
|
322
|
+
}));
|
|
323
|
+
return items.filter((v) => v);
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
missingParentEmail: {
|
|
327
|
+
callback: async (user, _, cohorts) => {
|
|
328
|
+
if (!getAccess(user, "editStudents")) return;
|
|
329
|
+
if (!Array.isArray(cohorts)) {
|
|
330
|
+
const requiresParents = Boolean(cohorts.workflow.find((node) => node.userType === "Parent"))
|
|
331
|
+
if (!requiresParents) return;
|
|
332
|
+
const constraints = [where("oId", "==", user.oId), where("cohort", "==", cohorts.id), where("details.parentEmail", "==", "null")];
|
|
333
|
+
|
|
334
|
+
if (user.groupData?.viewStudents === "filter") {
|
|
335
|
+
constraints.push(where(`details.${user.groupData?.filterUsersBy || ""}`, "==", user.groupData?.filterUsersValue || ""));
|
|
336
|
+
}
|
|
337
|
+
const studentCount = (await firebaseQuery.getCount(["users"], constraints));
|
|
338
|
+
if (studentCount > 0) {
|
|
339
|
+
return {
|
|
340
|
+
dismissible: false,
|
|
341
|
+
severity: "info",
|
|
342
|
+
title: `${studentCount} students do not have a parent email.`,
|
|
343
|
+
message: `Your cohort '${cohorts.name}' has students without a parent email. To allow proper processing of their placements, add these emails.`,
|
|
344
|
+
link: `/institutes/cohorts/${cohorts.id}/students?parentEmail=false`,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
const items = await Promise.all(cohorts.map(async ([id, cohort]) => {
|
|
350
|
+
const requiresParents = Boolean(cohort.workflow.find((node) => node.userType === "Parent"))
|
|
351
|
+
if (!requiresParents) return;
|
|
352
|
+
const constraints = [where("oId", "==", user.oId), where("cohort", "==", id), where("details.parentEmail", "==", "null")];
|
|
353
|
+
|
|
354
|
+
if (user.groupData?.viewStudents === "filter") {
|
|
355
|
+
constraints.push(where(`details.${user.groupData?.filterUsersBy || ""}`, "==", user.groupData?.filterUsersValue || ""));
|
|
356
|
+
}
|
|
357
|
+
const studentCount = (await firebaseQuery.getCount(["users"], constraints));
|
|
358
|
+
if (studentCount > 0) {
|
|
359
|
+
return {
|
|
360
|
+
dismissible: false,
|
|
361
|
+
severity: "info",
|
|
362
|
+
title: `${studentCount} students in '${cohort.name}' do not have a parent email.`,
|
|
363
|
+
message: `Your cohort '${cohort.name}' has students without a parent email. To allow proper processing of their placements, add these emails.`,
|
|
364
|
+
link: `/institutes/cohorts/${cohort.id}/students?parentEmail=false`,
|
|
365
|
+
buttonTitle: "View students",
|
|
366
|
+
} as TaskQueryReturnObject;
|
|
367
|
+
}
|
|
368
|
+
return;
|
|
369
|
+
}));
|
|
370
|
+
return items.filter((v) => v);
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
inactiveStudents: {
|
|
374
|
+
callback: async (user, _, cohorts) => {
|
|
375
|
+
if (!getAccess(user, "activateStudents")) return;
|
|
376
|
+
if (!Array.isArray(cohorts)) {
|
|
377
|
+
const constraints = [where("oId", "==", user.oId), where("cohort", "==", cohorts.id), where("status", "==", "inactive")];
|
|
378
|
+
|
|
379
|
+
if (user.groupData?.viewStudents === "filter") {
|
|
380
|
+
constraints.push(where(`details.${user.groupData?.filterUsersBy || ""}`, "==", user.groupData?.filterUsersValue || ""));
|
|
381
|
+
}
|
|
382
|
+
const studentCount = (await firebaseQuery.getCount(["users"], constraints));
|
|
383
|
+
if (studentCount > 0) {
|
|
384
|
+
return {
|
|
385
|
+
dismissible: false,
|
|
386
|
+
severity: "info",
|
|
387
|
+
title: `${studentCount} students in are inactive.`,
|
|
388
|
+
message: `Your cohort '${cohorts.name}' has inactive students. Activate them to enable them to use the platform.`,
|
|
389
|
+
link: `/institutes/cohorts/${cohorts.id}/students?status=inactive`,
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const items = await Promise.all(cohorts.map(async ([id, cohort]) => {
|
|
396
|
+
const constraints = [where("oId", "==", user.oId), where("cohort", "==", id), where("status", "==", "inactive")];
|
|
397
|
+
|
|
398
|
+
if (user.groupData?.viewStudents === "filter") {
|
|
399
|
+
constraints.push(where(`details.${user.groupData?.filterUsersBy || ""}`, "==", user.groupData?.filterUsersValue || ""));
|
|
400
|
+
}
|
|
401
|
+
const studentCount = (await firebaseQuery.getCount(["users"], constraints));
|
|
402
|
+
if (studentCount > 0) {
|
|
403
|
+
return {
|
|
404
|
+
dismissible: false,
|
|
405
|
+
severity: "info",
|
|
406
|
+
title: `${studentCount} students in '${cohort.name}' are inactive.`,
|
|
407
|
+
message: `Your cohort '${cohort.name}' has inactive students. Activate them to enable them to use the platform.`,
|
|
408
|
+
link: `/institutes/cohorts/${cohort.id}/students?status=inactive`,
|
|
409
|
+
buttonTitle: "Review placements",
|
|
410
|
+
} as TaskQueryReturnObject;
|
|
411
|
+
}
|
|
412
|
+
return;
|
|
413
|
+
}));
|
|
414
|
+
return items.filter((v) => v);
|
|
415
|
+
},
|
|
416
|
+
},
|
|
417
|
+
uploadStudents: {
|
|
418
|
+
callback: async (user, _, cohorts) => {
|
|
419
|
+
if (!Array.isArray(cohorts)) return;
|
|
420
|
+
if (!getAccess(user, "addStudents")) return;
|
|
421
|
+
if (user.product !== "institutes") return;
|
|
422
|
+
const returnObj: TaskQueryReturnObject = {
|
|
423
|
+
link: "",
|
|
424
|
+
dismissible: true,
|
|
425
|
+
severity: "warning",
|
|
426
|
+
};
|
|
427
|
+
const items = await Promise.all(cohorts.map(async ([id, cohort]) => {
|
|
428
|
+
const studentCount = (await firebaseQuery.getCount(["users"], [where("oId", "==", user.oId), where("userType", "==", "Students"), where("cohort", "==", id)]));
|
|
429
|
+
if (studentCount === 0) {
|
|
430
|
+
return {
|
|
431
|
+
...returnObj,
|
|
432
|
+
title: "Upload students",
|
|
433
|
+
message: `Your cohort '${cohort.name}' has no students. Add them in the cohort 'Students' tab`,
|
|
434
|
+
link: `/institutes/cohorts/${id}/students`,
|
|
435
|
+
buttonTitle: "Upload students",
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
return;
|
|
439
|
+
}));
|
|
440
|
+
return items.filter((v) => v);
|
|
441
|
+
},
|
|
442
|
+
},
|
|
443
|
+
inactiveStaff: {
|
|
444
|
+
callback: async (user, _, cohorts) => {
|
|
445
|
+
if (!getAccess(user, "addStaff")) return;
|
|
446
|
+
|
|
447
|
+
if (!Array.isArray(cohorts) || user.product === "students") return;
|
|
448
|
+
const returnObj: TaskQueryReturnObject = {
|
|
449
|
+
link: `/${user.product}/cohorts/staff/all?status=inactive`,
|
|
450
|
+
dismissible: false,
|
|
451
|
+
severity: "info",
|
|
452
|
+
};
|
|
453
|
+
const inactiveStaff = await firebaseQuery.getCount(["users"], [where("oId", "==", user.oId), where("userType", "==", "Staff"), where("status", "==", "inactive")]);
|
|
454
|
+
if (inactiveStaff > 0) {
|
|
455
|
+
return {
|
|
456
|
+
...returnObj,
|
|
457
|
+
title: "Inactive staff",
|
|
458
|
+
message: `You have ${inactiveStaff} inactive staff members. You can activate them in the 'Staff' cohorts tab.`,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
return;
|
|
462
|
+
},
|
|
463
|
+
},
|
|
464
|
+
overdueStage: {
|
|
465
|
+
callback: async (user, _, cohort) => {
|
|
466
|
+
console.log(user, cohort);
|
|
467
|
+
return undefined;
|
|
468
|
+
},
|
|
469
|
+
},
|
|
470
|
+
approveExternalPlacement: {
|
|
471
|
+
callback: async (user, _, cohort) => {
|
|
472
|
+
if (!getAccess(user, "verifyListings")) return;
|
|
473
|
+
if (!Array.isArray(cohort)) return;
|
|
474
|
+
const externalCount = await firebaseQuery.getCount(["placementListings"],
|
|
475
|
+
[where(`savedBy.${user.oId}.exists`, "==", true), where(`savedBy.${user.oId}.status`, "==", "uploaded"), where("mapConsent", "==", "institute")]);
|
|
476
|
+
console.log("EXT", externalCount);
|
|
477
|
+
if (externalCount > 0) {
|
|
478
|
+
return {
|
|
479
|
+
dismissible: false,
|
|
480
|
+
severity: "warning",
|
|
481
|
+
title: `${externalCount} external placements require approval`,
|
|
482
|
+
message: "Review and approve these placements to add them to your institute placement map",
|
|
483
|
+
link: "/institutes/placements",
|
|
484
|
+
buttonTitle: "View placements",
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
return;
|
|
488
|
+
},
|
|
489
|
+
},
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
const studentTasks:StudentTaskObject = {
|
|
493
|
+
completeOnboarding: {
|
|
494
|
+
callback: async (user) => {
|
|
495
|
+
const placementsWithoutOnboarding = await firebaseQuery.getDocsWhere("placements", [where("uid", "==", user.id), where("onboarding.deadline", "<=", convertDate(new Date(), "dbstring")), where("onboarding.completed.submitted", "==", false)]) as {[key: string]: StudentPlacementData};
|
|
496
|
+
console.log("placementsWithoutONboarding", placementsWithoutOnboarding);
|
|
497
|
+
if (Object.keys(placementsWithoutOnboarding).length === 0) return;
|
|
498
|
+
const items = Object.entries(placementsWithoutOnboarding).map(([k, placement]) => ({
|
|
499
|
+
dismissible: false,
|
|
500
|
+
severity: "primary",
|
|
501
|
+
title: `Complete required onboarding documents for ${placement.name}`,
|
|
502
|
+
message: `${placement.name} has requested you to complete some onboarding documents.`,
|
|
503
|
+
link: `/${user.product}/placements/${k}`,
|
|
504
|
+
buttonTitle: "View onboarding",
|
|
505
|
+
} as TaskQueryReturnObject))
|
|
506
|
+
return items;
|
|
507
|
+
},
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
const providerTasks:ProviderTaskObject = {
|
|
512
|
+
requestedVisibleAddresses: {
|
|
513
|
+
callback: async (user) => {
|
|
514
|
+
const accessRequests = await firebaseQuery.getCount("users", [where("oId", "==", user.oId), where("product", "==", "providers"), orderBy("requestedVisibleAddresses")]);
|
|
515
|
+
if (accessRequests === 0) return;
|
|
516
|
+
if (accessRequests === 1) {
|
|
517
|
+
const userRequestingAccess = Object.entries(await firebaseQuery.getDocsWhere("users", [where("oId", "==", user.oId), where("product", "==", "providers"), orderBy("requestedVisibleAddresses")]) || {})[0] as [string, UserData];
|
|
518
|
+
return {
|
|
519
|
+
dismissible: false,
|
|
520
|
+
severity: "primary",
|
|
521
|
+
title: `${userRequestingAccess[1].details.forename} ${userRequestingAccess[1].details.surname} has requested access to view addresses.`,
|
|
522
|
+
message: `Click to review the addresses and grant access to the user.`,
|
|
523
|
+
link: `/${user.product}/users/${userRequestingAccess[0]}`,
|
|
524
|
+
buttonTitle: "View request",
|
|
525
|
+
} as TaskQueryReturnObject;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
return {
|
|
529
|
+
dismissible: false,
|
|
530
|
+
severity: "warning",
|
|
531
|
+
title: `Multiple users have requested access to view addresses.`,
|
|
532
|
+
message: `Click to review the addresses and grant access to the user.`,
|
|
533
|
+
link: `/${user.product}/organisation/staff/all`,
|
|
534
|
+
buttonTitle: "View request",
|
|
535
|
+
} as TaskQueryReturnObject;
|
|
536
|
+
},
|
|
537
|
+
},
|
|
538
|
+
requestedVisiblePlacementListings: {
|
|
539
|
+
callback: async (user) => {
|
|
540
|
+
const accessRequests = await firebaseQuery.getCount("users", [where("oId", "==", user.oId), where("product", "==", "providers"), orderBy("requestedVisibleListings")]);
|
|
541
|
+
if (accessRequests === 0) return;
|
|
542
|
+
if (accessRequests === 1) {
|
|
543
|
+
const userRequestingAccess = Object.entries(await firebaseQuery.getDocsWhere("users", [where("oId", "==", user.oId), where("product", "==", "providers"), orderBy("requestedVisibleListings")]) || {})[0] as [string, UserData];
|
|
544
|
+
return {
|
|
545
|
+
dismissible: false,
|
|
546
|
+
severity: "primary",
|
|
547
|
+
title: `${userRequestingAccess[1].details.forename} ${userRequestingAccess[1].details.surname} has requested access to view placement listings.`,
|
|
548
|
+
message: `Click to review the placement listings and grant access to the user.`,
|
|
549
|
+
link: `/${user.product}/users/${userRequestingAccess[0]}`,
|
|
550
|
+
buttonTitle: "View request",
|
|
551
|
+
} as TaskQueryReturnObject;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
return {
|
|
555
|
+
dismissible: false,
|
|
556
|
+
severity: "warning",
|
|
557
|
+
title: `Multiple users have requested access to view placement listings.`,
|
|
558
|
+
message: `Click to review the placement listings and grant access to the user.`,
|
|
559
|
+
link: `/${user.product}/organisation/staff/all`,
|
|
560
|
+
buttonTitle: "View request",
|
|
561
|
+
} as TaskQueryReturnObject;
|
|
562
|
+
},
|
|
563
|
+
},
|
|
564
|
+
applicationRequireReview: {
|
|
565
|
+
callback: async (user) => {
|
|
566
|
+
const applicationCount = await firebaseQuery.getCount("applications", [where("providerId", "==", user.oId), where("reqUserType", "==", "Staff"), where("status", "==", "submitted")]);
|
|
567
|
+
if (applicationCount === 0) return;
|
|
568
|
+
|
|
569
|
+
return {
|
|
570
|
+
dismissible: false,
|
|
571
|
+
severity: "primary",
|
|
572
|
+
title: `${applicationCount} applications require your review.`,
|
|
573
|
+
message: `Click to view ${applicationCount} that require your attention.`,
|
|
574
|
+
link: `/${user.product}/placementListings/applicants`,
|
|
575
|
+
buttonTitle: "View applications",
|
|
576
|
+
} as TaskQueryReturnObject;
|
|
577
|
+
},
|
|
578
|
+
},
|
|
579
|
+
completeStudentDocs: {
|
|
580
|
+
callback: async (user) => {
|
|
581
|
+
return {} as TaskQueryReturnObject;
|
|
582
|
+
},
|
|
583
|
+
},
|
|
584
|
+
reviewOnboarding: {
|
|
585
|
+
callback: async (user) => {
|
|
586
|
+
return {} as TaskQueryReturnObject;
|
|
587
|
+
},
|
|
588
|
+
},
|
|
589
|
+
completeListing: {
|
|
590
|
+
callback: async (user) => {
|
|
591
|
+
return {} as TaskQueryReturnObject;
|
|
592
|
+
},
|
|
593
|
+
},
|
|
594
|
+
completeAddress: {
|
|
595
|
+
callback: async (user) => {
|
|
596
|
+
return {} as TaskQueryReturnObject;
|
|
597
|
+
},
|
|
598
|
+
},
|
|
599
|
+
registrationRequests: {
|
|
600
|
+
callback: async (user) => {
|
|
601
|
+
return {} as TaskQueryReturnObject;
|
|
602
|
+
},
|
|
603
|
+
},
|
|
604
|
+
placementStarting: {
|
|
605
|
+
callback: async (user) => {
|
|
606
|
+
return {} as TaskQueryReturnObject;
|
|
607
|
+
},
|
|
608
|
+
},
|
|
609
|
+
completeFeedback: {
|
|
610
|
+
callback: async (user) => {
|
|
611
|
+
return {} as TaskQueryReturnObject;
|
|
612
|
+
},
|
|
613
|
+
},
|
|
614
|
+
setUpFeedback: {
|
|
615
|
+
callback: async (user) => {
|
|
616
|
+
return {} as TaskQueryReturnObject;
|
|
617
|
+
},
|
|
618
|
+
},
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
export const getTips = async (user: UserData, organisation: InstituteData|ProviderData):Promise<(TaskQueryReturnObject)[]> => {
|
|
622
|
+
const tipsObject = {
|
|
623
|
+
providers: providerTips,
|
|
624
|
+
institutes: instituteTips,
|
|
625
|
+
studentTips: studentTips,
|
|
626
|
+
}
|
|
627
|
+
const includedItems = Object.entries(tipsObject[user.product]).filter(([k]) => !user.dismissedTips?.includes(k));
|
|
628
|
+
|
|
629
|
+
const processedTips = await includedItems.reduce(async (acc, [itemName, item]) => {
|
|
630
|
+
const queryResult = await (item as {
|
|
631
|
+
callback: (user: UserData, organisation?:InstituteData|ProviderData) => Promise<TaskQueryReturnObject|TaskQueryReturnObject[]>,
|
|
632
|
+
}).callback(user, organisation);
|
|
633
|
+
if (!queryResult) return await acc;
|
|
634
|
+
|
|
635
|
+
const queryResultArray = Array.isArray(queryResult) ? queryResult : [queryResult];
|
|
636
|
+
const results = queryResultArray.map((r) => ({itemName: itemName as InstituteTipNames|ProviderTipNames|StudentTipNames|InstituteTaskNames|ProviderTaskNames|StudentTaskNames, ...r}));
|
|
637
|
+
|
|
638
|
+
(await acc).push(...results);
|
|
639
|
+
return await acc;
|
|
640
|
+
}, Promise.resolve<TaskQueryReturnObject[]>([]));
|
|
641
|
+
return processedTips;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
export const getTasks = async (user: UserData, organisation?: InstituteData|ProviderData, cohort?: CohortData):Promise<(TaskQueryReturnObject)[]> => {
|
|
645
|
+
// Cohort is either a specific one or all.
|
|
646
|
+
|
|
647
|
+
if (user.product === "institutes" && user.userType === "Staff" && organisation) {
|
|
648
|
+
return await getInstituteTasks(user, organisation, cohort);
|
|
649
|
+
}
|
|
650
|
+
if (user.product === "students" || user.userType === "Students") {
|
|
651
|
+
return await getStudentTasks(user, organisation, cohort);
|
|
652
|
+
}
|
|
653
|
+
if (user.product === "providers" && organisation) {
|
|
654
|
+
return await getProviderTasks(user, organisation);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
return [];
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
const getStudentTasks = async (user: UserData, organisation?: InstituteData|ProviderData, cohort?: CohortData):Promise<(TaskQueryReturnObject)[]> => {
|
|
661
|
+
const processedTasks = await Object.entries(studentTasks).reduce(async (acc, [itemName, item]) => {
|
|
662
|
+
|
|
663
|
+
const queryResult = await item.callback(user);
|
|
664
|
+
if (!queryResult) return await acc;
|
|
665
|
+
|
|
666
|
+
const queryResultArray = Array.isArray(queryResult) ? queryResult : [queryResult];
|
|
667
|
+
const results = queryResultArray.map((r) => ({itemName: itemName as StudentTaskNames, ...r}));
|
|
668
|
+
|
|
669
|
+
(await acc).push(...results);
|
|
670
|
+
return await acc;
|
|
671
|
+
}, Promise.resolve<TaskQueryReturnObject[]>([]));
|
|
672
|
+
return processedTasks;
|
|
673
|
+
};
|
|
674
|
+
|
|
675
|
+
const getProviderTasks = async (user: UserData, organisation: InstituteData|ProviderData, cohort?: CohortData):Promise<(TaskQueryReturnObject)[]> => {
|
|
676
|
+
const processedTasks = await Object.entries(providerTasks).reduce(async (acc, [itemName, item]) => {
|
|
677
|
+
|
|
678
|
+
const queryResult = await item.callback(user);
|
|
679
|
+
if (!queryResult) return await acc;
|
|
680
|
+
|
|
681
|
+
const queryResultArray = Array.isArray(queryResult) ? queryResult : [queryResult];
|
|
682
|
+
const results = queryResultArray.map((r) => ({itemName: itemName as ProviderTaskNames, ...r}));
|
|
683
|
+
|
|
684
|
+
(await acc).push(...results);
|
|
685
|
+
return await acc;
|
|
686
|
+
}, Promise.resolve<TaskQueryReturnObject[]>([]));
|
|
687
|
+
return processedTasks;};
|
|
688
|
+
|
|
689
|
+
const getInstituteTasks = async (user: UserData, organisation: InstituteData|ProviderData, cohort?: CohortData):Promise<(TaskQueryReturnObject)[]> => {
|
|
690
|
+
let fCohort:CohortData|[string, CohortData][]|undefined = cohort;
|
|
691
|
+
|
|
692
|
+
if (!fCohort) {
|
|
693
|
+
// get all associated cohorts.
|
|
694
|
+
if (user.viewCohorts === "none") return([]);
|
|
695
|
+
if (user.userGroup === "admin" || user.viewCohorts === "all") {
|
|
696
|
+
const cohorts = await firebaseQuery.getDocsWhere("cohorts", [where("product", "==", user.product), where("oId", "==", user.oId), where("stage", "==", "created")]) as {[key:string]: CohortData};
|
|
697
|
+
fCohort = Object.entries(cohorts);
|
|
698
|
+
}
|
|
699
|
+
if (user.viewCohorts === "some") {
|
|
700
|
+
const cohorts = await user.visibleCohorts?.split(",").reduce(async (acc, cohortId) => {
|
|
701
|
+
const cohort = await firebaseQuery.getDocData(["cohorts", cohortId]) as CohortData;
|
|
702
|
+
if (cohort.stage !== "created") {
|
|
703
|
+
return acc;
|
|
704
|
+
}
|
|
705
|
+
acc[cohortId] = cohort;
|
|
706
|
+
return acc;
|
|
707
|
+
}, Promise.resolve<[string, CohortData][]>([]));
|
|
708
|
+
fCohort = cohorts;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
const processedTasks = await Object.entries(instituteTasks).reduce(async (acc, [itemName, item]) => {
|
|
713
|
+
if (!fCohort) {
|
|
714
|
+
console.log("No cohorts to retrieve tasks for");
|
|
715
|
+
return([]);
|
|
716
|
+
}
|
|
717
|
+
const queryResult = await item.callback(user, organisation, fCohort);
|
|
718
|
+
if (!queryResult) return await acc;
|
|
719
|
+
|
|
720
|
+
const queryResultArray = Array.isArray(queryResult) ? queryResult : [queryResult];
|
|
721
|
+
const results = queryResultArray.map((r) => ({itemName: itemName as InstituteTaskNames, ...r}));
|
|
722
|
+
|
|
723
|
+
(await acc).push(...results);
|
|
724
|
+
return await acc;
|
|
725
|
+
}, Promise.resolve<TaskQueryReturnObject[]>([]));
|
|
726
|
+
return processedTasks;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
/*
|
|
730
|
+
export const getTasks = async (user: UserData):Promise<{[key:string]: TaskQueryReturnObject}> => {
|
|
731
|
+
return Object.fromEntries((await Promise.all(Object.entries(tasks).filter(([k]) => !user.dismissedTasks?.includes(k)).map(async ([taskName, task]) => {
|
|
732
|
+
const queryResult = await task.callback(user);
|
|
733
|
+
return [taskName, queryResult ? {...queryResult, ...task} : undefined];
|
|
734
|
+
}))).filter(([, v]) => v));
|
|
735
|
+
};
|
|
736
|
+
|
|
737
|
+
export const dismissTask = (user: UserData, taskName:TaskNames) => {
|
|
738
|
+
firebaseQuery.update(["users", user.id], {dismissedTasks: arrayUnion(taskName)});
|
|
739
|
+
};
|
|
740
|
+
*/
|
|
741
|
+
export const dismissTip = async (user: UserData, itemName:InstituteTaskNames | ProviderTaskNames | StudentTaskNames | InstituteTipNames | ProviderTipNames | StudentTipNames | undefined) => {
|
|
742
|
+
if (!itemName) return;
|
|
743
|
+
return await firebaseQuery.update(["users", user.id], {dismissedTips: arrayUnion(itemName)});
|
|
744
|
+
};
|