placementt-core 11.0.533 → 11.0.892
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 +23 -12
- 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 +277 -192
- package/lib/hooks.js +1437 -704
- package/lib/hooks.js.map +1 -1
- package/lib/reduxHooks.d.ts +122 -5
- package/lib/reduxHooks.js +132 -29
- package/lib/reduxHooks.js.map +1 -1
- package/lib/tasksAndTips.d.ts +19 -7
- package/lib/tasksAndTips.js +637 -164
- package/lib/tasksAndTips.js.map +1 -1
- package/lib/typeDefinitions.d.ts +321 -110
- package/lib/util.d.ts +15 -3
- package/lib/util.js +47 -10
- package/lib/util.js.map +1 -1
- package/package.json +7 -4
- 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 +26 -15
- 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 +1804 -935
- package/src/reduxHooks.ts +144 -32
- package/src/tasksAndTips.ts +689 -166
- package/src/typeDefinitions.ts +373 -109
- package/src/util.ts +63 -18
package/lib/hooks.js
CHANGED
|
@@ -5,23 +5,28 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.useRefDimensions = void 0;
|
|
7
7
|
exports.useStudentPlacementList = useStudentPlacementList;
|
|
8
|
-
exports.useNewInstitutePlacementList = useNewInstitutePlacementList;
|
|
9
8
|
exports.useOldInstitutePlacementList = useOldInstitutePlacementList;
|
|
9
|
+
exports.useNewInstitutePlacementList = useNewInstitutePlacementList;
|
|
10
|
+
exports.useAlumniPaginator = useAlumniPaginator;
|
|
11
|
+
exports.useVeryOldInstitutePlacementList = useVeryOldInstitutePlacementList;
|
|
10
12
|
exports.useFilterTablePaginator = useFilterTablePaginator;
|
|
11
|
-
exports.
|
|
13
|
+
exports.useProviderContactPaginator = useProviderContactPaginator;
|
|
12
14
|
exports.useCohortUserPaginator = useCohortUserPaginator;
|
|
13
15
|
exports.useAdmissionsPaginator = useAdmissionsPaginator;
|
|
14
16
|
exports.useLazyLoadQueryList = useLazyLoadQueryList;
|
|
15
|
-
exports.usePublicPlacementListingLoader = usePublicPlacementListingLoader;
|
|
16
|
-
exports.useCreateApplicationRenderer = useCreateApplicationRenderer;
|
|
17
17
|
exports.useProposePlacementRenderer = useProposePlacementRenderer;
|
|
18
18
|
exports.useCreateCohortRenderer = useCreateCohortRenderer;
|
|
19
19
|
exports.useUserUploadHandler = useUserUploadHandler;
|
|
20
20
|
exports.useWorkflowEditor = useWorkflowEditor;
|
|
21
21
|
exports.useApplicantWorkflowEditor = useApplicantWorkflowEditor;
|
|
22
|
-
exports.
|
|
22
|
+
exports.useInstituteProviderContactsHandler = useInstituteProviderContactsHandler;
|
|
23
23
|
exports.useGetIndividualPlacementForPlacementPage = useGetIndividualPlacementForPlacementPage;
|
|
24
24
|
exports.useOnboardingPopup = useOnboardingPopup;
|
|
25
|
+
exports.useLoadAddresses = useLoadAddresses;
|
|
26
|
+
exports.useLoadListings = useLoadListings;
|
|
27
|
+
exports.useLoadProviderPlacements = useLoadProviderPlacements;
|
|
28
|
+
exports.useLoadApplications = useLoadApplications;
|
|
29
|
+
exports.useDataViewerPaginator = useDataViewerPaginator;
|
|
25
30
|
const firestore_1 = require("firebase/firestore");
|
|
26
31
|
const react_1 = require("react");
|
|
27
32
|
const constants_1 = require("./constants");
|
|
@@ -60,19 +65,19 @@ function useStudentPlacementList({ user, student, queryConstraint, ql = DEFAULTQ
|
|
|
60
65
|
setStudentId(student.id);
|
|
61
66
|
return;
|
|
62
67
|
}
|
|
63
|
-
if (!user.viewCohorts || !user.
|
|
68
|
+
if (!user.viewCohorts || !user.viewStudents || user.viewCohorts === "none") {
|
|
64
69
|
setStudentId(undefined);
|
|
65
70
|
return;
|
|
66
71
|
}
|
|
67
|
-
if (user.viewCohorts === "all" && user.
|
|
72
|
+
if (user.viewCohorts === "all" && user.viewStudents == "all") {
|
|
68
73
|
setStudentId(student.id);
|
|
69
74
|
}
|
|
70
|
-
if (user.viewCohorts === "some" && ((_a = user.visibleCohorts) === null || _a === void 0 ? void 0 : _a.
|
|
71
|
-
if (user.
|
|
75
|
+
if (user.viewCohorts === "some" && ((_a = user.visibleCohorts) === null || _a === void 0 ? void 0 : _a.includes(student.cohort || ""))) {
|
|
76
|
+
if (user.viewStudents === "all") {
|
|
72
77
|
setStudentId(student.id);
|
|
73
78
|
return;
|
|
74
79
|
}
|
|
75
|
-
if ((_b = user.studentFilterValues) === null || _b === void 0 ? void 0 : _b.
|
|
80
|
+
if ((_b = user.studentFilterValues) === null || _b === void 0 ? void 0 : _b.includes(student.details[user.studentFilter || ""])) {
|
|
76
81
|
setStudentId(student.id);
|
|
77
82
|
return;
|
|
78
83
|
}
|
|
@@ -121,7 +126,7 @@ function useStudentPlacementList({ user, student, queryConstraint, ql = DEFAULTQ
|
|
|
121
126
|
};
|
|
122
127
|
return ({ ...{ placements, loadMoreIcon, loadMorePlacements, setQuery, setInitialQueryLimit, reset, changeQueryConstraints } });
|
|
123
128
|
}
|
|
124
|
-
function
|
|
129
|
+
function useOldInstitutePlacementList({ id, user, cohort, queryConstraint, ql = DEFAULTQUERYLIMIT, inProgress }) {
|
|
125
130
|
const [loadMoreIcon, setLoadMoreIcon] = (0, react_1.useState)(true);
|
|
126
131
|
const [query, setQuery] = (0, react_1.useState)();
|
|
127
132
|
const [initialQueryLimit, setInitialQueryLimit] = (0, react_1.useState)(ql);
|
|
@@ -131,7 +136,6 @@ function useNewInstitutePlacementList({ id, user, cohort, queryConstraint, ql =
|
|
|
131
136
|
const [startPlacementAfter, setStartPlacementAfter] = (0, react_1.useState)(); // uid, pId
|
|
132
137
|
const algoliaClient = (0, algoliasearch_1.default)(process.env.NODE_ENV === "development" ? "A0ZB50I7VS" : "XMPXCMUUOJ", user.algoliaKey);
|
|
133
138
|
const placementsIndex = algoliaClient.initIndex("placements");
|
|
134
|
-
const usersIndex = algoliaClient.initIndex("users");
|
|
135
139
|
(0, react_1.useEffect)(() => {
|
|
136
140
|
if (user.product !== "institutes" || user.userType !== "Staff") {
|
|
137
141
|
setOId(undefined);
|
|
@@ -147,30 +151,6 @@ function useNewInstitutePlacementList({ id, user, cohort, queryConstraint, ql =
|
|
|
147
151
|
}
|
|
148
152
|
const searchPlacements = async () => {
|
|
149
153
|
let placementsFound = {};
|
|
150
|
-
let userSearchString = `userType:Students AND status:active AND oId:${user.oId} AND product:${user.product}`;
|
|
151
|
-
if (cohort) {
|
|
152
|
-
userSearchString = userSearchString + ` AND cohort:${cohort}`;
|
|
153
|
-
}
|
|
154
|
-
if (user.product === "institutes" && user.userType === "Staff") {
|
|
155
|
-
const searchStudentHits = await usersIndex.search(query, {
|
|
156
|
-
filters: userSearchString
|
|
157
|
-
});
|
|
158
|
-
if (searchStudentHits) {
|
|
159
|
-
console.log("FOUND", searchStudentHits.hits.length, "students");
|
|
160
|
-
await Promise.all(searchStudentHits.hits.map(async (hit) => {
|
|
161
|
-
console.log("STUDENT", hit.objectID);
|
|
162
|
-
const constraints = [...(cohort ? [(0, firestore_1.where)("cohort", "==", cohort)] : [])];
|
|
163
|
-
if (inProgress !== undefined) {
|
|
164
|
-
constraints.push(inProgress ? (0, firestore_1.where)("inProgress", "==", true) : (0, firestore_1.where)("completed", "==", true));
|
|
165
|
-
}
|
|
166
|
-
const fPlacements = await (0, readDatabase_1.getPlacementsWhere)({ w: constraints, uid: hit.objectID, oId: hit.oId });
|
|
167
|
-
console.log("PLACEMENTS", fPlacements);
|
|
168
|
-
Object.entries(fPlacements).forEach(([k, v]) => {
|
|
169
|
-
placementsFound[k] = { ...v, student: hit };
|
|
170
|
-
});
|
|
171
|
-
}));
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
154
|
let placementSearchString = `oId:${user.oId} AND ` + (inProgress !== undefined ? (inProgress ? "inProgress:true" : "completed:true") : "");
|
|
175
155
|
if (cohort) {
|
|
176
156
|
placementSearchString = placementSearchString + ` AND cohort:${cohort}`;
|
|
@@ -216,7 +196,7 @@ function useNewInstitutePlacementList({ id, user, cohort, queryConstraint, ql =
|
|
|
216
196
|
}
|
|
217
197
|
setLoadMoreIcon(true);
|
|
218
198
|
let fPlacements = {};
|
|
219
|
-
if (((user.userGroup === "admin" || (cohort && user.viewCohorts === "some" && ((_a = user === null || user === void 0 ? void 0 : user.visibleCohorts) === null || _a === void 0 ? void 0 : _a.
|
|
199
|
+
if (((user.userGroup === "admin" || (cohort && user.viewCohorts === "some" && ((_a = user === null || user === void 0 ? void 0 : user.visibleCohorts) === null || _a === void 0 ? void 0 : _a.includes(cohort))) || (user.viewCohorts === "all" && user.viewStudents === "all")))) {
|
|
220
200
|
const queryConstraintOrdered = Boolean(queryConstraints && queryConstraints.find((v) => v.type === "orderBy"));
|
|
221
201
|
const constraints = (fStartPlacementAfter === null || fStartPlacementAfter === void 0 ? void 0 : fStartPlacementAfter.length) === 2 && fStartPlacementAfter[0] ?
|
|
222
202
|
[(0, firestore_1.limit)(placements ? DEFAULTQUERYLIMIT : initialQueryLimit),
|
|
@@ -227,13 +207,16 @@ function useNewInstitutePlacementList({ id, user, cohort, queryConstraint, ql =
|
|
|
227
207
|
// query && constraints.unshift(where("name", "==", query));
|
|
228
208
|
cohort && constraints.unshift((0, firestore_1.where)("cohort", "==", cohort));
|
|
229
209
|
const placementsQuery = await (0, readDatabase_1.getPlacementsWhere)({ w: constraints, oId: oId, raw: true });
|
|
210
|
+
console.log("PLACEMENTS RETRIEVED", placementsQuery.size);
|
|
230
211
|
const placementsWithStudentData = placementsQuery.empty ? [] : await Promise.all(placementsQuery.docs.map(async (placement) => {
|
|
231
212
|
const pData = placement.data();
|
|
232
213
|
const student = pData.uid === user.id ? user : (await (0, readDatabase_1.getUserById)(pData.uid).catch(() => false));
|
|
233
|
-
|
|
214
|
+
console.log("STUDENT", student, "PLACEMENT", id);
|
|
215
|
+
// if (!student) return false;
|
|
216
|
+
if (user.viewStudents === "some") {
|
|
234
217
|
if (!(user.studentFilter && user.studentFilterValues))
|
|
235
218
|
return false;
|
|
236
|
-
if (!user.studentFilterValues.
|
|
219
|
+
if (!user.studentFilterValues.includes(student.details[user.studentFilter])) {
|
|
237
220
|
return false;
|
|
238
221
|
}
|
|
239
222
|
}
|
|
@@ -258,7 +241,197 @@ function useNewInstitutePlacementList({ id, user, cohort, queryConstraint, ql =
|
|
|
258
241
|
};
|
|
259
242
|
return ({ ...{ placements, loadMoreIcon, loadMorePlacements, setQuery, setInitialQueryLimit, reset, changeQueryConstraints } });
|
|
260
243
|
}
|
|
261
|
-
function
|
|
244
|
+
function useNewInstitutePlacementList({ id, user, filters, view, cohort, queryConstraints, ql = DEFAULTQUERYLIMIT, inProgress }) {
|
|
245
|
+
const [query, setQuery] = (0, react_1.useState)();
|
|
246
|
+
const sorts = {
|
|
247
|
+
["Student Forename - Asc"]: {
|
|
248
|
+
value: "studentForename",
|
|
249
|
+
direction: "asc",
|
|
250
|
+
},
|
|
251
|
+
["Student Forename - Desc"]: {
|
|
252
|
+
value: "studentForename",
|
|
253
|
+
direction: "desc",
|
|
254
|
+
},
|
|
255
|
+
["Student Surname - Asc"]: {
|
|
256
|
+
value: "studentSurname",
|
|
257
|
+
direction: "asc",
|
|
258
|
+
},
|
|
259
|
+
["Student Surname - Desc"]: {
|
|
260
|
+
value: "studentSurname",
|
|
261
|
+
direction: "desc",
|
|
262
|
+
},
|
|
263
|
+
["Student Email - Asc"]: {
|
|
264
|
+
value: "studentEmail",
|
|
265
|
+
direction: "asc",
|
|
266
|
+
},
|
|
267
|
+
["Student Email - Desc"]: {
|
|
268
|
+
value: "studentEmaile",
|
|
269
|
+
direction: "desc",
|
|
270
|
+
},
|
|
271
|
+
["Provider email - Asc"]: {
|
|
272
|
+
value: "providerEmail",
|
|
273
|
+
direction: "asc",
|
|
274
|
+
},
|
|
275
|
+
["Provider email - Desc"]: {
|
|
276
|
+
value: "providerEmail",
|
|
277
|
+
direction: "desc",
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
const additionalProcessing = async (k, placement) => {
|
|
281
|
+
if (user.viewStudents === "some") {
|
|
282
|
+
if (!(user.studentFilter && user.studentFilterValues))
|
|
283
|
+
return false;
|
|
284
|
+
const student = await (0, readDatabase_1.getUserById)(placement.uid).catch(() => false);
|
|
285
|
+
if (!student)
|
|
286
|
+
return;
|
|
287
|
+
if (!user.studentFilterValues.includes(student.details[user.studentFilter])) {
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return { ...placement, id: k };
|
|
292
|
+
};
|
|
293
|
+
const { tableData, pageUp, pageDown, setFilters, page, setView, loading, updateSearch, updateSort, sort } = useDataViewerPaginator({ view, filters, sorts, queryLimit: ql, data: query, additionalEntryProcessing: additionalProcessing, onSearch: async (s, sort, page, filters, limit) => await algoliaPlacementSearch(user, s, sort, page, filters, limit, cohort, inProgress) });
|
|
294
|
+
(0, react_1.useEffect)(() => {
|
|
295
|
+
var _a;
|
|
296
|
+
// Sets the query of for the DataViewerPaginator
|
|
297
|
+
if (user.product !== "institutes" || user.userType !== "Staff") {
|
|
298
|
+
setQuery(undefined);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (((user.userGroup === "admin" || (cohort && user.viewCohorts === "some" && ((_a = user === null || user === void 0 ? void 0 : user.visibleCohorts) === null || _a === void 0 ? void 0 : _a.includes(cohort))) || (user.viewCohorts === "all" && user.viewStudents === "all")))) {
|
|
302
|
+
const constraints = [["oId", "==", user.oId], ["draft", "==", false]];
|
|
303
|
+
cohort && constraints.push(["cohort", "==", cohort]);
|
|
304
|
+
queryConstraints && constraints.unshift(...queryConstraints);
|
|
305
|
+
inProgress !== undefined && constraints.push(["inProgress", "==", inProgress]);
|
|
306
|
+
setQuery([{
|
|
307
|
+
path: ["placements"],
|
|
308
|
+
where: constraints
|
|
309
|
+
}]);
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
setQuery(undefined);
|
|
313
|
+
}, [user, queryConstraints, cohort]);
|
|
314
|
+
return { tableData, page, loading, updateSearch, setFilters, setView, pageUp, pageDown, sorts, updateSort, sort };
|
|
315
|
+
}
|
|
316
|
+
function useAlumniPaginator({ user, alumniConvoUser, filters, view, school, queryConstraints, ql = DEFAULTQUERYLIMIT }) {
|
|
317
|
+
const [query, setQuery] = (0, react_1.useState)();
|
|
318
|
+
const sorts = {};
|
|
319
|
+
const { tableData, pageUp, pageDown, setFilters, page, setView, loading } = useDataViewerPaginator({ view, filters, sorts, queryLimit: ql, data: query });
|
|
320
|
+
const firebaseQuery = new firebaseQuery_1.default();
|
|
321
|
+
(0, react_1.useEffect)(() => {
|
|
322
|
+
const createQuery = async () => {
|
|
323
|
+
// Sets the query of for the DataViewerPaginator
|
|
324
|
+
const getQueryAccess = async () => {
|
|
325
|
+
var _a;
|
|
326
|
+
const constraints = [];
|
|
327
|
+
if (user) {
|
|
328
|
+
constraints.push(["oId", "==", user.oId]);
|
|
329
|
+
if (user.userGroup === "admin" && user.userType === "Staff")
|
|
330
|
+
return constraints;
|
|
331
|
+
if (user.userType === "Staff") {
|
|
332
|
+
if (user.viewSchools === "all")
|
|
333
|
+
return constraints;
|
|
334
|
+
if (user.viewSchools === "none")
|
|
335
|
+
return false;
|
|
336
|
+
if (user.viewSchools === "some") {
|
|
337
|
+
if (!school)
|
|
338
|
+
return false;
|
|
339
|
+
if ((_a = user === null || user === void 0 ? void 0 : user.visibleSchools) === null || _a === void 0 ? void 0 : _a.includes(school))
|
|
340
|
+
return constraints;
|
|
341
|
+
}
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
if (alumniConvoUser) {
|
|
347
|
+
constraints.push(["oId", "==", alumniConvoUser.oId]);
|
|
348
|
+
console.log("ALUMNI CONVO USER");
|
|
349
|
+
if ((school || alumniConvoUser.schoolId) && school === alumniConvoUser.schoolId)
|
|
350
|
+
return constraints;
|
|
351
|
+
console.log("ALUMNI ACCESS TRUE");
|
|
352
|
+
if (alumniConvoUser.schoolId) {
|
|
353
|
+
const school = await firebaseQuery.getDocData(["schools", alumniConvoUser.schoolId]);
|
|
354
|
+
console.log("SCHOOL ACCESS", school, school.alumniConversations);
|
|
355
|
+
return school.alumniConversations ? constraints : false;
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
const institute = await firebaseQuery.getDocData(["institutes", alumniConvoUser.oId]);
|
|
359
|
+
return institute.alumniConversations ? constraints : false;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return false;
|
|
363
|
+
};
|
|
364
|
+
const constraints = await getQueryAccess();
|
|
365
|
+
console.log("CONSTRAINTS", constraints);
|
|
366
|
+
if (!constraints)
|
|
367
|
+
return;
|
|
368
|
+
school && constraints.push(["schoolId", "==", school]);
|
|
369
|
+
queryConstraints && constraints.unshift(...queryConstraints);
|
|
370
|
+
return constraints;
|
|
371
|
+
};
|
|
372
|
+
console.log("Creating query");
|
|
373
|
+
createQuery().then((constraints) => {
|
|
374
|
+
setQuery([{
|
|
375
|
+
path: ["alumni"],
|
|
376
|
+
where: constraints
|
|
377
|
+
}]);
|
|
378
|
+
});
|
|
379
|
+
}, [user, queryConstraints, school]);
|
|
380
|
+
(0, react_1.useEffect)(() => {
|
|
381
|
+
console.log("Alumni data", query, tableData);
|
|
382
|
+
}, [tableData]);
|
|
383
|
+
return { tableData, page, loading, setFilters, setView, pageUp, pageDown, sorts };
|
|
384
|
+
}
|
|
385
|
+
const algoliaPlacementSearch = async (user, query, sort, page, filters, limit, cohort, inProgress) => {
|
|
386
|
+
const algoliaClient = (0, algoliasearch_1.default)(process.env.NODE_ENV === "development" ? "A0ZB50I7VS" : "XMPXCMUUOJ", user.algoliaKey);
|
|
387
|
+
const placementsIndex = algoliaClient.initIndex(sort ? Object.values(sort[1]).join("_") : "placements");
|
|
388
|
+
// const usersIndex = algoliaClient.initIndex("users");
|
|
389
|
+
// let userSearchString = `userType:Students AND status:active AND oId:${user.oId} AND product:${user.product}`
|
|
390
|
+
// if (cohort) {
|
|
391
|
+
// userSearchString = userSearchString + ` AND cohort:${cohort}`;
|
|
392
|
+
// }
|
|
393
|
+
// if (user.product === "institutes" && user.userType === "Staff") {
|
|
394
|
+
// const searchStudentHits = await usersIndex.search<UserData>(query, {
|
|
395
|
+
// filters: userSearchString,
|
|
396
|
+
// hitsPerPage: limit,
|
|
397
|
+
// page: page
|
|
398
|
+
// });
|
|
399
|
+
// if (searchStudentHits) {
|
|
400
|
+
// console.log("FOUND", searchStudentHits.hits.length, "students");
|
|
401
|
+
// await Promise.all(searchStudentHits.hits.map(async (hit) => {
|
|
402
|
+
// console.log("STUDENT", hit.objectID);
|
|
403
|
+
// const constraints = [...(cohort ? [where("cohort", "==", cohort)] : [])]
|
|
404
|
+
// if (inProgress !== undefined) {
|
|
405
|
+
// constraints.push(inProgress ? where("inProgress", "==", true) : where("completed", "==", true));
|
|
406
|
+
// }
|
|
407
|
+
// const fPlacements = await getPlacementsWhere({w: constraints, uid: hit.objectID, oId: hit.oId}) as {[key: string]: StudentPlacementData};
|
|
408
|
+
// console.log("PLACEMENTS", fPlacements)
|
|
409
|
+
// Object.entries(fPlacements).forEach(([k, v]) => {
|
|
410
|
+
// placementsFound[k] = {...v, student: hit};
|
|
411
|
+
// })
|
|
412
|
+
// }))
|
|
413
|
+
// }
|
|
414
|
+
// }
|
|
415
|
+
let placementSearchString = `oId:${user.oId} AND ` + (inProgress !== undefined ? (inProgress ? "inProgress:true" : "completed:true") : "");
|
|
416
|
+
if (cohort) {
|
|
417
|
+
placementSearchString = placementSearchString + ` AND cohort:${cohort}`;
|
|
418
|
+
}
|
|
419
|
+
filters && Object.entries(filters).filter(([, filter]) => filter.value).map(([id, filter]) => {
|
|
420
|
+
placementSearchString = placementSearchString + ` AND ${id}:${filter.value}`;
|
|
421
|
+
});
|
|
422
|
+
const options = {
|
|
423
|
+
filters: placementSearchString,
|
|
424
|
+
hitsPerPage: limit,
|
|
425
|
+
page: page ? page - 1 : undefined,
|
|
426
|
+
};
|
|
427
|
+
const searchPlacementHits = await placementsIndex.search(query || "", options);
|
|
428
|
+
console.log(searchPlacementHits.hits);
|
|
429
|
+
const i = (searchPlacementHits ? (await Promise.all(searchPlacementHits.hits.map(async (hit) => {
|
|
430
|
+
return [hit.objectID, hit];
|
|
431
|
+
}))) : []).filter((e) => e !== undefined);
|
|
432
|
+
return Object.fromEntries(i);
|
|
433
|
+
};
|
|
434
|
+
function useVeryOldInstitutePlacementList({ user, cohort, queryConstraint, ql = DEFAULTQUERYLIMIT }) {
|
|
262
435
|
const [loadMoreIcon, setLoadMoreIcon] = (0, react_1.useState)(true);
|
|
263
436
|
const [query, setQuery] = (0, react_1.useState)("");
|
|
264
437
|
const [initialQueryLimit, setInitialQueryLimit] = (0, react_1.useState)(ql);
|
|
@@ -299,7 +472,7 @@ function useOldInstitutePlacementList({ user, cohort, queryConstraint, ql = DEFA
|
|
|
299
472
|
setLoadMoreIcon(true);
|
|
300
473
|
// If can view all, query placements directly. Otherwise query students.
|
|
301
474
|
let fPlacements = {};
|
|
302
|
-
if (((user.userGroup === "admin" || (cohort && user.viewCohorts === "some" && ((_a = user === null || user === void 0 ? void 0 : user.visibleCohorts) === null || _a === void 0 ? void 0 : _a.
|
|
475
|
+
if (((user.userGroup === "admin" || (cohort && user.viewCohorts === "some" && ((_a = user === null || user === void 0 ? void 0 : user.visibleCohorts) === null || _a === void 0 ? void 0 : _a.includes(cohort))) || (user.viewCohorts === "all" && user.viewStudents === "all") || query) && (fStartPlacementAfter && fStartPlacementAfter[0] === "placement"))) {
|
|
303
476
|
const queryConstraintOrdered = Boolean(queryConstraints && queryConstraints.find((v) => v.type === "orderBy"));
|
|
304
477
|
const constraints = (fStartPlacementAfter === null || fStartPlacementAfter === void 0 ? void 0 : fStartPlacementAfter.length) === 4 && fStartPlacementAfter[1] ?
|
|
305
478
|
[(0, firestore_1.limit)(placements ? DEFAULTQUERYLIMIT : initialQueryLimit),
|
|
@@ -314,10 +487,10 @@ function useOldInstitutePlacementList({ user, cohort, queryConstraint, ql = DEFA
|
|
|
314
487
|
const placementsWithStudentData = placementsQuery.empty ? [] : await Promise.all(placementsQuery.docs.map(async (placement) => {
|
|
315
488
|
const pData = placement.data();
|
|
316
489
|
const student = pData.uid === user.id ? user : (await (0, readDatabase_1.getUserById)(pData.uid).catch(() => false));
|
|
317
|
-
if (user.
|
|
490
|
+
if (user.viewStudents === "some") {
|
|
318
491
|
if (!(user.studentFilter && user.studentFilterValues))
|
|
319
492
|
return false;
|
|
320
|
-
if (!user.studentFilterValues.
|
|
493
|
+
if (!user.studentFilterValues.includes(student.details[user.studentFilter])) {
|
|
321
494
|
return false;
|
|
322
495
|
}
|
|
323
496
|
}
|
|
@@ -342,13 +515,13 @@ function useOldInstitutePlacementList({ user, cohort, queryConstraint, ql = DEFA
|
|
|
342
515
|
return;
|
|
343
516
|
}
|
|
344
517
|
}
|
|
345
|
-
if (!(user.studentFilterValues && user.studentFilter && user.
|
|
518
|
+
if (!(user.studentFilterValues && user.studentFilter && user.viewStudents === "some")) {
|
|
346
519
|
console.log("fenaibn");
|
|
347
520
|
return;
|
|
348
521
|
}
|
|
349
522
|
;
|
|
350
523
|
const getStudentPlacements = async (ffStartPlacementAfter = fStartPlacementAfter, ffPlacements = fPlacements) => {
|
|
351
|
-
var _a
|
|
524
|
+
var _a;
|
|
352
525
|
if (ffStartPlacementAfter && ffStartPlacementAfter[0] === "placement") {
|
|
353
526
|
ffStartPlacementAfter = [undefined, undefined, undefined, 0];
|
|
354
527
|
}
|
|
@@ -358,7 +531,7 @@ function useOldInstitutePlacementList({ user, cohort, queryConstraint, ql = DEFA
|
|
|
358
531
|
[(0, firestore_1.limit)(1), (0, firestore_1.orderBy)((0, firestore_1.documentId)())];
|
|
359
532
|
constraints.push((0, firestore_1.where)("oId", "==", oId), (0, firestore_1.where)("userType", "==", "Students"));
|
|
360
533
|
if (ffStartPlacementAfter && ffStartPlacementAfter[3]) {
|
|
361
|
-
const currentFilter = (_a = user === null || user === void 0 ? void 0 : user.studentFilterValues) === null || _a === void 0 ? void 0 : _a
|
|
534
|
+
const currentFilter = (_a = user === null || user === void 0 ? void 0 : user.studentFilterValues) === null || _a === void 0 ? void 0 : _a[ffStartPlacementAfter[3]];
|
|
362
535
|
if (currentFilter && user.studentFilter) {
|
|
363
536
|
constraints.push((0, firestore_1.where)(user.studentFilter, "==", currentFilter));
|
|
364
537
|
}
|
|
@@ -367,7 +540,7 @@ function useOldInstitutePlacementList({ user, cohort, queryConstraint, ql = DEFA
|
|
|
367
540
|
const student = Object.entries((await firebaseQuery.getDocsWhere("users", constraints)))[0];
|
|
368
541
|
// console.log("student", student);
|
|
369
542
|
// If there is no students but more filters
|
|
370
|
-
if (!student && ffStartPlacementAfter && ffStartPlacementAfter[3] + 1 < ((
|
|
543
|
+
if (!student && ffStartPlacementAfter && ffStartPlacementAfter[3] + 1 < ((user === null || user === void 0 ? void 0 : user.studentFilterValues) || []).length) {
|
|
371
544
|
// console.log("No more students. Calling recursion");
|
|
372
545
|
return await getStudentPlacements(["student", undefined, undefined, ffStartPlacementAfter[3] + 1], ffPlacements);
|
|
373
546
|
}
|
|
@@ -577,7 +750,7 @@ function useFilterTablePaginator({ data }) {
|
|
|
577
750
|
if (!Object.keys(itemList).length)
|
|
578
751
|
return;
|
|
579
752
|
console.log("Fetching filter table updates");
|
|
580
|
-
const itemListUpdateQuery = (0, firestore_1.query)((0, firestore_1.collection)(firebaseConfig_1.db,
|
|
753
|
+
const itemListUpdateQuery = (0, firestore_1.query)((0, firestore_1.collection)(firebaseConfig_1.db, ...querySchema.path), (0, firestore_1.where)((0, firestore_1.documentId)(), "in", Object.keys(itemList)));
|
|
581
754
|
const itemUpdateSnapshot = (0, firestore_1.onSnapshot)(itemListUpdateQuery, (querySnapshot) => {
|
|
582
755
|
querySnapshot.docs.forEach((doc) => {
|
|
583
756
|
setTableData((data) => {
|
|
@@ -609,186 +782,37 @@ function useFilterTablePaginator({ data }) {
|
|
|
609
782
|
}, [page]);
|
|
610
783
|
return ({ ...{ tableData, setPage, setFilters, page } });
|
|
611
784
|
}
|
|
612
|
-
function
|
|
613
|
-
const [
|
|
614
|
-
const [page, setPage] = (0, react_1.useState)([1, 0]);
|
|
615
|
-
const [filters, setFilters] = (0, react_1.useState)();
|
|
616
|
-
const [queryAnchor, setQueryAnchor] = (0, react_1.useState)({ startKey: "", endKey: "", startQueryPos: 0, endQueryPos: 0 });
|
|
617
|
-
const [prevEntryIds, setPrevEntryIds] = (0, react_1.useState)({});
|
|
785
|
+
function useProviderContactPaginator({ data, user, view, filters }) {
|
|
786
|
+
const [query, setQuery] = (0, react_1.useState)();
|
|
618
787
|
const firebaseQuery = new firebaseQuery_1.default();
|
|
619
|
-
const
|
|
620
|
-
|
|
621
|
-
if (
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
else {
|
|
625
|
-
cursorPos = currentQueryAnchor.startQueryPos;
|
|
626
|
-
}
|
|
627
|
-
const querySchema = data === null || data === void 0 ? void 0 : data[cursorPos];
|
|
628
|
-
const createQuery = (queryData) => {
|
|
629
|
-
const constraints = [
|
|
630
|
-
(0, firestore_1.where)("savedById", "==", user.userType === "Staff" ? user.oId : user.id),
|
|
631
|
-
(0, firestore_1.where)("savedByProduct", "==", user.product),
|
|
632
|
-
(0, firestore_1.where)("savedByUserType", "==", user.userType === "Staff" ? "Organisation" : "Student"),
|
|
633
|
-
];
|
|
634
|
-
if (user.userType === "Students") {
|
|
635
|
-
constraints.push((0, firestore_1.where)("listed", "==", true));
|
|
636
|
-
}
|
|
637
|
-
(queryData === null || queryData === void 0 ? void 0 : queryData.where) && queryData.where.forEach((w) => {
|
|
638
|
-
constraints.push((0, firestore_1.where)(...w));
|
|
639
|
-
});
|
|
640
|
-
filters && Object.entries(filters).forEach(([key, value]) => {
|
|
641
|
-
constraints.push((0, firestore_1.where)(key, "==", value));
|
|
642
|
-
});
|
|
643
|
-
if (queryData === null || queryData === void 0 ? void 0 : queryData.orderBy) {
|
|
644
|
-
if (queryData.orderBy === "documentId") {
|
|
645
|
-
constraints.push((0, firestore_1.orderBy)((0, firestore_1.documentId)()));
|
|
646
|
-
}
|
|
647
|
-
else {
|
|
648
|
-
constraints.push((0, firestore_1.orderBy)(queryData.orderBy));
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
else {
|
|
652
|
-
constraints.push((0, firestore_1.orderBy)((0, firestore_1.documentId)()));
|
|
653
|
-
}
|
|
654
|
-
if (page[0] > page[1] && !cursorDirection) { // Going up
|
|
655
|
-
currentQueryAnchor.endKey && constraints.push((0, firestore_1.startAfter)(currentQueryAnchor.endKey));
|
|
656
|
-
constraints.push((0, firestore_1.limit)(10));
|
|
657
|
-
if (!loadMoreFromQuery) {
|
|
658
|
-
currentQueryAnchor = { ...currentQueryAnchor, startQueryPos: currentQueryAnchor.endQueryPos };
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
else if (page[0] < page[1] && !cursorDirection) { // Going down
|
|
662
|
-
if (!loadMoreFromQuery) {
|
|
663
|
-
currentQueryAnchor = { ...currentQueryAnchor, endQueryPos: currentQueryAnchor.startQueryPos };
|
|
664
|
-
}
|
|
665
|
-
constraints.push((0, firestore_1.limitToLast)(10));
|
|
666
|
-
if (currentQueryAnchor.startKey) {
|
|
667
|
-
currentQueryAnchor.startKey && constraints.push((0, firestore_1.endBefore)(currentQueryAnchor.startKey));
|
|
668
|
-
}
|
|
669
|
-
else {
|
|
670
|
-
currentQueryAnchor.startKey && constraints.push((0, firestore_1.endAt)(currentQueryAnchor.startKey));
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
else {
|
|
674
|
-
if (cursorDirection === "decrease") {
|
|
675
|
-
constraints.push((0, firestore_1.limitToLast)(10));
|
|
676
|
-
}
|
|
677
|
-
else {
|
|
678
|
-
constraints.push((0, firestore_1.limit)(10));
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
return constraints;
|
|
682
|
-
};
|
|
683
|
-
const constraints = createQuery(querySchema);
|
|
684
|
-
// console.log(queryId, "constraints", constraints)
|
|
685
|
-
const q = (0, firestore_1.query)((0, firestore_1.collection)(firebaseConfig_1.db, "savedPlacements"), ...(constraints));
|
|
686
|
-
const queryResults = {};
|
|
687
|
-
const queryData = await (0, firestore_1.getDocs)(q);
|
|
688
|
-
// console.log("queryData.size", queryData.size)
|
|
689
|
-
const reverseIfBack = (docs) => {
|
|
690
|
-
if (page[0] < page[1]) {
|
|
691
|
-
return docs.reverse();
|
|
692
|
-
}
|
|
693
|
-
return docs;
|
|
694
|
-
};
|
|
695
|
-
let index = 0;
|
|
696
|
-
reverseIfBack(queryData.docs).forEach(async (doc) => {
|
|
697
|
-
if (Object.keys(queryResults).length + Object.keys(itemList).length === 10) {
|
|
698
|
-
return;
|
|
699
|
-
}
|
|
700
|
-
let position = Object.keys(itemList).length + (page[0] - 1) * 10 + index + 1;
|
|
701
|
-
if (page[0] < page[1]) {
|
|
702
|
-
position = (page[0]) * 10 - index - Object.keys(itemList).length;
|
|
703
|
-
}
|
|
704
|
-
// console.log(index, "doc.id", doc.id, position, "E", prevEntries[doc.id])
|
|
705
|
-
if (itemList[doc.id] || (prevEntries[doc.id] && prevEntries[doc.id] !== position)) {
|
|
706
|
-
console.log("Removing ", doc.id, ": E=", prevEntries[doc.id], ", G=", position);
|
|
707
|
-
return;
|
|
708
|
-
}
|
|
709
|
-
const item = doc.data();
|
|
710
|
-
item.id = doc.id;
|
|
711
|
-
queryResults[doc.id] = item;
|
|
712
|
-
index = index + 1;
|
|
713
|
-
if (prevEntries[doc.id])
|
|
714
|
-
return;
|
|
715
|
-
prevEntries[doc.id] = position;
|
|
716
|
-
});
|
|
717
|
-
if (cursorDirection === "decrease" || page[0] < page[1]) {
|
|
718
|
-
itemList = { ...Object.fromEntries(Object.entries(queryResults).reverse()), ...itemList };
|
|
719
|
-
}
|
|
720
|
-
else {
|
|
721
|
-
itemList = { ...itemList, ...queryResults };
|
|
722
|
-
}
|
|
723
|
-
setPrevEntryIds(prevEntries);
|
|
724
|
-
if (queryData.size < 10 && Object.keys(itemList).length < 10) {
|
|
725
|
-
if (page[0] > page[1] && cursorPos + 1 < data.length) {
|
|
726
|
-
console.log("Increase query index");
|
|
727
|
-
return getDataFromQuery(itemList, { ...currentQueryAnchor, endQueryPos: currentQueryAnchor.endQueryPos + 1 }, "increase", prevEntries);
|
|
728
|
-
}
|
|
729
|
-
else if (page[0] < page[1] && cursorPos > 0) {
|
|
730
|
-
console.log("Decrease query index");
|
|
731
|
-
return getDataFromQuery(itemList, { ...currentQueryAnchor, startQueryPos: currentQueryAnchor.startQueryPos - 1 }, "decrease", prevEntries);
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
if (Object.keys(itemList).length < 10 && queryData.size === 10) {
|
|
735
|
-
console.log("Shorter than ten");
|
|
736
|
-
// if(loadMoreFromQuery){return}
|
|
737
|
-
return getDataFromQuery(itemList, { ...currentQueryAnchor, startKey: Object.keys(itemList)[0], endKey: Object.keys(itemList).slice(-1)[0] }, undefined, prevEntries, true);
|
|
738
|
-
}
|
|
739
|
-
if (queryData.size === 0 &&
|
|
740
|
-
Object.keys(itemList).length === 0 &&
|
|
741
|
-
currentQueryAnchor.endQueryPos + 1 === data.length &&
|
|
742
|
-
page[0] > 1) {
|
|
743
|
-
setTableData({});
|
|
744
|
-
setQueryAnchor((a) => ({ ...a, startKey: "" }));
|
|
745
|
-
return;
|
|
746
|
-
}
|
|
747
|
-
setQueryAnchor({ ...currentQueryAnchor, startKey: Object.keys(itemList)[0], endKey: Object.keys(itemList).slice(-1)[0] });
|
|
748
|
-
const finalData = Object.fromEntries(await Promise.all(Object.entries(itemList).map(async ([k, v]) => {
|
|
749
|
-
const placement = await firebaseQuery.getDocData(["placementListings", v.placementId || ""]);
|
|
750
|
-
const address = await firebaseQuery.getDocData(["addresses", placement.addressId || ""]);
|
|
751
|
-
const provider = await firebaseQuery.getDocData(["providers", placement.providerId || ""]);
|
|
752
|
-
const status = getPlacementStatus(provider, placement, v);
|
|
753
|
-
return [k, { ...address, ...provider, ...placement, email: placement.providerEmail, status: status, savedPlacement: v }];
|
|
754
|
-
})));
|
|
755
|
-
setTableData(finalData);
|
|
756
|
-
};
|
|
757
|
-
const getPlacementStatus = (provider, placement, savedPlacement) => {
|
|
758
|
-
if (savedPlacement.status === "Blocked")
|
|
759
|
-
return "blocked";
|
|
760
|
-
if (savedPlacement.status === "Accepted")
|
|
761
|
-
return "active";
|
|
762
|
-
if (user.product === "admin") {
|
|
763
|
-
if (placement.mapConsent === undefined)
|
|
764
|
-
return "notReviewed";
|
|
765
|
-
if (placement.mapConsent === false)
|
|
766
|
-
return "notPublic";
|
|
767
|
-
return "unknown";
|
|
788
|
+
const getAdditionalData = async (k, v) => {
|
|
789
|
+
var _a, _b;
|
|
790
|
+
if ((_b = (_a = v.savedBy) === null || _a === void 0 ? void 0 : _a[user.oId].activities) === null || _b === void 0 ? void 0 : _b.includes("workExperience")) {
|
|
791
|
+
const placementsCount = await firebaseQuery.getCount("placementListings", [(0, firestore_1.where)(`savedBy.${user.oId}.exists`, "==", true), (0, firestore_1.where)("providerContactId", "==", k)]);
|
|
792
|
+
return { ...v, plcaements: placementsCount };
|
|
768
793
|
}
|
|
769
|
-
;
|
|
770
|
-
if (!provider.insurance)
|
|
771
|
-
return "awaitingProviderApproval";
|
|
772
|
-
return "requiresApproval";
|
|
794
|
+
return v;
|
|
773
795
|
};
|
|
796
|
+
const { tableData, pageUp, pageDown, setFilters, page, setView, loading } = useDataViewerPaginator({ view, filters, queryLimit: 20, data: query, additionalEntryProcessing: getAdditionalData });
|
|
774
797
|
(0, react_1.useEffect)(() => {
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
}, [
|
|
786
|
-
return ({ ...{ tableData,
|
|
798
|
+
const constraints = [
|
|
799
|
+
[`savedBy.${user.oId}.exists`, "==", true],
|
|
800
|
+
];
|
|
801
|
+
if (user.userType === "Students") {
|
|
802
|
+
constraints.push([`savedBy.${user.oId}.cohorts.${user.cohort}.listed`, "==", true]);
|
|
803
|
+
}
|
|
804
|
+
setQuery([{
|
|
805
|
+
path: ["providerContacts"],
|
|
806
|
+
where: constraints
|
|
807
|
+
}]);
|
|
808
|
+
}, [user]);
|
|
809
|
+
return ({ ...{ tableData, pageUp, pageDown, setFilters, page, setView, loading } });
|
|
787
810
|
}
|
|
788
|
-
function useCohortUserPaginator({ user, cohort, data, search, userType }) {
|
|
811
|
+
function useCohortUserPaginator({ user, cohort, data, search, userType, sort }) {
|
|
789
812
|
const [tableData, setTableData] = (0, react_1.useState)({});
|
|
790
|
-
const [queryAnchor, setQueryAnchor] = (0, react_1.useState)({
|
|
813
|
+
const [queryAnchor, setQueryAnchor] = (0, react_1.useState)({ startDoc: undefined, endDoc: undefined, startQueryPos: 0, endQueryPos: 0 });
|
|
791
814
|
const [filters, setFilters] = (0, react_1.useState)();
|
|
815
|
+
const [sortResultsBy, setSortResultsBy] = (0, react_1.useState)(sort);
|
|
792
816
|
const [prevEntryIds, setPrevEntryIds] = (0, react_1.useState)({});
|
|
793
817
|
const [page, setPage] = (0, react_1.useState)([1, 0]);
|
|
794
818
|
const [dataListenerUnsubscribe, setDataListenerUnsubscribe] = (0, react_1.useState)();
|
|
@@ -796,6 +820,14 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
|
|
|
796
820
|
const [prevSearch, setPrevSearch] = (0, react_1.useState)();
|
|
797
821
|
const algoliaClient = (0, algoliasearch_1.default)(process.env.NODE_ENV === "development" ? "A0ZB50I7VS" : "XMPXCMUUOJ", user.algoliaKey);
|
|
798
822
|
const usersIndex = algoliaClient.initIndex("users");
|
|
823
|
+
const sortOptions = {
|
|
824
|
+
["Forename - Asc"]: ["details.forename", "asc"],
|
|
825
|
+
["Forename - Desc"]: ["details.forename", "desc"],
|
|
826
|
+
["Surname - Asc"]: ["details.surname", "desc"],
|
|
827
|
+
["Surname - Desc"]: ["details.surname", "asc"],
|
|
828
|
+
["Email - Asc"]: ["email", "asc"],
|
|
829
|
+
["Email - Desc"]: ["email", "desc"],
|
|
830
|
+
};
|
|
799
831
|
(0, react_1.useEffect)(() => {
|
|
800
832
|
var _a;
|
|
801
833
|
if (user.userType !== "Staff") {
|
|
@@ -804,8 +836,8 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
|
|
|
804
836
|
return;
|
|
805
837
|
}
|
|
806
838
|
if ((!user.viewCohorts && user.userGroup !== "admin") ||
|
|
807
|
-
user.viewCohorts === "none" ||
|
|
808
|
-
(user.viewCohorts === "some" && cohort !== "all" && !((_a = user.visibleCohorts) === null || _a === void 0 ? void 0 : _a.
|
|
839
|
+
(user.viewCohorts === "none" && user.userGroup !== "admin") ||
|
|
840
|
+
(user.viewCohorts === "some" && user.userGroup !== "admin" && cohort !== "all" && !((_a = user.visibleCohorts) === null || _a === void 0 ? void 0 : _a.includes(cohort || "")))) {
|
|
809
841
|
setQueries(undefined);
|
|
810
842
|
return;
|
|
811
843
|
}
|
|
@@ -821,13 +853,13 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
|
|
|
821
853
|
});
|
|
822
854
|
constraints.push((0, firestore_1.where)("oId", "==", user.oId));
|
|
823
855
|
cohort && cohort !== "all" && constraints.push((0, firestore_1.where)("cohort", "==", cohort));
|
|
824
|
-
if (user.userGroup === "admin" || user.
|
|
856
|
+
if (user.userGroup === "admin" || user.viewStudents === "all") {
|
|
825
857
|
finalConstraints.push(constraints);
|
|
826
858
|
continue;
|
|
827
859
|
}
|
|
828
860
|
if (!user.studentFilter || !user.studentFilterValues)
|
|
829
861
|
continue;
|
|
830
|
-
user.studentFilterValues.
|
|
862
|
+
user.studentFilterValues.forEach((filterValue) => {
|
|
831
863
|
user.studentFilter && finalConstraints.push([...constraints, (0, firestore_1.where)("details." + user.studentFilter, "==", filterValue)]);
|
|
832
864
|
});
|
|
833
865
|
}
|
|
@@ -837,7 +869,7 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
|
|
|
837
869
|
});
|
|
838
870
|
}, []);
|
|
839
871
|
const getDataFromQuery = async (itemList = {}, currentQueryAnchor = queryAnchor, cursorDirection, prevEntries = prevEntryIds, loadMoreFromQuery = false) => {
|
|
840
|
-
if (!queries) {
|
|
872
|
+
if (!(queries === null || queries === void 0 ? void 0 : queries.length)) {
|
|
841
873
|
setTableData({});
|
|
842
874
|
return;
|
|
843
875
|
}
|
|
@@ -854,17 +886,42 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
|
|
|
854
886
|
const createQuery = (mConstraints) => {
|
|
855
887
|
console.log("mConstraints", mConstraints);
|
|
856
888
|
const fConstraints = [...mConstraints];
|
|
889
|
+
let addOrderBy = true;
|
|
857
890
|
filters && Object.entries(filters).forEach(([key, value]) => {
|
|
858
|
-
if (
|
|
891
|
+
if (Array.isArray(value)) {
|
|
892
|
+
value.forEach((v) => {
|
|
893
|
+
if (typeof v === "object") {
|
|
894
|
+
if (v instanceof firestore_1.QueryOrderByConstraint) {
|
|
895
|
+
addOrderBy = false;
|
|
896
|
+
}
|
|
897
|
+
fConstraints.push(v);
|
|
898
|
+
}
|
|
899
|
+
else {
|
|
900
|
+
fConstraints.push((0, firestore_1.where)(key, "==", v));
|
|
901
|
+
}
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
else if (typeof value === "object") {
|
|
905
|
+
if (value instanceof firestore_1.QueryOrderByConstraint) {
|
|
906
|
+
addOrderBy = false;
|
|
907
|
+
}
|
|
859
908
|
fConstraints.push(value);
|
|
860
909
|
}
|
|
861
910
|
else {
|
|
862
911
|
fConstraints.push((0, firestore_1.where)(key, "==", value));
|
|
863
912
|
}
|
|
864
913
|
});
|
|
865
|
-
|
|
914
|
+
console.log("Add order by", addOrderBy);
|
|
915
|
+
if (addOrderBy) {
|
|
916
|
+
if (sortResultsBy) {
|
|
917
|
+
fConstraints.push((0, firestore_1.orderBy)(sortOptions[sortResultsBy][0], sortOptions[sortResultsBy][1]));
|
|
918
|
+
}
|
|
919
|
+
else {
|
|
920
|
+
fConstraints.push((0, firestore_1.orderBy)((0, firestore_1.documentId)()));
|
|
921
|
+
}
|
|
922
|
+
}
|
|
866
923
|
if (page[0] > page[1] && !cursorDirection) { // Going up
|
|
867
|
-
currentQueryAnchor.
|
|
924
|
+
currentQueryAnchor.endDoc && fConstraints.push((0, firestore_1.startAfter)(currentQueryAnchor.endDoc));
|
|
868
925
|
fConstraints.push((0, firestore_1.limit)(10));
|
|
869
926
|
if (!loadMoreFromQuery) {
|
|
870
927
|
currentQueryAnchor = { ...currentQueryAnchor, startQueryPos: currentQueryAnchor.endQueryPos };
|
|
@@ -875,11 +932,11 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
|
|
|
875
932
|
currentQueryAnchor = { ...currentQueryAnchor, endQueryPos: currentQueryAnchor.startQueryPos };
|
|
876
933
|
}
|
|
877
934
|
fConstraints.push((0, firestore_1.limitToLast)(10));
|
|
878
|
-
if (currentQueryAnchor.
|
|
879
|
-
currentQueryAnchor.
|
|
935
|
+
if (currentQueryAnchor.startDoc) {
|
|
936
|
+
currentQueryAnchor.startDoc && fConstraints.push((0, firestore_1.endBefore)(currentQueryAnchor.startDoc));
|
|
880
937
|
}
|
|
881
938
|
else {
|
|
882
|
-
currentQueryAnchor.
|
|
939
|
+
currentQueryAnchor.startDoc && fConstraints.push((0, firestore_1.endAt)(currentQueryAnchor.startDoc));
|
|
883
940
|
}
|
|
884
941
|
}
|
|
885
942
|
else {
|
|
@@ -918,9 +975,7 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
|
|
|
918
975
|
console.log("Removing ", doc.id, ": E=", prevEntries[doc.id], ", G=", position);
|
|
919
976
|
return;
|
|
920
977
|
}
|
|
921
|
-
|
|
922
|
-
item.id = doc.id;
|
|
923
|
-
queryResults[doc.id] = item;
|
|
978
|
+
queryResults[doc.id] = doc;
|
|
924
979
|
index = index + 1;
|
|
925
980
|
if (prevEntries[doc.id])
|
|
926
981
|
return;
|
|
@@ -942,7 +997,7 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
|
|
|
942
997
|
}
|
|
943
998
|
}
|
|
944
999
|
if (Object.keys(itemList).length < 10 && queryData.size === 10) {
|
|
945
|
-
return getDataFromQuery(itemList, { ...currentQueryAnchor,
|
|
1000
|
+
return getDataFromQuery(itemList, { ...currentQueryAnchor, startDoc: Object.values(itemList)[0], endDoc: Object.values(itemList).slice(-1)[0] }, undefined, prevEntries, true);
|
|
946
1001
|
}
|
|
947
1002
|
if (queryData.size === 0 &&
|
|
948
1003
|
Object.keys(itemList).length === 0 &&
|
|
@@ -968,8 +1023,8 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
|
|
|
968
1023
|
setDataListenerUnsubscribe(() => itemUpdateSnapshot);
|
|
969
1024
|
};
|
|
970
1025
|
listenForUpdates();
|
|
971
|
-
setQueryAnchor({ ...currentQueryAnchor,
|
|
972
|
-
setTableData(itemList);
|
|
1026
|
+
setQueryAnchor({ ...currentQueryAnchor, startDoc: Object.values(itemList)[0], endDoc: Object.values(itemList).slice(-1)[0] });
|
|
1027
|
+
setTableData(Object.fromEntries(Object.entries(itemList).map(([k, v]) => [k, { id: k, ...v.data() }])));
|
|
973
1028
|
};
|
|
974
1029
|
const searchUsers = async () => {
|
|
975
1030
|
if (!search)
|
|
@@ -1006,10 +1061,10 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
|
|
|
1006
1061
|
setPage([1, 0]);
|
|
1007
1062
|
console.log("Set page");
|
|
1008
1063
|
setTableData({});
|
|
1009
|
-
setQueryAnchor({
|
|
1064
|
+
setQueryAnchor({ startQueryPos: 0, endQueryPos: 0 });
|
|
1010
1065
|
setPrevEntryIds({});
|
|
1011
1066
|
dataListenerUnsubscribe && dataListenerUnsubscribe();
|
|
1012
|
-
}, [filters, search]);
|
|
1067
|
+
}, [filters, search, sortResultsBy]);
|
|
1013
1068
|
// Fetch new data when queries or page change
|
|
1014
1069
|
(0, react_1.useEffect)(() => {
|
|
1015
1070
|
if (search) {
|
|
@@ -1020,7 +1075,8 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
|
|
|
1020
1075
|
getDataFromQuery();
|
|
1021
1076
|
dataListenerUnsubscribe && dataListenerUnsubscribe();
|
|
1022
1077
|
}, [page, queries, prevSearch]);
|
|
1023
|
-
|
|
1078
|
+
const setSort = (s) => setSortResultsBy(s);
|
|
1079
|
+
return ({ ...{ tableData, setPage, page, setFilters, setSort, sortOptions: Object.keys(sortOptions), sortBy: sortResultsBy } });
|
|
1024
1080
|
}
|
|
1025
1081
|
function useAdmissionsPaginator({ data }) {
|
|
1026
1082
|
const [tableData, setTableData] = (0, react_1.useState)({});
|
|
@@ -1066,371 +1122,440 @@ function useLazyLoadQueryList({ path, constraints, number, onItemFetched }) {
|
|
|
1066
1122
|
return [doc.id, onItemFetched ? await onItemFetched(itemObj) : itemObj];
|
|
1067
1123
|
})));
|
|
1068
1124
|
setItems((i) => ({ ...i, ...processedItems }));
|
|
1069
|
-
setLoadMoreIcon(false);
|
|
1070
|
-
};
|
|
1071
|
-
(0, react_1.useEffect)(() => {
|
|
1072
|
-
loadMore();
|
|
1073
|
-
}, []);
|
|
1074
|
-
return ({ ...{ items, loadMore, loadMoreIcon, reset } });
|
|
1075
|
-
}
|
|
1076
|
-
function usePublicPlacementListingLoader({ providerId, number = 5 }) {
|
|
1077
|
-
const [items, setItems] = (0, react_1.useState)({});
|
|
1078
|
-
const [loadMoreIcon, setLoadMoreIcon] = (0, react_1.useState)(false);
|
|
1079
|
-
const [lastItem, setLastItem] = (0, react_1.useState)();
|
|
1080
|
-
const firebaseQuery = new firebaseQuery_1.default();
|
|
1081
|
-
const reset = () => {
|
|
1082
|
-
setItems({});
|
|
1083
|
-
setLastItem(undefined);
|
|
1084
|
-
};
|
|
1085
|
-
const loadMore = async () => {
|
|
1086
|
-
setLoadMoreIcon(true);
|
|
1087
|
-
let formattedConstraints = [
|
|
1088
|
-
(0, firestore_1.where)("status", "==", "listed"),
|
|
1089
|
-
(0, firestore_1.limit)(number)
|
|
1090
|
-
];
|
|
1091
|
-
if (providerId) {
|
|
1092
|
-
formattedConstraints.push((0, firestore_1.where)("providerId", "==", providerId));
|
|
1093
|
-
}
|
|
1094
|
-
if (lastItem) {
|
|
1095
|
-
formattedConstraints.push((0, firestore_1.startAfter)(lastItem));
|
|
1096
|
-
}
|
|
1097
|
-
const documents = await firebaseQuery.getDocsWhere("placementListings", formattedConstraints, true);
|
|
1098
|
-
console.log("docs", documents.docs);
|
|
1099
|
-
setLastItem(documents.docs[documents.docs.length - 1]);
|
|
1100
|
-
const processedItems = Object.fromEntries(await Promise.all(Object.values(documents.docs).map(async (doc) => {
|
|
1101
|
-
var _a, _b;
|
|
1102
|
-
let itemObj = { ...doc.data(), id: doc.id };
|
|
1103
|
-
if (itemObj.addressId) {
|
|
1104
|
-
const address = await firebaseQuery.getDocData(["addresses", itemObj.addressId]);
|
|
1105
|
-
delete address.id;
|
|
1106
|
-
itemObj = { ...address, ...itemObj };
|
|
1107
|
-
}
|
|
1108
|
-
if (itemObj.applicantWorkflowId) {
|
|
1109
|
-
const applicantWorkflow = (await firebaseQuery.getDocData(["applicantWorkflows", itemObj.applicantWorkflowId])).workflow.filter((i) => i.id === 1)[0];
|
|
1110
|
-
const applicantFiles = applicantWorkflow.files ? Object.fromEntries(await Promise.all((_a = applicantWorkflow.files) === null || _a === void 0 ? void 0 : _a.map(async (fileId) => {
|
|
1111
|
-
const file = await firebaseQuery.getDocData(["files", fileId]);
|
|
1112
|
-
file.url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `userFiles/${file.fileName}`));
|
|
1113
|
-
return [fileId, file];
|
|
1114
|
-
}))) : [];
|
|
1115
|
-
const applicantForms = applicantWorkflow.forms ? Object.fromEntries(await Promise.all((_b = applicantWorkflow.forms) === null || _b === void 0 ? void 0 : _b.map(async (formId) => {
|
|
1116
|
-
return [formId, await firebaseQuery.getDocData(["forms", formId])];
|
|
1117
|
-
}))) : [];
|
|
1118
|
-
applicantWorkflow.viewableFiles = applicantFiles;
|
|
1119
|
-
applicantWorkflow.formDetails = applicantForms;
|
|
1120
|
-
itemObj = { ...itemObj, applicantWorkflow: [applicantWorkflow] };
|
|
1121
|
-
}
|
|
1122
|
-
return [doc.id, itemObj];
|
|
1123
|
-
})));
|
|
1124
|
-
setItems((i) => ({ ...i, ...processedItems }));
|
|
1125
|
-
setLoadMoreIcon(false);
|
|
1126
|
-
};
|
|
1127
|
-
(0, react_1.useEffect)(() => {
|
|
1128
|
-
loadMore();
|
|
1129
|
-
}, []);
|
|
1130
|
-
return ({ ...{ items, loadMore, loadMoreIcon, reset } });
|
|
1131
|
-
}
|
|
1132
|
-
function useCreateApplicationRenderer({ user, listingId, listing, provider, application, applicationId, orgContext }) {
|
|
1133
|
-
const firebaseQuery = new firebaseQuery_1.default();
|
|
1134
|
-
let applicationWithoutAdditionalData = { ...(application || {}) };
|
|
1135
|
-
delete applicationWithoutAdditionalData.listing;
|
|
1136
|
-
delete applicationWithoutAdditionalData.address;
|
|
1137
|
-
delete applicationWithoutAdditionalData.provider;
|
|
1138
|
-
const [fApplication, setFApplication] = (0, react_1.useState)(application ? applicationWithoutAdditionalData : {
|
|
1139
|
-
uid: user.userType === "Students" ? user.id : undefined,
|
|
1140
|
-
listingId: listingId,
|
|
1141
|
-
stage: 1,
|
|
1142
|
-
reqUserType: "Students",
|
|
1143
|
-
status: "draft"
|
|
1144
|
-
});
|
|
1145
|
-
const [fApplicationId, setFApplicationId] = (0, react_1.useState)(applicationId);
|
|
1146
|
-
const [draftSaved, setDraftSaved] = (0, react_1.useState)(false);
|
|
1147
|
-
const [fProvider, setFProvider] = (0, react_1.useState)(provider);
|
|
1148
|
-
const [fListing, setFListing] = (0, react_1.useState)(listing);
|
|
1149
|
-
const [student, setStudent] = (0, react_1.useState)(user.userType === "Students" ? user : undefined);
|
|
1150
|
-
const [profileUrl, setProfileUrl] = (0, react_1.useState)();
|
|
1151
|
-
const [successPopup, setSuccessPopup] = (0, react_1.useState)();
|
|
1152
|
-
const [uploadedFiles, setUploadedFiles] = (0, react_1.useState)();
|
|
1153
|
-
const [currentStageComplete, setCurrentStageComplete] = (0, react_1.useState)();
|
|
1154
|
-
(0, react_1.useEffect)(() => {
|
|
1155
|
-
const getListing = async () => {
|
|
1156
|
-
console.log("Checking ID");
|
|
1157
|
-
if (!listingId)
|
|
1158
|
-
return;
|
|
1159
|
-
console.log("Getting listing");
|
|
1160
|
-
const listingData = listing || await firebaseQuery.getDocData(["placementListings", listingId]);
|
|
1161
|
-
const address = (user.product === "providers" && orgContext) ? orgContext.addresses[listingData.addressId || ""] : await firebaseQuery.getDocData(["addresses", listingData.addressId]);
|
|
1162
|
-
const workflow = (user.product === "providers" && orgContext) ? orgContext.applicantWorkflows[listingData.applicantWorkflowId || ""] : await firebaseQuery.getDocData(["applicantWorkflows", listingData.applicantWorkflowId]);
|
|
1163
|
-
workflow.workflow = await Promise.all(workflow.workflow.map(async (s) => {
|
|
1164
|
-
var _a, _b;
|
|
1165
|
-
const applicantFiles = s.files ? Object.fromEntries(await Promise.all((_a = s.files) === null || _a === void 0 ? void 0 : _a.map(async (fileId) => {
|
|
1166
|
-
const file = await firebaseQuery.getDocData(["files", fileId]);
|
|
1167
|
-
file.url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `userFiles/${file.fileName}`));
|
|
1168
|
-
return [fileId, file];
|
|
1169
|
-
}))) : [];
|
|
1170
|
-
const applicantForms = s.forms ? Object.fromEntries(await Promise.all((_b = s.forms) === null || _b === void 0 ? void 0 : _b.map(async (formId) => {
|
|
1171
|
-
return [formId, await firebaseQuery.getDocData(["forms", formId])];
|
|
1172
|
-
}))) : [];
|
|
1173
|
-
return { ...s, viewableFiles: applicantFiles, formDetails: applicantForms };
|
|
1174
|
-
}));
|
|
1175
|
-
delete address.id;
|
|
1176
|
-
delete workflow.id;
|
|
1177
|
-
console.log("Setting listing");
|
|
1178
|
-
setFListing({ ...listingData, ...address, applicantWorkflow: workflow.workflow });
|
|
1179
|
-
console.log("Getting provider", listingData === null || listingData === void 0 ? void 0 : listingData.providerId);
|
|
1180
|
-
if (((fProvider === null || fProvider === void 0 ? void 0 : fProvider.id) === (application === null || application === void 0 ? void 0 : application.providerId)) && user.product === "providers") {
|
|
1181
|
-
setFProvider({ details: orgContext === null || orgContext === void 0 ? void 0 : orgContext.details, id: user.oId });
|
|
1182
|
-
}
|
|
1183
|
-
else if (listingData === null || listingData === void 0 ? void 0 : listingData.providerId) {
|
|
1184
|
-
console.log("Getting provider from DB");
|
|
1185
|
-
const provider = await firebaseQuery.getDocData(["providers", listingData.providerId]);
|
|
1186
|
-
console.log("Provider", provider);
|
|
1187
|
-
setFProvider({ details: provider, id: listingData.providerId });
|
|
1188
|
-
}
|
|
1189
|
-
};
|
|
1190
|
-
getListing();
|
|
1191
|
-
}, [listingId, listing]);
|
|
1192
|
-
(0, react_1.useEffect)(() => {
|
|
1193
|
-
if ((student === null || student === void 0 ? void 0 : student.id) !== (application === null || application === void 0 ? void 0 : application.uid)) {
|
|
1194
|
-
if (user.userType === "Students") {
|
|
1195
|
-
setStudent(user);
|
|
1196
|
-
}
|
|
1197
|
-
else if (user.product === "providers" && (application === null || application === void 0 ? void 0 : application.uid)) {
|
|
1198
|
-
firebaseQuery.getDocData(["users", application.uid]).then((s) => setStudent(s));
|
|
1199
|
-
}
|
|
1200
|
-
}
|
|
1201
|
-
}, []);
|
|
1202
|
-
(0, react_1.useEffect)(() => {
|
|
1203
|
-
setFListing(listing);
|
|
1204
|
-
}, [listing]);
|
|
1205
|
-
(0, react_1.useEffect)(() => {
|
|
1206
|
-
if (provider === null || provider === void 0 ? void 0 : provider.profile)
|
|
1207
|
-
return;
|
|
1208
|
-
if (!(provider === null || provider === void 0 ? void 0 : provider.id))
|
|
1209
|
-
return;
|
|
1210
|
-
(0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `providers/${provider === null || provider === void 0 ? void 0 : provider.id}/profilePic.png`)).then(setProfileUrl).catch(() => null);
|
|
1211
|
-
}, [provider]);
|
|
1212
|
-
(0, react_1.useEffect)(() => {
|
|
1213
|
-
console.log("APPLICATIONID", applicationId);
|
|
1214
|
-
if (!applicationId) {
|
|
1215
|
-
if (!listingId)
|
|
1216
|
-
return;
|
|
1217
|
-
firebaseQuery.getDocsWhere("applications", [(0, firestore_1.where)("status", "not-in", ["approved", "declined"]), (0, firestore_1.where)("uid", "==", user.id), (0, firestore_1.where)("listingId", "==", listingId)]).then((existingApplication) => {
|
|
1218
|
-
console.log("EXISTING", existingApplication);
|
|
1219
|
-
// get uploaded files
|
|
1220
|
-
if (existingApplication && Object.keys(existingApplication).length) {
|
|
1221
|
-
setFApplication(Object.values(existingApplication)[0]);
|
|
1222
|
-
setFApplicationId(Object.keys(existingApplication)[0]);
|
|
1223
|
-
}
|
|
1224
|
-
});
|
|
1225
|
-
return;
|
|
1226
|
-
}
|
|
1227
|
-
if (applicationId)
|
|
1228
|
-
setFApplicationId(applicationId);
|
|
1229
|
-
}, [application, applicationId]);
|
|
1230
|
-
const getCurrentStage = async (stage) => {
|
|
1231
|
-
var _a, _b, _c, _d;
|
|
1232
|
-
if (!(fListing === null || fListing === void 0 ? void 0 : fListing.applicantWorkflowId))
|
|
1233
|
-
throw new Error("No workflow stage");
|
|
1234
|
-
const mApplicantWorkflow = await firebaseQuery.getDocData(["applicantWorkflows", fListing.applicantWorkflowId]);
|
|
1235
|
-
const stageObj = (_a = mApplicantWorkflow === null || mApplicantWorkflow === void 0 ? void 0 : mApplicantWorkflow.workflow) === null || _a === void 0 ? void 0 : _a.find((s) => s.id === stage);
|
|
1236
|
-
if (!stageObj)
|
|
1237
|
-
throw new Error("Can't find stage.");
|
|
1238
|
-
const applicantFiles = stageObj.files ? Object.fromEntries(await Promise.all((_b = stageObj.files) === null || _b === void 0 ? void 0 : _b.map(async (fileId) => {
|
|
1239
|
-
const file = await firebaseQuery.getDocData(["files", fileId]);
|
|
1240
|
-
file.url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `userFiles/${file.fileName}`));
|
|
1241
|
-
return [fileId, file];
|
|
1242
|
-
}))) : [];
|
|
1243
|
-
const applicantForms = stageObj.forms ? Object.fromEntries(await Promise.all((_c = stageObj.forms) === null || _c === void 0 ? void 0 : _c.map(async (formId) => {
|
|
1244
|
-
return [formId, await firebaseQuery.getDocData(["forms", formId])];
|
|
1245
|
-
}))) : [];
|
|
1246
|
-
stageObj.viewableFiles = applicantFiles;
|
|
1247
|
-
stageObj.formDetails = applicantForms;
|
|
1248
|
-
return { stage: stageObj, completedSections: ((_d = fApplication === null || fApplication === void 0 ? void 0 : fApplication.completedSections) === null || _d === void 0 ? void 0 : _d[stage]) || {} };
|
|
1249
|
-
};
|
|
1250
|
-
(0, react_1.useEffect)(() => {
|
|
1251
|
-
const getUploadedFiles = async () => {
|
|
1252
|
-
if (!fApplication.completedSections) {
|
|
1253
|
-
setUploadedFiles({});
|
|
1254
|
-
return;
|
|
1255
|
-
}
|
|
1256
|
-
;
|
|
1257
|
-
const fileIds = Object.values(fApplication.completedSections)
|
|
1258
|
-
.flatMap(stageData => Object.values(stageData.filesUploaded || {}).flatMap(fileIds => fileIds));
|
|
1259
|
-
const fileDataPromises = fileIds.map(async (fileId) => {
|
|
1260
|
-
const fileData = await firebaseQuery.getDocData(["files", fileId]);
|
|
1261
|
-
fileData.url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `userFiles/${fileData.fileName}`));
|
|
1262
|
-
return [fileId, fileData];
|
|
1263
|
-
});
|
|
1264
|
-
const fileDataArray = await Promise.all(fileDataPromises);
|
|
1265
|
-
const fileDataObj = Object.fromEntries(fileDataArray);
|
|
1266
|
-
setUploadedFiles(fileDataObj);
|
|
1267
|
-
};
|
|
1268
|
-
const addApplication = async () => {
|
|
1269
|
-
console.log("ADDING APPLICATION");
|
|
1270
|
-
if (!(fListing === null || fListing === void 0 ? void 0 : fListing.id) || !(fProvider === null || fProvider === void 0 ? void 0 : fProvider.id) || !(student === null || student === void 0 ? void 0 : student.id))
|
|
1271
|
-
return;
|
|
1272
|
-
const applicationData = {
|
|
1273
|
-
uid: student.id,
|
|
1274
|
-
listingId: fListing === null || fListing === void 0 ? void 0 : fListing.id,
|
|
1275
|
-
applicantWorkflowId: fListing === null || fListing === void 0 ? void 0 : fListing.applicantWorkflowId,
|
|
1276
|
-
providerId: fProvider.id,
|
|
1277
|
-
stage: 1,
|
|
1278
|
-
status: "draft",
|
|
1279
|
-
created: (new Date()).toISOString(),
|
|
1280
|
-
...fApplication,
|
|
1281
|
-
};
|
|
1282
|
-
const mApplicationId = (await firebaseQuery.add(["applications"], applicationData)).id;
|
|
1283
|
-
console.log("APPLICATION ADDED");
|
|
1284
|
-
setFApplicationId(mApplicationId);
|
|
1285
|
-
setFApplication(applicationData);
|
|
1286
|
-
setDraftSaved(true);
|
|
1287
|
-
return;
|
|
1288
|
-
};
|
|
1289
|
-
getUploadedFiles();
|
|
1290
|
-
console.log("Checking IDs");
|
|
1291
|
-
console.log(fListing === null || fListing === void 0 ? void 0 : fListing.id, fProvider === null || fProvider === void 0 ? void 0 : fProvider.id, student === null || student === void 0 ? void 0 : student.id);
|
|
1292
|
-
if (!(fListing === null || fListing === void 0 ? void 0 : fListing.id) || !(fProvider === null || fProvider === void 0 ? void 0 : fProvider.id) || !(student === null || student === void 0 ? void 0 : student.id))
|
|
1293
|
-
return;
|
|
1294
|
-
if (user.product === "providers")
|
|
1295
|
-
throw new Error("Providers cannot create applications");
|
|
1296
|
-
console.log("Checking dates and sections");
|
|
1297
|
-
if (!fApplication.completedSections && !fApplication.startDate && !fApplication.endDate)
|
|
1298
|
-
return;
|
|
1299
|
-
console.log("Application updated");
|
|
1300
|
-
if (!fApplicationId && !applicationId) {
|
|
1301
|
-
// save new
|
|
1302
|
-
console.log("Add application");
|
|
1303
|
-
addApplication();
|
|
1304
|
-
return;
|
|
1305
|
-
}
|
|
1306
|
-
// update
|
|
1307
|
-
firebaseQuery.update(["applications", (fApplicationId || applicationId)], fApplication);
|
|
1308
|
-
setDraftSaved(true);
|
|
1309
|
-
}, [fApplication]);
|
|
1310
|
-
const openSuccessPopup = (type) => {
|
|
1311
|
-
setSuccessPopup(type);
|
|
1312
|
-
setTimeout(() => {
|
|
1313
|
-
// onClose();
|
|
1314
|
-
}, 1500);
|
|
1315
|
-
};
|
|
1316
|
-
(0, react_1.useEffect)(() => {
|
|
1317
|
-
const areStagesCompleted = async () => {
|
|
1318
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
1319
|
-
if (!fListing)
|
|
1320
|
-
return;
|
|
1321
|
-
if (fApplication.stage === undefined)
|
|
1322
|
-
return undefined;
|
|
1323
|
-
const currentStage = await getCurrentStage(fApplication.stage);
|
|
1324
|
-
console.log("Checking current stage is complete");
|
|
1325
|
-
for (const fileViewed of ((_a = currentStage.stage) === null || _a === void 0 ? void 0 : _a.files) || []) {
|
|
1326
|
-
console.log("Checking file viewed", fileViewed, "in", (_b = currentStage === null || currentStage === void 0 ? void 0 : currentStage.completedSections) === null || _b === void 0 ? void 0 : _b.filesViewed);
|
|
1327
|
-
if (!((_d = (_c = currentStage === null || currentStage === void 0 ? void 0 : currentStage.completedSections) === null || _c === void 0 ? void 0 : _c.filesViewed) === null || _d === void 0 ? void 0 : _d.includes(fileViewed))) {
|
|
1328
|
-
console.log("File not viewed");
|
|
1329
|
-
return false;
|
|
1330
|
-
}
|
|
1331
|
-
else {
|
|
1332
|
-
console.log("File viewed");
|
|
1333
|
-
}
|
|
1334
|
-
}
|
|
1335
|
-
for (const formCompleted of ((_e = currentStage === null || currentStage === void 0 ? void 0 : currentStage.stage) === null || _e === void 0 ? void 0 : _e.forms) || []) {
|
|
1336
|
-
console.log("Checking form completed", formCompleted, "in", (_f = currentStage === null || currentStage === void 0 ? void 0 : currentStage.completedSections) === null || _f === void 0 ? void 0 : _f.formsCompleted);
|
|
1337
|
-
if (!Object.keys(((_g = currentStage === null || currentStage === void 0 ? void 0 : currentStage.completedSections) === null || _g === void 0 ? void 0 : _g.formsCompleted) || {}).includes(formCompleted)) {
|
|
1338
|
-
console.log("Form not completed");
|
|
1339
|
-
return false;
|
|
1340
|
-
}
|
|
1341
|
-
else {
|
|
1342
|
-
console.log("Form completed");
|
|
1343
|
-
}
|
|
1344
|
-
}
|
|
1345
|
-
for (let i = 0; i++; i < (((_h = currentStage === null || currentStage === void 0 ? void 0 : currentStage.stage) === null || _h === void 0 ? void 0 : _h.requiredFiles) || []).length) {
|
|
1346
|
-
if (!Object.keys(((_j = currentStage === null || currentStage === void 0 ? void 0 : currentStage.completedSections) === null || _j === void 0 ? void 0 : _j.filesUploaded) || {}).includes(i.toString())) {
|
|
1347
|
-
console.log("Form not uploaded");
|
|
1348
|
-
return false;
|
|
1349
|
-
}
|
|
1350
|
-
else {
|
|
1351
|
-
console.log("Form uploaded");
|
|
1352
|
-
}
|
|
1353
|
-
}
|
|
1354
|
-
return true;
|
|
1355
|
-
};
|
|
1356
|
-
areStagesCompleted().then(setCurrentStageComplete);
|
|
1357
|
-
}, [fApplication, fListing]);
|
|
1358
|
-
const viewFile = (file, onOpen) => {
|
|
1359
|
-
var _a, _b;
|
|
1360
|
-
if (fApplication.reqUserType !== user.userType)
|
|
1361
|
-
return;
|
|
1362
|
-
if (fApplication.stage === undefined)
|
|
1363
|
-
throw new Error("Missing applciation stage.");
|
|
1364
|
-
const viewableFiles = (_b = (_a = fListing === null || fListing === void 0 ? void 0 : fListing.applicantWorkflow) === null || _a === void 0 ? void 0 : _a.find((stage) => stage.id === fApplication.stage)) === null || _b === void 0 ? void 0 : _b.viewableFiles;
|
|
1365
|
-
setFApplication((a) => {
|
|
1366
|
-
var _a, _b;
|
|
1367
|
-
const oldA = { ...a };
|
|
1368
|
-
const viewedFiles = ((_b = (_a = a.completedSections) === null || _a === void 0 ? void 0 : _a[1]) === null || _b === void 0 ? void 0 : _b.filesViewed) || [];
|
|
1369
|
-
if (viewedFiles === null || viewedFiles === void 0 ? void 0 : viewedFiles.includes(file))
|
|
1370
|
-
return a;
|
|
1371
|
-
(viewableFiles === null || viewableFiles === void 0 ? void 0 : viewableFiles[file].url) && onOpen(viewableFiles === null || viewableFiles === void 0 ? void 0 : viewableFiles[file].url);
|
|
1372
|
-
viewedFiles === null || viewedFiles === void 0 ? void 0 : viewedFiles.push(file);
|
|
1373
|
-
const newA = (0, util_1.editNestedObject)(["completedSections", 1, "filesViewed"], oldA, viewedFiles);
|
|
1374
|
-
return newA;
|
|
1375
|
-
});
|
|
1376
|
-
};
|
|
1377
|
-
const addFile = (files, fileId) => {
|
|
1378
|
-
if (fApplication.reqUserType !== user.userType)
|
|
1379
|
-
throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
|
|
1380
|
-
if (fApplication.stage === undefined)
|
|
1381
|
-
throw new Error("Missing applciation stage.");
|
|
1382
|
-
if (!files.length)
|
|
1383
|
-
throw new Error("No files to upload");
|
|
1384
|
-
setFApplication((a) => (0, util_1.editNestedObject)(["completedSections", fApplication.stage, "filesUploaded", fileId], a, files));
|
|
1385
|
-
};
|
|
1386
|
-
const setFormComplete = (formId, e) => {
|
|
1387
|
-
if (fApplication.reqUserType !== user.userType)
|
|
1388
|
-
throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
|
|
1389
|
-
if (fApplication.stage === undefined)
|
|
1390
|
-
throw new Error("Missing applciation stage.");
|
|
1391
|
-
setFApplication((a) => (0, util_1.editNestedObject)(["completedSections", fApplication.stage, "formsCompleted", formId], a, e));
|
|
1392
|
-
};
|
|
1393
|
-
const successText = {
|
|
1394
|
-
submitted: {
|
|
1395
|
-
title: "Application submitted",
|
|
1396
|
-
desc: "We've sent your application to the placement provider. You will hear what the next steps are soon.",
|
|
1397
|
-
},
|
|
1398
|
-
draftSaved: {
|
|
1399
|
-
title: "Draft saved",
|
|
1400
|
-
desc: "Your draft has been saved. Go to the 'Applications' section from your home screen to edit.",
|
|
1401
|
-
},
|
|
1402
|
-
stageComplete: {
|
|
1403
|
-
title: "Stage complete",
|
|
1404
|
-
desc: "We have sent this to the next stage in the application process. We will update you with any progress.",
|
|
1405
|
-
},
|
|
1406
|
-
outcome: {
|
|
1407
|
-
title: "Outcome submitted",
|
|
1408
|
-
desc: "We have sent the student an email with the outcome of their application.",
|
|
1409
|
-
},
|
|
1410
|
-
};
|
|
1411
|
-
const onFApply = async (draft) => {
|
|
1412
|
-
if (draft) {
|
|
1413
|
-
openSuccessPopup("draftSaved");
|
|
1414
|
-
return;
|
|
1415
|
-
}
|
|
1416
|
-
// Check all items have been filled in.
|
|
1417
|
-
if (!fApplication.startDate || !fApplication.endDate)
|
|
1418
|
-
throw new Error("Please select dates for your placement.");
|
|
1419
|
-
await (0, firebase_1.executeCallable)("applications-submit", { applicationId: fApplicationId });
|
|
1420
|
-
openSuccessPopup("submitted");
|
|
1421
|
-
};
|
|
1422
|
-
const progressStage = async (type, e) => {
|
|
1423
|
-
// Check all stages completed.
|
|
1424
|
-
if (!currentStageComplete)
|
|
1425
|
-
throw new Error("Complete all forms before submitting.");
|
|
1426
|
-
if (fApplication.reqUserType !== user.userType)
|
|
1427
|
-
throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
|
|
1428
|
-
if (fApplication.stage === undefined)
|
|
1429
|
-
throw new Error("Missing applciation stage.");
|
|
1430
|
-
await (0, firebase_1.executeCallable)("applications-changeStage", { applicationId: fApplicationId, type: type, feedback: e === null || e === void 0 ? void 0 : e.feedback });
|
|
1125
|
+
setLoadMoreIcon(false);
|
|
1431
1126
|
};
|
|
1432
|
-
|
|
1127
|
+
(0, react_1.useEffect)(() => {
|
|
1128
|
+
loadMore();
|
|
1129
|
+
}, []);
|
|
1130
|
+
return ({ ...{ items, loadMore, loadMoreIcon, reset } });
|
|
1433
1131
|
}
|
|
1132
|
+
// type PublicPlacementListingLoaderParams = {
|
|
1133
|
+
// providerId?: string,
|
|
1134
|
+
// number: number,
|
|
1135
|
+
// }
|
|
1136
|
+
// export function usePublicPlacementListingLoader({providerId, number=5}:PublicPlacementListingLoaderParams) {
|
|
1137
|
+
// const [items, setItems] = useState<{[key:string]:{[key:string]:unknown}}>({});
|
|
1138
|
+
// const [loadMoreIcon, setLoadMoreIcon] = useState<boolean>(false);
|
|
1139
|
+
// const [lastItem, setLastItem] = useState<QueryDocumentSnapshot<DocumentData>>();
|
|
1140
|
+
// const firebaseQuery = new FirebaseQuery();
|
|
1141
|
+
// const reset = () => {
|
|
1142
|
+
// setItems({});
|
|
1143
|
+
// setLastItem(undefined);
|
|
1144
|
+
// };
|
|
1145
|
+
// const loadMore = async () => {
|
|
1146
|
+
// setLoadMoreIcon(true);
|
|
1147
|
+
// let formattedConstraints:QueryConstraint[] = [
|
|
1148
|
+
// where("status", "==", "listed"),
|
|
1149
|
+
// limit(number)
|
|
1150
|
+
// ];
|
|
1151
|
+
// if (providerId) {
|
|
1152
|
+
// formattedConstraints.push(where("providerId", "==", providerId));
|
|
1153
|
+
// }
|
|
1154
|
+
// if (lastItem) {
|
|
1155
|
+
// formattedConstraints.push(startAfter(lastItem));
|
|
1156
|
+
// }
|
|
1157
|
+
// const documents = await firebaseQuery.getDocsWhere("placementListings", formattedConstraints, true) as QuerySnapshot<DocumentData>;
|
|
1158
|
+
// console.log("docs", documents.docs);
|
|
1159
|
+
// setLastItem(documents.docs[documents.docs.length-1]);
|
|
1160
|
+
// const processedItems = Object.fromEntries(await Promise.all(Object.values(documents.docs).map(async (doc) => {
|
|
1161
|
+
// let itemObj = {...doc.data(), id: doc.id} as PlacementListing;
|
|
1162
|
+
// if (itemObj.addressId) {
|
|
1163
|
+
// const address = await firebaseQuery.getDocData(["addresses", itemObj.addressId]) as Address;
|
|
1164
|
+
// delete address.id;
|
|
1165
|
+
// itemObj = {...address, ...itemObj};
|
|
1166
|
+
// }
|
|
1167
|
+
// if (itemObj.applicantWorkflowId) {
|
|
1168
|
+
// const applicantWorkflow = (await firebaseQuery.getDocData(["applicantWorkflows", itemObj.applicantWorkflowId]) as ApplicantWorkflow).workflow.filter((i) => i.id === 1)[0];
|
|
1169
|
+
// const applicantFiles = applicantWorkflow.files ? Object.fromEntries(await Promise.all(applicantWorkflow.files?.map(async (fileId) => {
|
|
1170
|
+
// const file = await firebaseQuery.getDocData(["files", fileId]);
|
|
1171
|
+
// file.url = await getDownloadURL(ref(storage, `providers/${itemObj.providerId}/${file.fileName}`));
|
|
1172
|
+
// return [fileId, file];
|
|
1173
|
+
// }))) : [];
|
|
1174
|
+
// const applicantForms = applicantWorkflow.forms ? Object.fromEntries(await Promise.all(applicantWorkflow.forms?.map(async (formId) => {
|
|
1175
|
+
// return [formId, await firebaseQuery.getDocData(["forms", formId])];
|
|
1176
|
+
// }))) : [];
|
|
1177
|
+
// applicantWorkflow.viewableFiles = applicantFiles;
|
|
1178
|
+
// applicantWorkflow.formDetails = applicantForms;
|
|
1179
|
+
// itemObj = {...itemObj, applicantWorkflow: [applicantWorkflow]};
|
|
1180
|
+
// }
|
|
1181
|
+
// return [doc.id, itemObj];
|
|
1182
|
+
// })))
|
|
1183
|
+
// setItems((i) => ({...i, ...processedItems}));
|
|
1184
|
+
// setLoadMoreIcon(false);
|
|
1185
|
+
// };
|
|
1186
|
+
// useEffect(() => {
|
|
1187
|
+
// loadMore();
|
|
1188
|
+
// }, []);
|
|
1189
|
+
// return ({...{items, loadMore, loadMoreIcon, reset}});
|
|
1190
|
+
// }
|
|
1191
|
+
// export type ApplicationHookParams = {
|
|
1192
|
+
// successText: {
|
|
1193
|
+
// submitted: {
|
|
1194
|
+
// title: string;
|
|
1195
|
+
// desc: string;
|
|
1196
|
+
// };
|
|
1197
|
+
// draftSaved: {
|
|
1198
|
+
// title: string;
|
|
1199
|
+
// desc: string;
|
|
1200
|
+
// };
|
|
1201
|
+
// stageComplete: {
|
|
1202
|
+
// title: string;
|
|
1203
|
+
// desc: string;
|
|
1204
|
+
// };
|
|
1205
|
+
// outcome: {
|
|
1206
|
+
// title: string;
|
|
1207
|
+
// desc: string;
|
|
1208
|
+
// };
|
|
1209
|
+
// };
|
|
1210
|
+
// setSuccessPopup: import("react").Dispatch<import("react").SetStateAction<"submitted" | "draftSaved" | "stageComplete" | "outcome" | undefined>>;
|
|
1211
|
+
// openSuccessPopup: (type: "submitted" | "draftSaved" | "stageComplete" | "outcome") => void;
|
|
1212
|
+
// setFApplication: import("react").Dispatch<import("react").SetStateAction<Partial<Application>>>;
|
|
1213
|
+
// fApplication: Partial<Application>;
|
|
1214
|
+
// draftSaved: boolean;
|
|
1215
|
+
// profileUrl: string | undefined;
|
|
1216
|
+
// successPopup: "submitted" | "draftSaved" | "stageComplete" | "outcome" | undefined;
|
|
1217
|
+
// fApplicationId: string | undefined;
|
|
1218
|
+
// fListing: PlacementListing | false | undefined;
|
|
1219
|
+
// student: UserData | undefined;
|
|
1220
|
+
// fProvider: {
|
|
1221
|
+
// details?: ProviderData;
|
|
1222
|
+
// profile?: string;
|
|
1223
|
+
// id?: string;
|
|
1224
|
+
// } | undefined;
|
|
1225
|
+
// onFApply: (draft?: boolean) => Promise<void>;
|
|
1226
|
+
// setFormComplete: (formId: string, e: {
|
|
1227
|
+
// [key: string]: unknown;
|
|
1228
|
+
// }) => void;
|
|
1229
|
+
// viewFile: (file: string, onOpen: (url: string) => void) => void
|
|
1230
|
+
// addFile: (files: string[], fileId: number) => void;
|
|
1231
|
+
// uploadedFiles?: {
|
|
1232
|
+
// [key: string]: FileItem;
|
|
1233
|
+
// };
|
|
1234
|
+
// getCurrentStage: (stage: number) => Promise<{
|
|
1235
|
+
// stage: ApplicantStage;
|
|
1236
|
+
// completedSections: {
|
|
1237
|
+
// submitted?: string | undefined;
|
|
1238
|
+
// filesViewed?: string[] | undefined;
|
|
1239
|
+
// formsCompleted?: {
|
|
1240
|
+
// [key: string]: unknown;
|
|
1241
|
+
// } | undefined;
|
|
1242
|
+
// filesUploaded?: {
|
|
1243
|
+
// [key: number]: string[];
|
|
1244
|
+
// } | undefined;
|
|
1245
|
+
// };
|
|
1246
|
+
// }>;
|
|
1247
|
+
// currentStageComplete?: boolean;
|
|
1248
|
+
// progressStage: (type: number | "accept" | "reject", e?: {
|
|
1249
|
+
// feedback?: string;
|
|
1250
|
+
// }) => Promise<void>;
|
|
1251
|
+
// };
|
|
1252
|
+
// export function useCreateApplicationRenderer({user, listingId, listing, provider, application, applicationId, orgContext}:
|
|
1253
|
+
// {user:UserData, listingId:string, applicationId?: string, listing?: PlacementListing, application?: Partial<Application>,
|
|
1254
|
+
// orgContext?: {details: ProviderData, addresses: {[key: string]: OrganisationAddress}, applicantWorkflows: {[key: string]: ApplicantWorkflow}},
|
|
1255
|
+
// provider?: {details?: ProviderData, profile?: string, id?: string}}) {
|
|
1256
|
+
// const firebaseQuery = new FirebaseQuery();
|
|
1257
|
+
// let applicationWithoutAdditionalData = {...(application || {})} as any;
|
|
1258
|
+
// delete applicationWithoutAdditionalData.listing;
|
|
1259
|
+
// delete applicationWithoutAdditionalData.address;
|
|
1260
|
+
// delete applicationWithoutAdditionalData.provider;
|
|
1261
|
+
// const [fApplication, setFApplication] = useState<Partial<Application>>(application ? applicationWithoutAdditionalData : {
|
|
1262
|
+
// uid: user.userType === "Students" ? user.id : undefined,
|
|
1263
|
+
// listingId: listingId,
|
|
1264
|
+
// addressId: listing?.addressId,
|
|
1265
|
+
// stage: 1,
|
|
1266
|
+
// reqUserType: "Students",
|
|
1267
|
+
// status: "draft"});
|
|
1268
|
+
// const [fApplicationId, setFApplicationId] = useState<string|undefined>(applicationId);
|
|
1269
|
+
// const [draftSaved, setDraftSaved] = useState(false);
|
|
1270
|
+
// const [fProvider, setFProvider] = useState<{details?: ProviderData, profile?: string, id?: string}|undefined>(provider);
|
|
1271
|
+
// const [fListing, setFListing] = useState<PlacementListing|false|undefined>(Object.keys(listing || {}).length > 5 ? listing : undefined);
|
|
1272
|
+
// const [student, setStudent] = useState<UserData|undefined>(user.userType === "Students" ? user : undefined);
|
|
1273
|
+
// const [profileUrl, setProfileUrl] = useState<string>();
|
|
1274
|
+
// const [successPopup, setSuccessPopup] = useState<"submitted"|"draftSaved"|"stageComplete"|"outcome">();
|
|
1275
|
+
// const [uploadedFiles, setUploadedFiles] = useState<{[key: string]: FileItem}>();
|
|
1276
|
+
// const [currentStageComplete, setCurrentStageComplete] = useState<boolean>();
|
|
1277
|
+
// useEffect(() => {
|
|
1278
|
+
// const getListing = async () => {
|
|
1279
|
+
// console.log("Checking ID")
|
|
1280
|
+
// if (!listingId) return;
|
|
1281
|
+
// console.log("Getting listing")
|
|
1282
|
+
// console.log("LISTING PARAM", listing, Object.keys(listing || {}).length > 5);
|
|
1283
|
+
// const listingData = (Object.keys(listing || {}).length > 5) ? listing : (await firebaseQuery.getDocData(["placementListings", listingId]).catch(() => false) as PlacementListing|false);
|
|
1284
|
+
// console.log("LISTINGDATA", listingData, Object.keys(listing || {}).length > 5 ? {a: "string"} : "AAA");
|
|
1285
|
+
// const address = listingData ? (user.product === "providers" && orgContext) ? orgContext.addresses[listingData.addressId || ""] : await firebaseQuery.getDocData(["addresses", listingData.addressId as string]) as Address : undefined;
|
|
1286
|
+
// const workflow = listingData ? (user.product === "providers" && orgContext) ? orgContext.applicantWorkflows[listingData.applicantWorkflowId || ""] as ApplicantWorkflow : await firebaseQuery.getDocData(["applicantWorkflows", listingData.applicantWorkflowId as string]) as ApplicantWorkflow : undefined;
|
|
1287
|
+
// if (workflow && listingData) {
|
|
1288
|
+
// workflow.workflow = await Promise.all(workflow.workflow.map(async (s) => {
|
|
1289
|
+
// const applicantFiles = s.files ? Object.fromEntries(await Promise.all(s.files?.map(async (fileId: string) => {
|
|
1290
|
+
// const file = await firebaseQuery.getDocData(["files", fileId]);
|
|
1291
|
+
// file.url = await getDownloadURL(ref(storage, `providers/${listingData?.providerId}/${file.fileName}`));
|
|
1292
|
+
// return [fileId, file];
|
|
1293
|
+
// }))) : [];
|
|
1294
|
+
// const applicantForms = s.forms ? Object.fromEntries(await Promise.all(s.forms?.map(async (formId: string) => {
|
|
1295
|
+
// return [formId, await firebaseQuery.getDocData(["forms", formId])];
|
|
1296
|
+
// }))) : [];
|
|
1297
|
+
// return {...s, viewableFiles: applicantFiles, formDetails: applicantForms};
|
|
1298
|
+
// }));
|
|
1299
|
+
// delete workflow.id;
|
|
1300
|
+
// }
|
|
1301
|
+
// if (address) {
|
|
1302
|
+
// delete address.id;
|
|
1303
|
+
// }
|
|
1304
|
+
// console.log("Setting listing")
|
|
1305
|
+
// setFListing((listingData && workflow) ? {...listingData, ...address, applicantWorkflow: workflow.workflow} as PlacementListing : false);
|
|
1306
|
+
// if ((fProvider?.id === application?.providerId) && user.product === "providers") {
|
|
1307
|
+
// setFProvider({details: orgContext?.details, id: user.oId});
|
|
1308
|
+
// } else if (listingData && listingData?.providerId) {
|
|
1309
|
+
// console.log("Getting provider from DB");
|
|
1310
|
+
// const provider = await firebaseQuery.getDocData(["providers", listingData.providerId]) as ProviderData;
|
|
1311
|
+
// console.log("Provider", provider);
|
|
1312
|
+
// setFProvider({details: provider, id: listingData.providerId});
|
|
1313
|
+
// }
|
|
1314
|
+
// }
|
|
1315
|
+
// getListing();
|
|
1316
|
+
// }, [listingId, listing]);
|
|
1317
|
+
// useEffect(() => {
|
|
1318
|
+
// if (student?.id !== application?.uid) {
|
|
1319
|
+
// if (user.userType === "Students") {
|
|
1320
|
+
// setStudent(user);
|
|
1321
|
+
// } else if (user.product === "providers" && application?.uid) {
|
|
1322
|
+
// firebaseQuery.getDocData(["users", application.uid]).then((s) => setStudent(s as UserData));
|
|
1323
|
+
// }
|
|
1324
|
+
// }
|
|
1325
|
+
// }, []);
|
|
1326
|
+
// useEffect(() => {
|
|
1327
|
+
// setFListing(Object.keys(listing || {}).length > 5 ? listing : undefined);
|
|
1328
|
+
// }, [listing]);
|
|
1329
|
+
// useEffect(() => {
|
|
1330
|
+
// if (provider?.profile) return;
|
|
1331
|
+
// if (!provider?.id) return;
|
|
1332
|
+
// getDownloadURL(ref(storage, `providers/${provider?.id}/profilePic.png`)).then(setProfileUrl).catch(() => null);
|
|
1333
|
+
// }, [provider]);
|
|
1334
|
+
// useEffect(() => {
|
|
1335
|
+
// console.log("APPLICATIONID", applicationId);
|
|
1336
|
+
// if (!applicationId) {
|
|
1337
|
+
// if (!listingId) return;
|
|
1338
|
+
// firebaseQuery.getDocsWhere("applications", [where("status", "not-in", ["approved", "declined"]), where("uid", "==", user.id), where("listingId", "==", listingId)]).then((existingApplication) => {
|
|
1339
|
+
// console.log("EXISTING", existingApplication);
|
|
1340
|
+
// // get uploaded files
|
|
1341
|
+
// if (existingApplication && Object.keys(existingApplication).length) {
|
|
1342
|
+
// setFApplication(Object.values(existingApplication)[0]);
|
|
1343
|
+
// setFApplicationId(Object.keys(existingApplication)[0]);
|
|
1344
|
+
// }
|
|
1345
|
+
// });
|
|
1346
|
+
// return;
|
|
1347
|
+
// }
|
|
1348
|
+
// if (applicationId) {
|
|
1349
|
+
// setFApplicationId(applicationId);
|
|
1350
|
+
// if (application) {
|
|
1351
|
+
// let applicationWithoutAdditionalData = {...(application || {})} as any;
|
|
1352
|
+
// delete applicationWithoutAdditionalData.listing;
|
|
1353
|
+
// delete applicationWithoutAdditionalData.address;
|
|
1354
|
+
// delete applicationWithoutAdditionalData.provider;
|
|
1355
|
+
// setFApplication(applicationWithoutAdditionalData);
|
|
1356
|
+
// } else {
|
|
1357
|
+
// firebaseQuery.getDocData(["applications", applicationId]).then(setFApplication);
|
|
1358
|
+
// }
|
|
1359
|
+
// }
|
|
1360
|
+
// }, [application, applicationId]);
|
|
1361
|
+
// const getCurrentStage = async (stage: number): Promise<{
|
|
1362
|
+
// stage: ApplicantStage; completedSections: {
|
|
1363
|
+
// submitted?: string | undefined;
|
|
1364
|
+
// filesViewed?: string[] | undefined;
|
|
1365
|
+
// formsCompleted?: {
|
|
1366
|
+
// [key: string]: unknown;
|
|
1367
|
+
// } | undefined;
|
|
1368
|
+
// filesUploaded?: {
|
|
1369
|
+
// [key: number]: string[];
|
|
1370
|
+
// } | undefined;
|
|
1371
|
+
// };
|
|
1372
|
+
// }> => {
|
|
1373
|
+
// console.log("fLSITING CURRENT STAGE", fListing);
|
|
1374
|
+
// if (!fListing) throw new Error("Listing deleted");
|
|
1375
|
+
// if (!fListing?.applicantWorkflowId) throw new Error("No workflow stage");
|
|
1376
|
+
// const mApplicantWorkflow = (await firebaseQuery.getDocData(["applicantWorkflows", fListing.applicantWorkflowId]) as ApplicantWorkflow);
|
|
1377
|
+
// const stageObj = mApplicantWorkflow?.workflow?.find((s) => s.id === stage);
|
|
1378
|
+
// if (!stageObj) throw new Error("Can't find stage.");
|
|
1379
|
+
// const applicantFiles = stageObj.files ? Object.fromEntries(await Promise.all(stageObj.files?.map(async (fileId) => {
|
|
1380
|
+
// const file = await firebaseQuery.getDocData(["files", fileId]);
|
|
1381
|
+
// file.url = await getDownloadURL(ref(storage, `providers/${mApplicantWorkflow?.oId}/${file.fileName}`));
|
|
1382
|
+
// return [fileId, file];
|
|
1383
|
+
// }))) : [];
|
|
1384
|
+
// const applicantForms = stageObj.forms ? Object.fromEntries(await Promise.all(stageObj.forms?.map(async (formId) => {
|
|
1385
|
+
// return [formId, await firebaseQuery.getDocData(["forms", formId])];
|
|
1386
|
+
// }))) : [];
|
|
1387
|
+
// stageObj.viewableFiles = applicantFiles;
|
|
1388
|
+
// stageObj.formDetails = applicantForms;
|
|
1389
|
+
// return {stage: stageObj, completedSections: fApplication?.completedSections?.[stage] || {}};
|
|
1390
|
+
// };
|
|
1391
|
+
// useEffect(() => {
|
|
1392
|
+
// const getUploadedFiles = async () => {
|
|
1393
|
+
// if (!fApplication.completedSections) {
|
|
1394
|
+
// setUploadedFiles({});
|
|
1395
|
+
// return
|
|
1396
|
+
// };
|
|
1397
|
+
// const fileIds = Object.values(fApplication.completedSections)
|
|
1398
|
+
// .flatMap(stageData =>
|
|
1399
|
+
// Object.values(stageData.filesUploaded || {}).flatMap(fileIds => fileIds)
|
|
1400
|
+
// );
|
|
1401
|
+
// const fileDataPromises = fileIds.map(async (fileId) => {
|
|
1402
|
+
// const fileData = await firebaseQuery.getDocData(["files", fileId]) as FileItem;
|
|
1403
|
+
// fileData.url = await getDownloadURL(ref(storage, `userFiles/${fileData.fileName}`));
|
|
1404
|
+
// return [fileId, fileData] as [string, FileItem]
|
|
1405
|
+
// });
|
|
1406
|
+
// const fileDataArray = await Promise.all(fileDataPromises);
|
|
1407
|
+
// const fileDataObj = Object.fromEntries(fileDataArray)
|
|
1408
|
+
// setUploadedFiles(fileDataObj)
|
|
1409
|
+
// }
|
|
1410
|
+
// const addApplication = async () => {
|
|
1411
|
+
// console.log("ADDING APPLICATION");
|
|
1412
|
+
// if (!fListing || !fListing?.id || !fProvider?.id || !student?.id) return;
|
|
1413
|
+
// const applicationData = {
|
|
1414
|
+
// uid: student.id,
|
|
1415
|
+
// listingId: fListing?.id,
|
|
1416
|
+
// addressId: fListing.addressId,
|
|
1417
|
+
// applicantWorkflowId: fListing?.applicantWorkflowId,
|
|
1418
|
+
// providerId: fProvider.id,
|
|
1419
|
+
// stage: 1,
|
|
1420
|
+
// status: "draft",
|
|
1421
|
+
// created: (new Date()).toISOString(),
|
|
1422
|
+
// ...fApplication,
|
|
1423
|
+
// } as Partial<Application>;
|
|
1424
|
+
// const mApplicationId = (await firebaseQuery.add(["applications"], applicationData)).id;
|
|
1425
|
+
// console.log("APPLICATION ADDED");
|
|
1426
|
+
// setFApplicationId(mApplicationId);
|
|
1427
|
+
// setFApplication(applicationData);
|
|
1428
|
+
// setDraftSaved(true);
|
|
1429
|
+
// return;
|
|
1430
|
+
// };
|
|
1431
|
+
// getUploadedFiles();
|
|
1432
|
+
// console.log("Checking IDs");
|
|
1433
|
+
// if (!fListing || !fListing?.id || !fProvider?.id || !student?.id) return;
|
|
1434
|
+
// if (user.product === "providers") return;
|
|
1435
|
+
// console.log("Checking dates and sections");
|
|
1436
|
+
// if (!fApplication.completedSections && !fApplication.startDate && !fApplication.endDate) return;
|
|
1437
|
+
// console.log("Application updated");
|
|
1438
|
+
// if (!fApplicationId && !applicationId) {
|
|
1439
|
+
// // save new
|
|
1440
|
+
// console.log("Add application")
|
|
1441
|
+
// addApplication();
|
|
1442
|
+
// return;
|
|
1443
|
+
// }
|
|
1444
|
+
// // update
|
|
1445
|
+
// firebaseQuery.update(["applications", (fApplicationId || applicationId) as string], fApplication);
|
|
1446
|
+
// setDraftSaved(true);
|
|
1447
|
+
// }, [fApplication]);
|
|
1448
|
+
// const openSuccessPopup = (type: "submitted"|"draftSaved"|"stageComplete"|"outcome") => {
|
|
1449
|
+
// setSuccessPopup(type);
|
|
1450
|
+
// setTimeout(() => {
|
|
1451
|
+
// // onClose();
|
|
1452
|
+
// }, 1500);
|
|
1453
|
+
// };
|
|
1454
|
+
// useEffect(() => {
|
|
1455
|
+
// const areStagesCompleted = async ():Promise<boolean|undefined> => {
|
|
1456
|
+
// if (!fListing) return;
|
|
1457
|
+
// if (fApplication.stage === undefined) return undefined;
|
|
1458
|
+
// const currentStage = await getCurrentStage(fApplication.stage);
|
|
1459
|
+
// console.log("Checking current stage is complete");
|
|
1460
|
+
// for (const fileViewed of currentStage.stage?.files || []) {
|
|
1461
|
+
// console.log("Checking file viewed", fileViewed, "in", currentStage?.completedSections?.filesViewed);
|
|
1462
|
+
// if (!currentStage?.completedSections?.filesViewed?.includes(fileViewed)) {
|
|
1463
|
+
// console.log("File not viewed");
|
|
1464
|
+
// return false;
|
|
1465
|
+
// } else {
|
|
1466
|
+
// console.log("File viewed");
|
|
1467
|
+
// }
|
|
1468
|
+
// }
|
|
1469
|
+
// for (const formCompleted of currentStage?.stage?.forms || []) {
|
|
1470
|
+
// console.log("Checking form completed", formCompleted, "in", currentStage?.completedSections?.formsCompleted);
|
|
1471
|
+
// if (!Object.keys(currentStage?.completedSections?.formsCompleted || {}).includes(formCompleted)) {
|
|
1472
|
+
// console.log("Form not completed");
|
|
1473
|
+
// return false;
|
|
1474
|
+
// } else {
|
|
1475
|
+
// console.log("Form completed")
|
|
1476
|
+
// }
|
|
1477
|
+
// }
|
|
1478
|
+
// for (let i = 0; i++; i < (currentStage?.stage?.requiredFiles || []).length) {
|
|
1479
|
+
// if (!Object.keys(currentStage?.completedSections?.filesUploaded || {}).includes(i.toString())) {
|
|
1480
|
+
// console.log("Form not uploaded");
|
|
1481
|
+
// return false;
|
|
1482
|
+
// } else {
|
|
1483
|
+
// console.log("Form uploaded");
|
|
1484
|
+
// }
|
|
1485
|
+
// }
|
|
1486
|
+
// return true;
|
|
1487
|
+
// };
|
|
1488
|
+
// areStagesCompleted().then(setCurrentStageComplete);
|
|
1489
|
+
// }, [fApplication, fListing])
|
|
1490
|
+
// const viewFile = (file: string, onOpen: (url: string) => void) => {
|
|
1491
|
+
// if (fApplication.reqUserType !== user.userType) return;
|
|
1492
|
+
// if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
|
|
1493
|
+
// if (!fListing) throw new Error("No associated listing.");
|
|
1494
|
+
// const viewableFiles = fListing?.applicantWorkflow?.find((stage) => stage.id === fApplication.stage)?.viewableFiles;
|
|
1495
|
+
// setFApplication((a) => {
|
|
1496
|
+
// const oldA = {...a};
|
|
1497
|
+
// const viewedFiles = a.completedSections?.[1]?.filesViewed || [];
|
|
1498
|
+
// if (viewedFiles?.includes(file)) return a;
|
|
1499
|
+
// viewableFiles?.[file].url && onOpen(viewableFiles?.[file].url);
|
|
1500
|
+
// viewedFiles?.push(file);
|
|
1501
|
+
// const newA = editNestedObject(["completedSections", 1, "filesViewed"], oldA, viewedFiles) as Partial<Application>;
|
|
1502
|
+
// return newA;
|
|
1503
|
+
// });
|
|
1504
|
+
// };
|
|
1505
|
+
// const addFile = (files: string[], fileId: number) => {
|
|
1506
|
+
// if (fApplication.reqUserType !== user.userType) throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
|
|
1507
|
+
// if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
|
|
1508
|
+
// if (!files.length) throw new Error("No files to upload");
|
|
1509
|
+
// setFApplication((a) => editNestedObject(["completedSections", fApplication.stage as number, "filesUploaded", fileId], a, files) as Application);
|
|
1510
|
+
// };
|
|
1511
|
+
// const setFormComplete = (formId: string, e: {[key: string]: unknown}) => {
|
|
1512
|
+
// if (fApplication.reqUserType !== user.userType) throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
|
|
1513
|
+
// if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
|
|
1514
|
+
// setFApplication((a) => editNestedObject(["completedSections", fApplication.stage as number, "formsCompleted", formId], a, e) as Application);
|
|
1515
|
+
// };
|
|
1516
|
+
// const successText = {
|
|
1517
|
+
// submitted: {
|
|
1518
|
+
// title: "Application submitted",
|
|
1519
|
+
// desc: "We've sent your application to the placement provider. You will hear what the next steps are soon.",
|
|
1520
|
+
// },
|
|
1521
|
+
// draftSaved: {
|
|
1522
|
+
// title: "Draft saved",
|
|
1523
|
+
// desc: "Your draft has been saved. Go to the 'Applications' section from your home screen to edit.",
|
|
1524
|
+
// },
|
|
1525
|
+
// stageComplete: {
|
|
1526
|
+
// title: "Stage complete",
|
|
1527
|
+
// desc: "We have sent this to the next stage in the application process. We will update you with any progress.",
|
|
1528
|
+
// },
|
|
1529
|
+
// outcome: {
|
|
1530
|
+
// title: "Outcome submitted",
|
|
1531
|
+
// desc: "We have sent the student an email with the outcome of their application.",
|
|
1532
|
+
// },
|
|
1533
|
+
// };
|
|
1534
|
+
// const onFApply = async (draft?: boolean) => {
|
|
1535
|
+
// if (draft) {
|
|
1536
|
+
// openSuccessPopup("draftSaved")
|
|
1537
|
+
// return;
|
|
1538
|
+
// }
|
|
1539
|
+
// if (!fApplicationId) return;
|
|
1540
|
+
// // Check all items have been filled in.
|
|
1541
|
+
// if (!fApplication.startDate || !fApplication.endDate) throw new Error("Please select dates for your placement.");
|
|
1542
|
+
// await executeCallable("applications-submit", {applicationId: fApplicationId});
|
|
1543
|
+
// const newApplication = await firebaseQuery.getDocData(["applications", fApplicationId]) as Application;
|
|
1544
|
+
// setFApplication(newApplication);
|
|
1545
|
+
// openSuccessPopup("submitted")
|
|
1546
|
+
// };
|
|
1547
|
+
// const progressStage = async (type: number|"accept"|"reject", e?: {feedback?: string}) => {
|
|
1548
|
+
// // Check all stages completed.
|
|
1549
|
+
// if (!fApplicationId) return;
|
|
1550
|
+
// if (!currentStageComplete) throw new Error("Complete all forms before submitting.");
|
|
1551
|
+
// if (fApplication.reqUserType !== user.userType) throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
|
|
1552
|
+
// if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
|
|
1553
|
+
// await executeCallable("applications-changeStage", {applicationId: fApplicationId, type: type, feedback: e?.feedback});
|
|
1554
|
+
// const newApplication = await firebaseQuery.getDocData(["applications", fApplicationId]) as Application;
|
|
1555
|
+
// setFApplication(newApplication);
|
|
1556
|
+
// };
|
|
1557
|
+
// return {successText, onFApply, progressStage, currentStageComplete, uploadedFiles, getCurrentStage, setFormComplete, viewFile, addFile, setSuccessPopup, openSuccessPopup, setFApplication, fApplication, draftSaved, profileUrl, successPopup, fApplicationId, fListing, student, fProvider}
|
|
1558
|
+
// }
|
|
1434
1559
|
function useProposePlacementRenderer({ user, orgContext, placement }) {
|
|
1435
1560
|
const [businessSectionComplete, setBusinessSectionComplete] = (0, react_1.useState)(false);
|
|
1436
1561
|
const [addressSectionComplete, setAddressSectionComplete] = (0, react_1.useState)(false);
|
|
@@ -1481,11 +1606,9 @@ function useProposePlacementRenderer({ user, orgContext, placement }) {
|
|
|
1481
1606
|
}, [cohort]);
|
|
1482
1607
|
const submitSection = (type, data) => {
|
|
1483
1608
|
setFormData((f) => {
|
|
1484
|
-
const { id, ...values } = data;
|
|
1485
1609
|
return {
|
|
1486
1610
|
...f,
|
|
1487
|
-
...
|
|
1488
|
-
id: ((placement === null || placement === void 0 ? void 0 : placement.placementId) || (formData === null || formData === void 0 ? void 0 : formData.id))
|
|
1611
|
+
...data
|
|
1489
1612
|
};
|
|
1490
1613
|
});
|
|
1491
1614
|
if ((placement === null || placement === void 0 ? void 0 : placement.placementId) && type === "dates") {
|
|
@@ -1498,22 +1621,44 @@ function useProposePlacementRenderer({ user, orgContext, placement }) {
|
|
|
1498
1621
|
setFormData(undefined);
|
|
1499
1622
|
};
|
|
1500
1623
|
const proposePlacement = async (draft = false) => {
|
|
1624
|
+
const getPlacementStatus = (startDate, endDate) => {
|
|
1625
|
+
const today = new Date();
|
|
1626
|
+
if (startDate <= today && endDate >= today)
|
|
1627
|
+
return { active: !draft ? true : false, inProgress: true, completed: false };
|
|
1628
|
+
else if (endDate <= today)
|
|
1629
|
+
return { completed: true, inProgress: false, active: false };
|
|
1630
|
+
return { completed: false, inProgress: true, active: false };
|
|
1631
|
+
};
|
|
1501
1632
|
if (!formData || !student) {
|
|
1502
1633
|
throw new Error("Cannot find placement details.");
|
|
1503
1634
|
}
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
throw e;
|
|
1513
|
-
}).then((e) => {
|
|
1635
|
+
try {
|
|
1636
|
+
console.log("formData", formData);
|
|
1637
|
+
const status = getPlacementStatus(new Date(formData.startDate), new Date(formData.endDate));
|
|
1638
|
+
const newFormData = { ...formData, ...status };
|
|
1639
|
+
if (newFormData.id && newFormData.uid && draft === newFormData.draft)
|
|
1640
|
+
await firebaseQuery.update(["placements", newFormData.id], newFormData);
|
|
1641
|
+
else
|
|
1642
|
+
await (0, writeDatabase_1.addPlacement)(newFormData, student.id, draft);
|
|
1514
1643
|
setComplete(true);
|
|
1515
|
-
return
|
|
1516
|
-
}
|
|
1644
|
+
return { status };
|
|
1645
|
+
}
|
|
1646
|
+
catch (error) {
|
|
1647
|
+
console.log("Error:", error);
|
|
1648
|
+
throw error;
|
|
1649
|
+
}
|
|
1650
|
+
/*
|
|
1651
|
+
console.log("STUDENTID", student.id);
|
|
1652
|
+
|
|
1653
|
+
return await addPlacement(formData, student.id, draft).catch((e) => {
|
|
1654
|
+
console.log("error");
|
|
1655
|
+
console.log(e);
|
|
1656
|
+
throw e;
|
|
1657
|
+
}).then((e) => {
|
|
1658
|
+
setComplete(true);
|
|
1659
|
+
return e;
|
|
1660
|
+
});
|
|
1661
|
+
*/
|
|
1517
1662
|
};
|
|
1518
1663
|
const deletePlacement = async (id) => {
|
|
1519
1664
|
return await firebaseQuery.delete(["placements", id]);
|
|
@@ -1598,9 +1743,6 @@ function useUserUploadHandler({ product, oId, userType, user, onComplete, userGr
|
|
|
1598
1743
|
const [alert, setAlert] = (0, react_1.useState)();
|
|
1599
1744
|
const { execute } = (0, firebase_1.useExecuteCallableJob)({ user: user });
|
|
1600
1745
|
const requiredFields = ["forename", "surname", "email"];
|
|
1601
|
-
if (userType === "Students") {
|
|
1602
|
-
requiredFields.push("year");
|
|
1603
|
-
}
|
|
1604
1746
|
const checkData = (userData) => {
|
|
1605
1747
|
setAlert(undefined);
|
|
1606
1748
|
userData = userData.filter((u) => Object.entries(u).some(([, v]) => v));
|
|
@@ -1643,10 +1785,6 @@ function useUserUploadHandler({ product, oId, userType, user, onComplete, userGr
|
|
|
1643
1785
|
}
|
|
1644
1786
|
}
|
|
1645
1787
|
// Add more test cases
|
|
1646
|
-
if (userType === "Students" && (!user.year || !((user.year | 0) > 0 && user.year % 1 === 0))) {
|
|
1647
|
-
setAlert({ msg: "'Year' must be a number, e.g. 10.", severity: "error" });
|
|
1648
|
-
return false;
|
|
1649
|
-
}
|
|
1650
1788
|
}
|
|
1651
1789
|
if (emptyRequiredCell) {
|
|
1652
1790
|
return false;
|
|
@@ -1685,10 +1823,10 @@ function useUserUploadHandler({ product, oId, userType, user, onComplete, userGr
|
|
|
1685
1823
|
setAlert(undefined);
|
|
1686
1824
|
if (fUsers.length) {
|
|
1687
1825
|
console.log("fUsers", fUsers);
|
|
1688
|
-
execute("userManagement-addUsers", { product: product, oId: oId, users: fUsers, userType: userType, userGroupId: userGroupId, cohortId: cohortId });
|
|
1826
|
+
const jobId = await execute("userManagement-addUsers", { product: product, oId: oId, users: fUsers, userType: userType, userGroupId: userGroupId, cohortId: cohortId });
|
|
1827
|
+
onComplete && onComplete(jobId);
|
|
1689
1828
|
}
|
|
1690
1829
|
console.log("Complete", onComplete);
|
|
1691
|
-
onComplete && onComplete();
|
|
1692
1830
|
console.log("Finished");
|
|
1693
1831
|
};
|
|
1694
1832
|
const onChange = () => {
|
|
@@ -2239,34 +2377,34 @@ function useGenericWorkflowEditor({ user, initialData, defaultData, onSubmit })
|
|
|
2239
2377
|
includedForms, fSubmitWorkflow, openPopup, snackbar, setSnackbar, setMousePosFunc, mousePos, tutorialActive,
|
|
2240
2378
|
onDeleteArrow, fWorkflowNodes, containerRef, setError, setArrows, setFWorkflowNodes } });
|
|
2241
2379
|
}
|
|
2242
|
-
function
|
|
2380
|
+
function useInstituteProviderContactsHandler({ user }) {
|
|
2243
2381
|
const [emptyCellsWarning, setEmptyCellsWarning] = (0, react_1.useState)(false);
|
|
2244
2382
|
const [alert, setAlert] = (0, react_1.useState)();
|
|
2245
|
-
const requiredFields = ["
|
|
2383
|
+
const requiredFields = ["business", "forename", "email"];
|
|
2246
2384
|
const { execute } = (0, firebase_1.useExecuteCallableJob)({ user: user });
|
|
2247
|
-
const checkData = (
|
|
2385
|
+
const checkData = (providerContacts) => {
|
|
2248
2386
|
setAlert(undefined);
|
|
2249
|
-
|
|
2250
|
-
if (!Object.entries(
|
|
2387
|
+
providerContacts = providerContacts.filter((u) => Object.entries(u).some(([, v]) => v));
|
|
2388
|
+
if (!Object.entries(providerContacts)) {
|
|
2251
2389
|
return [];
|
|
2252
2390
|
}
|
|
2253
|
-
console.log("P",
|
|
2254
|
-
if (
|
|
2391
|
+
console.log("P", providerContacts);
|
|
2392
|
+
if (providerContacts.filter((u) => u.email).length < providerContacts.length) {
|
|
2255
2393
|
setAlert({ msg: "Your data contains missing email addresses.", severity: "error" });
|
|
2256
2394
|
return false;
|
|
2257
2395
|
}
|
|
2258
2396
|
let emptyOptionalCell = false;
|
|
2259
2397
|
let emptyRequiredCell = false;
|
|
2260
|
-
for (const
|
|
2261
|
-
if (!checkEmailValidity(
|
|
2398
|
+
for (const providerContact of providerContacts) {
|
|
2399
|
+
if (!checkEmailValidity(providerContact)) {
|
|
2262
2400
|
return false;
|
|
2263
2401
|
}
|
|
2264
|
-
if (Object.keys(
|
|
2402
|
+
if (Object.keys(providerContact).includes("")) {
|
|
2265
2403
|
setAlert({ msg: "Data cannot be uploaded in unnamed columns.", severity: "error" });
|
|
2266
2404
|
return false;
|
|
2267
2405
|
}
|
|
2268
|
-
for (const field in
|
|
2269
|
-
if (!
|
|
2406
|
+
for (const field in providerContact) {
|
|
2407
|
+
if (!providerContact[field]) {
|
|
2270
2408
|
if (requiredFields.includes(field)) {
|
|
2271
2409
|
setAlert({ msg: "All users must contain " + requiredFields.join(", "), severity: "error" });
|
|
2272
2410
|
emptyRequiredCell = true;
|
|
@@ -2286,39 +2424,26 @@ function useInstitutePlacementListingHandler({ user }) {
|
|
|
2286
2424
|
else {
|
|
2287
2425
|
setEmptyCellsWarning(false);
|
|
2288
2426
|
}
|
|
2289
|
-
return
|
|
2427
|
+
return providerContacts;
|
|
2290
2428
|
};
|
|
2291
|
-
const checkEmailValidity = (
|
|
2292
|
-
if (!(0, util_1.validateEmail)(
|
|
2293
|
-
setAlert({ msg: `Error in email formatting: ${
|
|
2429
|
+
const checkEmailValidity = (providerContact) => {
|
|
2430
|
+
if (!(0, util_1.validateEmail)(providerContact.email)) {
|
|
2431
|
+
setAlert({ msg: `Error in email formatting: ${providerContact.email}. Amend errors and reupload.`, severity: "error" });
|
|
2294
2432
|
return false;
|
|
2295
2433
|
}
|
|
2296
2434
|
return true;
|
|
2297
2435
|
};
|
|
2298
|
-
const
|
|
2299
|
-
let
|
|
2300
|
-
console.log("PP",
|
|
2301
|
-
const cleanUpload = checkData(
|
|
2436
|
+
const uploadProviderContacts = async (providers, schoolId) => {
|
|
2437
|
+
let fProviders = [];
|
|
2438
|
+
console.log("PP", providers);
|
|
2439
|
+
const cleanUpload = checkData(providers);
|
|
2302
2440
|
if (!cleanUpload) {
|
|
2303
2441
|
return false;
|
|
2304
2442
|
}
|
|
2305
|
-
|
|
2443
|
+
fProviders = cleanUpload;
|
|
2306
2444
|
setAlert(undefined);
|
|
2307
|
-
if (
|
|
2308
|
-
|
|
2309
|
-
name: v.provider,
|
|
2310
|
-
title: v.jobTitle,
|
|
2311
|
-
providerEmail: v.email,
|
|
2312
|
-
providerPhone: v.phone,
|
|
2313
|
-
["address-line1"]: v.addressOne,
|
|
2314
|
-
["address-line2"]: v.addressTwo,
|
|
2315
|
-
locality: v.city,
|
|
2316
|
-
postal_code: v.postcode,
|
|
2317
|
-
country: v.country,
|
|
2318
|
-
}));
|
|
2319
|
-
console.log("P", placements);
|
|
2320
|
-
console.log("callable params", { placements: formattedPlacements, instituteId: user.product === "admin" ? "admin" : user.oId });
|
|
2321
|
-
execute("placementListing-add", { data: formattedPlacements, instituteId: user.product === "admin" ? "admin" : user.oId });
|
|
2445
|
+
if (fProviders.length) {
|
|
2446
|
+
execute("providerContacts-add", { providerContacts: fProviders, instituteId: user.product === "admin" ? "admin" : user.oId, schoolId: schoolId });
|
|
2322
2447
|
}
|
|
2323
2448
|
return true;
|
|
2324
2449
|
};
|
|
@@ -2326,7 +2451,7 @@ function useInstitutePlacementListingHandler({ user }) {
|
|
|
2326
2451
|
setAlert(undefined);
|
|
2327
2452
|
setEmptyCellsWarning(false);
|
|
2328
2453
|
};
|
|
2329
|
-
return ({ ...{
|
|
2454
|
+
return ({ ...{ uploadProviderContacts, alert, onChange } });
|
|
2330
2455
|
}
|
|
2331
2456
|
function useGetIndividualPlacementForPlacementPage({ user, placementId, organisation }) {
|
|
2332
2457
|
var _a;
|
|
@@ -2340,7 +2465,7 @@ function useGetIndividualPlacementForPlacementPage({ user, placementId, organisa
|
|
|
2340
2465
|
const [disableEmail, setDisableEmail] = (0, react_1.useState)({ parent: false, provider: false });
|
|
2341
2466
|
const [rejectELIPopup, setRejectELIPopup] = (0, react_1.useState)(false);
|
|
2342
2467
|
const [eliPopupOpen, setEliPopupOpen] = (0, react_1.useState)(false);
|
|
2343
|
-
const [
|
|
2468
|
+
const [eliData, setELIData] = (0, react_1.useState)();
|
|
2344
2469
|
const [rejectExternalDocPopup, setRejectExternalDocPopup] = (0, react_1.useState)(false);
|
|
2345
2470
|
const [externalDocPopupOpen, setExternalDocPopupOpen] = (0, react_1.useState)(false);
|
|
2346
2471
|
const [riskAssessmentURL, setRiskAssessmentURL] = (0, react_1.useState)("");
|
|
@@ -2353,6 +2478,9 @@ function useGetIndividualPlacementForPlacementPage({ user, placementId, organisa
|
|
|
2353
2478
|
const [uploadRA, setUploadRA] = (0, react_1.useState)(false);
|
|
2354
2479
|
const [uploadDBS, setUploadDBS] = (0, react_1.useState)(false);
|
|
2355
2480
|
const [onboardingPopup, setOnboardingPopup] = (0, react_1.useState)(false);
|
|
2481
|
+
const [dismissOnboardingPopup, setDismissOnboardingPopup] = (0, react_1.useState)(false);
|
|
2482
|
+
const [addOnboardingDocsPopup, setAddOnboardingDocsPopup] = (0, react_1.useState)(false);
|
|
2483
|
+
const [shareStudentRequestPopup, setShareStudentRequestPopup] = (0, react_1.useState)(false);
|
|
2356
2484
|
const [editable, setEditable] = (0, react_1.useState)(false);
|
|
2357
2485
|
const [withdrawFromPlacementPopup, setWithdrawFromPlacementPopup] = (0, react_1.useState)(false);
|
|
2358
2486
|
const firebaseQuery = new firebaseQuery_1.default();
|
|
@@ -2395,25 +2523,43 @@ function useGetIndividualPlacementForPlacementPage({ user, placementId, organisa
|
|
|
2395
2523
|
setStudent(user);
|
|
2396
2524
|
}
|
|
2397
2525
|
else {
|
|
2398
|
-
|
|
2526
|
+
if (placement.uid) {
|
|
2527
|
+
(0, readDatabase_1.getUserById)(placement.uid, undefined, false).then(setStudent);
|
|
2528
|
+
}
|
|
2529
|
+
else {
|
|
2530
|
+
setStudent({
|
|
2531
|
+
details: {
|
|
2532
|
+
forename: placement.studentForename || "",
|
|
2533
|
+
surname: placement.studentSurname || "",
|
|
2534
|
+
},
|
|
2535
|
+
email: placement.studentEmail || ""
|
|
2536
|
+
});
|
|
2537
|
+
}
|
|
2399
2538
|
}
|
|
2400
2539
|
}, [placement]);
|
|
2401
2540
|
(0, react_1.useEffect)(() => {
|
|
2402
2541
|
if (!workflow || !placement)
|
|
2403
2542
|
return;
|
|
2404
|
-
const
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
currentWorkflowStage.
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2543
|
+
const getAdditionalStageData = async () => {
|
|
2544
|
+
const currentWorkflowStage = { ...workflow.find((obj) => obj.id === placement.status) };
|
|
2545
|
+
// console.log("currentWorkflowStage", currentWorkflowStage)
|
|
2546
|
+
currentWorkflowStage.id = placement.status;
|
|
2547
|
+
// Get form data for current stage
|
|
2548
|
+
if (currentWorkflowStage.forms) {
|
|
2549
|
+
(0, readDatabase_1.getFormsFromId)(["forms"], currentWorkflowStage.forms).then((details) => {
|
|
2550
|
+
currentWorkflowStage.formDetails = details;
|
|
2551
|
+
});
|
|
2552
|
+
}
|
|
2553
|
+
if (currentWorkflowStage.files) {
|
|
2554
|
+
currentWorkflowStage.files = Object.fromEntries(await Promise.all(currentWorkflowStage.files.map(async (file) => {
|
|
2555
|
+
const fileItem = await firebaseQuery.getDocData(["files", file]);
|
|
2556
|
+
const url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `institutes/${placement.oId}/${fileItem.fileName}`));
|
|
2557
|
+
return [file, { name: fileItem.name, url: url }];
|
|
2558
|
+
})));
|
|
2559
|
+
}
|
|
2560
|
+
return currentWorkflowStage;
|
|
2561
|
+
};
|
|
2562
|
+
getAdditionalStageData().then(setWStage);
|
|
2417
2563
|
}, [placement, workflow]);
|
|
2418
2564
|
const editStage = async (nextStageId) => {
|
|
2419
2565
|
if (!placementId || !wStage)
|
|
@@ -2451,10 +2597,7 @@ function useGetIndividualPlacementForPlacementPage({ user, placementId, organisa
|
|
|
2451
2597
|
const onboardingStatus = (placement === null || placement === void 0 ? void 0 : placement.onboarding) ? ((_a = placement.onboarding.completed) === null || _a === void 0 ? void 0 : _a.submitted) ? placement.onboarding.completed.accepted ? "Onboarding docs approved" : "Onboarding docs completed" : (user.userType === "Staff" ? "Onboarding sent" : "Complete onboarding") : "Add onboarding documents";
|
|
2452
2598
|
const signOffPlacements = (0, util_1.getAccess)(user, "signOffPlacements");
|
|
2453
2599
|
let canEdit = false;
|
|
2454
|
-
if (((wStage === null || wStage === void 0 ? void 0 : wStage.userType) === "Staff" && user.product === "
|
|
2455
|
-
canEdit = true;
|
|
2456
|
-
}
|
|
2457
|
-
else if (((wStage === null || wStage === void 0 ? void 0 : wStage.userType) === "Staff" && user.userType === "Staff" && user.product === "institutes") || (user.product === "providers" && (wStage === null || wStage === void 0 ? void 0 : wStage.userType) === "Provider") || user.userType === "Students" && (wStage === null || wStage === void 0 ? void 0 : wStage.userType) === "Students") {
|
|
2600
|
+
if (((wStage === null || wStage === void 0 ? void 0 : wStage.userType) === "Staff" && user.userType === "Staff" && user.product === "institutes") || (user.product === "providers" && (wStage === null || wStage === void 0 ? void 0 : wStage.userType) === "Provider") || user.userType === "Students" && (wStage === null || wStage === void 0 ? void 0 : wStage.userType) === "Students") {
|
|
2458
2601
|
console.log("ALMOST CAN EDIT");
|
|
2459
2602
|
if (user.userType === "Staff" && !signOffPlacements) {
|
|
2460
2603
|
canEdit = false;
|
|
@@ -2463,17 +2606,20 @@ function useGetIndividualPlacementForPlacementPage({ user, placementId, organisa
|
|
|
2463
2606
|
canEdit = true;
|
|
2464
2607
|
}
|
|
2465
2608
|
}
|
|
2466
|
-
const onFlagClick = async (e) => {
|
|
2609
|
+
const onFlagClick = async (e, onClose) => {
|
|
2467
2610
|
if (!placement)
|
|
2468
2611
|
return;
|
|
2469
2612
|
if (e === "completeOnboarding" || e === "reviewOnboarding") {
|
|
2470
2613
|
setOnboardingPopup(true);
|
|
2471
2614
|
}
|
|
2615
|
+
if (e === "studentNotAccepted") {
|
|
2616
|
+
setShareStudentRequestPopup(true);
|
|
2617
|
+
}
|
|
2472
2618
|
if (e === "noInsurance") {
|
|
2473
|
-
if (!
|
|
2619
|
+
if (!eliData) {
|
|
2474
2620
|
const storageRef = (0, storage_1.ref)(firebaseConfig_1.storage, `insurance/${placement.providerId}.pdf`);
|
|
2475
|
-
const file = await (0, storage_1.getDownloadURL)(storageRef);
|
|
2476
|
-
|
|
2621
|
+
const file = await (0, storage_1.getDownloadURL)(storageRef).catch(() => placement.insuranceSkippedReason);
|
|
2622
|
+
setELIData(file);
|
|
2477
2623
|
}
|
|
2478
2624
|
setEliPopupOpen(true);
|
|
2479
2625
|
}
|
|
@@ -2494,18 +2640,26 @@ function useGetIndividualPlacementForPlacementPage({ user, placementId, organisa
|
|
|
2494
2640
|
}
|
|
2495
2641
|
setExternalDocPopupOpen("dbsCheck");
|
|
2496
2642
|
}
|
|
2643
|
+
if (e === "addOnboarding") {
|
|
2644
|
+
if (onClose) {
|
|
2645
|
+
setDismissOnboardingPopup(true);
|
|
2646
|
+
}
|
|
2647
|
+
else {
|
|
2648
|
+
setAddOnboardingDocsPopup(true);
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2497
2651
|
};
|
|
2498
2652
|
const approveELI = async () => {
|
|
2499
2653
|
if (!placement)
|
|
2500
2654
|
return;
|
|
2501
|
-
await (0, firebase_1.executeCallable)("insurance-approve", { oId: user.oId,
|
|
2655
|
+
await (0, firebase_1.executeCallable)("insurance-approve", { oId: user.oId, providerContactId: placement.providerContactId });
|
|
2502
2656
|
setEliPopupOpen(false);
|
|
2503
2657
|
};
|
|
2504
2658
|
const rejectELI = async ({ reason }) => {
|
|
2505
2659
|
if (!placement || !institute)
|
|
2506
2660
|
return;
|
|
2507
|
-
console.log("Reject", { reason: reason, placement: placement, instituteName: institute.name
|
|
2508
|
-
await (0, firebase_1.executeCallable)("insurance-reject", { reason: reason, placementId: placementId, instituteName: institute.name
|
|
2661
|
+
console.log("Reject", { reason: reason, placement: placement, instituteName: institute.name });
|
|
2662
|
+
await (0, firebase_1.executeCallable)("insurance-reject", { reason: reason, placementId: placementId, instituteName: institute.name });
|
|
2509
2663
|
setRejectELIPopup(false);
|
|
2510
2664
|
setEliPopupOpen(false);
|
|
2511
2665
|
};
|
|
@@ -2524,10 +2678,12 @@ function useGetIndividualPlacementForPlacementPage({ user, placementId, organisa
|
|
|
2524
2678
|
if (!placement)
|
|
2525
2679
|
return;
|
|
2526
2680
|
if (!placement.providerId) {
|
|
2527
|
-
const res = await (0, firebase_1.executeCallable)("
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2681
|
+
const res = await (0, firebase_1.executeCallable)("providerContacts-uploadProviderDetails", {
|
|
2682
|
+
placement: {
|
|
2683
|
+
id: placementId,
|
|
2684
|
+
data: Object.fromEntries(Object.entries(placement).filter(([k]) => k !== "contactId")),
|
|
2685
|
+
stage: wStage,
|
|
2686
|
+
},
|
|
2531
2687
|
skipSearch: true
|
|
2532
2688
|
}).catch((e) => {
|
|
2533
2689
|
throw e;
|
|
@@ -2553,15 +2709,17 @@ function useGetIndividualPlacementForPlacementPage({ user, placementId, organisa
|
|
|
2553
2709
|
throw new Error("Must be a student to withdraw.");
|
|
2554
2710
|
await (0, firebase_1.executeCallable)("placement-withdraw", { placementId: placementId });
|
|
2555
2711
|
};
|
|
2556
|
-
return { placement, wStage, student, workflow, editable, withdrawFromPlacementPopup, setWithdrawFromPlacementPopup, withdrawFromPlacement, onFlagClick, setUploadInsurance, setUploadProviderDocPopup, setUploadRA, setUploadDBS, onboardingStatus, setSkipStagePopup, onboardingPopup, setViewExternalLinkPopup, setOnboardingPopup, setRejectELIPopup,
|
|
2712
|
+
return { placement, wStage, student, workflow, editable, withdrawFromPlacementPopup, addOnboardingDocsPopup, setAddOnboardingDocsPopup, dismissOnboardingPopup, setDismissOnboardingPopup, setWithdrawFromPlacementPopup, withdrawFromPlacement, onFlagClick, setUploadInsurance, setUploadProviderDocPopup, setUploadRA, setUploadDBS, onboardingStatus, setSkipStagePopup, onboardingPopup, setViewExternalLinkPopup, setOnboardingPopup, setRejectELIPopup, eliData, riskAssessmentURL, dbsCheckURL, setExternalLinkCopied, skipStagePopup, snackbar, setSnackbar, cohort, disableEmail, rejectELIPopup, eliPopupOpen, rejectExternalDocPopup, externalDocPopupOpen, viewExternalLinkPopup, externalLinkCopied, uploadInsurance, uploadRA, uploadDBS, editStage, sendEmail, canEdit, approveELI, setEliPopupOpen, uploadProviderDocPopup, rejectELI, setRejectExternalDocPopup, setExternalDocPopupOpen, approveProviderDoc, rejectProviderDoc, manuallyConfigureProvider, institute, shareStudentRequestPopup, setShareStudentRequestPopup };
|
|
2557
2713
|
}
|
|
2558
|
-
function useOnboardingPopup({ onboarding, placementId, user, onClose }) {
|
|
2714
|
+
function useOnboardingPopup({ onboarding, providerId, placementId, user, onClose }) {
|
|
2559
2715
|
const [fileUploadPopup, setFileUploadPopup] = (0, react_1.useState)(false);
|
|
2560
2716
|
const [form, setForm] = (0, react_1.useState)();
|
|
2561
2717
|
const [rejectPopup, setRejectPopup] = (0, react_1.useState)(false);
|
|
2562
2718
|
const [mOnboarding, setMOnboarding] = (0, react_1.useState)(onboarding);
|
|
2563
2719
|
const [completedSections, setCompletedSections] = (0, react_1.useState)();
|
|
2564
2720
|
const [uploadedFiles, setUploadedFiles] = (0, react_1.useState)({});
|
|
2721
|
+
const [viewableFiles, setViewableFiles] = (0, react_1.useState)();
|
|
2722
|
+
const [formDetails, setFormDetails] = (0, react_1.useState)({});
|
|
2565
2723
|
const firebaseQuery = new firebaseQuery_1.default();
|
|
2566
2724
|
const addFile = (files) => {
|
|
2567
2725
|
if (!files.length || fileUploadPopup === false)
|
|
@@ -2571,12 +2729,12 @@ function useOnboardingPopup({ onboarding, placementId, user, onClose }) {
|
|
|
2571
2729
|
};
|
|
2572
2730
|
const viewFile = (file, onOpen) => {
|
|
2573
2731
|
setMOnboarding((a) => {
|
|
2574
|
-
var _a
|
|
2732
|
+
var _a;
|
|
2575
2733
|
const oldA = { ...a };
|
|
2576
2734
|
const viewedFiles = a.completed ? ((_a = a.completed) === null || _a === void 0 ? void 0 : _a.filesViewed) || [] : [];
|
|
2577
2735
|
if (viewedFiles === null || viewedFiles === void 0 ? void 0 : viewedFiles.includes(file))
|
|
2578
2736
|
return a;
|
|
2579
|
-
(
|
|
2737
|
+
(viewableFiles === null || viewableFiles === void 0 ? void 0 : viewableFiles[file].url) && onOpen(viewableFiles === null || viewableFiles === void 0 ? void 0 : viewableFiles[file].url);
|
|
2580
2738
|
viewedFiles === null || viewedFiles === void 0 ? void 0 : viewedFiles.push(file);
|
|
2581
2739
|
const newA = (0, util_1.editNestedObject)(["completed", "filesViewed"], oldA, viewedFiles);
|
|
2582
2740
|
return newA;
|
|
@@ -2597,14 +2755,14 @@ function useOnboardingPopup({ onboarding, placementId, user, onClose }) {
|
|
|
2597
2755
|
const onboardingNew = { ...onboarding };
|
|
2598
2756
|
const onboardingFiles = onboarding.files ? Object.fromEntries(await Promise.all((_a = onboarding.files) === null || _a === void 0 ? void 0 : _a.map(async (fileId) => {
|
|
2599
2757
|
const file = await firebaseQuery.getDocData(["files", fileId]);
|
|
2600
|
-
file.url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `
|
|
2758
|
+
file.url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `providers/${providerId}/${file.fileName}`));
|
|
2601
2759
|
return [fileId, file];
|
|
2602
2760
|
}))) : [];
|
|
2603
2761
|
const onboardingForms = onboarding.forms ? Object.fromEntries(await Promise.all((_b = onboarding.forms) === null || _b === void 0 ? void 0 : _b.map(async (formId) => {
|
|
2604
2762
|
return [formId, await firebaseQuery.getDocData(["forms", formId])];
|
|
2605
2763
|
}))) : [];
|
|
2606
|
-
|
|
2607
|
-
|
|
2764
|
+
setViewableFiles(onboardingFiles);
|
|
2765
|
+
setFormDetails(onboardingForms);
|
|
2608
2766
|
return onboardingNew;
|
|
2609
2767
|
};
|
|
2610
2768
|
getOnboardingData().then(setMOnboarding);
|
|
@@ -2659,7 +2817,8 @@ function useOnboardingPopup({ onboarding, placementId, user, onClose }) {
|
|
|
2659
2817
|
return;
|
|
2660
2818
|
if (!stagesCompleted())
|
|
2661
2819
|
throw new Error("Complete all forms before submitting.");
|
|
2662
|
-
await firebaseQuery.update(["placements", placementId], { ["onboarding.completed.submitted"]: (0, util_1.convertDate)(new Date(), "dbstring") });
|
|
2820
|
+
await firebaseQuery.update(["placements", placementId], { ["onboarding.completed.accepted"]: false, ["onboarding.completed.submitted"]: true, ["onboarding.completed.submittedDate"]: (0, util_1.convertDate)(new Date(), "dbstring") });
|
|
2821
|
+
//executeCallable("sendOnboardingSubmittedEmail", {});
|
|
2663
2822
|
};
|
|
2664
2823
|
(0, react_1.useEffect)(() => {
|
|
2665
2824
|
const getUploadedFiles = async () => {
|
|
@@ -2695,6 +2854,580 @@ function useOnboardingPopup({ onboarding, placementId, user, onClose }) {
|
|
|
2695
2854
|
getUploadedFiles();
|
|
2696
2855
|
addCompletedSectionURLs();
|
|
2697
2856
|
}, [mOnboarding]);
|
|
2698
|
-
return { addFile, viewFile, uploadedFiles, setFormComplete, setRejectPopup, stagesCompleted, setForm, mOnboarding, form, submit, acceptOnboarding, rejectOnboarding, rejectPopup, completedSections, fileUploadPopup, setFileUploadPopup };
|
|
2857
|
+
return { addFile, viewFile, uploadedFiles, setFormComplete, setRejectPopup, stagesCompleted, setForm, mOnboarding, form, submit, acceptOnboarding, rejectOnboarding, rejectPopup, completedSections, fileUploadPopup, setFileUploadPopup, viewableFiles, formDetails };
|
|
2858
|
+
}
|
|
2859
|
+
function useLoadAddresses(user, limitItems, queryConstraint, request) {
|
|
2860
|
+
const [addresses, setAddresses] = (0, react_1.useState)({});
|
|
2861
|
+
const [lastDoc, setLastDoc] = (0, react_1.useState)(null);
|
|
2862
|
+
const [loading, setLoading] = (0, react_1.useState)(false);
|
|
2863
|
+
const firebaseQuery = new firebaseQuery_1.default();
|
|
2864
|
+
const [queryConstraints, setQueryConstraints] = (0, react_1.useState)(queryConstraint || []);
|
|
2865
|
+
const changeQueryConstraints = (e) => {
|
|
2866
|
+
setQueryConstraints([...(queryConstraint || []), ...e]);
|
|
2867
|
+
};
|
|
2868
|
+
const loadAddresses = () => {
|
|
2869
|
+
var _a;
|
|
2870
|
+
const constraints = [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("product", "==", user.product), (0, firestore_1.orderBy)((0, firestore_1.documentId)())];
|
|
2871
|
+
if (limitItems) {
|
|
2872
|
+
constraints.push((0, firestore_1.limit)(limitItems));
|
|
2873
|
+
}
|
|
2874
|
+
if (user.viewAddresses === "all" || user.userGroup === "admin" || request) {
|
|
2875
|
+
if (lastDoc === null || lastDoc === void 0 ? void 0 : lastDoc.id) {
|
|
2876
|
+
constraints.push((0, firestore_1.startAfter)(lastDoc === null || lastDoc === void 0 ? void 0 : lastDoc.id));
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
2879
|
+
else if (user.viewAddresses === "request") {
|
|
2880
|
+
if (!((_a = user.visibleAddresses) === null || _a === void 0 ? void 0 : _a.length))
|
|
2881
|
+
return;
|
|
2882
|
+
constraints.push((0, firestore_1.where)((0, firestore_1.documentId)(), "in", user.visibleAddresses));
|
|
2883
|
+
if (lastDoc === null || lastDoc === void 0 ? void 0 : lastDoc.id) {
|
|
2884
|
+
constraints.push((0, firestore_1.startAfter)(lastDoc === null || lastDoc === void 0 ? void 0 : lastDoc.id));
|
|
2885
|
+
}
|
|
2886
|
+
}
|
|
2887
|
+
else {
|
|
2888
|
+
setLoading(false);
|
|
2889
|
+
return; // viewAddresses === "none", no need to load anything
|
|
2890
|
+
}
|
|
2891
|
+
queryConstraints && constraints.unshift(...queryConstraints);
|
|
2892
|
+
return firebaseQuery.collectionSnapshot((async (snapshot) => {
|
|
2893
|
+
const deletedAddresses = snapshot.docChanges().map((change) => {
|
|
2894
|
+
if (change.type === "removed") {
|
|
2895
|
+
return change.doc.id;
|
|
2896
|
+
}
|
|
2897
|
+
return;
|
|
2898
|
+
});
|
|
2899
|
+
setAddresses((prev) => Object.fromEntries(Object.entries(prev).filter(([k]) => !deletedAddresses.includes(k))));
|
|
2900
|
+
if (!snapshot.empty) {
|
|
2901
|
+
const newAddresses = snapshot.docs.map(doc => ([doc.id, { id: doc.id, ...doc.data() }]));
|
|
2902
|
+
const withListings = Object.fromEntries(await Promise.all(newAddresses.map(async ([k, address]) => {
|
|
2903
|
+
const listings = await firebaseQuery.getCount("placementListings", [(0, firestore_1.where)("providerId", "==", user.oId), (0, firestore_1.where)("addressId", "==", k)]);
|
|
2904
|
+
return [k, { ...address, listings: listings }];
|
|
2905
|
+
})));
|
|
2906
|
+
setAddresses(prev => ({ ...prev, ...withListings }));
|
|
2907
|
+
setLastDoc(snapshot.docs[snapshot.docs.length - 1]);
|
|
2908
|
+
}
|
|
2909
|
+
setLoading(false);
|
|
2910
|
+
}), "addresses", constraints, undefined, true);
|
|
2911
|
+
};
|
|
2912
|
+
(0, react_1.useEffect)(() => {
|
|
2913
|
+
const unsubscribe = loadAddresses();
|
|
2914
|
+
return () => {
|
|
2915
|
+
if (unsubscribe) {
|
|
2916
|
+
unsubscribe(); // Unsubscribe from the snapshot listener when the component unmounts
|
|
2917
|
+
}
|
|
2918
|
+
};
|
|
2919
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2920
|
+
}, [queryConstraints]);
|
|
2921
|
+
const onScrollBottom = () => {
|
|
2922
|
+
if (!limitItems)
|
|
2923
|
+
return;
|
|
2924
|
+
if (!loading) {
|
|
2925
|
+
setLoading(true);
|
|
2926
|
+
loadAddresses();
|
|
2927
|
+
}
|
|
2928
|
+
};
|
|
2929
|
+
return { addresses, onScrollBottom, loading, changeQueryConstraints };
|
|
2930
|
+
}
|
|
2931
|
+
function useLoadListings(user, queryConstraint, request) {
|
|
2932
|
+
const [listings, setListings] = (0, react_1.useState)([]);
|
|
2933
|
+
const [lastDoc, setLastDoc] = (0, react_1.useState)(null);
|
|
2934
|
+
const [loading, setLoading] = (0, react_1.useState)(false);
|
|
2935
|
+
const firebaseQuery = new firebaseQuery_1.default();
|
|
2936
|
+
const [queryConstraints, setQueryConstraints] = (0, react_1.useState)(queryConstraint || []);
|
|
2937
|
+
const changeQueryConstraints = (e) => {
|
|
2938
|
+
setQueryConstraints([...(queryConstraint || []), ...e]);
|
|
2939
|
+
};
|
|
2940
|
+
const loadListings = () => {
|
|
2941
|
+
var _a, _b;
|
|
2942
|
+
const constraints = [(0, firestore_1.where)("providerId", "==", user.oId), (0, firestore_1.limit)(10), (0, firestore_1.orderBy)((0, firestore_1.documentId)())];
|
|
2943
|
+
if (user.viewPlacementListings === "all" || user.userGroup === "admin" || request) {
|
|
2944
|
+
if (lastDoc === null || lastDoc === void 0 ? void 0 : lastDoc.id) {
|
|
2945
|
+
constraints.push((0, firestore_1.startAfter)(lastDoc));
|
|
2946
|
+
}
|
|
2947
|
+
}
|
|
2948
|
+
else {
|
|
2949
|
+
if (!((_a = user.visibleListings) === null || _a === void 0 ? void 0 : _a.length))
|
|
2950
|
+
return;
|
|
2951
|
+
constraints.push((0, firestore_1.where)((0, firestore_1.documentId)(), 'in', user.visibleListings));
|
|
2952
|
+
if (lastDoc === null || lastDoc === void 0 ? void 0 : lastDoc.id) {
|
|
2953
|
+
constraints.push((0, firestore_1.startAfter)(lastDoc));
|
|
2954
|
+
}
|
|
2955
|
+
}
|
|
2956
|
+
if (user.viewAddresses !== "all" && user.viewPlacementListings === "all" && user.userGroup !== "admin") {
|
|
2957
|
+
if (!((_b = user.visibleAddresses) === null || _b === void 0 ? void 0 : _b.length))
|
|
2958
|
+
return;
|
|
2959
|
+
constraints.push((0, firestore_1.where)('addressId', 'in', user.visibleAddresses));
|
|
2960
|
+
}
|
|
2961
|
+
queryConstraints && constraints.unshift(...queryConstraints);
|
|
2962
|
+
return firebaseQuery.collectionSnapshot((async (snapshot) => {
|
|
2963
|
+
const deletedListings = snapshot.docChanges().map((change) => {
|
|
2964
|
+
if (change.type === "removed") {
|
|
2965
|
+
return change.doc.id;
|
|
2966
|
+
}
|
|
2967
|
+
return;
|
|
2968
|
+
});
|
|
2969
|
+
setListings((prev) => prev.filter(([k]) => !deletedListings.includes(k)));
|
|
2970
|
+
if (!snapshot.empty) {
|
|
2971
|
+
const newListings = snapshot.docs.map(doc => ([doc.id, { ...doc.data(), id: doc.id }]));
|
|
2972
|
+
const listingsWithAdditionalData = await Promise.all(newListings.map(async ([id, listing]) => {
|
|
2973
|
+
const listingWithAdditionalData = { ...listing };
|
|
2974
|
+
if (listingWithAdditionalData.applicants !== undefined)
|
|
2975
|
+
return [id, listingWithAdditionalData];
|
|
2976
|
+
listingWithAdditionalData.applicants = await firebaseQuery.getCount("applications", [(0, firestore_1.where)("providerId", "==", user.oId), (0, firestore_1.where)("placementId", "==", id), (0, firestore_1.where)("status", "==", "submitted")]);
|
|
2977
|
+
listingWithAdditionalData.scheduled = await firebaseQuery.getCount("placements", [(0, firestore_1.where)("providerId", "==", user.oId), (0, firestore_1.where)("placementId", "==", id), (0, firestore_1.where)("inProgress", "==", true), (0, firestore_1.where)("startDate", ">", (0, util_1.convertDate)(new Date(), "dbstring"))]);
|
|
2978
|
+
listingWithAdditionalData.active = await firebaseQuery.getCount("placements", [(0, firestore_1.where)("providerId", "==", user.oId), (0, firestore_1.where)("placementId", "==", id), (0, firestore_1.where)("active", "==", true)]);
|
|
2979
|
+
return [id, listingWithAdditionalData];
|
|
2980
|
+
}));
|
|
2981
|
+
setListings(prev => (Object.entries({ ...Object.fromEntries(prev), ...Object.fromEntries(listingsWithAdditionalData) })));
|
|
2982
|
+
setLastDoc(snapshot.docs[snapshot.docs.length - 1]);
|
|
2983
|
+
}
|
|
2984
|
+
setLoading(false);
|
|
2985
|
+
}), "placementListings", constraints, undefined, true);
|
|
2986
|
+
};
|
|
2987
|
+
(0, react_1.useEffect)(() => {
|
|
2988
|
+
loadListings();
|
|
2989
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2990
|
+
}, [queryConstraints]);
|
|
2991
|
+
const onScrollBottom = () => {
|
|
2992
|
+
if (!loading) {
|
|
2993
|
+
setLoading(true);
|
|
2994
|
+
loadListings();
|
|
2995
|
+
}
|
|
2996
|
+
};
|
|
2997
|
+
return { listings, onScrollBottom, loading, changeQueryConstraints };
|
|
2998
|
+
}
|
|
2999
|
+
function useLoadProviderPlacements(user, queryConstraint, placementId) {
|
|
3000
|
+
const [placements, setPlacements] = (0, react_1.useState)([]);
|
|
3001
|
+
const [lastDoc, setLastDoc] = (0, react_1.useState)(null);
|
|
3002
|
+
const [loading, setLoading] = (0, react_1.useState)(false);
|
|
3003
|
+
const firebaseQuery = new firebaseQuery_1.default();
|
|
3004
|
+
const [queryConstraints, setQueryConstraints] = (0, react_1.useState)(queryConstraint || []);
|
|
3005
|
+
if (user.product !== "providers")
|
|
3006
|
+
throw new Error("Only providers can use this hook.");
|
|
3007
|
+
const changeQueryConstraints = (e) => {
|
|
3008
|
+
setQueryConstraints([...(queryConstraint || []), ...e]);
|
|
3009
|
+
};
|
|
3010
|
+
const loadListings = () => {
|
|
3011
|
+
var _a, _b;
|
|
3012
|
+
const constraints = [(0, firestore_1.where)("providerId", "==", user.oId), (0, firestore_1.limit)(10), (0, firestore_1.orderBy)((0, firestore_1.documentId)())];
|
|
3013
|
+
if (placementId) {
|
|
3014
|
+
constraints.push((0, firestore_1.where)("placementId", "==", placementId));
|
|
3015
|
+
}
|
|
3016
|
+
if (user.viewPlacementListings === "all" || user.userGroup === "admin") {
|
|
3017
|
+
if (lastDoc === null || lastDoc === void 0 ? void 0 : lastDoc.id) {
|
|
3018
|
+
constraints.push((0, firestore_1.startAfter)(lastDoc));
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
else {
|
|
3022
|
+
if (!((_a = user.visibleListings) === null || _a === void 0 ? void 0 : _a.length))
|
|
3023
|
+
return;
|
|
3024
|
+
constraints.push((0, firestore_1.where)("placementId", 'in', user.visibleListings));
|
|
3025
|
+
if (lastDoc === null || lastDoc === void 0 ? void 0 : lastDoc.id) {
|
|
3026
|
+
constraints.push((0, firestore_1.startAfter)(lastDoc));
|
|
3027
|
+
}
|
|
3028
|
+
}
|
|
3029
|
+
if (user.viewAddresses !== "all" && user.viewPlacementListings === "all" && user.userGroup !== "admin") {
|
|
3030
|
+
if (!((_b = user.visibleAddresses) === null || _b === void 0 ? void 0 : _b.length))
|
|
3031
|
+
return;
|
|
3032
|
+
constraints.push((0, firestore_1.where)('addressId', 'in', user.visibleAddresses));
|
|
3033
|
+
}
|
|
3034
|
+
queryConstraints && constraints.unshift(...queryConstraints);
|
|
3035
|
+
return firebaseQuery.collectionSnapshot((async (snapshot) => {
|
|
3036
|
+
const deletedListings = snapshot.docChanges().map((change) => {
|
|
3037
|
+
if (change.type === "removed") {
|
|
3038
|
+
return change.doc.id;
|
|
3039
|
+
}
|
|
3040
|
+
return;
|
|
3041
|
+
});
|
|
3042
|
+
setPlacements((prev) => prev.filter(([k]) => !deletedListings.includes(k)));
|
|
3043
|
+
if (!snapshot.empty) {
|
|
3044
|
+
const newPlacements = snapshot.docs.map(doc => ([doc.id, { ...doc.data(), id: doc.id }]));
|
|
3045
|
+
const withAdditionalData = await Promise.all(newPlacements.map(async ([id, placement]) => {
|
|
3046
|
+
const student = placement.uid ? await firebaseQuery.getDocData(["users", placement.uid || ""]).catch(() => false) :
|
|
3047
|
+
{
|
|
3048
|
+
details: {
|
|
3049
|
+
forename: placement.studentForename,
|
|
3050
|
+
surname: placement.studentSurname,
|
|
3051
|
+
},
|
|
3052
|
+
email: placement.studentEmail
|
|
3053
|
+
};
|
|
3054
|
+
const listing = await firebaseQuery.getDocData(["placementListings", placement.placementId || ""]).catch(() => false);
|
|
3055
|
+
return [id, { ...placement, student: student, listing: listing }];
|
|
3056
|
+
}));
|
|
3057
|
+
setPlacements(prev => (Object.entries({ ...Object.fromEntries(prev), ...Object.fromEntries(withAdditionalData) })));
|
|
3058
|
+
setLastDoc(snapshot.docs[snapshot.docs.length - 1]);
|
|
3059
|
+
}
|
|
3060
|
+
setLoading(false);
|
|
3061
|
+
}), "placements", constraints, undefined, true);
|
|
3062
|
+
};
|
|
3063
|
+
(0, react_1.useEffect)(() => {
|
|
3064
|
+
loadListings();
|
|
3065
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
3066
|
+
}, [queryConstraints]);
|
|
3067
|
+
const onScrollBottom = () => {
|
|
3068
|
+
if (!loading) {
|
|
3069
|
+
setLoading(true);
|
|
3070
|
+
loadListings();
|
|
3071
|
+
}
|
|
3072
|
+
};
|
|
3073
|
+
return { placements: Object.fromEntries(placements), onScrollBottom, loading, changeQueryConstraints };
|
|
3074
|
+
}
|
|
3075
|
+
function useLoadApplications({ user, applicationType, listingId, queryConstraint }) {
|
|
3076
|
+
const [applications, setApplications] = (0, react_1.useState)([]);
|
|
3077
|
+
const [lastDoc, setLastDoc] = (0, react_1.useState)(null);
|
|
3078
|
+
const [loading, setLoading] = (0, react_1.useState)(false);
|
|
3079
|
+
const [type, setType] = (0, react_1.useState)(applicationType || "all");
|
|
3080
|
+
const firebaseQuery = new firebaseQuery_1.default();
|
|
3081
|
+
const [queryConstraints, setQueryConstraints] = (0, react_1.useState)(queryConstraint || []);
|
|
3082
|
+
const changeQueryConstraints = (e) => {
|
|
3083
|
+
setQueryConstraints([...(queryConstraint || []), ...e]);
|
|
3084
|
+
};
|
|
3085
|
+
const loadApplications = () => {
|
|
3086
|
+
var _a, _b;
|
|
3087
|
+
const constraints = [(0, firestore_1.where)("providerId", "==", user.oId), (0, firestore_1.limit)(10), (0, firestore_1.orderBy)((0, firestore_1.documentId)())];
|
|
3088
|
+
if (lastDoc === null || lastDoc === void 0 ? void 0 : lastDoc.id) {
|
|
3089
|
+
constraints.push((0, firestore_1.startAfter)(lastDoc));
|
|
3090
|
+
}
|
|
3091
|
+
switch (type) {
|
|
3092
|
+
case "actionRequired":
|
|
3093
|
+
constraints.push((0, firestore_1.where)("status", "==", "submitted"), (0, firestore_1.where)("reqUserType", "==", "Staff"));
|
|
3094
|
+
break;
|
|
3095
|
+
case "awaitingStudent":
|
|
3096
|
+
constraints.push((0, firestore_1.where)("status", "==", "submitted"), (0, firestore_1.where)("reqUserType", "==", "Students"));
|
|
3097
|
+
break;
|
|
3098
|
+
case "closed":
|
|
3099
|
+
constraints.push((0, firestore_1.where)("status", "in", ["approved", "declined"]));
|
|
3100
|
+
break;
|
|
3101
|
+
default:
|
|
3102
|
+
constraints.push((0, firestore_1.where)("status", "==", "submitted"));
|
|
3103
|
+
}
|
|
3104
|
+
if (listingId) {
|
|
3105
|
+
constraints.push((0, firestore_1.where)("listingId", "==", listingId));
|
|
3106
|
+
}
|
|
3107
|
+
console.log("Constraints before user group check", constraints);
|
|
3108
|
+
if (user.viewAddresses !== "all" && user.userGroup !== "admin") {
|
|
3109
|
+
if (user.viewPlacementListings === "all") {
|
|
3110
|
+
if (!((_a = user.visibleAddresses) === null || _a === void 0 ? void 0 : _a.length))
|
|
3111
|
+
return;
|
|
3112
|
+
constraints.push((0, firestore_1.where)('addressId', 'in', user.visibleAddresses));
|
|
3113
|
+
}
|
|
3114
|
+
else {
|
|
3115
|
+
if (!((_b = user.visibleListings) === null || _b === void 0 ? void 0 : _b.length))
|
|
3116
|
+
return;
|
|
3117
|
+
constraints.push((0, firestore_1.where)('placementId', 'in', user.visibleListings));
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
queryConstraints && constraints.unshift(...queryConstraints);
|
|
3121
|
+
console.log("Constraints after user group check", constraints);
|
|
3122
|
+
return firebaseQuery.collectionSnapshot((async (snapshot) => {
|
|
3123
|
+
const deletedApplications = snapshot.docChanges().map((change) => {
|
|
3124
|
+
if (change.type === "removed") {
|
|
3125
|
+
return change.doc.id;
|
|
3126
|
+
}
|
|
3127
|
+
return;
|
|
3128
|
+
});
|
|
3129
|
+
console.log("applicantCount", snapshot.size);
|
|
3130
|
+
setApplications((prev) => prev.filter(([k]) => !deletedApplications.includes(k)));
|
|
3131
|
+
if (!snapshot.empty) {
|
|
3132
|
+
const newApplications = snapshot.docs.map(doc => ([doc.id, { id: doc.id, ...doc.data() }])).filter(([, v]) => v.status !== "draft");
|
|
3133
|
+
setApplications(prev => ([...prev, ...newApplications]));
|
|
3134
|
+
setLastDoc(snapshot.docs[snapshot.docs.length - 1]);
|
|
3135
|
+
}
|
|
3136
|
+
else {
|
|
3137
|
+
setApplications([]);
|
|
3138
|
+
setLastDoc(null);
|
|
3139
|
+
}
|
|
3140
|
+
setLoading(false);
|
|
3141
|
+
}), "applications", constraints, undefined, true);
|
|
3142
|
+
};
|
|
3143
|
+
(0, react_1.useEffect)(() => {
|
|
3144
|
+
loadApplications();
|
|
3145
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
3146
|
+
}, [type, queryConstraints]);
|
|
3147
|
+
const onScrollBottom = () => {
|
|
3148
|
+
if (!loading) {
|
|
3149
|
+
setLoading(true);
|
|
3150
|
+
loadApplications();
|
|
3151
|
+
}
|
|
3152
|
+
};
|
|
3153
|
+
return { applications, type, setType, onScrollBottom, loading, changeQueryConstraints };
|
|
3154
|
+
}
|
|
3155
|
+
function useDataViewerPaginator({ view: initialView, sorts, queryLimit = 10, additionalEntryProcessing, formatItems, snapshot, filters: initialFilters, onSearch, data }) {
|
|
3156
|
+
const [tableData, setTableData] = (0, react_1.useState)(Array.isArray(data) ? Object.fromEntries(Object.entries(data).slice(0, queryLimit)) : {});
|
|
3157
|
+
const [page, setPage] = (0, react_1.useState)([1, 0]);
|
|
3158
|
+
const [view, setView] = (0, react_1.useState)(initialView);
|
|
3159
|
+
const [filters, setFilters] = (0, react_1.useState)(initialFilters);
|
|
3160
|
+
const [queryAnchor, setQueryAnchor] = (0, react_1.useState)({ startKey: "", endKey: "", startQueryPos: 0, endQueryPos: 0 });
|
|
3161
|
+
const [prevEntryIds, setPrevEntryIds] = (0, react_1.useState)({});
|
|
3162
|
+
const [dataListenerUnsubscribe, setDataListenerUnsubscribe] = (0, react_1.useState)();
|
|
3163
|
+
const [loading, setLoading] = (0, react_1.useState)(true);
|
|
3164
|
+
const [searchString, setSearchString] = (0, react_1.useState)();
|
|
3165
|
+
const [sort, setSort] = (0, react_1.useState)();
|
|
3166
|
+
const processedData = async (k, v) => additionalEntryProcessing ? await additionalEntryProcessing(k, v) : v;
|
|
3167
|
+
const setTableDataFromDefinedData = async () => {
|
|
3168
|
+
if (!data || Array.isArray(data))
|
|
3169
|
+
return;
|
|
3170
|
+
const dataWithAdditionalProcessingPossibleNulls = (await Promise.all(Object.entries(data).map(async ([k, v]) => [k, await processedData(k, v)])));
|
|
3171
|
+
const dataWithAdditionalProcessing = dataWithAdditionalProcessingPossibleNulls.filter(([k, v]) => v);
|
|
3172
|
+
const searchedData = searchString ? dataWithAdditionalProcessing.filter(([, v]) => {
|
|
3173
|
+
const values = Object.values(v).join(", ");
|
|
3174
|
+
console.log("VALUESTRING", v);
|
|
3175
|
+
return values.includes(searchString);
|
|
3176
|
+
}) : dataWithAdditionalProcessing;
|
|
3177
|
+
const filteredData = filters && Object.keys(filters).length > 0 ? searchedData.filter(([, dataValue]) => Object.entries(filters).every(([filterKey, filterValue]) => {
|
|
3178
|
+
const value = dataValue[filterKey];
|
|
3179
|
+
if ((typeof value === "number") && value === parseInt(filterValue.value))
|
|
3180
|
+
return true;
|
|
3181
|
+
if ((typeof value === "boolean") && value === (filterValue.value === "true"))
|
|
3182
|
+
return true;
|
|
3183
|
+
if ((typeof value === "boolean") && value === (filterValue.value === "false"))
|
|
3184
|
+
return true;
|
|
3185
|
+
if ((typeof value === "string" || Array.isArray(value)) && value.includes(filterValue.value))
|
|
3186
|
+
return true;
|
|
3187
|
+
return false;
|
|
3188
|
+
})) : searchedData;
|
|
3189
|
+
if (view === "table") {
|
|
3190
|
+
if (!queryLimit)
|
|
3191
|
+
throw new Error("Tables must have a limit defined.");
|
|
3192
|
+
const newData = filteredData.slice((page[0] - 1) * queryLimit, page[0] * queryLimit);
|
|
3193
|
+
setTableData(Object.fromEntries(newData));
|
|
3194
|
+
if (Object.keys(Object.fromEntries(newData)).pop() === Object.keys(data).pop()) {
|
|
3195
|
+
setLoading("loaded");
|
|
3196
|
+
}
|
|
3197
|
+
else {
|
|
3198
|
+
setLoading(false);
|
|
3199
|
+
}
|
|
3200
|
+
return;
|
|
3201
|
+
}
|
|
3202
|
+
if (view === "list") {
|
|
3203
|
+
setTableData(Object.fromEntries(filteredData));
|
|
3204
|
+
setLoading("loaded");
|
|
3205
|
+
}
|
|
3206
|
+
};
|
|
3207
|
+
const getDataFromQuery = async (itemList = {}, currentQueryAnchor = queryAnchor, cursorDirection, prevEntries = prevEntryIds, loadMoreFromQuery = false) => {
|
|
3208
|
+
// if (!filters) return;
|
|
3209
|
+
setLoading(true);
|
|
3210
|
+
if (!Array.isArray(data)) {
|
|
3211
|
+
setTableDataFromDefinedData();
|
|
3212
|
+
return;
|
|
3213
|
+
}
|
|
3214
|
+
if (!queryLimit)
|
|
3215
|
+
throw new Error("Firestore queries must have a limit defined.");
|
|
3216
|
+
if (onSearch && (searchString || sort)) {
|
|
3217
|
+
if (typeof onSearch === "boolean")
|
|
3218
|
+
throw new Error("When using Firestore queries, an onSearch function should be passed to retrieve data externally. Additional processing is however completed in this hook.");
|
|
3219
|
+
const data = await onSearch(searchString, sort, page[0], filters, queryLimit);
|
|
3220
|
+
const dataWithAdditionalProcessing = await Promise.all(Object.entries(data).map(async ([k, v]) => [k, await processedData(k, v)]));
|
|
3221
|
+
setTableData((old) => {
|
|
3222
|
+
if (view === "table") {
|
|
3223
|
+
return { ...Object.fromEntries(dataWithAdditionalProcessing) };
|
|
3224
|
+
}
|
|
3225
|
+
return { ...old, ...Object.fromEntries(dataWithAdditionalProcessing) };
|
|
3226
|
+
});
|
|
3227
|
+
if (dataWithAdditionalProcessing.length < queryLimit) {
|
|
3228
|
+
setLoading("loaded");
|
|
3229
|
+
}
|
|
3230
|
+
else {
|
|
3231
|
+
setLoading(false);
|
|
3232
|
+
}
|
|
3233
|
+
return;
|
|
3234
|
+
}
|
|
3235
|
+
let cursorPos;
|
|
3236
|
+
if (page[0] > page[1]) {
|
|
3237
|
+
cursorPos = currentQueryAnchor.endQueryPos;
|
|
3238
|
+
}
|
|
3239
|
+
else {
|
|
3240
|
+
cursorPos = currentQueryAnchor.startQueryPos;
|
|
3241
|
+
}
|
|
3242
|
+
const querySchema = data[cursorPos];
|
|
3243
|
+
const createQuery = (queryData) => {
|
|
3244
|
+
const constraints = [];
|
|
3245
|
+
queryData.where && queryData.where.forEach((w) => {
|
|
3246
|
+
constraints.push((0, firestore_1.where)(...w));
|
|
3247
|
+
});
|
|
3248
|
+
filters && Object.entries(filters).filter(([, value]) => value.value).forEach(([key, value]) => {
|
|
3249
|
+
const filterValue = (value.type === "number" || value.type === "dropdown") ? parseInt(value.value) || value.value : value.value;
|
|
3250
|
+
constraints.push((0, firestore_1.where)(key, "==", filterValue));
|
|
3251
|
+
});
|
|
3252
|
+
constraints.push((0, firestore_1.orderBy)(queryData.orderBy ? queryData.orderBy === "documentId" ? (0, firestore_1.documentId)() : queryData.orderBy : (0, firestore_1.documentId)()));
|
|
3253
|
+
if (page[0] > page[1] && !cursorDirection) { // Going up
|
|
3254
|
+
currentQueryAnchor.endKey && constraints.push((0, firestore_1.startAfter)(currentQueryAnchor.endKey));
|
|
3255
|
+
constraints.push((0, firestore_1.limit)(queryLimit));
|
|
3256
|
+
if (!loadMoreFromQuery) {
|
|
3257
|
+
currentQueryAnchor = { ...currentQueryAnchor, startQueryPos: currentQueryAnchor.endQueryPos };
|
|
3258
|
+
}
|
|
3259
|
+
}
|
|
3260
|
+
else if (page[0] < page[1] && !cursorDirection) { // Going down
|
|
3261
|
+
if (!loadMoreFromQuery) {
|
|
3262
|
+
currentQueryAnchor = { ...currentQueryAnchor, endQueryPos: currentQueryAnchor.startQueryPos };
|
|
3263
|
+
}
|
|
3264
|
+
constraints.push((0, firestore_1.limitToLast)(queryLimit));
|
|
3265
|
+
if (currentQueryAnchor.startKey) {
|
|
3266
|
+
currentQueryAnchor.startKey && constraints.push((0, firestore_1.endBefore)(currentQueryAnchor.startKey));
|
|
3267
|
+
}
|
|
3268
|
+
else {
|
|
3269
|
+
currentQueryAnchor.startKey && constraints.push((0, firestore_1.endAt)(currentQueryAnchor.startKey));
|
|
3270
|
+
}
|
|
3271
|
+
}
|
|
3272
|
+
else {
|
|
3273
|
+
if (cursorDirection === "decrease") {
|
|
3274
|
+
constraints.push((0, firestore_1.limitToLast)(queryLimit));
|
|
3275
|
+
}
|
|
3276
|
+
else {
|
|
3277
|
+
constraints.push((0, firestore_1.limit)(queryLimit));
|
|
3278
|
+
}
|
|
3279
|
+
}
|
|
3280
|
+
return constraints;
|
|
3281
|
+
};
|
|
3282
|
+
const constraints = createQuery(querySchema);
|
|
3283
|
+
const q = (0, firestore_1.query)((0, firestore_1.collection)(firebaseConfig_1.db, ...querySchema.path), ...(constraints));
|
|
3284
|
+
console.log("Fetching docs", constraints);
|
|
3285
|
+
if (snapshot) {
|
|
3286
|
+
// Use onSnapshot to get real-time updates
|
|
3287
|
+
const unsubscribe = (0, firestore_1.onSnapshot)(q, (querySnapshot) => {
|
|
3288
|
+
handleQuerySnapshot(querySnapshot);
|
|
3289
|
+
});
|
|
3290
|
+
// Save the unsubscribe function to state so we can dispose of it later
|
|
3291
|
+
setDataListenerUnsubscribe((d) => ({ ...(d || {}), [cursorPos]: unsubscribe }));
|
|
3292
|
+
return;
|
|
3293
|
+
}
|
|
3294
|
+
else {
|
|
3295
|
+
// Just get the docs without setting up a listener
|
|
3296
|
+
const queryData = await (0, firestore_1.getDocs)(q);
|
|
3297
|
+
handleQuerySnapshot(queryData);
|
|
3298
|
+
}
|
|
3299
|
+
// Function to handle query snapshot
|
|
3300
|
+
async function handleQuerySnapshot(querySnapshot) {
|
|
3301
|
+
if (!Array.isArray(data))
|
|
3302
|
+
throw new Error("Called querySnapshot but data is defined.");
|
|
3303
|
+
if (!queryLimit)
|
|
3304
|
+
throw new Error("Firestore queries must have a limit defined.");
|
|
3305
|
+
const queryResults = {};
|
|
3306
|
+
let index = 0; // Declare the index variable
|
|
3307
|
+
const reverseIfBack = (docs) => page[0] < page[1] ? docs.reverse() : docs;
|
|
3308
|
+
// Process each document in the querySnapshot
|
|
3309
|
+
for (const doc of reverseIfBack(querySnapshot.docs)) {
|
|
3310
|
+
if ((Object.keys(queryResults).length + Object.keys(itemList).length) === queryLimit) {
|
|
3311
|
+
break;
|
|
3312
|
+
}
|
|
3313
|
+
let position = Object.keys(itemList).length + (page[0] - 1) * queryLimit + index + 1;
|
|
3314
|
+
if (page[0] < page[1]) {
|
|
3315
|
+
position = (page[0]) * queryLimit - index - Object.keys(itemList).length;
|
|
3316
|
+
}
|
|
3317
|
+
if (itemList[doc.id] || (prevEntries[doc.id] && prevEntries[doc.id] !== position)) {
|
|
3318
|
+
console.log("Removing ", doc.id, ": E=", prevEntries[doc.id], ", G=", position);
|
|
3319
|
+
continue;
|
|
3320
|
+
}
|
|
3321
|
+
let item = doc.data();
|
|
3322
|
+
item.id = doc.id;
|
|
3323
|
+
// Apply additionalEntryProcessing if provided
|
|
3324
|
+
if (additionalEntryProcessing) {
|
|
3325
|
+
item = await additionalEntryProcessing(doc.id, item);
|
|
3326
|
+
}
|
|
3327
|
+
if (!item)
|
|
3328
|
+
continue;
|
|
3329
|
+
queryResults[doc.id] = item;
|
|
3330
|
+
index += 1;
|
|
3331
|
+
if (prevEntries[doc.id])
|
|
3332
|
+
continue;
|
|
3333
|
+
prevEntries[doc.id] = position;
|
|
3334
|
+
}
|
|
3335
|
+
if (cursorDirection === "decrease" || page[0] < page[1]) {
|
|
3336
|
+
itemList = { ...Object.fromEntries(Object.entries(queryResults).reverse()), ...itemList };
|
|
3337
|
+
}
|
|
3338
|
+
else {
|
|
3339
|
+
itemList = { ...itemList, ...queryResults };
|
|
3340
|
+
}
|
|
3341
|
+
// Updating state with the new data and query anchors
|
|
3342
|
+
setPrevEntryIds(prevEntries);
|
|
3343
|
+
if (querySnapshot.size < queryLimit && Object.keys(itemList).length < queryLimit) {
|
|
3344
|
+
// If we have ran out of entries, increase or decrease the index.
|
|
3345
|
+
if (page[0] > page[1] && cursorPos + 1 < data.length) {
|
|
3346
|
+
return getDataFromQuery(itemList, { ...currentQueryAnchor, endQueryPos: currentQueryAnchor.endQueryPos + 1 }, "increase", prevEntries);
|
|
3347
|
+
}
|
|
3348
|
+
else if (page[0] < page[1] && cursorPos > 0) {
|
|
3349
|
+
return getDataFromQuery(itemList, { ...currentQueryAnchor, startQueryPos: currentQueryAnchor.startQueryPos - 1 }, "decrease", prevEntries);
|
|
3350
|
+
}
|
|
3351
|
+
}
|
|
3352
|
+
if (Object.keys(itemList).length < queryLimit && querySnapshot.size === queryLimit) {
|
|
3353
|
+
console.log("Shorter than ten");
|
|
3354
|
+
return getDataFromQuery(itemList, { ...currentQueryAnchor, startKey: Object.keys(itemList)[0], endKey: Object.keys(itemList).slice(-1)[0] }, undefined, prevEntries, true);
|
|
3355
|
+
}
|
|
3356
|
+
if (querySnapshot.size === 0 &&
|
|
3357
|
+
Object.keys(itemList).length === 0 &&
|
|
3358
|
+
currentQueryAnchor.endQueryPos + 1 === data.length &&
|
|
3359
|
+
page[0] > 1) {
|
|
3360
|
+
if (view === "table") {
|
|
3361
|
+
setTableData({});
|
|
3362
|
+
}
|
|
3363
|
+
setQueryAnchor((a) => ({ ...a, startKey: "" }));
|
|
3364
|
+
setLoading("loaded");
|
|
3365
|
+
return;
|
|
3366
|
+
}
|
|
3367
|
+
if (querySnapshot.size < queryLimit) {
|
|
3368
|
+
setLoading("loaded");
|
|
3369
|
+
}
|
|
3370
|
+
else {
|
|
3371
|
+
setLoading(false);
|
|
3372
|
+
}
|
|
3373
|
+
setQueryAnchor({ ...currentQueryAnchor, startKey: Object.keys(itemList)[0], endKey: Object.keys(itemList).slice(-1)[0] });
|
|
3374
|
+
setTableData((old) => {
|
|
3375
|
+
if (view === "table") {
|
|
3376
|
+
return { ...itemList };
|
|
3377
|
+
}
|
|
3378
|
+
return { ...old, ...itemList };
|
|
3379
|
+
});
|
|
3380
|
+
}
|
|
3381
|
+
};
|
|
3382
|
+
const reset = () => {
|
|
3383
|
+
console.log("Resetting after filters?");
|
|
3384
|
+
setPage([1, 0]);
|
|
3385
|
+
setTableData({});
|
|
3386
|
+
setQueryAnchor({ startKey: "", endKey: "", startQueryPos: 0, endQueryPos: 0 });
|
|
3387
|
+
setPrevEntryIds({});
|
|
3388
|
+
dataListenerUnsubscribe && Object.values(dataListenerUnsubscribe).map((u) => u());
|
|
3389
|
+
setDataListenerUnsubscribe(undefined);
|
|
3390
|
+
};
|
|
3391
|
+
(0, react_1.useEffect)(() => {
|
|
3392
|
+
console.log("Filters updates", filters);
|
|
3393
|
+
if (!filters)
|
|
3394
|
+
return;
|
|
3395
|
+
console.log("Resetting cus filters");
|
|
3396
|
+
reset();
|
|
3397
|
+
}, [filters]);
|
|
3398
|
+
(0, react_1.useEffect)(() => {
|
|
3399
|
+
console.log("View reset.");
|
|
3400
|
+
reset();
|
|
3401
|
+
}, [view]);
|
|
3402
|
+
(0, react_1.useEffect)(() => {
|
|
3403
|
+
console.log("search reset.");
|
|
3404
|
+
reset();
|
|
3405
|
+
}, [searchString]);
|
|
3406
|
+
(0, react_1.useEffect)(() => {
|
|
3407
|
+
console.log("data reset.");
|
|
3408
|
+
reset();
|
|
3409
|
+
}, [data]);
|
|
3410
|
+
(0, react_1.useEffect)(() => {
|
|
3411
|
+
console.log("sort reset.");
|
|
3412
|
+
reset();
|
|
3413
|
+
}, [sort]);
|
|
3414
|
+
// Fetch new data when queries or page change
|
|
3415
|
+
(0, react_1.useEffect)(() => {
|
|
3416
|
+
getDataFromQuery();
|
|
3417
|
+
dataListenerUnsubscribe && Object.values(dataListenerUnsubscribe).map((u) => u());
|
|
3418
|
+
}, [page]);
|
|
3419
|
+
const pageUp = () => {
|
|
3420
|
+
setPage((p) => ([p[0] + 1, p[0]]));
|
|
3421
|
+
};
|
|
3422
|
+
const pageDown = () => {
|
|
3423
|
+
setPage((p) => ([p[0] - 1, p[0]]));
|
|
3424
|
+
};
|
|
3425
|
+
const updateSort = (sortLabel) => {
|
|
3426
|
+
if (!sorts || !sorts[sortLabel])
|
|
3427
|
+
return;
|
|
3428
|
+
setSort([sortLabel, sorts[sortLabel]]);
|
|
3429
|
+
};
|
|
3430
|
+
return ({ ...{ tableData, pageUp, pageDown, setFilters, page: page[0], sorts, loading, sort, updateSort: updateSort, setView, updateSearch: setSearchString } });
|
|
2699
3431
|
}
|
|
3432
|
+
;
|
|
2700
3433
|
//# sourceMappingURL=hooks.js.map
|