placementt-core 11.0.533 → 11.0.803

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 (76) hide show
  1. package/lib/constants.d.ts +13 -1
  2. package/lib/constants.js +86 -1
  3. package/lib/constants.js.map +1 -1
  4. package/lib/features/analytics/useAnalytics.d.ts +2 -0
  5. package/lib/features/analytics/useAnalytics.js +22 -19
  6. package/lib/features/analytics/useAnalytics.js.map +1 -1
  7. package/lib/features/global/downtime/useDowntime.d.ts +1 -0
  8. package/lib/features/global/downtime/useDowntime.js +9 -7
  9. package/lib/features/global/downtime/useDowntime.js.map +1 -1
  10. package/lib/features/global/users/useUserFunctions.js +1 -1
  11. package/lib/features/global/users/useUserFunctions.js.map +1 -1
  12. package/lib/features/jobs/jobsSlice.d.ts +10 -2
  13. package/lib/features/jobs/jobsSlice.js +5 -2
  14. package/lib/features/jobs/jobsSlice.js.map +1 -1
  15. package/lib/features/placements/studentPlacements/activePlacement.d.ts +5 -1
  16. package/lib/features/placements/studentPlacements/activePlacement.js +7 -3
  17. package/lib/features/placements/studentPlacements/activePlacement.js.map +1 -1
  18. package/lib/features/placements/studentPlacements/completedStudentPlacementsSlice.d.ts +3 -2
  19. package/lib/features/placements/studentPlacements/completedStudentPlacementsSlice.js +4 -1
  20. package/lib/features/placements/studentPlacements/completedStudentPlacementsSlice.js.map +1 -1
  21. package/lib/features/placements/studentPlacements/upcomingStudentPlacementsSlice.d.ts +2 -2
  22. package/lib/features/placements/studentPlacements/upcomingStudentPlacementsSlice.js +1 -1
  23. package/lib/features/placements/studentPlacements/upcomingStudentPlacementsSlice.js.map +1 -1
  24. package/lib/features/placements/studentPlacements/useStudentPlacements.d.ts +2 -12
  25. package/lib/features/placements/studentPlacements/useStudentPlacements.js +1 -26
  26. package/lib/features/placements/studentPlacements/useStudentPlacements.js.map +1 -1
  27. package/lib/features/updates/useUpdates.d.ts +1 -0
  28. package/lib/features/updates/useUpdates.js +13 -12
  29. package/lib/features/updates/useUpdates.js.map +1 -1
  30. package/lib/firebase/firebase.d.ts +5 -3
  31. package/lib/firebase/firebase.js +15 -9
  32. package/lib/firebase/firebase.js.map +1 -1
  33. package/lib/firebase/firebaseConfig.js.map +1 -1
  34. package/lib/firebase/firebaseQuery.d.ts +6 -2
  35. package/lib/firebase/firebaseQuery.js +11 -3
  36. package/lib/firebase/firebaseQuery.js.map +1 -1
  37. package/lib/firebase/readDatabase.d.ts +2 -4
  38. package/lib/firebase/readDatabase.js +30 -5
  39. package/lib/firebase/readDatabase.js.map +1 -1
  40. package/lib/firebase/writeDatabase.d.ts +6 -2
  41. package/lib/firebase/writeDatabase.js +2 -1
  42. package/lib/firebase/writeDatabase.js.map +1 -1
  43. package/lib/hooks.d.ts +226 -16
  44. package/lib/hooks.js +938 -146
  45. package/lib/hooks.js.map +1 -1
  46. package/lib/reduxHooks.d.ts +56 -4
  47. package/lib/reduxHooks.js +63 -19
  48. package/lib/reduxHooks.js.map +1 -1
  49. package/lib/tasksAndTips.d.ts +7 -5
  50. package/lib/tasksAndTips.js +487 -23
  51. package/lib/tasksAndTips.js.map +1 -1
  52. package/lib/typeDefinitions.d.ts +149 -30
  53. package/lib/util.d.ts +7 -2
  54. package/lib/util.js +32 -9
  55. package/lib/util.js.map +1 -1
  56. package/package.json +1 -1
  57. package/src/constants.ts +91 -3
  58. package/src/features/analytics/useAnalytics.tsx +25 -17
  59. package/src/features/global/downtime/useDowntime.tsx +11 -7
  60. package/src/features/global/users/useUserFunctions.tsx +1 -1
  61. package/src/features/jobs/jobsSlice.ts +9 -3
  62. package/src/features/placements/studentPlacements/activePlacement.ts +8 -3
  63. package/src/features/placements/studentPlacements/completedStudentPlacementsSlice.ts +5 -2
  64. package/src/features/placements/studentPlacements/upcomingStudentPlacementsSlice.ts +2 -2
  65. package/src/features/placements/studentPlacements/useStudentPlacements.tsx +4 -28
  66. package/src/features/updates/useUpdates.tsx +14 -12
  67. package/src/firebase/firebase.tsx +19 -12
  68. package/src/firebase/firebaseConfig.tsx +1 -1
  69. package/src/firebase/firebaseQuery.tsx +11 -3
  70. package/src/firebase/readDatabase.tsx +34 -6
  71. package/src/firebase/writeDatabase.tsx +3 -1
  72. package/src/hooks.tsx +1124 -166
  73. package/src/reduxHooks.ts +71 -22
  74. package/src/tasksAndTips.ts +495 -30
  75. package/src/typeDefinitions.ts +140 -35
  76. package/src/util.ts +45 -17
@@ -12,6 +12,22 @@ const firebaseQuery = new firebaseQuery_1.default;
12
12
  const providerTips = {};
13
13
  const studentTips = {};
14
14
  const instituteTips = {
15
+ addSchools: {
16
+ callback: async (user, institute, schools) => {
17
+ if (!(0, util_1.getAccess)(user, "addSchools") || (institute === null || institute === void 0 ? void 0 : institute.package) !== "institutes-two")
18
+ return;
19
+ if (Object.keys(schools).length < 2) {
20
+ return {
21
+ title: "Add your schools",
22
+ message: "Add your schools. These will show up in the 'Cohorts' tab where you can assign cohorts of students to them.",
23
+ link: "/institutes/organisation/overview",
24
+ buttonTitle: "Add schools",
25
+ dismissible: true
26
+ };
27
+ }
28
+ return;
29
+ },
30
+ },
15
31
  createCohort: {
16
32
  callback: async (user) => {
17
33
  if (!(0, util_1.getAccess)(user, "createCohorts"))
@@ -129,9 +145,158 @@ const instituteTips = {
129
145
  };
130
146
  // Accept a cohort to any task
131
147
  const instituteTasks = {
148
+ invalidStaffEmails: {
149
+ callback: async (user, organisation, cohort) => {
150
+ if (!(0, util_1.getAccess)(user, "viewStaff") || !Array.isArray(cohort))
151
+ return;
152
+ const staffCount = (await firebaseQuery.getCount(["users"], [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("userType", "==", "Staff"), (0, firestore_1.where)("flags", "array-contains", "userEmailFailed")]));
153
+ if (staffCount > 0) {
154
+ return {
155
+ dismissible: false,
156
+ severity: "error",
157
+ title: `${staffCount} staff have invalid emails.`,
158
+ message: `${staffCount} staff accounts have invalid email addresses. Delete and reupload these users.`,
159
+ link: "/institutes/cohorts/staff/all",
160
+ };
161
+ }
162
+ return;
163
+ },
164
+ },
165
+ invalidStudentEmails: {
166
+ callback: async (user, organisation, cohorts) => {
167
+ if (!(0, util_1.getAccess)(user, "viewStudents") || user.viewStudents === "none")
168
+ return;
169
+ if (!Array.isArray(cohorts)) {
170
+ const studentCount = (await firebaseQuery.getCount(["users"], [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("userType", "==", "Students"), (0, firestore_1.where)("cohort", "==", cohorts.id), (0, firestore_1.where)("flags", "array-contains", "userEmailFailed")]));
171
+ if (studentCount > 0) {
172
+ return {
173
+ dismissible: false,
174
+ severity: "error",
175
+ title: `${studentCount} students have invalid emails.`,
176
+ message: `${studentCount} student accounts have invalid email addresses. Delete and reupload these users.`,
177
+ link: `/institutes/cohorts/${cohorts.id}/students`,
178
+ };
179
+ }
180
+ return;
181
+ }
182
+ const items = await Promise.all(cohorts.map(async ([id, cohort]) => {
183
+ const studentCount = (await firebaseQuery.getCount(["users"], [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("userType", "==", "Students"), (0, firestore_1.where)("cohort", "==", id), (0, firestore_1.where)("flags", "array-contains", "userEmailFailed")]));
184
+ if (studentCount > 0) {
185
+ return {
186
+ dismissible: false,
187
+ severity: "error",
188
+ title: `${studentCount} students have invalid emails.`,
189
+ message: `Your cohort, ${cohort.name}, has ${studentCount} student accounts with invalid email addresses. Delete and reupload these users.`,
190
+ link: `/institutes/cohorts/${id}/students`,
191
+ };
192
+ }
193
+ return;
194
+ }));
195
+ return items.filter((v) => v);
196
+ },
197
+ },
198
+ outstandingReminders: {
199
+ callback: async (user, organisation, cohorts) => {
200
+ if (!Array.isArray(cohorts)) {
201
+ const reminderCount = (await firebaseQuery.getCount(["reminders"], [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("uid", "==", user.id), (0, firestore_1.where)("dueDate", "<=", (0, util_2.convertDate)(new Date(), "dbstring")), (0, firestore_1.where)("cohort", "==", cohorts.id), (0, firestore_1.where)("status", "==", "upcoming")]));
202
+ if (reminderCount > 0) {
203
+ return {
204
+ dismissible: false,
205
+ severity: "primary",
206
+ title: `You have ${reminderCount} reminder${reminderCount > 1 ? "s" : ""}.`,
207
+ message: `You have ${reminderCount} outstanding placement reminder${reminderCount > 1 ? "s" : ""}. Click to view.`,
208
+ link: `/institutes/cohorts/${cohorts.id}/placements`,
209
+ };
210
+ }
211
+ return;
212
+ }
213
+ const items = await Promise.all(cohorts.map(async ([id, cohort]) => {
214
+ const reminderCount = (await firebaseQuery.getCount(["reminders"], [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("uid", "==", user.id), (0, firestore_1.where)("dueDate", "<=", (0, util_2.convertDate)(new Date(), "dbstring")), (0, firestore_1.where)("cohort", "==", id), (0, firestore_1.where)("status", "==", "upcoming")]));
215
+ if (reminderCount > 0) {
216
+ return {
217
+ dismissible: false,
218
+ severity: "primary",
219
+ title: `You have ${reminderCount} reminder${reminderCount > 1 ? "s" : ""}.`,
220
+ message: `Your cohort, ${cohort.name}, has ${reminderCount} outstanding placement reminder${reminderCount > 1 ? "s" : ""}. Click to view.`,
221
+ link: `/institutes/cohorts/${id}/placements`,
222
+ };
223
+ }
224
+ return;
225
+ }));
226
+ return items.filter((v) => v);
227
+ },
228
+ },
229
+ invalidParentEmails: {
230
+ callback: async (user, _, cohorts) => {
231
+ if (!(0, util_1.getAccess)(user, "signOffPlacements") || user.viewStudents === "none")
232
+ return;
233
+ if (!Array.isArray(cohorts)) {
234
+ const placementCount = (await firebaseQuery.getCount(["placements"], [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("cohort", "==", cohorts.id), (0, firestore_1.where)("flags", "array-contains", "parentEmailFailed")]));
235
+ if (placementCount > 0) {
236
+ return {
237
+ dismissible: false,
238
+ severity: "error",
239
+ title: `${placementCount} placements have invalid parent emails.`,
240
+ message: `Your cohort '${cohorts.name}' has placements with invalid parent emails. Click to view these placements.`,
241
+ link: `/institutes/cohorts/${cohorts.id}/placements?id=upcoming`,
242
+ };
243
+ }
244
+ return;
245
+ }
246
+ const items = await Promise.all(cohorts.map(async ([id, cohort]) => {
247
+ const placementCount = (await firebaseQuery.getCount(["placements"], [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("cohort", "==", id), (0, firestore_1.where)("flags", "array-contains", "parentEmailFailed")]));
248
+ if (placementCount > 0) {
249
+ return {
250
+ dismissible: false,
251
+ severity: "error",
252
+ title: `${placementCount} placements in '${cohort.name}' have invalid parent emails.`,
253
+ message: `Your cohort '${cohort.name}' has placements with invalid parent emails. Click to view these placements.`,
254
+ link: `/institutes/cohorts/${id}/placements?id=upcoming`,
255
+ buttonTitle: "Review placements",
256
+ };
257
+ }
258
+ return;
259
+ }));
260
+ return items.filter((v) => v);
261
+ },
262
+ },
263
+ invalidProviderEmails: {
264
+ callback: async (user, organisation, cohorts) => {
265
+ if (!(0, util_1.getAccess)(user, "signOffPlacements") || user.viewStudents === "none")
266
+ return;
267
+ if (!Array.isArray(cohorts)) {
268
+ const placementCount = (await firebaseQuery.getCount(["placements"], [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("cohort", "==", cohorts.id), (0, firestore_1.where)("flags", "array-contains", "providerEmailFailed")]));
269
+ if (placementCount > 0) {
270
+ return {
271
+ dismissible: false,
272
+ severity: "error",
273
+ title: `${placementCount} placements have invalid provider emails.`,
274
+ message: `Your cohort '${cohorts.name}' has placements with invalid provider emails. Click to view these placements.`,
275
+ link: `/institutes/cohorts/${cohorts.id}/placements?id=upcoming`,
276
+ };
277
+ }
278
+ return;
279
+ }
280
+ const items = await Promise.all(cohorts.map(async ([id, cohort]) => {
281
+ const placementCount = (await firebaseQuery.getCount(["placements"], [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("cohort", "==", id), (0, firestore_1.where)("flags", "array-contains", "providerEmailFailed")]));
282
+ if (placementCount > 0) {
283
+ return {
284
+ dismissible: false,
285
+ severity: "error",
286
+ title: `${placementCount} placements in '${cohort.name}' have invalid provider emails.`,
287
+ message: `Your cohort '${cohort.name}' has placements with invalid provider emails. Click to view these placements.`,
288
+ link: `/institutes/cohorts/${id}/placements?id=upcoming`,
289
+ buttonTitle: "Review placements",
290
+ };
291
+ }
292
+ return;
293
+ }));
294
+ return items.filter((v) => v);
295
+ },
296
+ },
132
297
  requiredStage: {
133
298
  callback: async (user, _, cohorts) => {
134
- if (!(0, util_1.getAccess)(user, "signOffPlacements"))
299
+ if (!(0, util_1.getAccess)(user, "signOffPlacements") || user.viewStudents === "none")
135
300
  return;
136
301
  if (!Array.isArray(cohorts)) {
137
302
  const placementCount = (await firebaseQuery.getCount(["placements"], [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("cohort", "==", cohorts.id), (0, firestore_1.where)("reqUserType", "==", user.userType)]));
@@ -165,7 +330,7 @@ const instituteTasks = {
165
330
  },
166
331
  verifyInsurance: {
167
332
  callback: async (user, _, cohorts) => {
168
- if (!(0, util_1.getAccess)(user, "verifyInsurance"))
333
+ if (!(0, util_1.getAccess)(user, "verifyInsurance") || user.viewStudents === "none")
169
334
  return;
170
335
  if (!Array.isArray(cohorts)) {
171
336
  const placementCount = (await firebaseQuery.getCount(["placements"], [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("cohort", "==", cohorts.id), (0, firestore_1.where)("insurance", "==", "awaitingReview")]));
@@ -199,7 +364,7 @@ const instituteTasks = {
199
364
  },
200
365
  verifyDbsCheck: {
201
366
  callback: async (user, _, cohorts) => {
202
- if (!(0, util_1.getAccess)(user, "verifyDbsChecks"))
367
+ if (!(0, util_1.getAccess)(user, "verifyDbsChecks") || user.viewStudents === "none")
203
368
  return;
204
369
  if (!Array.isArray(cohorts)) {
205
370
  const placementCount = (await firebaseQuery.getCount(["placements"], [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("cohort", "==", cohorts.id), (0, firestore_1.where)("dbsCheck", "==", "awaitingReview")]));
@@ -233,7 +398,7 @@ const instituteTasks = {
233
398
  },
234
399
  verifyRiskAssessment: {
235
400
  callback: async (user, _, cohorts) => {
236
- if (!(0, util_1.getAccess)(user, "verifyRiskAssessments"))
401
+ if (!(0, util_1.getAccess)(user, "verifyRiskAssessments") || user.viewStudents === "none")
237
402
  return;
238
403
  if (!Array.isArray(cohorts)) {
239
404
  const placementCount = (await firebaseQuery.getCount(["placements"], [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("cohort", "==", cohorts.id), (0, firestore_1.where)("riskAssessment", "==", "awaitingReview")]));
@@ -268,7 +433,7 @@ const instituteTasks = {
268
433
  missingParentEmail: {
269
434
  callback: async (user, _, cohorts) => {
270
435
  var _a, _b, _c;
271
- if (!(0, util_1.getAccess)(user, "editStudents"))
436
+ if (!(0, util_1.getAccess)(user, "editStudents") || user.viewStudents === "none")
272
437
  return;
273
438
  if (!Array.isArray(cohorts)) {
274
439
  const requiresParents = Boolean(cohorts.workflow.find((node) => node.userType === "Parent"));
@@ -318,7 +483,7 @@ const instituteTasks = {
318
483
  inactiveStudents: {
319
484
  callback: async (user, _, cohorts) => {
320
485
  var _a, _b, _c;
321
- if (!(0, util_1.getAccess)(user, "activateStudents"))
486
+ if (!(0, util_1.getAccess)(user, "activateStudents") || user.viewStudents === "none")
322
487
  return;
323
488
  if (!Array.isArray(cohorts)) {
324
489
  const constraints = [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("cohort", "==", cohorts.id), (0, firestore_1.where)("status", "==", "inactive")];
@@ -351,7 +516,7 @@ const instituteTasks = {
351
516
  title: `${studentCount} students in '${cohort.name}' are inactive.`,
352
517
  message: `Your cohort '${cohort.name}' has inactive students. Activate them to enable them to use the platform.`,
353
518
  link: `/institutes/cohorts/${cohort.id}/students?status=inactive`,
354
- buttonTitle: "Review placements",
519
+ buttonTitle: "Review students",
355
520
  };
356
521
  }
357
522
  return;
@@ -363,7 +528,7 @@ const instituteTasks = {
363
528
  callback: async (user, _, cohorts) => {
364
529
  if (!Array.isArray(cohorts))
365
530
  return;
366
- if (!(0, util_1.getAccess)(user, "addStudents"))
531
+ if (!(0, util_1.getAccess)(user, "addStudents") || user.viewStudents === "none")
367
532
  return;
368
533
  if (user.product !== "institutes")
369
534
  return;
@@ -442,14 +607,13 @@ const studentTasks = {
442
607
  completeOnboarding: {
443
608
  callback: async (user) => {
444
609
  const placementsWithoutOnboarding = await firebaseQuery.getDocsWhere("placements", [(0, firestore_1.where)("uid", "==", user.id), (0, firestore_1.where)("onboarding.deadline", "<=", (0, util_2.convertDate)(new Date(), "dbstring")), (0, firestore_1.where)("onboarding.completed.submitted", "==", false)]);
445
- console.log("placementsWithoutONboarding", placementsWithoutOnboarding);
446
610
  if (Object.keys(placementsWithoutOnboarding).length === 0)
447
611
  return;
448
612
  const items = Object.entries(placementsWithoutOnboarding).map(([k, placement]) => ({
449
613
  dismissible: false,
450
614
  severity: "primary",
451
- title: `Complete required onboarding documents for ${placement.name}`,
452
- message: `${placement.name} has requested you to complete some onboarding documents.`,
615
+ title: `Complete onboarding for ${placement.name}`,
616
+ message: `Review onboarding for your placement starting on ${(0, util_2.convertDate)(placement.startDate, "visual")}`,
453
617
  link: `/${user.product}/placements/${k}`,
454
618
  buttonTitle: "View onboarding",
455
619
  }));
@@ -460,11 +624,13 @@ const studentTasks = {
460
624
  const providerTasks = {
461
625
  requestedVisibleAddresses: {
462
626
  callback: async (user) => {
463
- const accessRequests = await firebaseQuery.getCount("users", [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("product", "==", "providers"), (0, firestore_1.orderBy)("requestedVisibleAddresses")]);
627
+ if (!(0, util_1.getAccess)(user, "addStaff"))
628
+ return;
629
+ const accessRequests = await firebaseQuery.getCount("users", [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("product", "==", "providers"), (0, firestore_1.orderBy)("requestedVisibleAddresses")]) - ((Array.isArray(user === null || user === void 0 ? void 0 : user.requestedVisibleAddresses) && (user === null || user === void 0 ? void 0 : user.requestedVisibleAddresses.length) > 0) ? 1 : 0);
464
630
  if (accessRequests === 0)
465
631
  return;
466
632
  if (accessRequests === 1) {
467
- const userRequestingAccess = Object.entries(await firebaseQuery.getDocsWhere("users", [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("product", "==", "providers"), (0, firestore_1.orderBy)("requestedVisibleAddresses")]) || {})[0];
633
+ const userRequestingAccess = Object.entries(await firebaseQuery.getDocsWhere("users", [(0, firestore_1.where)("product", "==", "providers"), (0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.orderBy)("requestedVisibleAddresses")]) || {})[0];
468
634
  return {
469
635
  dismissible: false,
470
636
  severity: "primary",
@@ -486,7 +652,10 @@ const providerTasks = {
486
652
  },
487
653
  requestedVisiblePlacementListings: {
488
654
  callback: async (user) => {
489
- const accessRequests = await firebaseQuery.getCount("users", [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("product", "==", "providers"), (0, firestore_1.orderBy)("requestedVisibleListings")]);
655
+ if (!(0, util_1.getAccess)(user, "addStaff"))
656
+ return;
657
+ const accessRequests = await firebaseQuery.getCount("users", [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("product", "==", "providers"), (0, firestore_1.orderBy)("requestedVisibleListings")]) - ((Array.isArray(user === null || user === void 0 ? void 0 : user.requestedVisibleListings) && (user === null || user === void 0 ? void 0 : user.requestedVisibleListings.length) > 0) ? 1 : 0);
658
+ ;
490
659
  if (accessRequests === 0)
491
660
  return;
492
661
  if (accessRequests === 1) {
@@ -512,7 +681,28 @@ const providerTasks = {
512
681
  },
513
682
  applicationRequireReview: {
514
683
  callback: async (user) => {
515
- const applicationCount = await firebaseQuery.getCount("applications", [(0, firestore_1.where)("providerId", "==", user.oId), (0, firestore_1.where)("reqUserType", "==", "Staff"), (0, firestore_1.where)("status", "==", "submitted")]);
684
+ var _a, _b;
685
+ const constraints = [(0, firestore_1.where)("providerId", "==", user.oId), (0, firestore_1.where)("reqUserType", "==", "Staff"), (0, firestore_1.where)("status", "==", "submitted")];
686
+ if (user.userGroup !== "admin") {
687
+ if (!user.viewPlacementListings || user.viewPlacementListings === "none")
688
+ return;
689
+ if (!user.viewAddresses || user.viewAddresses === "none")
690
+ return;
691
+ if (user.viewPlacementListings === "request") {
692
+ if (!user.visibleListings || ((_a = user.visibleListings) === null || _a === void 0 ? void 0 : _a.length) === 0)
693
+ return;
694
+ constraints.push((0, firestore_1.where)("listingId", 'in', user.visibleListings));
695
+ }
696
+ else {
697
+ // viewPlacementListings must be 'all'
698
+ if (user.viewAddresses === "request") {
699
+ if (!user.visibleAddresses || ((_b = user.visibleAddresses) === null || _b === void 0 ? void 0 : _b.length) === 0)
700
+ return;
701
+ constraints.push((0, firestore_1.where)("addressId", 'in', user.visibleAddresses));
702
+ }
703
+ }
704
+ }
705
+ const applicationCount = await firebaseQuery.getCount("applications", constraints);
516
706
  if (applicationCount === 0)
517
707
  return;
518
708
  return {
@@ -527,46 +717,316 @@ const providerTasks = {
527
717
  },
528
718
  completeStudentDocs: {
529
719
  callback: async (user) => {
720
+ return;
530
721
  return {};
531
722
  },
532
723
  },
533
724
  reviewOnboarding: {
534
725
  callback: async (user) => {
535
- return {};
726
+ var _a, _b;
727
+ const constraints = [(0, firestore_1.where)("providerId", "==", user.oId), (0, firestore_1.where)("onboarding.completed.accepted", "==", false), (0, firestore_1.where)("onboarding.completed.submitted", "==", true), (0, firestore_1.where)("endDate", ">=", (0, util_1.dateToString)(new Date()))];
728
+ if (user.userGroup !== "admin") {
729
+ if (!user.viewPlacementListings || user.viewPlacementListings === "none")
730
+ return;
731
+ if (!user.viewAddresses || user.viewAddresses === "none")
732
+ return;
733
+ if (user.viewPlacementListings === "request") {
734
+ if (!user.visibleListings || ((_a = user.visibleListings) === null || _a === void 0 ? void 0 : _a.length) === 0)
735
+ return;
736
+ constraints.push((0, firestore_1.where)("placementId", 'in', user.visibleListings));
737
+ }
738
+ else {
739
+ // viewPlacementListings must be 'all'
740
+ if (user.viewAddresses === "request") {
741
+ if (!user.visibleAddresses || ((_b = user.visibleAddresses) === null || _b === void 0 ? void 0 : _b.length) === 0)
742
+ return;
743
+ constraints.push((0, firestore_1.where)("addressId", 'in', user.visibleAddresses));
744
+ }
745
+ }
746
+ }
747
+ const toReview = await firebaseQuery.getCount("placements", constraints);
748
+ if (toReview === 0)
749
+ return;
750
+ if (toReview === 1) {
751
+ const placement = Object.entries(await firebaseQuery.getDocsWhere("placements", constraints) || {})[0];
752
+ const student = await firebaseQuery.getDocData(["users", placement[1].uid]);
753
+ return {
754
+ dismissible: false,
755
+ severity: "primary",
756
+ title: `${student.details.forename} ${student.details.surname} has completed their onboarding for their placement from ${(0, util_2.convertDate)(placement[1].startDate, "visual")} to ${(0, util_2.convertDate)(placement[1].endDate, "visual")}`,
757
+ message: `Click to view the placement and review the onboarding.`,
758
+ link: `/${user.product}/placements/${placement[0]}`,
759
+ buttonTitle: "View",
760
+ };
761
+ }
762
+ return {
763
+ dismissible: false,
764
+ severity: "primary",
765
+ title: `${toReview} student have completed their onboarding.`,
766
+ message: `Click to view your placements and approve completed onboarding`,
767
+ link: `/${user.product}/placementListings/placements`,
768
+ buttonTitle: "View placements",
769
+ };
770
+ },
771
+ },
772
+ uploadOnboarding: {
773
+ callback: async (user) => {
774
+ var _a, _b;
775
+ const constraints = [(0, firestore_1.where)("providerId", "==", user.oId), (0, firestore_1.where)("onboarding", "==", null), (0, firestore_1.where)("endDate", ">=", (0, util_1.dateToString)(new Date()))];
776
+ if (user.userGroup !== "admin") {
777
+ if (!user.viewPlacementListings || user.viewPlacementListings === "none")
778
+ return;
779
+ if (!user.viewAddresses || user.viewAddresses === "none")
780
+ return;
781
+ if (user.viewPlacementListings === "request") {
782
+ if (!user.visibleListings || ((_a = user.visibleListings) === null || _a === void 0 ? void 0 : _a.length) === 0)
783
+ return;
784
+ constraints.push((0, firestore_1.where)("placementId", 'in', user.visibleListings));
785
+ }
786
+ else {
787
+ // viewPlacementListings must be 'all'
788
+ if (user.viewAddresses === "request") {
789
+ if (!user.visibleAddresses || ((_b = user.visibleAddresses) === null || _b === void 0 ? void 0 : _b.length) === 0)
790
+ return;
791
+ constraints.push((0, firestore_1.where)("addressId", 'in', user.visibleAddresses));
792
+ }
793
+ }
794
+ }
795
+ const withoutOnboarding = await firebaseQuery.getCount("placements", constraints);
796
+ if (withoutOnboarding === 0)
797
+ return;
798
+ if (withoutOnboarding === 1) {
799
+ const placement = Object.entries(await firebaseQuery.getDocsWhere("placements", constraints) || {})[0];
800
+ const student = await firebaseQuery.getDocData(["users", placement[1].uid]);
801
+ return {
802
+ dismissible: false,
803
+ severity: "primary",
804
+ title: `Send onboarding documents to ${student.details.forename} ${student.details.surname}'s placement from ${(0, util_2.convertDate)(placement[1].startDate, "visual")} to ${(0, util_2.convertDate)(placement[1].endDate, "visual")}`,
805
+ message: `Click to view the placement and add or dismiss onboarding reminders.`,
806
+ link: `/${user.product}/placements/${placement[0]}`,
807
+ buttonTitle: "View",
808
+ };
809
+ }
810
+ return {
811
+ dismissible: false,
812
+ severity: "primary",
813
+ title: `Set up onboarding for ${withoutOnboarding} placements to prepare yourself and your students.`,
814
+ message: `Click to view your placements and add or dismiss onboarding reminders.`,
815
+ link: `/${user.product}/placementListings/placements`,
816
+ buttonTitle: "View placements",
817
+ };
536
818
  },
537
819
  },
538
820
  completeListing: {
539
821
  callback: async (user) => {
540
- return {};
822
+ var _a, _b;
823
+ const constraints = [(0, firestore_1.where)("providerId", "==", user.oId), (0, firestore_1.where)("status", "==", "draft")];
824
+ if (user.userGroup !== "admin") {
825
+ if (!user.viewPlacementListings || user.viewPlacementListings === "none")
826
+ return;
827
+ if (!user.viewAddresses || user.viewAddresses === "none")
828
+ return;
829
+ if (user.viewPlacementListings === "request") {
830
+ if (!user.visibleListings || ((_a = user.visibleListings) === null || _a === void 0 ? void 0 : _a.length) === 0)
831
+ return;
832
+ constraints.push((0, firestore_1.where)((0, firestore_1.documentId)(), 'in', user.visibleListings));
833
+ }
834
+ else {
835
+ // viewPlacementListings must be 'all'
836
+ if (user.viewAddresses === "request") {
837
+ if (!user.visibleAddresses || ((_b = user.visibleAddresses) === null || _b === void 0 ? void 0 : _b.length) === 0)
838
+ return;
839
+ constraints.push((0, firestore_1.where)("addressId", 'in', user.visibleAddresses));
840
+ }
841
+ }
842
+ }
843
+ const incompleteListings = await firebaseQuery.getCount("placementListings", constraints);
844
+ if (incompleteListings === 0)
845
+ return;
846
+ if (incompleteListings === 1) {
847
+ const incompleteListing = Object.entries(await firebaseQuery.getDocsWhere("placementListings", constraints) || {})[0];
848
+ const address = incompleteListing[1].addressId ? await firebaseQuery.getDocData(["addresses", incompleteListing[1].addressId]) : undefined;
849
+ return {
850
+ dismissible: false,
851
+ severity: "info",
852
+ title: `Your listing '${incompleteListing[1].title || "unnamed"}' at ${address ? `${address["address-line1"]}, ${address.postal_code.toUpperCase()}, ${(0, util_1.capitaliseWords)((0, util_1.camelCaseToNormal)(address.country))}` : "unknown address"} requires more information before publishing.`,
853
+ message: `Click to complete and publish the placement listing.`,
854
+ link: `/${user.product}/addListing/${incompleteListing[0]}`,
855
+ buttonTitle: "View listing",
856
+ };
857
+ }
858
+ return {
859
+ dismissible: false,
860
+ severity: "info",
861
+ title: `You have ${incompleteListings} draft listings waiting to be published.`,
862
+ message: `Click to review and publish the placement listings.`,
863
+ link: `/${user.product}/placementListings/listings`,
864
+ buttonTitle: "View listings",
865
+ };
541
866
  },
542
867
  },
543
868
  completeAddress: {
544
869
  callback: async (user) => {
545
- return {};
870
+ var _a;
871
+ const constraints = [(0, firestore_1.where)("product", "==", "providers"), (0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("stage", "!=", "complete")];
872
+ if (user.userGroup !== "admin") {
873
+ if (!user.viewAddresses || user.viewAddresses === "none")
874
+ return;
875
+ if (user.viewAddresses === "request") {
876
+ if (!user.visibleAddresses || ((_a = user.visibleAddresses) === null || _a === void 0 ? void 0 : _a.length) === 0)
877
+ return;
878
+ constraints.push((0, firestore_1.where)("addressId", 'in', user.visibleAddresses));
879
+ }
880
+ }
881
+ const incompleteAddresses = await firebaseQuery.getCount("addresses", constraints);
882
+ if (incompleteAddresses === 0)
883
+ return;
884
+ if (incompleteAddresses === 1) {
885
+ const address = Object.entries(await firebaseQuery.getDocsWhere("addresses", constraints) || {})[0];
886
+ return {
887
+ dismissible: false,
888
+ severity: "info",
889
+ title: `Your address: ${address[1]["address-line1"]}, ${address[1].postal_code.toUpperCase()}, ${(0, util_1.capitaliseWords)((0, util_1.camelCaseToNormal)(address[1].country))} is currently incomplete.`,
890
+ message: `Click to complete the addresses.`,
891
+ link: `/${user.product}/addAddress/${address[0]}`,
892
+ buttonTitle: "View address",
893
+ };
894
+ }
895
+ return {
896
+ dismissible: false,
897
+ severity: "info",
898
+ title: `You have ${incompleteAddresses} draft addresses waiting to be published.`,
899
+ message: `Click to review the addresses.`,
900
+ link: `/${user.product}/organisation/addresses`,
901
+ buttonTitle: "View addresses",
902
+ };
546
903
  },
547
904
  },
548
905
  registrationRequests: {
549
906
  callback: async (user) => {
550
- return {};
907
+ if (!(0, util_1.getAccess)(user, "addStaff"))
908
+ return;
909
+ const regRequests = await firebaseQuery.getCount("requests", [(0, firestore_1.where)("product", "==", user.product), (0, firestore_1.where)("oId", "==", user.oId)]);
910
+ if (regRequests === 0)
911
+ return;
912
+ if (regRequests === 1) {
913
+ const request = Object.entries(await firebaseQuery.getDocsWhere("requests", [(0, firestore_1.where)("product", "==", user.product), (0, firestore_1.where)("oId", "==", user.oId)]) || {})[0];
914
+ return {
915
+ dismissible: false,
916
+ severity: "primary",
917
+ title: `${request[1].forename} ${request[1].surname} has requested to access your organisation.`,
918
+ message: `Click to review these request.`,
919
+ link: `/${user.product}/organisation/staff/requests`,
920
+ buttonTitle: "View requests",
921
+ };
922
+ }
923
+ return {
924
+ dismissible: false,
925
+ severity: "primary",
926
+ title: `${regRequests} people have requested to register with your organisation.`,
927
+ message: `Click to review these requests.`,
928
+ link: `/${user.product}/organisation/staff/requests`,
929
+ buttonTitle: "View requests",
930
+ };
931
+ },
932
+ },
933
+ activateStaff: {
934
+ callback: async (user) => {
935
+ if (!(0, util_1.getAccess)(user, "addStaff"))
936
+ return;
937
+ const inactiveAccounts = await firebaseQuery.getCount("users", [(0, firestore_1.where)("product", "==", user.product), (0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("status", "==", "inactive")]);
938
+ if (inactiveAccounts === 0)
939
+ return;
940
+ if (inactiveAccounts === 1) {
941
+ const account = Object.entries(await firebaseQuery.getDocsWhere("users", [(0, firestore_1.where)("product", "==", user.product), (0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("status", "==", "inactive")]) || {})[0];
942
+ return {
943
+ dismissible: false,
944
+ severity: "info",
945
+ title: `Activate ${account[1].details.forename} ${account[1].details.surname}'s staff account.`,
946
+ message: "Activate this account to give the user access to Placementt.",
947
+ link: `/${user.product}/organisation/staff/all`,
948
+ buttonTitle: "View accounts",
949
+ };
950
+ }
951
+ return {
952
+ dismissible: false,
953
+ severity: "info",
954
+ title: `${inactiveAccounts} staff have inactive active accounts.`,
955
+ message: "Activate these accounts to give the user access to Placementt.",
956
+ link: `/${user.product}/organisation/staff/all`,
957
+ buttonTitle: "View accounts",
958
+ };
551
959
  },
552
960
  },
553
961
  placementStarting: {
554
962
  callback: async (user) => {
555
- return {};
963
+ var _a, _b;
964
+ const sevenDaysInFuture = new Date();
965
+ sevenDaysInFuture.setDate(sevenDaysInFuture.getDate() + 7);
966
+ const constraints = [(0, firestore_1.where)("providerId", "==", user.oId), (0, firestore_1.where)("startDate", "<=", (0, util_2.convertDate)(sevenDaysInFuture, "dbstring")), (0, firestore_1.where)("startDate", ">", (0, util_1.dateToString)(new Date()))];
967
+ if (user.userGroup !== "admin") {
968
+ if (!user.viewPlacementListings || user.viewPlacementListings === "none")
969
+ return;
970
+ if (!user.viewAddresses || user.viewAddresses === "none")
971
+ return;
972
+ if (user.viewPlacementListings === "request") {
973
+ if (!user.visibleListings || ((_a = user.visibleListings) === null || _a === void 0 ? void 0 : _a.length) === 0)
974
+ return;
975
+ constraints.push((0, firestore_1.where)((0, firestore_1.documentId)(), 'in', user.visibleListings));
976
+ }
977
+ else {
978
+ // viewPlacementListings must be 'all'
979
+ if (user.viewAddresses === "request") {
980
+ if (!user.visibleAddresses || ((_b = user.visibleAddresses) === null || _b === void 0 ? void 0 : _b.length) === 0)
981
+ return;
982
+ constraints.push((0, firestore_1.where)("addressId", 'in', user.visibleAddresses));
983
+ }
984
+ }
985
+ }
986
+ const placementsStartingSoon = await firebaseQuery.getCount("placements", constraints);
987
+ if (placementsStartingSoon === 0)
988
+ return;
989
+ if (placementsStartingSoon === 1) {
990
+ const placement = Object.entries(await firebaseQuery.getDocsWhere("placements", constraints) || {})[0];
991
+ const student = placement[1].uid ? await firebaseQuery.getDocData(["users", placement[1].uid]) : {
992
+ details: {
993
+ forename: placement[1].studentForename,
994
+ surname: placement[1].studentSurname,
995
+ }
996
+ };
997
+ return {
998
+ dismissible: false,
999
+ severity: "success",
1000
+ title: `${student.details.forename} ${student.details.surname}'s placement from ${(0, util_2.convertDate)(placement[1].startDate, "visual")} to ${(0, util_2.convertDate)(placement[1].endDate, "visual")} is starting in less than a week.`,
1001
+ message: `Click to view the placement and acquaint yourself with the student.`,
1002
+ link: `/${user.product}/placements/${placement[0]}`,
1003
+ buttonTitle: "View",
1004
+ };
1005
+ }
1006
+ return {
1007
+ dismissible: false,
1008
+ severity: "success",
1009
+ title: `${placementsStartingSoon} placements starting soon.`,
1010
+ message: `Click to view scheduled placements.`,
1011
+ link: `/${user.product}/placementListings/placements`,
1012
+ buttonTitle: "View placements",
1013
+ };
556
1014
  },
557
1015
  },
558
1016
  completeFeedback: {
559
1017
  callback: async (user) => {
1018
+ return;
560
1019
  return {};
561
1020
  },
562
1021
  },
563
1022
  setUpFeedback: {
564
1023
  callback: async (user) => {
1024
+ return;
565
1025
  return {};
566
1026
  },
567
1027
  },
568
1028
  };
569
- const getTips = async (user, organisation) => {
1029
+ const getTips = async (user, organisation, addresses) => {
570
1030
  const tipsObject = {
571
1031
  providers: providerTips,
572
1032
  institutes: instituteTips,
@@ -574,7 +1034,11 @@ const getTips = async (user, organisation) => {
574
1034
  };
575
1035
  const includedItems = Object.entries(tipsObject[user.product]).filter(([k]) => { var _a; return !((_a = user.dismissedTips) === null || _a === void 0 ? void 0 : _a.includes(k)); });
576
1036
  const processedTips = await includedItems.reduce(async (acc, [itemName, item]) => {
577
- const queryResult = await item.callback(user, organisation);
1037
+ const callbackParams = [user, organisation];
1038
+ if ((itemName === "addAddresses" || itemName === "addSchools") && addresses) {
1039
+ callbackParams.push(addresses);
1040
+ }
1041
+ const queryResult = await item.callback(...callbackParams);
578
1042
  if (!queryResult)
579
1043
  return await acc;
580
1044
  const queryResultArray = Array.isArray(queryResult) ? queryResult : [queryResult];
@@ -635,7 +1099,7 @@ const getInstituteTasks = async (user, organisation, cohort) => {
635
1099
  fCohort = Object.entries(cohorts);
636
1100
  }
637
1101
  if (user.viewCohorts === "some") {
638
- const cohorts = await ((_a = user.visibleCohorts) === null || _a === void 0 ? void 0 : _a.split(",").reduce(async (acc, cohortId) => {
1102
+ const cohorts = await ((_a = user.visibleCohorts) === null || _a === void 0 ? void 0 : _a.reduce(async (acc, cohortId) => {
639
1103
  const cohort = await firebaseQuery.getDocData(["cohorts", cohortId]);
640
1104
  if (cohort.stage !== "created") {
641
1105
  return acc;