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.
- package/lib/constants.d.ts +13 -1
- package/lib/constants.js +86 -1
- package/lib/constants.js.map +1 -1
- package/lib/features/analytics/useAnalytics.d.ts +2 -0
- package/lib/features/analytics/useAnalytics.js +22 -19
- package/lib/features/analytics/useAnalytics.js.map +1 -1
- package/lib/features/global/downtime/useDowntime.d.ts +1 -0
- package/lib/features/global/downtime/useDowntime.js +9 -7
- package/lib/features/global/downtime/useDowntime.js.map +1 -1
- package/lib/features/global/users/useUserFunctions.js +1 -1
- package/lib/features/global/users/useUserFunctions.js.map +1 -1
- package/lib/features/jobs/jobsSlice.d.ts +10 -2
- package/lib/features/jobs/jobsSlice.js +5 -2
- package/lib/features/jobs/jobsSlice.js.map +1 -1
- package/lib/features/placements/studentPlacements/activePlacement.d.ts +5 -1
- package/lib/features/placements/studentPlacements/activePlacement.js +7 -3
- package/lib/features/placements/studentPlacements/activePlacement.js.map +1 -1
- package/lib/features/placements/studentPlacements/completedStudentPlacementsSlice.d.ts +3 -2
- package/lib/features/placements/studentPlacements/completedStudentPlacementsSlice.js +4 -1
- package/lib/features/placements/studentPlacements/completedStudentPlacementsSlice.js.map +1 -1
- package/lib/features/placements/studentPlacements/upcomingStudentPlacementsSlice.d.ts +2 -2
- 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 +2 -12
- package/lib/features/placements/studentPlacements/useStudentPlacements.js +1 -26
- package/lib/features/placements/studentPlacements/useStudentPlacements.js.map +1 -1
- package/lib/features/updates/useUpdates.d.ts +1 -0
- package/lib/features/updates/useUpdates.js +13 -12
- package/lib/features/updates/useUpdates.js.map +1 -1
- package/lib/firebase/firebase.d.ts +5 -3
- package/lib/firebase/firebase.js +15 -9
- package/lib/firebase/firebase.js.map +1 -1
- package/lib/firebase/firebaseConfig.js.map +1 -1
- package/lib/firebase/firebaseQuery.d.ts +6 -2
- package/lib/firebase/firebaseQuery.js +11 -3
- package/lib/firebase/firebaseQuery.js.map +1 -1
- package/lib/firebase/readDatabase.d.ts +2 -4
- package/lib/firebase/readDatabase.js +30 -5
- package/lib/firebase/readDatabase.js.map +1 -1
- package/lib/firebase/writeDatabase.d.ts +6 -2
- package/lib/firebase/writeDatabase.js +2 -1
- package/lib/firebase/writeDatabase.js.map +1 -1
- package/lib/hooks.d.ts +226 -16
- package/lib/hooks.js +938 -146
- package/lib/hooks.js.map +1 -1
- package/lib/reduxHooks.d.ts +56 -4
- package/lib/reduxHooks.js +63 -19
- package/lib/reduxHooks.js.map +1 -1
- package/lib/tasksAndTips.d.ts +7 -5
- package/lib/tasksAndTips.js +487 -23
- package/lib/tasksAndTips.js.map +1 -1
- package/lib/typeDefinitions.d.ts +149 -30
- package/lib/util.d.ts +7 -2
- package/lib/util.js +32 -9
- package/lib/util.js.map +1 -1
- package/package.json +1 -1
- package/src/constants.ts +91 -3
- package/src/features/analytics/useAnalytics.tsx +25 -17
- package/src/features/global/downtime/useDowntime.tsx +11 -7
- package/src/features/global/users/useUserFunctions.tsx +1 -1
- package/src/features/jobs/jobsSlice.ts +9 -3
- package/src/features/placements/studentPlacements/activePlacement.ts +8 -3
- package/src/features/placements/studentPlacements/completedStudentPlacementsSlice.ts +5 -2
- package/src/features/placements/studentPlacements/upcomingStudentPlacementsSlice.ts +2 -2
- package/src/features/placements/studentPlacements/useStudentPlacements.tsx +4 -28
- package/src/features/updates/useUpdates.tsx +14 -12
- package/src/firebase/firebase.tsx +19 -12
- package/src/firebase/firebaseConfig.tsx +1 -1
- package/src/firebase/firebaseQuery.tsx +11 -3
- package/src/firebase/readDatabase.tsx +34 -6
- package/src/firebase/writeDatabase.tsx +3 -1
- package/src/hooks.tsx +1124 -166
- package/src/reduxHooks.ts +71 -22
- package/src/tasksAndTips.ts +495 -30
- package/src/typeDefinitions.ts +140 -35
- package/src/util.ts +45 -17
package/src/tasksAndTips.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import {arrayUnion, orderBy, where} from "firebase/firestore";
|
|
1
|
+
import {arrayUnion, documentId, orderBy, where} from "firebase/firestore";
|
|
2
2
|
import FirebaseQuery from "./firebase/firebaseQuery";
|
|
3
|
-
import {CohortData, InstituteData, ProviderData, StudentPlacementData, UserData} from "./typeDefinitions";
|
|
4
|
-
import {getAccess} from "./firebase/util";
|
|
3
|
+
import {CohortData, InstituteData, OrganisationAddress, PlacementListing, ProviderData, RegistrationRequest, StudentPlacementData, UserData} from "./typeDefinitions";
|
|
4
|
+
import {camelCaseToNormal, capitaliseWords, dateToString, getAccess} from "./firebase/util";
|
|
5
5
|
import { convertDate } from "./firebase/util";
|
|
6
6
|
|
|
7
7
|
const firebaseQuery = new FirebaseQuery;
|
|
8
8
|
|
|
9
|
-
type InstituteTipNames = "createCohort"|"uploadStaff"|"assignStaffRoles"|"uploadPlacements"|"allowExternalPlacementUpload"|"uploadStaffGuidance"|"uploadStudentGuidance"
|
|
9
|
+
type InstituteTipNames = "createCohort"|"addSchools"|"uploadStaff"|"assignStaffRoles"|"uploadPlacements"|"allowExternalPlacementUpload"|"uploadStaffGuidance"|"uploadStudentGuidance"
|
|
10
10
|
type ProviderTipNames = string
|
|
11
11
|
type StudentTipNames = string
|
|
12
12
|
|
|
13
|
-
export type InstituteTaskNames = "missingParentEmail"|"verifyInsurance"|"verifyRiskAssessment"|"verifyDbsCheck"|"inactiveStudents"|"uploadStudents"|"inactiveStaff"|"requiredStage"|"approveExternalPlacement"|"overdueStage"
|
|
13
|
+
export type InstituteTaskNames = "missingParentEmail"|"outstandingReminders"|"invalidStaffEmails"|"invalidStudentEmails"|"invalidParentEmails"|"invalidProviderEmails"|"verifyInsurance"|"verifyRiskAssessment"|"verifyDbsCheck"|"inactiveStudents"|"uploadStudents"|"inactiveStaff"|"requiredStage"|"approveExternalPlacement"|"overdueStage"
|
|
14
14
|
export type StudentTaskNames = "completeOnboarding"
|
|
15
|
-
export type ProviderTaskNames = "applicationRequireReview"|"requestedVisiblePlacementListings"|"requestedVisibleAddresses"|"completeStudentDocs"|"reviewOnboarding"|"completeListing"|"completeAddress"|"registrationRequests"|"placementStarting"|"completeFeedback"|"setUpFeedback"
|
|
15
|
+
export type ProviderTaskNames = "applicationRequireReview"|"activateStaff"|"requestedVisiblePlacementListings"|"requestedVisibleAddresses"|"completeStudentDocs"|"uploadOnboarding"|"reviewOnboarding"|"completeListing"|"completeAddress"|"registrationRequests"|"placementStarting"|"completeFeedback"|"setUpFeedback"
|
|
16
16
|
|
|
17
17
|
// IF UPDATING LOGIC WITHIN THIS FILE, PLACEMENTT-BACKEND LOGIC MUST ALSO BE CHANGED ACCORDINGLY
|
|
18
18
|
|
|
@@ -34,7 +34,7 @@ type TasksObject = {
|
|
|
34
34
|
*/
|
|
35
35
|
type InstituteTipsObject = {
|
|
36
36
|
[key in InstituteTipNames]: {
|
|
37
|
-
callback: (user: UserData, organisation?:InstituteData|ProviderData) => Promise<TaskQueryReturnObject|TaskQueryReturnObject[]>,
|
|
37
|
+
callback: (user: UserData, organisation?:InstituteData|ProviderData, additional?:{[key: string]: OrganisationAddress}) => Promise<TaskQueryReturnObject|TaskQueryReturnObject[]>,
|
|
38
38
|
};
|
|
39
39
|
};
|
|
40
40
|
type ProviderTipsObject = {
|
|
@@ -69,6 +69,21 @@ const studentTips:StudentTipsObject = {}
|
|
|
69
69
|
|
|
70
70
|
|
|
71
71
|
const instituteTips:InstituteTipsObject = {
|
|
72
|
+
addSchools: {
|
|
73
|
+
callback: async (user, institute, schools) => {
|
|
74
|
+
if (!getAccess(user, "addSchools") || institute?.package !== "institutes-two") return;
|
|
75
|
+
if (Object.keys(schools as {[key: string]: OrganisationAddress}).length < 2) {
|
|
76
|
+
return {
|
|
77
|
+
title: "Add your schools",
|
|
78
|
+
message: "Add your schools. These will show up in the 'Cohorts' tab where you can assign cohorts of students to them.",
|
|
79
|
+
link: "/institutes/organisation/overview",
|
|
80
|
+
buttonTitle: "Add schools",
|
|
81
|
+
dismissible: true
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return;
|
|
85
|
+
},
|
|
86
|
+
},
|
|
72
87
|
createCohort: {
|
|
73
88
|
callback: async (user) => {
|
|
74
89
|
if (!getAccess(user, "createCohorts")) return;
|
|
@@ -183,9 +198,162 @@ const instituteTips:InstituteTipsObject = {
|
|
|
183
198
|
// Accept a cohort to any task
|
|
184
199
|
|
|
185
200
|
const instituteTasks:InstituteTaskObject = {
|
|
201
|
+
invalidStaffEmails: {
|
|
202
|
+
callback: async (user, organisation, cohort) => {
|
|
203
|
+
if (!getAccess(user, "viewStaff") || !Array.isArray(cohort)) return;
|
|
204
|
+
|
|
205
|
+
const staffCount = (await firebaseQuery.getCount(["users"], [where("oId", "==", user.oId), where("userType", "==", "Staff"), where("flags", "array-contains", "userEmailFailed")]));
|
|
206
|
+
if (staffCount > 0) {
|
|
207
|
+
return {
|
|
208
|
+
dismissible: false,
|
|
209
|
+
severity: "error",
|
|
210
|
+
title: `${staffCount} staff have invalid emails.`,
|
|
211
|
+
message: `${staffCount} staff accounts have invalid email addresses. Delete and reupload these users.`,
|
|
212
|
+
link: "/institutes/cohorts/staff/all",
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
return;
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
invalidStudentEmails: {
|
|
219
|
+
callback: async (user, organisation, cohorts) => {
|
|
220
|
+
if (!getAccess(user, "viewStudents") || user.viewStudents === "none") return;
|
|
221
|
+
|
|
222
|
+
if (!Array.isArray(cohorts)) {
|
|
223
|
+
const studentCount = (await firebaseQuery.getCount(["users"], [where("oId", "==", user.oId), where("userType", "==", "Students"), where("cohort", "==", cohorts.id), where("flags", "array-contains", "userEmailFailed")]));
|
|
224
|
+
if (studentCount > 0) {
|
|
225
|
+
return {
|
|
226
|
+
dismissible: false,
|
|
227
|
+
severity: "error",
|
|
228
|
+
title: `${studentCount} students have invalid emails.`,
|
|
229
|
+
message: `${studentCount} student accounts have invalid email addresses. Delete and reupload these users.`,
|
|
230
|
+
link: `/institutes/cohorts/${cohorts.id}/students`,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const items = await Promise.all(cohorts.map(async ([id, cohort]) => {
|
|
237
|
+
const studentCount = (await firebaseQuery.getCount(["users"], [where("oId", "==", user.oId), where("userType", "==", "Students"), where("cohort", "==", id), where("flags", "array-contains", "userEmailFailed")]));
|
|
238
|
+
if (studentCount > 0) {
|
|
239
|
+
return {
|
|
240
|
+
dismissible: false,
|
|
241
|
+
severity: "error",
|
|
242
|
+
title: `${studentCount} students have invalid emails.`,
|
|
243
|
+
message: `Your cohort, ${cohort.name}, has ${studentCount} student accounts with invalid email addresses. Delete and reupload these users.`,
|
|
244
|
+
link: `/institutes/cohorts/${id}/students`,
|
|
245
|
+
} as TaskQueryReturnObject;
|
|
246
|
+
}
|
|
247
|
+
return;
|
|
248
|
+
}));
|
|
249
|
+
return items.filter((v) => v);
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
outstandingReminders: {
|
|
253
|
+
callback: async (user, organisation, cohorts) => {
|
|
254
|
+
if (!Array.isArray(cohorts)) {
|
|
255
|
+
const reminderCount = (await firebaseQuery.getCount(["reminders"], [where("oId", "==", user.oId), where("uid", "==", user.id), where("dueDate", "<=", convertDate(new Date(), "dbstring") as string), where("cohort", "==", cohorts.id), where("status", "==", "upcoming")]));
|
|
256
|
+
if (reminderCount > 0) {
|
|
257
|
+
return {
|
|
258
|
+
dismissible: false,
|
|
259
|
+
severity: "primary",
|
|
260
|
+
title: `You have ${reminderCount} reminder${reminderCount > 1 ? "s" : ""}.`,
|
|
261
|
+
message: `You have ${reminderCount} outstanding placement reminder${reminderCount > 1 ? "s" : ""}. Click to view.`,
|
|
262
|
+
link: `/institutes/cohorts/${cohorts.id}/placements`,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const items = await Promise.all(cohorts.map(async ([id, cohort]) => {
|
|
269
|
+
const reminderCount = (await firebaseQuery.getCount(["reminders"], [where("oId", "==", user.oId), where("uid", "==", user.id), where("dueDate", "<=", convertDate(new Date(), "dbstring") as string), where("cohort", "==", id), where("status", "==", "upcoming")]));
|
|
270
|
+
if (reminderCount > 0) {
|
|
271
|
+
return {
|
|
272
|
+
dismissible: false,
|
|
273
|
+
severity: "primary",
|
|
274
|
+
title: `You have ${reminderCount} reminder${reminderCount > 1 ? "s" : ""}.`,
|
|
275
|
+
message: `Your cohort, ${cohort.name}, has ${reminderCount} outstanding placement reminder${reminderCount > 1 ? "s" : ""}. Click to view.`,
|
|
276
|
+
link: `/institutes/cohorts/${id}/placements`,
|
|
277
|
+
} as TaskQueryReturnObject;
|
|
278
|
+
}
|
|
279
|
+
return;
|
|
280
|
+
}));
|
|
281
|
+
return items.filter((v) => v);
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
invalidParentEmails: {
|
|
285
|
+
callback: async (user, _, cohorts) => {
|
|
286
|
+
if (!getAccess(user, "signOffPlacements") || user.viewStudents === "none") return;
|
|
287
|
+
|
|
288
|
+
if (!Array.isArray(cohorts)) {
|
|
289
|
+
const placementCount = (await firebaseQuery.getCount(["placements"], [where("oId", "==", user.oId), where("cohort", "==", cohorts.id), where("flags", "array-contains", "parentEmailFailed")]));
|
|
290
|
+
if (placementCount > 0) {
|
|
291
|
+
return {
|
|
292
|
+
dismissible: false,
|
|
293
|
+
severity: "error",
|
|
294
|
+
title: `${placementCount} placements have invalid parent emails.`,
|
|
295
|
+
message: `Your cohort '${cohorts.name}' has placements with invalid parent emails. Click to view these placements.`,
|
|
296
|
+
link: `/institutes/cohorts/${cohorts.id}/placements?id=upcoming`,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const items = await Promise.all(cohorts.map(async ([id, cohort]) => {
|
|
303
|
+
const placementCount = (await firebaseQuery.getCount(["placements"], [where("oId", "==", user.oId), where("cohort", "==", id), where("flags", "array-contains", "parentEmailFailed")]));
|
|
304
|
+
if (placementCount > 0) {
|
|
305
|
+
return {
|
|
306
|
+
dismissible: false,
|
|
307
|
+
severity: "error",
|
|
308
|
+
title: `${placementCount} placements in '${cohort.name}' have invalid parent emails.`,
|
|
309
|
+
message: `Your cohort '${cohort.name}' has placements with invalid parent emails. Click to view these placements.`,
|
|
310
|
+
link: `/institutes/cohorts/${id}/placements?id=upcoming`,
|
|
311
|
+
buttonTitle: "Review placements",
|
|
312
|
+
} as TaskQueryReturnObject;
|
|
313
|
+
}
|
|
314
|
+
return;
|
|
315
|
+
}));
|
|
316
|
+
return items.filter((v) => v);
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
invalidProviderEmails: {
|
|
320
|
+
callback: async (user, organisation, cohorts) => {
|
|
321
|
+
if (!getAccess(user, "signOffPlacements") || user.viewStudents === "none") return;
|
|
322
|
+
|
|
323
|
+
if (!Array.isArray(cohorts)) {
|
|
324
|
+
const placementCount = (await firebaseQuery.getCount(["placements"], [where("oId", "==", user.oId), where("cohort", "==", cohorts.id), where("flags", "array-contains", "providerEmailFailed")]));
|
|
325
|
+
if (placementCount > 0) {
|
|
326
|
+
return {
|
|
327
|
+
dismissible: false,
|
|
328
|
+
severity: "error",
|
|
329
|
+
title: `${placementCount} placements have invalid provider emails.`,
|
|
330
|
+
message: `Your cohort '${cohorts.name}' has placements with invalid provider emails. Click to view these placements.`,
|
|
331
|
+
link: `/institutes/cohorts/${cohorts.id}/placements?id=upcoming`,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const items = await Promise.all(cohorts.map(async ([id, cohort]) => {
|
|
338
|
+
const placementCount = (await firebaseQuery.getCount(["placements"], [where("oId", "==", user.oId), where("cohort", "==", id), where("flags", "array-contains", "providerEmailFailed")]));
|
|
339
|
+
if (placementCount > 0) {
|
|
340
|
+
return {
|
|
341
|
+
dismissible: false,
|
|
342
|
+
severity: "error",
|
|
343
|
+
title: `${placementCount} placements in '${cohort.name}' have invalid provider emails.`,
|
|
344
|
+
message: `Your cohort '${cohort.name}' has placements with invalid provider emails. Click to view these placements.`,
|
|
345
|
+
link: `/institutes/cohorts/${id}/placements?id=upcoming`,
|
|
346
|
+
buttonTitle: "Review placements",
|
|
347
|
+
} as TaskQueryReturnObject;
|
|
348
|
+
}
|
|
349
|
+
return;
|
|
350
|
+
}));
|
|
351
|
+
return items.filter((v) => v);
|
|
352
|
+
},
|
|
353
|
+
},
|
|
186
354
|
requiredStage: {
|
|
187
355
|
callback: async (user, _, cohorts) => {
|
|
188
|
-
if (!getAccess(user, "signOffPlacements")) return;
|
|
356
|
+
if (!getAccess(user, "signOffPlacements") || user.viewStudents === "none") return;
|
|
189
357
|
|
|
190
358
|
if (!Array.isArray(cohorts)) {
|
|
191
359
|
const placementCount = (await firebaseQuery.getCount(["placements"], [where("oId", "==", user.oId), where("cohort", "==", cohorts.id), where("reqUserType", "==", user.userType)]));
|
|
@@ -220,7 +388,7 @@ const instituteTasks:InstituteTaskObject = {
|
|
|
220
388
|
},
|
|
221
389
|
verifyInsurance: {
|
|
222
390
|
callback: async (user, _, cohorts) => {
|
|
223
|
-
if (!getAccess(user, "verifyInsurance")) return;
|
|
391
|
+
if (!getAccess(user, "verifyInsurance") || user.viewStudents === "none") return;
|
|
224
392
|
|
|
225
393
|
if (!Array.isArray(cohorts)) {
|
|
226
394
|
const placementCount = (await firebaseQuery.getCount(["placements"], [where("oId", "==", user.oId), where("cohort", "==", cohorts.id), where("insurance", "==", "awaitingReview")]));
|
|
@@ -255,7 +423,7 @@ const instituteTasks:InstituteTaskObject = {
|
|
|
255
423
|
},
|
|
256
424
|
verifyDbsCheck: {
|
|
257
425
|
callback: async (user, _, cohorts) => {
|
|
258
|
-
if (!getAccess(user, "verifyDbsChecks")) return;
|
|
426
|
+
if (!getAccess(user, "verifyDbsChecks") || user.viewStudents === "none") return;
|
|
259
427
|
|
|
260
428
|
if (!Array.isArray(cohorts)) {
|
|
261
429
|
const placementCount = (await firebaseQuery.getCount(["placements"], [where("oId", "==", user.oId), where("cohort", "==", cohorts.id), where("dbsCheck", "==", "awaitingReview")]));
|
|
@@ -290,7 +458,7 @@ const instituteTasks:InstituteTaskObject = {
|
|
|
290
458
|
},
|
|
291
459
|
verifyRiskAssessment: {
|
|
292
460
|
callback: async (user, _, cohorts) => {
|
|
293
|
-
if (!getAccess(user, "verifyRiskAssessments")) return;
|
|
461
|
+
if (!getAccess(user, "verifyRiskAssessments") || user.viewStudents === "none") return;
|
|
294
462
|
|
|
295
463
|
if (!Array.isArray(cohorts)) {
|
|
296
464
|
const placementCount = (await firebaseQuery.getCount(["placements"], [where("oId", "==", user.oId), where("cohort", "==", cohorts.id), where("riskAssessment", "==", "awaitingReview")]));
|
|
@@ -325,7 +493,7 @@ const instituteTasks:InstituteTaskObject = {
|
|
|
325
493
|
},
|
|
326
494
|
missingParentEmail: {
|
|
327
495
|
callback: async (user, _, cohorts) => {
|
|
328
|
-
if (!getAccess(user, "editStudents")) return;
|
|
496
|
+
if (!getAccess(user, "editStudents") || user.viewStudents === "none") return;
|
|
329
497
|
if (!Array.isArray(cohorts)) {
|
|
330
498
|
const requiresParents = Boolean(cohorts.workflow.find((node) => node.userType === "Parent"))
|
|
331
499
|
if (!requiresParents) return;
|
|
@@ -372,7 +540,7 @@ const instituteTasks:InstituteTaskObject = {
|
|
|
372
540
|
},
|
|
373
541
|
inactiveStudents: {
|
|
374
542
|
callback: async (user, _, cohorts) => {
|
|
375
|
-
if (!getAccess(user, "activateStudents")) return;
|
|
543
|
+
if (!getAccess(user, "activateStudents") || user.viewStudents === "none") return;
|
|
376
544
|
if (!Array.isArray(cohorts)) {
|
|
377
545
|
const constraints = [where("oId", "==", user.oId), where("cohort", "==", cohorts.id), where("status", "==", "inactive")];
|
|
378
546
|
|
|
@@ -406,7 +574,7 @@ const instituteTasks:InstituteTaskObject = {
|
|
|
406
574
|
title: `${studentCount} students in '${cohort.name}' are inactive.`,
|
|
407
575
|
message: `Your cohort '${cohort.name}' has inactive students. Activate them to enable them to use the platform.`,
|
|
408
576
|
link: `/institutes/cohorts/${cohort.id}/students?status=inactive`,
|
|
409
|
-
buttonTitle: "Review
|
|
577
|
+
buttonTitle: "Review students",
|
|
410
578
|
} as TaskQueryReturnObject;
|
|
411
579
|
}
|
|
412
580
|
return;
|
|
@@ -417,7 +585,7 @@ const instituteTasks:InstituteTaskObject = {
|
|
|
417
585
|
uploadStudents: {
|
|
418
586
|
callback: async (user, _, cohorts) => {
|
|
419
587
|
if (!Array.isArray(cohorts)) return;
|
|
420
|
-
if (!getAccess(user, "addStudents")) return;
|
|
588
|
+
if (!getAccess(user, "addStudents") || user.viewStudents === "none") return;
|
|
421
589
|
if (user.product !== "institutes") return;
|
|
422
590
|
const returnObj: TaskQueryReturnObject = {
|
|
423
591
|
link: "",
|
|
@@ -493,13 +661,12 @@ const studentTasks:StudentTaskObject = {
|
|
|
493
661
|
completeOnboarding: {
|
|
494
662
|
callback: async (user) => {
|
|
495
663
|
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
664
|
if (Object.keys(placementsWithoutOnboarding).length === 0) return;
|
|
498
665
|
const items = Object.entries(placementsWithoutOnboarding).map(([k, placement]) => ({
|
|
499
666
|
dismissible: false,
|
|
500
667
|
severity: "primary",
|
|
501
|
-
title: `Complete
|
|
502
|
-
message:
|
|
668
|
+
title: `Complete onboarding for ${placement.name}`,
|
|
669
|
+
message: `Review onboarding for your placement starting on ${convertDate(placement.startDate, "visual")}`,
|
|
503
670
|
link: `/${user.product}/placements/${k}`,
|
|
504
671
|
buttonTitle: "View onboarding",
|
|
505
672
|
} as TaskQueryReturnObject))
|
|
@@ -511,10 +678,11 @@ const studentTasks:StudentTaskObject = {
|
|
|
511
678
|
const providerTasks:ProviderTaskObject = {
|
|
512
679
|
requestedVisibleAddresses: {
|
|
513
680
|
callback: async (user) => {
|
|
514
|
-
|
|
681
|
+
if (!getAccess(user, "addStaff")) return;
|
|
682
|
+
const accessRequests = await firebaseQuery.getCount("users", [where("oId", "==", user.oId), where("product", "==", "providers"), orderBy("requestedVisibleAddresses")]) - ((Array.isArray(user?.requestedVisibleAddresses) && user?.requestedVisibleAddresses.length > 0) ? 1 : 0);
|
|
515
683
|
if (accessRequests === 0) return;
|
|
516
684
|
if (accessRequests === 1) {
|
|
517
|
-
const userRequestingAccess = Object.entries(await firebaseQuery.getDocsWhere("users", [where("
|
|
685
|
+
const userRequestingAccess = Object.entries(await firebaseQuery.getDocsWhere("users", [where("product", "==", "providers"), where("oId", "==", user.oId), orderBy("requestedVisibleAddresses")]) || {})[0] as [string, UserData];
|
|
518
686
|
return {
|
|
519
687
|
dismissible: false,
|
|
520
688
|
severity: "primary",
|
|
@@ -537,7 +705,8 @@ const providerTasks:ProviderTaskObject = {
|
|
|
537
705
|
},
|
|
538
706
|
requestedVisiblePlacementListings: {
|
|
539
707
|
callback: async (user) => {
|
|
540
|
-
|
|
708
|
+
if (!getAccess(user, "addStaff")) return;
|
|
709
|
+
const accessRequests = await firebaseQuery.getCount("users", [where("oId", "==", user.oId), where("product", "==", "providers"), orderBy("requestedVisibleListings")])- ((Array.isArray(user?.requestedVisibleListings) && user?.requestedVisibleListings.length > 0) ? 1 : 0);;
|
|
541
710
|
if (accessRequests === 0) return;
|
|
542
711
|
if (accessRequests === 1) {
|
|
543
712
|
const userRequestingAccess = Object.entries(await firebaseQuery.getDocsWhere("users", [where("oId", "==", user.oId), where("product", "==", "providers"), orderBy("requestedVisibleListings")]) || {})[0] as [string, UserData];
|
|
@@ -563,7 +732,26 @@ const providerTasks:ProviderTaskObject = {
|
|
|
563
732
|
},
|
|
564
733
|
applicationRequireReview: {
|
|
565
734
|
callback: async (user) => {
|
|
566
|
-
const
|
|
735
|
+
const constraints = [where("providerId", "==", user.oId), where("reqUserType", "==", "Staff"), where("status", "==", "submitted")];
|
|
736
|
+
|
|
737
|
+
if (user.userGroup !== "admin") {
|
|
738
|
+
|
|
739
|
+
if (!user.viewPlacementListings || user.viewPlacementListings === "none") return;
|
|
740
|
+
if (!user.viewAddresses || user.viewAddresses === "none") return;
|
|
741
|
+
|
|
742
|
+
if (user.viewPlacementListings === "request") {
|
|
743
|
+
if (!user.visibleListings || user.visibleListings?.length === 0) return;
|
|
744
|
+
constraints.push(where("listingId", 'in', user.visibleListings));
|
|
745
|
+
} else {
|
|
746
|
+
// viewPlacementListings must be 'all'
|
|
747
|
+
|
|
748
|
+
if (user.viewAddresses === "request") {
|
|
749
|
+
if (!user.visibleAddresses || user.visibleAddresses?.length === 0) return;
|
|
750
|
+
constraints.push(where("addressId", 'in', user.visibleAddresses));
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
const applicationCount = await firebaseQuery.getCount("applications", constraints);
|
|
567
755
|
if (applicationCount === 0) return;
|
|
568
756
|
|
|
569
757
|
return {
|
|
@@ -578,47 +766,319 @@ const providerTasks:ProviderTaskObject = {
|
|
|
578
766
|
},
|
|
579
767
|
completeStudentDocs: {
|
|
580
768
|
callback: async (user) => {
|
|
769
|
+
return;
|
|
581
770
|
return {} as TaskQueryReturnObject;
|
|
582
771
|
},
|
|
583
772
|
},
|
|
584
773
|
reviewOnboarding: {
|
|
585
774
|
callback: async (user) => {
|
|
586
|
-
|
|
775
|
+
const constraints = [where("providerId", "==", user.oId), where("onboarding.completed.accepted", "==", false), where("onboarding.completed.submitted", "==", true), where("endDate", ">=", dateToString(new Date()))]
|
|
776
|
+
|
|
777
|
+
if (user.userGroup !== "admin") {
|
|
778
|
+
|
|
779
|
+
if (!user.viewPlacementListings || user.viewPlacementListings === "none") return;
|
|
780
|
+
if (!user.viewAddresses || user.viewAddresses === "none") return;
|
|
781
|
+
|
|
782
|
+
if (user.viewPlacementListings === "request") {
|
|
783
|
+
if (!user.visibleListings || user.visibleListings?.length === 0) return;
|
|
784
|
+
constraints.push(where("placementId", 'in', user.visibleListings));
|
|
785
|
+
} else {
|
|
786
|
+
// viewPlacementListings must be 'all'
|
|
787
|
+
|
|
788
|
+
if (user.viewAddresses === "request") {
|
|
789
|
+
if (!user.visibleAddresses || user.visibleAddresses?.length === 0) return;
|
|
790
|
+
constraints.push(where("addressId", 'in', user.visibleAddresses));
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
const toReview = await firebaseQuery.getCount("placements", constraints);
|
|
795
|
+
|
|
796
|
+
if (toReview === 0) return;
|
|
797
|
+
if (toReview === 1) {
|
|
798
|
+
const placement = Object.entries(await firebaseQuery.getDocsWhere("placements", constraints) || {})[0] as [string, StudentPlacementData];
|
|
799
|
+
const student = await firebaseQuery.getDocData(["users", placement[1].uid]) as UserData;
|
|
800
|
+
return {
|
|
801
|
+
dismissible: false,
|
|
802
|
+
severity: "primary",
|
|
803
|
+
title: `${student.details.forename} ${student.details.surname} has completed their onboarding for their placement from ${convertDate(placement[1].startDate, "visual")} to ${convertDate(placement[1].endDate, "visual")}`,
|
|
804
|
+
message: `Click to view the placement and review the onboarding.`,
|
|
805
|
+
link: `/${user.product}/placements/${placement[0]}`,
|
|
806
|
+
buttonTitle: "View",
|
|
807
|
+
} as TaskQueryReturnObject;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
return {
|
|
811
|
+
dismissible: false,
|
|
812
|
+
severity: "primary",
|
|
813
|
+
title: `${toReview} student have completed their onboarding.`,
|
|
814
|
+
message: `Click to view your placements and approve completed onboarding`,
|
|
815
|
+
link: `/${user.product}/placementListings/placements`,
|
|
816
|
+
buttonTitle: "View placements",
|
|
817
|
+
} as TaskQueryReturnObject;
|
|
818
|
+
},
|
|
819
|
+
},
|
|
820
|
+
uploadOnboarding: {
|
|
821
|
+
callback: async (user) => {
|
|
822
|
+
|
|
823
|
+
const constraints = [where("providerId", "==", user.oId), where("onboarding", "==", null), where("endDate", ">=", dateToString(new Date()))];
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
if (user.userGroup !== "admin") {
|
|
827
|
+
|
|
828
|
+
if (!user.viewPlacementListings || user.viewPlacementListings === "none") return;
|
|
829
|
+
if (!user.viewAddresses || user.viewAddresses === "none") return;
|
|
830
|
+
|
|
831
|
+
if (user.viewPlacementListings === "request") {
|
|
832
|
+
if (!user.visibleListings || user.visibleListings?.length === 0) return;
|
|
833
|
+
constraints.push(where("placementId", 'in', user.visibleListings));
|
|
834
|
+
} else {
|
|
835
|
+
// viewPlacementListings must be 'all'
|
|
836
|
+
|
|
837
|
+
if (user.viewAddresses === "request") {
|
|
838
|
+
if (!user.visibleAddresses || user.visibleAddresses?.length === 0) return;
|
|
839
|
+
constraints.push(where("addressId", 'in', user.visibleAddresses));
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
const withoutOnboarding = await firebaseQuery.getCount("placements", constraints);
|
|
845
|
+
|
|
846
|
+
if (withoutOnboarding === 0) return;
|
|
847
|
+
if (withoutOnboarding === 1) {
|
|
848
|
+
const placement = Object.entries(await firebaseQuery.getDocsWhere("placements", constraints) || {})[0] as [string, StudentPlacementData];
|
|
849
|
+
const student = await firebaseQuery.getDocData(["users", placement[1].uid]) as UserData;
|
|
850
|
+
return {
|
|
851
|
+
dismissible: false,
|
|
852
|
+
severity: "primary",
|
|
853
|
+
title: `Send onboarding documents to ${student.details.forename} ${student.details.surname}'s placement from ${convertDate(placement[1].startDate, "visual")} to ${convertDate(placement[1].endDate, "visual")}`,
|
|
854
|
+
message: `Click to view the placement and add or dismiss onboarding reminders.`,
|
|
855
|
+
link: `/${user.product}/placements/${placement[0]}`,
|
|
856
|
+
buttonTitle: "View",
|
|
857
|
+
} as TaskQueryReturnObject;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
return {
|
|
861
|
+
dismissible: false,
|
|
862
|
+
severity: "primary",
|
|
863
|
+
title: `Set up onboarding for ${withoutOnboarding} placements to prepare yourself and your students.`,
|
|
864
|
+
message: `Click to view your placements and add or dismiss onboarding reminders.`,
|
|
865
|
+
link: `/${user.product}/placementListings/placements`,
|
|
866
|
+
buttonTitle: "View placements",
|
|
867
|
+
} as TaskQueryReturnObject;
|
|
587
868
|
},
|
|
588
869
|
},
|
|
589
870
|
completeListing: {
|
|
590
871
|
callback: async (user) => {
|
|
591
|
-
|
|
872
|
+
const constraints = [where("providerId", "==", user.oId), where("status", "==", "draft")];
|
|
873
|
+
|
|
874
|
+
|
|
875
|
+
if (user.userGroup !== "admin") {
|
|
876
|
+
|
|
877
|
+
if (!user.viewPlacementListings || user.viewPlacementListings === "none") return;
|
|
878
|
+
if (!user.viewAddresses || user.viewAddresses === "none") return;
|
|
879
|
+
|
|
880
|
+
if (user.viewPlacementListings === "request") {
|
|
881
|
+
if (!user.visibleListings || user.visibleListings?.length === 0) return;
|
|
882
|
+
constraints.push(where(documentId(), 'in', user.visibleListings));
|
|
883
|
+
} else {
|
|
884
|
+
// viewPlacementListings must be 'all'
|
|
885
|
+
|
|
886
|
+
if (user.viewAddresses === "request") {
|
|
887
|
+
if (!user.visibleAddresses || user.visibleAddresses?.length === 0) return;
|
|
888
|
+
constraints.push(where("addressId", 'in', user.visibleAddresses));
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
const incompleteListings = await firebaseQuery.getCount("placementListings", constraints);
|
|
893
|
+
if (incompleteListings === 0) return;
|
|
894
|
+
if (incompleteListings === 1) {
|
|
895
|
+
const incompleteListing = Object.entries(await firebaseQuery.getDocsWhere("placementListings", constraints) || {})[0] as [string, PlacementListing];
|
|
896
|
+
const address = incompleteListing[1].addressId ? await firebaseQuery.getDocData(["addresses", incompleteListing[1].addressId]) as OrganisationAddress : undefined;
|
|
897
|
+
return {
|
|
898
|
+
dismissible: false,
|
|
899
|
+
severity: "info",
|
|
900
|
+
title: `Your listing '${incompleteListing[1].title || "unnamed"}' at ${address ? `${address["address-line1"]}, ${address.postal_code.toUpperCase()}, ${capitaliseWords(camelCaseToNormal(address.country))}` : "unknown address"} requires more information before publishing.`,
|
|
901
|
+
message: `Click to complete and publish the placement listing.`,
|
|
902
|
+
link: `/${user.product}/addListing/${incompleteListing[0]}`,
|
|
903
|
+
buttonTitle: "View listing",
|
|
904
|
+
} as TaskQueryReturnObject;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
return {
|
|
908
|
+
dismissible: false,
|
|
909
|
+
severity: "info",
|
|
910
|
+
title: `You have ${incompleteListings} draft listings waiting to be published.`,
|
|
911
|
+
message: `Click to review and publish the placement listings.`,
|
|
912
|
+
link: `/${user.product}/placementListings/listings`,
|
|
913
|
+
buttonTitle: "View listings",
|
|
914
|
+
} as TaskQueryReturnObject;
|
|
592
915
|
},
|
|
593
916
|
},
|
|
594
917
|
completeAddress: {
|
|
595
918
|
callback: async (user) => {
|
|
596
|
-
|
|
919
|
+
const constraints = [where("product", "==", "providers"), where("oId", "==", user.oId), where("stage", "!=", "complete")];
|
|
920
|
+
|
|
921
|
+
|
|
922
|
+
if (user.userGroup !== "admin") {
|
|
923
|
+
if (!user.viewAddresses || user.viewAddresses === "none") return;
|
|
924
|
+
|
|
925
|
+
if (user.viewAddresses === "request") {
|
|
926
|
+
if (!user.visibleAddresses || user.visibleAddresses?.length === 0) return;
|
|
927
|
+
constraints.push(where("addressId", 'in', user.visibleAddresses));
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
const incompleteAddresses = await firebaseQuery.getCount("addresses", constraints);
|
|
931
|
+
if (incompleteAddresses === 0) return;
|
|
932
|
+
if (incompleteAddresses === 1) {
|
|
933
|
+
const address = Object.entries(await firebaseQuery.getDocsWhere("addresses", constraints) || {})[0] as [string, OrganisationAddress];
|
|
934
|
+
return {
|
|
935
|
+
dismissible: false,
|
|
936
|
+
severity: "info",
|
|
937
|
+
title: `Your address: ${address[1]["address-line1"]}, ${address[1].postal_code.toUpperCase()}, ${capitaliseWords(camelCaseToNormal(address[1].country))} is currently incomplete.`,
|
|
938
|
+
message: `Click to complete the addresses.`,
|
|
939
|
+
link: `/${user.product}/addAddress/${address[0]}`,
|
|
940
|
+
buttonTitle: "View address",
|
|
941
|
+
} as TaskQueryReturnObject;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
return {
|
|
945
|
+
dismissible: false,
|
|
946
|
+
severity: "info",
|
|
947
|
+
title: `You have ${incompleteAddresses} draft addresses waiting to be published.`,
|
|
948
|
+
message: `Click to review the addresses.`,
|
|
949
|
+
link: `/${user.product}/organisation/addresses`,
|
|
950
|
+
buttonTitle: "View addresses",
|
|
951
|
+
} as TaskQueryReturnObject;
|
|
597
952
|
},
|
|
598
953
|
},
|
|
599
954
|
registrationRequests: {
|
|
600
955
|
callback: async (user) => {
|
|
601
|
-
|
|
956
|
+
if (!getAccess(user, "addStaff")) return;
|
|
957
|
+
|
|
958
|
+
const regRequests = await firebaseQuery.getCount("requests", [where("product", "==", user.product), where("oId", "==", user.oId)]);
|
|
959
|
+
|
|
960
|
+
if (regRequests === 0) return;
|
|
961
|
+
if (regRequests === 1) {
|
|
962
|
+
const request = Object.entries(await firebaseQuery.getDocsWhere("requests", [where("product", "==", user.product), where("oId", "==", user.oId)]) || {})[0] as [string, RegistrationRequest];
|
|
963
|
+
return {
|
|
964
|
+
dismissible: false,
|
|
965
|
+
severity: "primary",
|
|
966
|
+
title: `${request[1].forename} ${request[1].surname} has requested to access your organisation.`,
|
|
967
|
+
message: `Click to review these request.`,
|
|
968
|
+
link: `/${user.product}/organisation/staff/requests`,
|
|
969
|
+
buttonTitle: "View requests",
|
|
970
|
+
} as TaskQueryReturnObject;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
return {
|
|
974
|
+
dismissible: false,
|
|
975
|
+
severity: "primary",
|
|
976
|
+
title: `${regRequests} people have requested to register with your organisation.`,
|
|
977
|
+
message: `Click to review these requests.`,
|
|
978
|
+
link: `/${user.product}/organisation/staff/requests`,
|
|
979
|
+
buttonTitle: "View requests",
|
|
980
|
+
} as TaskQueryReturnObject;
|
|
981
|
+
},
|
|
982
|
+
},
|
|
983
|
+
activateStaff: {
|
|
984
|
+
callback: async (user) => {
|
|
985
|
+
if (!getAccess(user, "addStaff")) return;
|
|
986
|
+
|
|
987
|
+
const inactiveAccounts = await firebaseQuery.getCount("users", [where("product", "==", user.product), where("oId", "==", user.oId), where("status", "==", "inactive")]);
|
|
988
|
+
|
|
989
|
+
if (inactiveAccounts === 0) return;
|
|
990
|
+
if (inactiveAccounts === 1) {
|
|
991
|
+
const account = Object.entries(await firebaseQuery.getDocsWhere("users", [where("product", "==", user.product), where("oId", "==", user.oId), where("status", "==", "inactive")]) || {})[0] as [string, UserData];
|
|
992
|
+
return {
|
|
993
|
+
dismissible: false,
|
|
994
|
+
severity: "info",
|
|
995
|
+
title: `Activate ${account[1].details.forename} ${account[1].details.surname}'s staff account.`,
|
|
996
|
+
message: "Activate this account to give the user access to Placementt.",
|
|
997
|
+
link: `/${user.product}/organisation/staff/all`,
|
|
998
|
+
buttonTitle: "View accounts",
|
|
999
|
+
} as TaskQueryReturnObject;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
return {
|
|
1003
|
+
dismissible: false,
|
|
1004
|
+
severity: "info",
|
|
1005
|
+
title: `${inactiveAccounts} staff have inactive active accounts.`,
|
|
1006
|
+
message: "Activate these accounts to give the user access to Placementt.",
|
|
1007
|
+
link: `/${user.product}/organisation/staff/all`,
|
|
1008
|
+
buttonTitle: "View accounts",
|
|
1009
|
+
} as TaskQueryReturnObject;
|
|
602
1010
|
},
|
|
603
1011
|
},
|
|
604
1012
|
placementStarting: {
|
|
605
1013
|
callback: async (user) => {
|
|
606
|
-
|
|
1014
|
+
const sevenDaysInFuture = new Date();
|
|
1015
|
+
sevenDaysInFuture.setDate(sevenDaysInFuture.getDate() + 7)
|
|
1016
|
+
|
|
1017
|
+
const constraints = [where("providerId", "==", user.oId), where("startDate", "<=", convertDate(sevenDaysInFuture, "dbstring")), where("startDate", ">", dateToString(new Date()))];
|
|
1018
|
+
|
|
1019
|
+
if (user.userGroup !== "admin") {
|
|
1020
|
+
|
|
1021
|
+
if (!user.viewPlacementListings || user.viewPlacementListings === "none") return;
|
|
1022
|
+
if (!user.viewAddresses || user.viewAddresses === "none") return;
|
|
1023
|
+
|
|
1024
|
+
if (user.viewPlacementListings === "request") {
|
|
1025
|
+
if (!user.visibleListings || user.visibleListings?.length === 0) return;
|
|
1026
|
+
constraints.push(where(documentId(), 'in', user.visibleListings));
|
|
1027
|
+
} else {
|
|
1028
|
+
// viewPlacementListings must be 'all'
|
|
1029
|
+
|
|
1030
|
+
if (user.viewAddresses === "request") {
|
|
1031
|
+
if (!user.visibleAddresses || user.visibleAddresses?.length === 0) return;
|
|
1032
|
+
constraints.push(where("addressId", 'in', user.visibleAddresses));
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
const placementsStartingSoon = await firebaseQuery.getCount("placements", constraints);
|
|
1037
|
+
|
|
1038
|
+
if (placementsStartingSoon === 0) return;
|
|
1039
|
+
if (placementsStartingSoon === 1) {
|
|
1040
|
+
const placement = Object.entries(await firebaseQuery.getDocsWhere("placements", constraints) || {})[0] as [string, StudentPlacementData];
|
|
1041
|
+
const student = placement[1].uid ? await firebaseQuery.getDocData(["users", placement[1].uid]) as UserData : {
|
|
1042
|
+
details: {
|
|
1043
|
+
forename: placement[1].studentForename,
|
|
1044
|
+
surname: placement[1].studentSurname,
|
|
1045
|
+
}
|
|
1046
|
+
};
|
|
1047
|
+
return {
|
|
1048
|
+
dismissible: false,
|
|
1049
|
+
severity: "success",
|
|
1050
|
+
title: `${student.details.forename} ${student.details.surname}'s placement from ${convertDate(placement[1].startDate, "visual")} to ${convertDate(placement[1].endDate, "visual")} is starting in less than a week.`,
|
|
1051
|
+
message: `Click to view the placement and acquaint yourself with the student.`,
|
|
1052
|
+
link: `/${user.product}/placements/${placement[0]}`,
|
|
1053
|
+
buttonTitle: "View",
|
|
1054
|
+
} as TaskQueryReturnObject;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
return {
|
|
1058
|
+
dismissible: false,
|
|
1059
|
+
severity: "success",
|
|
1060
|
+
title: `${placementsStartingSoon} placements starting soon.`,
|
|
1061
|
+
message: `Click to view scheduled placements.`,
|
|
1062
|
+
link: `/${user.product}/placementListings/placements`,
|
|
1063
|
+
buttonTitle: "View placements",
|
|
1064
|
+
} as TaskQueryReturnObject;
|
|
607
1065
|
},
|
|
608
1066
|
},
|
|
609
1067
|
completeFeedback: {
|
|
610
1068
|
callback: async (user) => {
|
|
1069
|
+
return;
|
|
611
1070
|
return {} as TaskQueryReturnObject;
|
|
612
1071
|
},
|
|
613
1072
|
},
|
|
614
1073
|
setUpFeedback: {
|
|
615
1074
|
callback: async (user) => {
|
|
1075
|
+
return;
|
|
616
1076
|
return {} as TaskQueryReturnObject;
|
|
617
1077
|
},
|
|
618
1078
|
},
|
|
619
1079
|
}
|
|
620
1080
|
|
|
621
|
-
export const getTips = async (user: UserData, organisation: InstituteData|ProviderData):Promise<(TaskQueryReturnObject)[]> => {
|
|
1081
|
+
export const getTips = async (user: UserData, organisation: InstituteData|ProviderData, addresses?: {[key: string]: OrganisationAddress}):Promise<(TaskQueryReturnObject)[]> => {
|
|
622
1082
|
const tipsObject = {
|
|
623
1083
|
providers: providerTips,
|
|
624
1084
|
institutes: instituteTips,
|
|
@@ -627,9 +1087,14 @@ export const getTips = async (user: UserData, organisation: InstituteData|Provid
|
|
|
627
1087
|
const includedItems = Object.entries(tipsObject[user.product]).filter(([k]) => !user.dismissedTips?.includes(k));
|
|
628
1088
|
|
|
629
1089
|
const processedTips = await includedItems.reduce(async (acc, [itemName, item]) => {
|
|
1090
|
+
const callbackParams:[UserData, InstituteData|ProviderData] = [user, organisation];
|
|
1091
|
+
|
|
1092
|
+
if ((itemName === "addAddresses" || itemName === "addSchools") && addresses) {
|
|
1093
|
+
callbackParams.push(addresses as any);
|
|
1094
|
+
}
|
|
630
1095
|
const queryResult = await (item as {
|
|
631
1096
|
callback: (user: UserData, organisation?:InstituteData|ProviderData) => Promise<TaskQueryReturnObject|TaskQueryReturnObject[]>,
|
|
632
|
-
}).callback(
|
|
1097
|
+
}).callback(...callbackParams);
|
|
633
1098
|
if (!queryResult) return await acc;
|
|
634
1099
|
|
|
635
1100
|
const queryResultArray = Array.isArray(queryResult) ? queryResult : [queryResult];
|
|
@@ -697,7 +1162,7 @@ const getInstituteTasks = async (user: UserData, organisation: InstituteData|Pro
|
|
|
697
1162
|
fCohort = Object.entries(cohorts);
|
|
698
1163
|
}
|
|
699
1164
|
if (user.viewCohorts === "some") {
|
|
700
|
-
const cohorts = await user.visibleCohorts?.
|
|
1165
|
+
const cohorts = await user.visibleCohorts?.reduce(async (acc, cohortId) => {
|
|
701
1166
|
const cohort = await firebaseQuery.getDocData(["cohorts", cohortId]) as CohortData;
|
|
702
1167
|
if (cohort.stage !== "created") {
|
|
703
1168
|
return acc;
|