placementt-core 11.0.533 → 11.0.803

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/lib/constants.d.ts +13 -1
  2. package/lib/constants.js +86 -1
  3. package/lib/constants.js.map +1 -1
  4. package/lib/features/analytics/useAnalytics.d.ts +2 -0
  5. package/lib/features/analytics/useAnalytics.js +22 -19
  6. package/lib/features/analytics/useAnalytics.js.map +1 -1
  7. package/lib/features/global/downtime/useDowntime.d.ts +1 -0
  8. package/lib/features/global/downtime/useDowntime.js +9 -7
  9. package/lib/features/global/downtime/useDowntime.js.map +1 -1
  10. package/lib/features/global/users/useUserFunctions.js +1 -1
  11. package/lib/features/global/users/useUserFunctions.js.map +1 -1
  12. package/lib/features/jobs/jobsSlice.d.ts +10 -2
  13. package/lib/features/jobs/jobsSlice.js +5 -2
  14. package/lib/features/jobs/jobsSlice.js.map +1 -1
  15. package/lib/features/placements/studentPlacements/activePlacement.d.ts +5 -1
  16. package/lib/features/placements/studentPlacements/activePlacement.js +7 -3
  17. package/lib/features/placements/studentPlacements/activePlacement.js.map +1 -1
  18. package/lib/features/placements/studentPlacements/completedStudentPlacementsSlice.d.ts +3 -2
  19. package/lib/features/placements/studentPlacements/completedStudentPlacementsSlice.js +4 -1
  20. package/lib/features/placements/studentPlacements/completedStudentPlacementsSlice.js.map +1 -1
  21. package/lib/features/placements/studentPlacements/upcomingStudentPlacementsSlice.d.ts +2 -2
  22. package/lib/features/placements/studentPlacements/upcomingStudentPlacementsSlice.js +1 -1
  23. package/lib/features/placements/studentPlacements/upcomingStudentPlacementsSlice.js.map +1 -1
  24. package/lib/features/placements/studentPlacements/useStudentPlacements.d.ts +2 -12
  25. package/lib/features/placements/studentPlacements/useStudentPlacements.js +1 -26
  26. package/lib/features/placements/studentPlacements/useStudentPlacements.js.map +1 -1
  27. package/lib/features/updates/useUpdates.d.ts +1 -0
  28. package/lib/features/updates/useUpdates.js +13 -12
  29. package/lib/features/updates/useUpdates.js.map +1 -1
  30. package/lib/firebase/firebase.d.ts +5 -3
  31. package/lib/firebase/firebase.js +15 -9
  32. package/lib/firebase/firebase.js.map +1 -1
  33. package/lib/firebase/firebaseConfig.js.map +1 -1
  34. package/lib/firebase/firebaseQuery.d.ts +6 -2
  35. package/lib/firebase/firebaseQuery.js +11 -3
  36. package/lib/firebase/firebaseQuery.js.map +1 -1
  37. package/lib/firebase/readDatabase.d.ts +2 -4
  38. package/lib/firebase/readDatabase.js +30 -5
  39. package/lib/firebase/readDatabase.js.map +1 -1
  40. package/lib/firebase/writeDatabase.d.ts +6 -2
  41. package/lib/firebase/writeDatabase.js +2 -1
  42. package/lib/firebase/writeDatabase.js.map +1 -1
  43. package/lib/hooks.d.ts +226 -16
  44. package/lib/hooks.js +938 -146
  45. package/lib/hooks.js.map +1 -1
  46. package/lib/reduxHooks.d.ts +56 -4
  47. package/lib/reduxHooks.js +63 -19
  48. package/lib/reduxHooks.js.map +1 -1
  49. package/lib/tasksAndTips.d.ts +7 -5
  50. package/lib/tasksAndTips.js +487 -23
  51. package/lib/tasksAndTips.js.map +1 -1
  52. package/lib/typeDefinitions.d.ts +149 -30
  53. package/lib/util.d.ts +7 -2
  54. package/lib/util.js +32 -9
  55. package/lib/util.js.map +1 -1
  56. package/package.json +1 -1
  57. package/src/constants.ts +91 -3
  58. package/src/features/analytics/useAnalytics.tsx +25 -17
  59. package/src/features/global/downtime/useDowntime.tsx +11 -7
  60. package/src/features/global/users/useUserFunctions.tsx +1 -1
  61. package/src/features/jobs/jobsSlice.ts +9 -3
  62. package/src/features/placements/studentPlacements/activePlacement.ts +8 -3
  63. package/src/features/placements/studentPlacements/completedStudentPlacementsSlice.ts +5 -2
  64. package/src/features/placements/studentPlacements/upcomingStudentPlacementsSlice.ts +2 -2
  65. package/src/features/placements/studentPlacements/useStudentPlacements.tsx +4 -28
  66. package/src/features/updates/useUpdates.tsx +14 -12
  67. package/src/firebase/firebase.tsx +19 -12
  68. package/src/firebase/firebaseConfig.tsx +1 -1
  69. package/src/firebase/firebaseQuery.tsx +11 -3
  70. package/src/firebase/readDatabase.tsx +34 -6
  71. package/src/firebase/writeDatabase.tsx +3 -1
  72. package/src/hooks.tsx +1124 -166
  73. package/src/reduxHooks.ts +71 -22
  74. package/src/tasksAndTips.ts +495 -30
  75. package/src/typeDefinitions.ts +140 -35
  76. package/src/util.ts +45 -17
package/lib/hooks.js CHANGED
@@ -5,8 +5,9 @@ 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.useVeryOldInstitutePlacementList = useVeryOldInstitutePlacementList;
10
11
  exports.useFilterTablePaginator = useFilterTablePaginator;
11
12
  exports.usePlacementListingPaginator = usePlacementListingPaginator;
12
13
  exports.useCohortUserPaginator = useCohortUserPaginator;
@@ -22,6 +23,11 @@ exports.useApplicantWorkflowEditor = useApplicantWorkflowEditor;
22
23
  exports.useInstitutePlacementListingHandler = useInstitutePlacementListingHandler;
23
24
  exports.useGetIndividualPlacementForPlacementPage = useGetIndividualPlacementForPlacementPage;
24
25
  exports.useOnboardingPopup = useOnboardingPopup;
26
+ exports.useLoadAddresses = useLoadAddresses;
27
+ exports.useLoadListings = useLoadListings;
28
+ exports.useLoadProviderPlacements = useLoadProviderPlacements;
29
+ exports.useLoadApplications = useLoadApplications;
30
+ exports.useDataViewerPaginator = useDataViewerPaginator;
25
31
  const firestore_1 = require("firebase/firestore");
26
32
  const react_1 = require("react");
27
33
  const constants_1 = require("./constants");
@@ -60,19 +66,19 @@ function useStudentPlacementList({ user, student, queryConstraint, ql = DEFAULTQ
60
66
  setStudentId(student.id);
61
67
  return;
62
68
  }
63
- if (!user.viewCohorts || !user.viewUsers || user.viewCohorts === "none") {
69
+ if (!user.viewCohorts || !user.viewStudents || user.viewCohorts === "none") {
64
70
  setStudentId(undefined);
65
71
  return;
66
72
  }
67
- if (user.viewCohorts === "all" && user.viewUsers == "all") {
73
+ if (user.viewCohorts === "all" && user.viewStudents == "all") {
68
74
  setStudentId(student.id);
69
75
  }
70
- if (user.viewCohorts === "some" && ((_a = user.visibleCohorts) === null || _a === void 0 ? void 0 : _a.split(",").includes(student.cohort || ""))) {
71
- if (user.viewUsers === "all") {
76
+ if (user.viewCohorts === "some" && ((_a = user.visibleCohorts) === null || _a === void 0 ? void 0 : _a.includes(student.cohort || ""))) {
77
+ if (user.viewStudents === "all") {
72
78
  setStudentId(student.id);
73
79
  return;
74
80
  }
75
- if ((_b = user.studentFilterValues) === null || _b === void 0 ? void 0 : _b.split(", ").includes(student.details[user.studentFilter || ""])) {
81
+ if ((_b = user.studentFilterValues) === null || _b === void 0 ? void 0 : _b.includes(student.details[user.studentFilter || ""])) {
76
82
  setStudentId(student.id);
77
83
  return;
78
84
  }
@@ -121,7 +127,7 @@ function useStudentPlacementList({ user, student, queryConstraint, ql = DEFAULTQ
121
127
  };
122
128
  return ({ ...{ placements, loadMoreIcon, loadMorePlacements, setQuery, setInitialQueryLimit, reset, changeQueryConstraints } });
123
129
  }
124
- function useNewInstitutePlacementList({ id, user, cohort, queryConstraint, ql = DEFAULTQUERYLIMIT, inProgress }) {
130
+ function useOldInstitutePlacementList({ id, user, cohort, queryConstraint, ql = DEFAULTQUERYLIMIT, inProgress }) {
125
131
  const [loadMoreIcon, setLoadMoreIcon] = (0, react_1.useState)(true);
126
132
  const [query, setQuery] = (0, react_1.useState)();
127
133
  const [initialQueryLimit, setInitialQueryLimit] = (0, react_1.useState)(ql);
@@ -131,7 +137,6 @@ function useNewInstitutePlacementList({ id, user, cohort, queryConstraint, ql =
131
137
  const [startPlacementAfter, setStartPlacementAfter] = (0, react_1.useState)(); // uid, pId
132
138
  const algoliaClient = (0, algoliasearch_1.default)(process.env.NODE_ENV === "development" ? "A0ZB50I7VS" : "XMPXCMUUOJ", user.algoliaKey);
133
139
  const placementsIndex = algoliaClient.initIndex("placements");
134
- const usersIndex = algoliaClient.initIndex("users");
135
140
  (0, react_1.useEffect)(() => {
136
141
  if (user.product !== "institutes" || user.userType !== "Staff") {
137
142
  setOId(undefined);
@@ -147,30 +152,6 @@ function useNewInstitutePlacementList({ id, user, cohort, queryConstraint, ql =
147
152
  }
148
153
  const searchPlacements = async () => {
149
154
  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
155
  let placementSearchString = `oId:${user.oId} AND ` + (inProgress !== undefined ? (inProgress ? "inProgress:true" : "completed:true") : "");
175
156
  if (cohort) {
176
157
  placementSearchString = placementSearchString + ` AND cohort:${cohort}`;
@@ -216,7 +197,7 @@ function useNewInstitutePlacementList({ id, user, cohort, queryConstraint, ql =
216
197
  }
217
198
  setLoadMoreIcon(true);
218
199
  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.split(",").includes(cohort))) || (user.viewCohorts === "all" && user.viewUsers === "all")))) {
200
+ 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
201
  const queryConstraintOrdered = Boolean(queryConstraints && queryConstraints.find((v) => v.type === "orderBy"));
221
202
  const constraints = (fStartPlacementAfter === null || fStartPlacementAfter === void 0 ? void 0 : fStartPlacementAfter.length) === 2 && fStartPlacementAfter[0] ?
222
203
  [(0, firestore_1.limit)(placements ? DEFAULTQUERYLIMIT : initialQueryLimit),
@@ -227,13 +208,16 @@ function useNewInstitutePlacementList({ id, user, cohort, queryConstraint, ql =
227
208
  // query && constraints.unshift(where("name", "==", query));
228
209
  cohort && constraints.unshift((0, firestore_1.where)("cohort", "==", cohort));
229
210
  const placementsQuery = await (0, readDatabase_1.getPlacementsWhere)({ w: constraints, oId: oId, raw: true });
211
+ console.log("PLACEMENTS RETRIEVED", placementsQuery.size);
230
212
  const placementsWithStudentData = placementsQuery.empty ? [] : await Promise.all(placementsQuery.docs.map(async (placement) => {
231
213
  const pData = placement.data();
232
214
  const student = pData.uid === user.id ? user : (await (0, readDatabase_1.getUserById)(pData.uid).catch(() => false));
233
- if (user.viewUsers === "some") {
215
+ console.log("STUDENT", student, "PLACEMENT", id);
216
+ // if (!student) return false;
217
+ if (user.viewStudents === "some") {
234
218
  if (!(user.studentFilter && user.studentFilterValues))
235
219
  return false;
236
- if (!user.studentFilterValues.split(", ").includes(student.details[user.studentFilter])) {
220
+ if (!user.studentFilterValues.includes(student.details[user.studentFilter])) {
237
221
  return false;
238
222
  }
239
223
  }
@@ -258,7 +242,128 @@ function useNewInstitutePlacementList({ id, user, cohort, queryConstraint, ql =
258
242
  };
259
243
  return ({ ...{ placements, loadMoreIcon, loadMorePlacements, setQuery, setInitialQueryLimit, reset, changeQueryConstraints } });
260
244
  }
261
- function useOldInstitutePlacementList({ user, cohort, queryConstraint, ql = DEFAULTQUERYLIMIT }) {
245
+ function useNewInstitutePlacementList({ id, user, filters, view, cohort, queryConstraints, ql = DEFAULTQUERYLIMIT, inProgress }) {
246
+ const [query, setQuery] = (0, react_1.useState)();
247
+ const sorts = {
248
+ ["Student Forename - Asc"]: {
249
+ value: "studentForename",
250
+ direction: "asc",
251
+ },
252
+ ["Student Forename - Desc"]: {
253
+ value: "studentForename",
254
+ direction: "desc",
255
+ },
256
+ ["Student Surname - Asc"]: {
257
+ value: "studentSurname",
258
+ direction: "asc",
259
+ },
260
+ ["Student Surname - Desc"]: {
261
+ value: "studentSurname",
262
+ direction: "desc",
263
+ },
264
+ ["Student Email - Asc"]: {
265
+ value: "studentEmail",
266
+ direction: "asc",
267
+ },
268
+ ["Student Email - Desc"]: {
269
+ value: "studentEmaile",
270
+ direction: "desc",
271
+ },
272
+ ["Provider email - Asc"]: {
273
+ value: "providerEmail",
274
+ direction: "asc",
275
+ },
276
+ ["Provider email - Desc"]: {
277
+ value: "providerEmail",
278
+ direction: "desc",
279
+ }
280
+ };
281
+ const additionalProcessing = async (k, placement) => {
282
+ if (user.viewStudents === "some") {
283
+ if (!(user.studentFilter && user.studentFilterValues))
284
+ return false;
285
+ const student = await (0, readDatabase_1.getUserById)(placement.uid).catch(() => false);
286
+ if (!student)
287
+ return;
288
+ if (!user.studentFilterValues.includes(student.details[user.studentFilter])) {
289
+ return false;
290
+ }
291
+ }
292
+ return { ...placement, id: k };
293
+ };
294
+ 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) });
295
+ (0, react_1.useEffect)(() => {
296
+ var _a;
297
+ // Sets the query of for the DataViewerPaginator
298
+ if (user.product !== "institutes" || user.userType !== "Staff") {
299
+ setQuery(undefined);
300
+ return;
301
+ }
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.includes(cohort))) || (user.viewCohorts === "all" && user.viewStudents === "all")))) {
303
+ const constraints = [["oId", "==", user.oId], ["draft", "==", false]];
304
+ cohort && constraints.push(["cohort", "==", cohort]);
305
+ queryConstraints && constraints.unshift(...queryConstraints);
306
+ inProgress !== undefined && constraints.push(["inProgress", "==", inProgress]);
307
+ setQuery([{
308
+ path: ["placements"],
309
+ where: constraints
310
+ }]);
311
+ return;
312
+ }
313
+ setQuery(undefined);
314
+ }, [user, queryConstraints, cohort]);
315
+ return { tableData, page, loading, updateSearch, setFilters, setView, pageUp, pageDown, sorts, updateSort, sort };
316
+ }
317
+ const algoliaPlacementSearch = async (user, query, sort, page, filters, limit, cohort, inProgress) => {
318
+ const algoliaClient = (0, algoliasearch_1.default)(process.env.NODE_ENV === "development" ? "A0ZB50I7VS" : "XMPXCMUUOJ", user.algoliaKey);
319
+ const placementsIndex = algoliaClient.initIndex(sort ? Object.values(sort[1]).join("_") : "placements");
320
+ // const usersIndex = algoliaClient.initIndex("users");
321
+ // let userSearchString = `userType:Students AND status:active AND oId:${user.oId} AND product:${user.product}`
322
+ // if (cohort) {
323
+ // userSearchString = userSearchString + ` AND cohort:${cohort}`;
324
+ // }
325
+ // if (user.product === "institutes" && user.userType === "Staff") {
326
+ // const searchStudentHits = await usersIndex.search<UserData>(query, {
327
+ // filters: userSearchString,
328
+ // hitsPerPage: limit,
329
+ // page: page
330
+ // });
331
+ // if (searchStudentHits) {
332
+ // console.log("FOUND", searchStudentHits.hits.length, "students");
333
+ // await Promise.all(searchStudentHits.hits.map(async (hit) => {
334
+ // console.log("STUDENT", hit.objectID);
335
+ // const constraints = [...(cohort ? [where("cohort", "==", cohort)] : [])]
336
+ // if (inProgress !== undefined) {
337
+ // constraints.push(inProgress ? where("inProgress", "==", true) : where("completed", "==", true));
338
+ // }
339
+ // const fPlacements = await getPlacementsWhere({w: constraints, uid: hit.objectID, oId: hit.oId}) as {[key: string]: StudentPlacementData};
340
+ // console.log("PLACEMENTS", fPlacements)
341
+ // Object.entries(fPlacements).forEach(([k, v]) => {
342
+ // placementsFound[k] = {...v, student: hit};
343
+ // })
344
+ // }))
345
+ // }
346
+ // }
347
+ let placementSearchString = `oId:${user.oId} AND ` + (inProgress !== undefined ? (inProgress ? "inProgress:true" : "completed:true") : "");
348
+ if (cohort) {
349
+ placementSearchString = placementSearchString + ` AND cohort:${cohort}`;
350
+ }
351
+ filters && Object.entries(filters).filter(([, filter]) => filter.value).map(([id, filter]) => {
352
+ placementSearchString = placementSearchString + ` AND ${id}:${filter.value}`;
353
+ });
354
+ const options = {
355
+ filters: placementSearchString,
356
+ hitsPerPage: limit,
357
+ page: page ? page - 1 : undefined,
358
+ };
359
+ const searchPlacementHits = await placementsIndex.search(query || "", options);
360
+ console.log(searchPlacementHits.hits);
361
+ const i = (searchPlacementHits ? (await Promise.all(searchPlacementHits.hits.map(async (hit) => {
362
+ return [hit.objectID, hit];
363
+ }))) : []).filter((e) => e !== undefined);
364
+ return Object.fromEntries(i);
365
+ };
366
+ function useVeryOldInstitutePlacementList({ user, cohort, queryConstraint, ql = DEFAULTQUERYLIMIT }) {
262
367
  const [loadMoreIcon, setLoadMoreIcon] = (0, react_1.useState)(true);
263
368
  const [query, setQuery] = (0, react_1.useState)("");
264
369
  const [initialQueryLimit, setInitialQueryLimit] = (0, react_1.useState)(ql);
@@ -299,7 +404,7 @@ function useOldInstitutePlacementList({ user, cohort, queryConstraint, ql = DEFA
299
404
  setLoadMoreIcon(true);
300
405
  // If can view all, query placements directly. Otherwise query students.
301
406
  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.split(", ").includes(cohort))) || (user.viewCohorts === "all" && user.viewUsers === "all") || query) && (fStartPlacementAfter && fStartPlacementAfter[0] === "placement"))) {
407
+ 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
408
  const queryConstraintOrdered = Boolean(queryConstraints && queryConstraints.find((v) => v.type === "orderBy"));
304
409
  const constraints = (fStartPlacementAfter === null || fStartPlacementAfter === void 0 ? void 0 : fStartPlacementAfter.length) === 4 && fStartPlacementAfter[1] ?
305
410
  [(0, firestore_1.limit)(placements ? DEFAULTQUERYLIMIT : initialQueryLimit),
@@ -314,10 +419,10 @@ function useOldInstitutePlacementList({ user, cohort, queryConstraint, ql = DEFA
314
419
  const placementsWithStudentData = placementsQuery.empty ? [] : await Promise.all(placementsQuery.docs.map(async (placement) => {
315
420
  const pData = placement.data();
316
421
  const student = pData.uid === user.id ? user : (await (0, readDatabase_1.getUserById)(pData.uid).catch(() => false));
317
- if (user.viewUsers === "some") {
422
+ if (user.viewStudents === "some") {
318
423
  if (!(user.studentFilter && user.studentFilterValues))
319
424
  return false;
320
- if (!user.studentFilterValues.split(", ").includes(student.details[user.studentFilter])) {
425
+ if (!user.studentFilterValues.includes(student.details[user.studentFilter])) {
321
426
  return false;
322
427
  }
323
428
  }
@@ -342,13 +447,13 @@ function useOldInstitutePlacementList({ user, cohort, queryConstraint, ql = DEFA
342
447
  return;
343
448
  }
344
449
  }
345
- if (!(user.studentFilterValues && user.studentFilter && user.viewUsers === "some")) {
450
+ if (!(user.studentFilterValues && user.studentFilter && user.viewStudents === "some")) {
346
451
  console.log("fenaibn");
347
452
  return;
348
453
  }
349
454
  ;
350
455
  const getStudentPlacements = async (ffStartPlacementAfter = fStartPlacementAfter, ffPlacements = fPlacements) => {
351
- var _a, _b;
456
+ var _a;
352
457
  if (ffStartPlacementAfter && ffStartPlacementAfter[0] === "placement") {
353
458
  ffStartPlacementAfter = [undefined, undefined, undefined, 0];
354
459
  }
@@ -358,7 +463,7 @@ function useOldInstitutePlacementList({ user, cohort, queryConstraint, ql = DEFA
358
463
  [(0, firestore_1.limit)(1), (0, firestore_1.orderBy)((0, firestore_1.documentId)())];
359
464
  constraints.push((0, firestore_1.where)("oId", "==", oId), (0, firestore_1.where)("userType", "==", "Students"));
360
465
  if (ffStartPlacementAfter && ffStartPlacementAfter[3]) {
361
- const currentFilter = (_a = user === null || user === void 0 ? void 0 : user.studentFilterValues) === null || _a === void 0 ? void 0 : _a.split(", ")[ffStartPlacementAfter[3]];
466
+ const currentFilter = (_a = user === null || user === void 0 ? void 0 : user.studentFilterValues) === null || _a === void 0 ? void 0 : _a[ffStartPlacementAfter[3]];
362
467
  if (currentFilter && user.studentFilter) {
363
468
  constraints.push((0, firestore_1.where)(user.studentFilter, "==", currentFilter));
364
469
  }
@@ -367,7 +472,7 @@ function useOldInstitutePlacementList({ user, cohort, queryConstraint, ql = DEFA
367
472
  const student = Object.entries((await firebaseQuery.getDocsWhere("users", constraints)))[0];
368
473
  // console.log("student", student);
369
474
  // If there is no students but more filters
370
- if (!student && ffStartPlacementAfter && ffStartPlacementAfter[3] + 1 < (((_b = user === null || user === void 0 ? void 0 : user.studentFilterValues) === null || _b === void 0 ? void 0 : _b.split(", ")) || []).length) {
475
+ if (!student && ffStartPlacementAfter && ffStartPlacementAfter[3] + 1 < ((user === null || user === void 0 ? void 0 : user.studentFilterValues) || []).length) {
371
476
  // console.log("No more students. Calling recursion");
372
477
  return await getStudentPlacements(["student", undefined, undefined, ffStartPlacementAfter[3] + 1], ffPlacements);
373
478
  }
@@ -577,7 +682,7 @@ function useFilterTablePaginator({ data }) {
577
682
  if (!Object.keys(itemList).length)
578
683
  return;
579
684
  console.log("Fetching filter table updates");
580
- const itemListUpdateQuery = (0, firestore_1.query)((0, firestore_1.collection)(firebaseConfig_1.db, "users"), (0, firestore_1.where)((0, firestore_1.documentId)(), "in", Object.keys(itemList)));
685
+ 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
686
  const itemUpdateSnapshot = (0, firestore_1.onSnapshot)(itemListUpdateQuery, (querySnapshot) => {
582
687
  querySnapshot.docs.forEach((doc) => {
583
688
  setTableData((data) => {
@@ -747,9 +852,9 @@ function usePlacementListingPaginator({ data, user }) {
747
852
  setQueryAnchor({ ...currentQueryAnchor, startKey: Object.keys(itemList)[0], endKey: Object.keys(itemList).slice(-1)[0] });
748
853
  const finalData = Object.fromEntries(await Promise.all(Object.entries(itemList).map(async ([k, v]) => {
749
854
  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);
855
+ const address = await firebaseQuery.getDocData(["addresses", placement.addressId || ""]).catch(() => ({ ["address-line1"]: "Unknown address" }));
856
+ const provider = await firebaseQuery.getDocData(["providers", placement.providerId || ""]).catch(() => ({ name: "Unknown" }));
857
+ const status = provider.name !== "Unknown" ? getPlacementStatus(provider, placement, v) : "Deleted";
753
858
  return [k, { ...address, ...provider, ...placement, email: placement.providerEmail, status: status, savedPlacement: v }];
754
859
  })));
755
860
  setTableData(finalData);
@@ -785,10 +890,11 @@ function usePlacementListingPaginator({ data, user }) {
785
890
  }, [page]);
786
891
  return ({ ...{ tableData, setPage, setFilters, page } });
787
892
  }
788
- function useCohortUserPaginator({ user, cohort, data, search, userType }) {
893
+ function useCohortUserPaginator({ user, cohort, data, search, userType, sort }) {
789
894
  const [tableData, setTableData] = (0, react_1.useState)({});
790
- const [queryAnchor, setQueryAnchor] = (0, react_1.useState)({ startKey: "", endKey: "", startQueryPos: 0, endQueryPos: 0 });
895
+ const [queryAnchor, setQueryAnchor] = (0, react_1.useState)({ startDoc: undefined, endDoc: undefined, startQueryPos: 0, endQueryPos: 0 });
791
896
  const [filters, setFilters] = (0, react_1.useState)();
897
+ const [sortResultsBy, setSortResultsBy] = (0, react_1.useState)(sort);
792
898
  const [prevEntryIds, setPrevEntryIds] = (0, react_1.useState)({});
793
899
  const [page, setPage] = (0, react_1.useState)([1, 0]);
794
900
  const [dataListenerUnsubscribe, setDataListenerUnsubscribe] = (0, react_1.useState)();
@@ -796,6 +902,14 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
796
902
  const [prevSearch, setPrevSearch] = (0, react_1.useState)();
797
903
  const algoliaClient = (0, algoliasearch_1.default)(process.env.NODE_ENV === "development" ? "A0ZB50I7VS" : "XMPXCMUUOJ", user.algoliaKey);
798
904
  const usersIndex = algoliaClient.initIndex("users");
905
+ const sortOptions = {
906
+ ["Forename - Asc"]: ["details.forename", "asc"],
907
+ ["Forename - Desc"]: ["details.forename", "desc"],
908
+ ["Surname - Asc"]: ["details.surname", "desc"],
909
+ ["Surname - Desc"]: ["details.surname", "asc"],
910
+ ["Email - Asc"]: ["email", "asc"],
911
+ ["Email - Desc"]: ["email", "desc"],
912
+ };
799
913
  (0, react_1.useEffect)(() => {
800
914
  var _a;
801
915
  if (user.userType !== "Staff") {
@@ -805,7 +919,7 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
805
919
  }
806
920
  if ((!user.viewCohorts && user.userGroup !== "admin") ||
807
921
  user.viewCohorts === "none" ||
808
- (user.viewCohorts === "some" && cohort !== "all" && !((_a = user.visibleCohorts) === null || _a === void 0 ? void 0 : _a.split(",").includes(cohort || "")))) {
922
+ (user.viewCohorts === "some" && cohort !== "all" && !((_a = user.visibleCohorts) === null || _a === void 0 ? void 0 : _a.includes(cohort || "")))) {
809
923
  setQueries(undefined);
810
924
  return;
811
925
  }
@@ -821,13 +935,13 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
821
935
  });
822
936
  constraints.push((0, firestore_1.where)("oId", "==", user.oId));
823
937
  cohort && cohort !== "all" && constraints.push((0, firestore_1.where)("cohort", "==", cohort));
824
- if (user.userGroup === "admin" || user.viewUsers === "all") {
938
+ if (user.userGroup === "admin" || user.viewStudents === "all") {
825
939
  finalConstraints.push(constraints);
826
940
  continue;
827
941
  }
828
942
  if (!user.studentFilter || !user.studentFilterValues)
829
943
  continue;
830
- user.studentFilterValues.split(", ").forEach((filterValue) => {
944
+ user.studentFilterValues.forEach((filterValue) => {
831
945
  user.studentFilter && finalConstraints.push([...constraints, (0, firestore_1.where)("details." + user.studentFilter, "==", filterValue)]);
832
946
  });
833
947
  }
@@ -837,7 +951,7 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
837
951
  });
838
952
  }, []);
839
953
  const getDataFromQuery = async (itemList = {}, currentQueryAnchor = queryAnchor, cursorDirection, prevEntries = prevEntryIds, loadMoreFromQuery = false) => {
840
- if (!queries) {
954
+ if (!(queries === null || queries === void 0 ? void 0 : queries.length)) {
841
955
  setTableData({});
842
956
  return;
843
957
  }
@@ -854,17 +968,42 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
854
968
  const createQuery = (mConstraints) => {
855
969
  console.log("mConstraints", mConstraints);
856
970
  const fConstraints = [...mConstraints];
971
+ let addOrderBy = true;
857
972
  filters && Object.entries(filters).forEach(([key, value]) => {
858
- if (typeof value === "object") {
973
+ if (Array.isArray(value)) {
974
+ value.forEach((v) => {
975
+ if (typeof v === "object") {
976
+ if (v instanceof firestore_1.QueryOrderByConstraint) {
977
+ addOrderBy = false;
978
+ }
979
+ fConstraints.push(v);
980
+ }
981
+ else {
982
+ fConstraints.push((0, firestore_1.where)(key, "==", v));
983
+ }
984
+ });
985
+ }
986
+ else if (typeof value === "object") {
987
+ if (value instanceof firestore_1.QueryOrderByConstraint) {
988
+ addOrderBy = false;
989
+ }
859
990
  fConstraints.push(value);
860
991
  }
861
992
  else {
862
993
  fConstraints.push((0, firestore_1.where)(key, "==", value));
863
994
  }
864
995
  });
865
- fConstraints.push((0, firestore_1.orderBy)((0, firestore_1.documentId)()));
996
+ console.log("Add order by", addOrderBy);
997
+ if (addOrderBy) {
998
+ if (sortResultsBy) {
999
+ fConstraints.push((0, firestore_1.orderBy)(sortOptions[sortResultsBy][0], sortOptions[sortResultsBy][1]));
1000
+ }
1001
+ else {
1002
+ fConstraints.push((0, firestore_1.orderBy)((0, firestore_1.documentId)()));
1003
+ }
1004
+ }
866
1005
  if (page[0] > page[1] && !cursorDirection) { // Going up
867
- currentQueryAnchor.endKey && fConstraints.push((0, firestore_1.startAfter)(currentQueryAnchor.endKey));
1006
+ currentQueryAnchor.endDoc && fConstraints.push((0, firestore_1.startAfter)(currentQueryAnchor.endDoc));
868
1007
  fConstraints.push((0, firestore_1.limit)(10));
869
1008
  if (!loadMoreFromQuery) {
870
1009
  currentQueryAnchor = { ...currentQueryAnchor, startQueryPos: currentQueryAnchor.endQueryPos };
@@ -875,11 +1014,11 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
875
1014
  currentQueryAnchor = { ...currentQueryAnchor, endQueryPos: currentQueryAnchor.startQueryPos };
876
1015
  }
877
1016
  fConstraints.push((0, firestore_1.limitToLast)(10));
878
- if (currentQueryAnchor.startKey) {
879
- currentQueryAnchor.startKey && fConstraints.push((0, firestore_1.endBefore)(currentQueryAnchor.startKey));
1017
+ if (currentQueryAnchor.startDoc) {
1018
+ currentQueryAnchor.startDoc && fConstraints.push((0, firestore_1.endBefore)(currentQueryAnchor.startDoc));
880
1019
  }
881
1020
  else {
882
- currentQueryAnchor.startKey && fConstraints.push((0, firestore_1.endAt)(currentQueryAnchor.startKey));
1021
+ currentQueryAnchor.startDoc && fConstraints.push((0, firestore_1.endAt)(currentQueryAnchor.startDoc));
883
1022
  }
884
1023
  }
885
1024
  else {
@@ -918,9 +1057,7 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
918
1057
  console.log("Removing ", doc.id, ": E=", prevEntries[doc.id], ", G=", position);
919
1058
  return;
920
1059
  }
921
- const item = doc.data();
922
- item.id = doc.id;
923
- queryResults[doc.id] = item;
1060
+ queryResults[doc.id] = doc;
924
1061
  index = index + 1;
925
1062
  if (prevEntries[doc.id])
926
1063
  return;
@@ -942,7 +1079,7 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
942
1079
  }
943
1080
  }
944
1081
  if (Object.keys(itemList).length < 10 && queryData.size === 10) {
945
- return getDataFromQuery(itemList, { ...currentQueryAnchor, startKey: Object.keys(itemList)[0], endKey: Object.keys(itemList).slice(-1)[0] }, undefined, prevEntries, true);
1082
+ return getDataFromQuery(itemList, { ...currentQueryAnchor, startDoc: Object.values(itemList)[0], endDoc: Object.values(itemList).slice(-1)[0] }, undefined, prevEntries, true);
946
1083
  }
947
1084
  if (queryData.size === 0 &&
948
1085
  Object.keys(itemList).length === 0 &&
@@ -968,8 +1105,8 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
968
1105
  setDataListenerUnsubscribe(() => itemUpdateSnapshot);
969
1106
  };
970
1107
  listenForUpdates();
971
- setQueryAnchor({ ...currentQueryAnchor, startKey: Object.keys(itemList)[0], endKey: Object.keys(itemList).slice(-1)[0] });
972
- setTableData(itemList);
1108
+ setQueryAnchor({ ...currentQueryAnchor, startDoc: Object.values(itemList)[0], endDoc: Object.values(itemList).slice(-1)[0] });
1109
+ setTableData(Object.fromEntries(Object.entries(itemList).map(([k, v]) => [k, { id: k, ...v.data() }])));
973
1110
  };
974
1111
  const searchUsers = async () => {
975
1112
  if (!search)
@@ -1006,10 +1143,10 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
1006
1143
  setPage([1, 0]);
1007
1144
  console.log("Set page");
1008
1145
  setTableData({});
1009
- setQueryAnchor({ startKey: "", endKey: "", startQueryPos: 0, endQueryPos: 0 });
1146
+ setQueryAnchor({ startQueryPos: 0, endQueryPos: 0 });
1010
1147
  setPrevEntryIds({});
1011
1148
  dataListenerUnsubscribe && dataListenerUnsubscribe();
1012
- }, [filters, search]);
1149
+ }, [filters, search, sortResultsBy]);
1013
1150
  // Fetch new data when queries or page change
1014
1151
  (0, react_1.useEffect)(() => {
1015
1152
  if (search) {
@@ -1020,7 +1157,8 @@ function useCohortUserPaginator({ user, cohort, data, search, userType }) {
1020
1157
  getDataFromQuery();
1021
1158
  dataListenerUnsubscribe && dataListenerUnsubscribe();
1022
1159
  }, [page, queries, prevSearch]);
1023
- return ({ ...{ tableData, setPage, page, setFilters } });
1160
+ const setSort = (s) => setSortResultsBy(s);
1161
+ return ({ ...{ tableData, setPage, page, setFilters, setSort, sortOptions: Object.keys(sortOptions), sortBy: sortResultsBy } });
1024
1162
  }
1025
1163
  function useAdmissionsPaginator({ data }) {
1026
1164
  const [tableData, setTableData] = (0, react_1.useState)({});
@@ -1109,7 +1247,7 @@ function usePublicPlacementListingLoader({ providerId, number = 5 }) {
1109
1247
  const applicantWorkflow = (await firebaseQuery.getDocData(["applicantWorkflows", itemObj.applicantWorkflowId])).workflow.filter((i) => i.id === 1)[0];
1110
1248
  const applicantFiles = applicantWorkflow.files ? Object.fromEntries(await Promise.all((_a = applicantWorkflow.files) === null || _a === void 0 ? void 0 : _a.map(async (fileId) => {
1111
1249
  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}`));
1250
+ file.url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `providers/${itemObj.providerId}/${file.fileName}`));
1113
1251
  return [fileId, file];
1114
1252
  }))) : [];
1115
1253
  const applicantForms = applicantWorkflow.forms ? Object.fromEntries(await Promise.all((_b = applicantWorkflow.forms) === null || _b === void 0 ? void 0 : _b.map(async (formId) => {
@@ -1138,6 +1276,7 @@ function useCreateApplicationRenderer({ user, listingId, listing, provider, appl
1138
1276
  const [fApplication, setFApplication] = (0, react_1.useState)(application ? applicationWithoutAdditionalData : {
1139
1277
  uid: user.userType === "Students" ? user.id : undefined,
1140
1278
  listingId: listingId,
1279
+ addressId: listing === null || listing === void 0 ? void 0 : listing.addressId,
1141
1280
  stage: 1,
1142
1281
  reqUserType: "Students",
1143
1282
  status: "draft"
@@ -1145,7 +1284,7 @@ function useCreateApplicationRenderer({ user, listingId, listing, provider, appl
1145
1284
  const [fApplicationId, setFApplicationId] = (0, react_1.useState)(applicationId);
1146
1285
  const [draftSaved, setDraftSaved] = (0, react_1.useState)(false);
1147
1286
  const [fProvider, setFProvider] = (0, react_1.useState)(provider);
1148
- const [fListing, setFListing] = (0, react_1.useState)(listing);
1287
+ const [fListing, setFListing] = (0, react_1.useState)(Object.keys(listing || {}).length > 5 ? listing : undefined);
1149
1288
  const [student, setStudent] = (0, react_1.useState)(user.userType === "Students" ? user : undefined);
1150
1289
  const [profileUrl, setProfileUrl] = (0, react_1.useState)();
1151
1290
  const [successPopup, setSuccessPopup] = (0, react_1.useState)();
@@ -1157,30 +1296,35 @@ function useCreateApplicationRenderer({ user, listingId, listing, provider, appl
1157
1296
  if (!listingId)
1158
1297
  return;
1159
1298
  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;
1299
+ console.log("LISTING PARAM", listing, Object.keys(listing || {}).length > 5);
1300
+ const listingData = (Object.keys(listing || {}).length > 5) ? listing : await firebaseQuery.getDocData(["placementListings", listingId]).catch(() => false);
1301
+ console.log("LISTINGDATA", listingData, Object.keys(listing || {}).length > 5 ? { a: "string" } : "AAA");
1302
+ const address = listingData ? (user.product === "providers" && orgContext) ? orgContext.addresses[listingData.addressId || ""] : await firebaseQuery.getDocData(["addresses", listingData.addressId]) : undefined;
1303
+ const workflow = listingData ? (user.product === "providers" && orgContext) ? orgContext.applicantWorkflows[listingData.applicantWorkflowId || ""] : await firebaseQuery.getDocData(["applicantWorkflows", listingData.applicantWorkflowId]) : undefined;
1304
+ if (workflow && listingData) {
1305
+ workflow.workflow = await Promise.all(workflow.workflow.map(async (s) => {
1306
+ var _a, _b;
1307
+ const applicantFiles = s.files ? Object.fromEntries(await Promise.all((_a = s.files) === null || _a === void 0 ? void 0 : _a.map(async (fileId) => {
1308
+ const file = await firebaseQuery.getDocData(["files", fileId]);
1309
+ file.url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `providers/${listingData === null || listingData === void 0 ? void 0 : listingData.providerId}/${file.fileName}`));
1310
+ return [fileId, file];
1311
+ }))) : [];
1312
+ const applicantForms = s.forms ? Object.fromEntries(await Promise.all((_b = s.forms) === null || _b === void 0 ? void 0 : _b.map(async (formId) => {
1313
+ return [formId, await firebaseQuery.getDocData(["forms", formId])];
1314
+ }))) : [];
1315
+ return { ...s, viewableFiles: applicantFiles, formDetails: applicantForms };
1316
+ }));
1317
+ delete workflow.id;
1318
+ }
1319
+ if (address) {
1320
+ delete address.id;
1321
+ }
1177
1322
  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);
1323
+ setFListing((listingData && workflow) ? { ...listingData, ...address, applicantWorkflow: workflow.workflow } : false);
1180
1324
  if (((fProvider === null || fProvider === void 0 ? void 0 : fProvider.id) === (application === null || application === void 0 ? void 0 : application.providerId)) && user.product === "providers") {
1181
1325
  setFProvider({ details: orgContext === null || orgContext === void 0 ? void 0 : orgContext.details, id: user.oId });
1182
1326
  }
1183
- else if (listingData === null || listingData === void 0 ? void 0 : listingData.providerId) {
1327
+ else if (listingData && (listingData === null || listingData === void 0 ? void 0 : listingData.providerId)) {
1184
1328
  console.log("Getting provider from DB");
1185
1329
  const provider = await firebaseQuery.getDocData(["providers", listingData.providerId]);
1186
1330
  console.log("Provider", provider);
@@ -1200,7 +1344,7 @@ function useCreateApplicationRenderer({ user, listingId, listing, provider, appl
1200
1344
  }
1201
1345
  }, []);
1202
1346
  (0, react_1.useEffect)(() => {
1203
- setFListing(listing);
1347
+ setFListing(Object.keys(listing || {}).length > 5 ? listing : undefined);
1204
1348
  }, [listing]);
1205
1349
  (0, react_1.useEffect)(() => {
1206
1350
  if (provider === null || provider === void 0 ? void 0 : provider.profile)
@@ -1224,11 +1368,25 @@ function useCreateApplicationRenderer({ user, listingId, listing, provider, appl
1224
1368
  });
1225
1369
  return;
1226
1370
  }
1227
- if (applicationId)
1371
+ if (applicationId) {
1228
1372
  setFApplicationId(applicationId);
1373
+ if (application) {
1374
+ let applicationWithoutAdditionalData = { ...(application || {}) };
1375
+ delete applicationWithoutAdditionalData.listing;
1376
+ delete applicationWithoutAdditionalData.address;
1377
+ delete applicationWithoutAdditionalData.provider;
1378
+ setFApplication(applicationWithoutAdditionalData);
1379
+ }
1380
+ else {
1381
+ firebaseQuery.getDocData(["applications", applicationId]).then(setFApplication);
1382
+ }
1383
+ }
1229
1384
  }, [application, applicationId]);
1230
1385
  const getCurrentStage = async (stage) => {
1231
1386
  var _a, _b, _c, _d;
1387
+ console.log("fLSITING CURRENT STAGE", fListing);
1388
+ if (!fListing)
1389
+ throw new Error("Listing deleted");
1232
1390
  if (!(fListing === null || fListing === void 0 ? void 0 : fListing.applicantWorkflowId))
1233
1391
  throw new Error("No workflow stage");
1234
1392
  const mApplicantWorkflow = await firebaseQuery.getDocData(["applicantWorkflows", fListing.applicantWorkflowId]);
@@ -1237,7 +1395,7 @@ function useCreateApplicationRenderer({ user, listingId, listing, provider, appl
1237
1395
  throw new Error("Can't find stage.");
1238
1396
  const applicantFiles = stageObj.files ? Object.fromEntries(await Promise.all((_b = stageObj.files) === null || _b === void 0 ? void 0 : _b.map(async (fileId) => {
1239
1397
  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}`));
1398
+ file.url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `providers/${mApplicantWorkflow === null || mApplicantWorkflow === void 0 ? void 0 : mApplicantWorkflow.oId}/${file.fileName}`));
1241
1399
  return [fileId, file];
1242
1400
  }))) : [];
1243
1401
  const applicantForms = stageObj.forms ? Object.fromEntries(await Promise.all((_c = stageObj.forms) === null || _c === void 0 ? void 0 : _c.map(async (formId) => {
@@ -1267,11 +1425,12 @@ function useCreateApplicationRenderer({ user, listingId, listing, provider, appl
1267
1425
  };
1268
1426
  const addApplication = async () => {
1269
1427
  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))
1428
+ if (!fListing || !(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
1429
  return;
1272
1430
  const applicationData = {
1273
1431
  uid: student.id,
1274
1432
  listingId: fListing === null || fListing === void 0 ? void 0 : fListing.id,
1433
+ addressId: fListing.addressId,
1275
1434
  applicantWorkflowId: fListing === null || fListing === void 0 ? void 0 : fListing.applicantWorkflowId,
1276
1435
  providerId: fProvider.id,
1277
1436
  stage: 1,
@@ -1288,11 +1447,10 @@ function useCreateApplicationRenderer({ user, listingId, listing, provider, appl
1288
1447
  };
1289
1448
  getUploadedFiles();
1290
1449
  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))
1450
+ if (!fListing || !(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
1451
  return;
1294
1452
  if (user.product === "providers")
1295
- throw new Error("Providers cannot create applications");
1453
+ return;
1296
1454
  console.log("Checking dates and sections");
1297
1455
  if (!fApplication.completedSections && !fApplication.startDate && !fApplication.endDate)
1298
1456
  return;
@@ -1361,6 +1519,8 @@ function useCreateApplicationRenderer({ user, listingId, listing, provider, appl
1361
1519
  return;
1362
1520
  if (fApplication.stage === undefined)
1363
1521
  throw new Error("Missing applciation stage.");
1522
+ if (!fListing)
1523
+ throw new Error("No associated listing.");
1364
1524
  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
1525
  setFApplication((a) => {
1366
1526
  var _a, _b;
@@ -1413,14 +1573,20 @@ function useCreateApplicationRenderer({ user, listingId, listing, provider, appl
1413
1573
  openSuccessPopup("draftSaved");
1414
1574
  return;
1415
1575
  }
1576
+ if (!fApplicationId)
1577
+ return;
1416
1578
  // Check all items have been filled in.
1417
1579
  if (!fApplication.startDate || !fApplication.endDate)
1418
1580
  throw new Error("Please select dates for your placement.");
1419
1581
  await (0, firebase_1.executeCallable)("applications-submit", { applicationId: fApplicationId });
1582
+ const newApplication = await firebaseQuery.getDocData(["applications", fApplicationId]);
1583
+ setFApplication(newApplication);
1420
1584
  openSuccessPopup("submitted");
1421
1585
  };
1422
1586
  const progressStage = async (type, e) => {
1423
1587
  // Check all stages completed.
1588
+ if (!fApplicationId)
1589
+ return;
1424
1590
  if (!currentStageComplete)
1425
1591
  throw new Error("Complete all forms before submitting.");
1426
1592
  if (fApplication.reqUserType !== user.userType)
@@ -1428,6 +1594,8 @@ function useCreateApplicationRenderer({ user, listingId, listing, provider, appl
1428
1594
  if (fApplication.stage === undefined)
1429
1595
  throw new Error("Missing applciation stage.");
1430
1596
  await (0, firebase_1.executeCallable)("applications-changeStage", { applicationId: fApplicationId, type: type, feedback: e === null || e === void 0 ? void 0 : e.feedback });
1597
+ const newApplication = await firebaseQuery.getDocData(["applications", fApplicationId]);
1598
+ setFApplication(newApplication);
1431
1599
  };
1432
1600
  return { successText, onFApply, progressStage, currentStageComplete, uploadedFiles, getCurrentStage, setFormComplete, viewFile, addFile, setSuccessPopup, openSuccessPopup, setFApplication, fApplication, draftSaved, profileUrl, successPopup, fApplicationId, fListing, student, fProvider };
1433
1601
  }
@@ -1498,22 +1666,44 @@ function useProposePlacementRenderer({ user, orgContext, placement }) {
1498
1666
  setFormData(undefined);
1499
1667
  };
1500
1668
  const proposePlacement = async (draft = false) => {
1669
+ const getPlacementStatus = (startDate, endDate) => {
1670
+ const today = new Date();
1671
+ if (startDate <= today && endDate >= today)
1672
+ return { active: !draft ? true : false, inProgress: true, completed: false };
1673
+ else if (endDate <= today)
1674
+ return { completed: true, inProgress: false, active: false };
1675
+ return { completed: false, inProgress: true, active: false };
1676
+ };
1501
1677
  if (!formData || !student) {
1502
1678
  throw new Error("Cannot find placement details.");
1503
1679
  }
1504
- console.log("formData", formData);
1505
- if (formData.id && formData.uid && formData.id && draft === formData.draft) {
1506
- return await firebaseQuery.update(["placements", formData.id], formData);
1507
- }
1508
- console.log("STUDENTID", student.id);
1509
- return await (0, writeDatabase_1.addPlacement)(formData, student.id, draft).catch((e) => {
1510
- console.log("error");
1511
- console.log(e);
1512
- throw e;
1513
- }).then((e) => {
1680
+ try {
1681
+ console.log("formData", formData);
1682
+ const status = getPlacementStatus(new Date(formData.startDate), new Date(formData.endDate));
1683
+ const newFormData = { ...formData, ...status };
1684
+ if (newFormData.id && newFormData.uid && draft === newFormData.draft)
1685
+ await firebaseQuery.update(["placements", newFormData.id], newFormData);
1686
+ else
1687
+ await (0, writeDatabase_1.addPlacement)(newFormData, student.id, draft);
1514
1688
  setComplete(true);
1515
- return e;
1516
- });
1689
+ return { status };
1690
+ }
1691
+ catch (error) {
1692
+ console.log("Error:", error);
1693
+ throw error;
1694
+ }
1695
+ /*
1696
+ console.log("STUDENTID", student.id);
1697
+
1698
+ return await addPlacement(formData, student.id, draft).catch((e) => {
1699
+ console.log("error");
1700
+ console.log(e);
1701
+ throw e;
1702
+ }).then((e) => {
1703
+ setComplete(true);
1704
+ return e;
1705
+ });
1706
+ */
1517
1707
  };
1518
1708
  const deletePlacement = async (id) => {
1519
1709
  return await firebaseQuery.delete(["placements", id]);
@@ -1598,9 +1788,6 @@ function useUserUploadHandler({ product, oId, userType, user, onComplete, userGr
1598
1788
  const [alert, setAlert] = (0, react_1.useState)();
1599
1789
  const { execute } = (0, firebase_1.useExecuteCallableJob)({ user: user });
1600
1790
  const requiredFields = ["forename", "surname", "email"];
1601
- if (userType === "Students") {
1602
- requiredFields.push("year");
1603
- }
1604
1791
  const checkData = (userData) => {
1605
1792
  setAlert(undefined);
1606
1793
  userData = userData.filter((u) => Object.entries(u).some(([, v]) => v));
@@ -1643,10 +1830,6 @@ function useUserUploadHandler({ product, oId, userType, user, onComplete, userGr
1643
1830
  }
1644
1831
  }
1645
1832
  // 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
1833
  }
1651
1834
  if (emptyRequiredCell) {
1652
1835
  return false;
@@ -1685,10 +1868,10 @@ function useUserUploadHandler({ product, oId, userType, user, onComplete, userGr
1685
1868
  setAlert(undefined);
1686
1869
  if (fUsers.length) {
1687
1870
  console.log("fUsers", fUsers);
1688
- execute("userManagement-addUsers", { product: product, oId: oId, users: fUsers, userType: userType, userGroupId: userGroupId, cohortId: cohortId });
1871
+ const jobId = await execute("userManagement-addUsers", { product: product, oId: oId, users: fUsers, userType: userType, userGroupId: userGroupId, cohortId: cohortId });
1872
+ onComplete && onComplete(jobId);
1689
1873
  }
1690
1874
  console.log("Complete", onComplete);
1691
- onComplete && onComplete();
1692
1875
  console.log("Finished");
1693
1876
  };
1694
1877
  const onChange = () => {
@@ -2353,6 +2536,9 @@ function useGetIndividualPlacementForPlacementPage({ user, placementId, organisa
2353
2536
  const [uploadRA, setUploadRA] = (0, react_1.useState)(false);
2354
2537
  const [uploadDBS, setUploadDBS] = (0, react_1.useState)(false);
2355
2538
  const [onboardingPopup, setOnboardingPopup] = (0, react_1.useState)(false);
2539
+ const [dismissOnboardingPopup, setDismissOnboardingPopup] = (0, react_1.useState)(false);
2540
+ const [addOnboardingDocsPopup, setAddOnboardingDocsPopup] = (0, react_1.useState)(false);
2541
+ const [shareStudentRequestPopup, setShareStudentRequestPopup] = (0, react_1.useState)(false);
2356
2542
  const [editable, setEditable] = (0, react_1.useState)(false);
2357
2543
  const [withdrawFromPlacementPopup, setWithdrawFromPlacementPopup] = (0, react_1.useState)(false);
2358
2544
  const firebaseQuery = new firebaseQuery_1.default();
@@ -2395,25 +2581,43 @@ function useGetIndividualPlacementForPlacementPage({ user, placementId, organisa
2395
2581
  setStudent(user);
2396
2582
  }
2397
2583
  else {
2398
- (0, readDatabase_1.getUserById)(placement.uid).then(setStudent);
2584
+ if (placement.uid) {
2585
+ (0, readDatabase_1.getUserById)(placement.uid, undefined, false).then(setStudent);
2586
+ }
2587
+ else {
2588
+ setStudent({
2589
+ details: {
2590
+ forename: placement.studentForename || "",
2591
+ surname: placement.studentSurname || "",
2592
+ },
2593
+ email: placement.studentEmail || ""
2594
+ });
2595
+ }
2399
2596
  }
2400
2597
  }, [placement]);
2401
2598
  (0, react_1.useEffect)(() => {
2402
2599
  if (!workflow || !placement)
2403
2600
  return;
2404
- const currentWorkflowStage = { ...workflow.find((obj) => obj.id === placement.status) };
2405
- // console.log("currentWorkflowStage", currentWorkflowStage)
2406
- currentWorkflowStage.id = placement.status;
2407
- // Get form data for current stage
2408
- if (currentWorkflowStage.forms) {
2409
- (0, readDatabase_1.getFormsFromId)(["forms"], currentWorkflowStage.forms).then((details) => {
2410
- currentWorkflowStage.formDetails = details;
2411
- setWStage(currentWorkflowStage);
2412
- });
2413
- }
2414
- else {
2415
- setWStage(currentWorkflowStage);
2416
- }
2601
+ const getAdditionalStageData = async () => {
2602
+ const currentWorkflowStage = { ...workflow.find((obj) => obj.id === placement.status) };
2603
+ // console.log("currentWorkflowStage", currentWorkflowStage)
2604
+ currentWorkflowStage.id = placement.status;
2605
+ // Get form data for current stage
2606
+ if (currentWorkflowStage.forms) {
2607
+ (0, readDatabase_1.getFormsFromId)(["forms"], currentWorkflowStage.forms).then((details) => {
2608
+ currentWorkflowStage.formDetails = details;
2609
+ });
2610
+ }
2611
+ if (currentWorkflowStage.files) {
2612
+ currentWorkflowStage.files = Object.fromEntries(await Promise.all(currentWorkflowStage.files.map(async (file) => {
2613
+ const fileItem = await firebaseQuery.getDocData(["files", file]);
2614
+ const url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `institutes/${placement.oId}/${fileItem.fileName}`));
2615
+ return [file, { name: fileItem.name, url: url }];
2616
+ })));
2617
+ }
2618
+ return currentWorkflowStage;
2619
+ };
2620
+ getAdditionalStageData().then(setWStage);
2417
2621
  }, [placement, workflow]);
2418
2622
  const editStage = async (nextStageId) => {
2419
2623
  if (!placementId || !wStage)
@@ -2451,10 +2655,7 @@ function useGetIndividualPlacementForPlacementPage({ user, placementId, organisa
2451
2655
  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
2656
  const signOffPlacements = (0, util_1.getAccess)(user, "signOffPlacements");
2453
2657
  let canEdit = false;
2454
- if (((wStage === null || wStage === void 0 ? void 0 : wStage.userType) === "Staff" && user.product === "providers") && user.userGroup === "admin") {
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") {
2658
+ 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
2659
  console.log("ALMOST CAN EDIT");
2459
2660
  if (user.userType === "Staff" && !signOffPlacements) {
2460
2661
  canEdit = false;
@@ -2463,12 +2664,15 @@ function useGetIndividualPlacementForPlacementPage({ user, placementId, organisa
2463
2664
  canEdit = true;
2464
2665
  }
2465
2666
  }
2466
- const onFlagClick = async (e) => {
2667
+ const onFlagClick = async (e, onClose) => {
2467
2668
  if (!placement)
2468
2669
  return;
2469
2670
  if (e === "completeOnboarding" || e === "reviewOnboarding") {
2470
2671
  setOnboardingPopup(true);
2471
2672
  }
2673
+ if (e === "studentNotAccepted") {
2674
+ setShareStudentRequestPopup(true);
2675
+ }
2472
2676
  if (e === "noInsurance") {
2473
2677
  if (!eliURL) {
2474
2678
  const storageRef = (0, storage_1.ref)(firebaseConfig_1.storage, `insurance/${placement.providerId}.pdf`);
@@ -2494,6 +2698,14 @@ function useGetIndividualPlacementForPlacementPage({ user, placementId, organisa
2494
2698
  }
2495
2699
  setExternalDocPopupOpen("dbsCheck");
2496
2700
  }
2701
+ if (e === "addOnboarding") {
2702
+ if (onClose) {
2703
+ setDismissOnboardingPopup(true);
2704
+ }
2705
+ else {
2706
+ setAddOnboardingDocsPopup(true);
2707
+ }
2708
+ }
2497
2709
  };
2498
2710
  const approveELI = async () => {
2499
2711
  if (!placement)
@@ -2553,15 +2765,17 @@ function useGetIndividualPlacementForPlacementPage({ user, placementId, organisa
2553
2765
  throw new Error("Must be a student to withdraw.");
2554
2766
  await (0, firebase_1.executeCallable)("placement-withdraw", { placementId: placementId });
2555
2767
  };
2556
- return { placement, wStage, student, workflow, editable, withdrawFromPlacementPopup, setWithdrawFromPlacementPopup, withdrawFromPlacement, onFlagClick, setUploadInsurance, setUploadProviderDocPopup, setUploadRA, setUploadDBS, onboardingStatus, setSkipStagePopup, onboardingPopup, setViewExternalLinkPopup, setOnboardingPopup, setRejectELIPopup, eliURL, 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 };
2768
+ return { placement, wStage, student, workflow, editable, withdrawFromPlacementPopup, addOnboardingDocsPopup, setAddOnboardingDocsPopup, dismissOnboardingPopup, setDismissOnboardingPopup, setWithdrawFromPlacementPopup, withdrawFromPlacement, onFlagClick, setUploadInsurance, setUploadProviderDocPopup, setUploadRA, setUploadDBS, onboardingStatus, setSkipStagePopup, onboardingPopup, setViewExternalLinkPopup, setOnboardingPopup, setRejectELIPopup, eliURL, 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
2769
  }
2558
- function useOnboardingPopup({ onboarding, placementId, user, onClose }) {
2770
+ function useOnboardingPopup({ onboarding, providerId, placementId, user, onClose }) {
2559
2771
  const [fileUploadPopup, setFileUploadPopup] = (0, react_1.useState)(false);
2560
2772
  const [form, setForm] = (0, react_1.useState)();
2561
2773
  const [rejectPopup, setRejectPopup] = (0, react_1.useState)(false);
2562
2774
  const [mOnboarding, setMOnboarding] = (0, react_1.useState)(onboarding);
2563
2775
  const [completedSections, setCompletedSections] = (0, react_1.useState)();
2564
2776
  const [uploadedFiles, setUploadedFiles] = (0, react_1.useState)({});
2777
+ const [viewableFiles, setViewableFiles] = (0, react_1.useState)();
2778
+ const [formDetails, setFormDetails] = (0, react_1.useState)({});
2565
2779
  const firebaseQuery = new firebaseQuery_1.default();
2566
2780
  const addFile = (files) => {
2567
2781
  if (!files.length || fileUploadPopup === false)
@@ -2571,12 +2785,12 @@ function useOnboardingPopup({ onboarding, placementId, user, onClose }) {
2571
2785
  };
2572
2786
  const viewFile = (file, onOpen) => {
2573
2787
  setMOnboarding((a) => {
2574
- var _a, _b, _c;
2788
+ var _a;
2575
2789
  const oldA = { ...a };
2576
2790
  const viewedFiles = a.completed ? ((_a = a.completed) === null || _a === void 0 ? void 0 : _a.filesViewed) || [] : [];
2577
2791
  if (viewedFiles === null || viewedFiles === void 0 ? void 0 : viewedFiles.includes(file))
2578
2792
  return a;
2579
- ((_b = a === null || a === void 0 ? void 0 : a.viewableFiles) === null || _b === void 0 ? void 0 : _b[file].url) && onOpen((_c = a === null || a === void 0 ? void 0 : a.viewableFiles) === null || _c === void 0 ? void 0 : _c[file].url);
2793
+ (viewableFiles === null || viewableFiles === void 0 ? void 0 : viewableFiles[file].url) && onOpen(viewableFiles === null || viewableFiles === void 0 ? void 0 : viewableFiles[file].url);
2580
2794
  viewedFiles === null || viewedFiles === void 0 ? void 0 : viewedFiles.push(file);
2581
2795
  const newA = (0, util_1.editNestedObject)(["completed", "filesViewed"], oldA, viewedFiles);
2582
2796
  return newA;
@@ -2597,14 +2811,14 @@ function useOnboardingPopup({ onboarding, placementId, user, onClose }) {
2597
2811
  const onboardingNew = { ...onboarding };
2598
2812
  const onboardingFiles = onboarding.files ? Object.fromEntries(await Promise.all((_a = onboarding.files) === null || _a === void 0 ? void 0 : _a.map(async (fileId) => {
2599
2813
  const file = await firebaseQuery.getDocData(["files", fileId]);
2600
- file.url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `userFiles/${file.fileName}`));
2814
+ file.url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `providers/${providerId}/${file.fileName}`));
2601
2815
  return [fileId, file];
2602
2816
  }))) : [];
2603
2817
  const onboardingForms = onboarding.forms ? Object.fromEntries(await Promise.all((_b = onboarding.forms) === null || _b === void 0 ? void 0 : _b.map(async (formId) => {
2604
2818
  return [formId, await firebaseQuery.getDocData(["forms", formId])];
2605
2819
  }))) : [];
2606
- onboardingNew.viewableFiles = onboardingFiles;
2607
- onboardingNew.formDetails = onboardingForms;
2820
+ setViewableFiles(onboardingFiles);
2821
+ setFormDetails(onboardingForms);
2608
2822
  return onboardingNew;
2609
2823
  };
2610
2824
  getOnboardingData().then(setMOnboarding);
@@ -2659,7 +2873,8 @@ function useOnboardingPopup({ onboarding, placementId, user, onClose }) {
2659
2873
  return;
2660
2874
  if (!stagesCompleted())
2661
2875
  throw new Error("Complete all forms before submitting.");
2662
- await firebaseQuery.update(["placements", placementId], { ["onboarding.completed.submitted"]: (0, util_1.convertDate)(new Date(), "dbstring") });
2876
+ await firebaseQuery.update(["placements", placementId], { ["onboarding.completed.accepted"]: false, ["onboarding.completed.submitted"]: true, ["onboarding.completed.submittedDate"]: (0, util_1.convertDate)(new Date(), "dbstring") });
2877
+ //executeCallable("sendOnboardingSubmittedEmail", {});
2663
2878
  };
2664
2879
  (0, react_1.useEffect)(() => {
2665
2880
  const getUploadedFiles = async () => {
@@ -2695,6 +2910,583 @@ function useOnboardingPopup({ onboarding, placementId, user, onClose }) {
2695
2910
  getUploadedFiles();
2696
2911
  addCompletedSectionURLs();
2697
2912
  }, [mOnboarding]);
2698
- return { addFile, viewFile, uploadedFiles, setFormComplete, setRejectPopup, stagesCompleted, setForm, mOnboarding, form, submit, acceptOnboarding, rejectOnboarding, rejectPopup, completedSections, fileUploadPopup, setFileUploadPopup };
2913
+ return { addFile, viewFile, uploadedFiles, setFormComplete, setRejectPopup, stagesCompleted, setForm, mOnboarding, form, submit, acceptOnboarding, rejectOnboarding, rejectPopup, completedSections, fileUploadPopup, setFileUploadPopup, viewableFiles, formDetails };
2914
+ }
2915
+ function useLoadAddresses(user, limitItems, queryConstraint, request) {
2916
+ const [addresses, setAddresses] = (0, react_1.useState)({});
2917
+ const [lastDoc, setLastDoc] = (0, react_1.useState)(null);
2918
+ const [loading, setLoading] = (0, react_1.useState)(false);
2919
+ const firebaseQuery = new firebaseQuery_1.default();
2920
+ const [queryConstraints, setQueryConstraints] = (0, react_1.useState)(queryConstraint || []);
2921
+ const changeQueryConstraints = (e) => {
2922
+ setQueryConstraints([...(queryConstraint || []), ...e]);
2923
+ };
2924
+ const loadAddresses = () => {
2925
+ var _a;
2926
+ const constraints = [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("product", "==", user.product), (0, firestore_1.orderBy)((0, firestore_1.documentId)())];
2927
+ if (limitItems) {
2928
+ constraints.push((0, firestore_1.limit)(limitItems));
2929
+ }
2930
+ if (user.viewAddresses === "all" || user.userGroup === "admin" || request) {
2931
+ if (lastDoc === null || lastDoc === void 0 ? void 0 : lastDoc.id) {
2932
+ constraints.push((0, firestore_1.startAfter)(lastDoc === null || lastDoc === void 0 ? void 0 : lastDoc.id));
2933
+ }
2934
+ }
2935
+ else if (user.viewAddresses === "request") {
2936
+ if (!((_a = user.visibleAddresses) === null || _a === void 0 ? void 0 : _a.length))
2937
+ return;
2938
+ constraints.push((0, firestore_1.where)((0, firestore_1.documentId)(), "in", user.visibleAddresses));
2939
+ if (lastDoc === null || lastDoc === void 0 ? void 0 : lastDoc.id) {
2940
+ constraints.push((0, firestore_1.startAfter)(lastDoc === null || lastDoc === void 0 ? void 0 : lastDoc.id));
2941
+ }
2942
+ }
2943
+ else {
2944
+ setLoading(false);
2945
+ return; // viewAddresses === "none", no need to load anything
2946
+ }
2947
+ queryConstraints && constraints.unshift(...queryConstraints);
2948
+ return firebaseQuery.collectionSnapshot((async (snapshot) => {
2949
+ const deletedAddresses = snapshot.docChanges().map((change) => {
2950
+ if (change.type === "removed") {
2951
+ return change.doc.id;
2952
+ }
2953
+ return;
2954
+ });
2955
+ setAddresses((prev) => Object.fromEntries(Object.entries(prev).filter(([k]) => !deletedAddresses.includes(k))));
2956
+ if (!snapshot.empty) {
2957
+ const newAddresses = snapshot.docs.map(doc => ([doc.id, { id: doc.id, ...doc.data() }]));
2958
+ const withListings = Object.fromEntries(await Promise.all(newAddresses.map(async ([k, address]) => {
2959
+ const listings = await firebaseQuery.getCount("placementListings", [(0, firestore_1.where)("providerId", "==", user.oId), (0, firestore_1.where)("addressId", "==", k)]);
2960
+ return [k, { ...address, listings: listings }];
2961
+ })));
2962
+ setAddresses(prev => ({ ...prev, ...withListings }));
2963
+ setLastDoc(snapshot.docs[snapshot.docs.length - 1]);
2964
+ }
2965
+ setLoading(false);
2966
+ }), "addresses", constraints, undefined, true);
2967
+ };
2968
+ (0, react_1.useEffect)(() => {
2969
+ const unsubscribe = loadAddresses();
2970
+ return () => {
2971
+ if (unsubscribe) {
2972
+ unsubscribe(); // Unsubscribe from the snapshot listener when the component unmounts
2973
+ }
2974
+ };
2975
+ // eslint-disable-next-line react-hooks/exhaustive-deps
2976
+ }, [queryConstraints]);
2977
+ const onScrollBottom = () => {
2978
+ if (!limitItems)
2979
+ return;
2980
+ if (!loading) {
2981
+ setLoading(true);
2982
+ loadAddresses();
2983
+ }
2984
+ };
2985
+ return { addresses, onScrollBottom, loading, changeQueryConstraints };
2986
+ }
2987
+ function useLoadListings(user, queryConstraint, request) {
2988
+ const [listings, setListings] = (0, react_1.useState)([]);
2989
+ const [lastDoc, setLastDoc] = (0, react_1.useState)(null);
2990
+ const [loading, setLoading] = (0, react_1.useState)(false);
2991
+ const firebaseQuery = new firebaseQuery_1.default();
2992
+ const [queryConstraints, setQueryConstraints] = (0, react_1.useState)(queryConstraint || []);
2993
+ const changeQueryConstraints = (e) => {
2994
+ setQueryConstraints([...(queryConstraint || []), ...e]);
2995
+ };
2996
+ const loadListings = () => {
2997
+ var _a, _b;
2998
+ const constraints = [(0, firestore_1.where)("providerId", "==", user.oId), (0, firestore_1.limit)(10), (0, firestore_1.orderBy)((0, firestore_1.documentId)())];
2999
+ if (user.viewPlacementListings === "all" || user.userGroup === "admin" || request) {
3000
+ if (lastDoc === null || lastDoc === void 0 ? void 0 : lastDoc.id) {
3001
+ constraints.push((0, firestore_1.startAfter)(lastDoc));
3002
+ }
3003
+ }
3004
+ else {
3005
+ if (!((_a = user.visibleListings) === null || _a === void 0 ? void 0 : _a.length))
3006
+ return;
3007
+ constraints.push((0, firestore_1.where)((0, firestore_1.documentId)(), 'in', user.visibleListings));
3008
+ if (lastDoc === null || lastDoc === void 0 ? void 0 : lastDoc.id) {
3009
+ constraints.push((0, firestore_1.startAfter)(lastDoc));
3010
+ }
3011
+ }
3012
+ if (user.viewAddresses !== "all" && user.viewPlacementListings === "all" && user.userGroup !== "admin") {
3013
+ if (!((_b = user.visibleAddresses) === null || _b === void 0 ? void 0 : _b.length))
3014
+ return;
3015
+ constraints.push((0, firestore_1.where)('addressId', 'in', user.visibleAddresses));
3016
+ }
3017
+ queryConstraints && constraints.unshift(...queryConstraints);
3018
+ return firebaseQuery.collectionSnapshot((async (snapshot) => {
3019
+ const deletedListings = snapshot.docChanges().map((change) => {
3020
+ if (change.type === "removed") {
3021
+ return change.doc.id;
3022
+ }
3023
+ return;
3024
+ });
3025
+ setListings((prev) => prev.filter(([k]) => !deletedListings.includes(k)));
3026
+ if (!snapshot.empty) {
3027
+ const newListings = snapshot.docs.map(doc => ([doc.id, { ...doc.data(), id: doc.id }]));
3028
+ const listingsWithAdditionalData = await Promise.all(newListings.map(async ([id, listing]) => {
3029
+ const listingWithAdditionalData = { ...listing };
3030
+ if (listingWithAdditionalData.applicants !== undefined)
3031
+ return [id, listingWithAdditionalData];
3032
+ 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")]);
3033
+ 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"))]);
3034
+ 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)]);
3035
+ return [id, listingWithAdditionalData];
3036
+ }));
3037
+ setListings(prev => (Object.entries({ ...Object.fromEntries(prev), ...Object.fromEntries(listingsWithAdditionalData) })));
3038
+ setLastDoc(snapshot.docs[snapshot.docs.length - 1]);
3039
+ }
3040
+ setLoading(false);
3041
+ }), "placementListings", constraints, undefined, true);
3042
+ };
3043
+ (0, react_1.useEffect)(() => {
3044
+ let unsubscribe;
3045
+ loadListings();
3046
+ return () => {
3047
+ if (unsubscribe) {
3048
+ unsubscribe(); // Unsubscribe from the snapshot listener when the component unmounts
3049
+ }
3050
+ };
3051
+ // eslint-disable-next-line react-hooks/exhaustive-deps
3052
+ }, [queryConstraints]);
3053
+ const onScrollBottom = () => {
3054
+ if (!loading) {
3055
+ setLoading(true);
3056
+ loadListings();
3057
+ }
3058
+ };
3059
+ return { listings, onScrollBottom, loading, changeQueryConstraints };
3060
+ }
3061
+ function useLoadProviderPlacements(user, queryConstraint, placementId) {
3062
+ const [placements, setPlacements] = (0, react_1.useState)([]);
3063
+ const [lastDoc, setLastDoc] = (0, react_1.useState)(null);
3064
+ const [loading, setLoading] = (0, react_1.useState)(false);
3065
+ const firebaseQuery = new firebaseQuery_1.default();
3066
+ const [queryConstraints, setQueryConstraints] = (0, react_1.useState)(queryConstraint || []);
3067
+ if (user.product !== "providers")
3068
+ throw new Error("Only providers can use this hook.");
3069
+ const changeQueryConstraints = (e) => {
3070
+ setQueryConstraints([...(queryConstraint || []), ...e]);
3071
+ };
3072
+ const loadListings = () => {
3073
+ var _a, _b;
3074
+ const constraints = [(0, firestore_1.where)("providerId", "==", user.oId), (0, firestore_1.limit)(10), (0, firestore_1.orderBy)((0, firestore_1.documentId)())];
3075
+ if (placementId) {
3076
+ constraints.push((0, firestore_1.where)("placementId", "==", placementId));
3077
+ }
3078
+ if (user.viewPlacementListings === "all" || user.userGroup === "admin") {
3079
+ if (lastDoc === null || lastDoc === void 0 ? void 0 : lastDoc.id) {
3080
+ constraints.push((0, firestore_1.startAfter)(lastDoc));
3081
+ }
3082
+ }
3083
+ else {
3084
+ if (!((_a = user.visibleListings) === null || _a === void 0 ? void 0 : _a.length))
3085
+ return;
3086
+ constraints.push((0, firestore_1.where)("placementId", 'in', user.visibleListings));
3087
+ if (lastDoc === null || lastDoc === void 0 ? void 0 : lastDoc.id) {
3088
+ constraints.push((0, firestore_1.startAfter)(lastDoc));
3089
+ }
3090
+ }
3091
+ if (user.viewAddresses !== "all" && user.viewPlacementListings === "all" && user.userGroup !== "admin") {
3092
+ if (!((_b = user.visibleAddresses) === null || _b === void 0 ? void 0 : _b.length))
3093
+ return;
3094
+ constraints.push((0, firestore_1.where)('addressId', 'in', user.visibleAddresses));
3095
+ }
3096
+ queryConstraints && constraints.unshift(...queryConstraints);
3097
+ return firebaseQuery.collectionSnapshot((async (snapshot) => {
3098
+ const deletedListings = snapshot.docChanges().map((change) => {
3099
+ if (change.type === "removed") {
3100
+ return change.doc.id;
3101
+ }
3102
+ return;
3103
+ });
3104
+ setPlacements((prev) => prev.filter(([k]) => !deletedListings.includes(k)));
3105
+ if (!snapshot.empty) {
3106
+ const newPlacements = snapshot.docs.map(doc => ([doc.id, { ...doc.data(), id: doc.id }]));
3107
+ const withAdditionalData = await Promise.all(newPlacements.map(async ([id, placement]) => {
3108
+ const student = placement.uid ? await firebaseQuery.getDocData(["users", placement.uid || ""]).catch(() => false) :
3109
+ {
3110
+ details: {
3111
+ forename: placement.studentForename,
3112
+ surname: placement.studentSurname,
3113
+ },
3114
+ email: placement.studentEmail
3115
+ };
3116
+ const listing = await firebaseQuery.getDocData(["placementListings", placement.placementId || ""]).catch(() => false);
3117
+ return [id, { ...placement, student: student, listing: listing }];
3118
+ }));
3119
+ setPlacements(prev => (Object.entries({ ...Object.fromEntries(prev), ...Object.fromEntries(withAdditionalData) })));
3120
+ setLastDoc(snapshot.docs[snapshot.docs.length - 1]);
3121
+ }
3122
+ setLoading(false);
3123
+ }), "placements", constraints, undefined, true);
3124
+ };
3125
+ (0, react_1.useEffect)(() => {
3126
+ let unsubscribe;
3127
+ loadListings();
3128
+ return () => {
3129
+ if (unsubscribe) {
3130
+ unsubscribe(); // Unsubscribe from the snapshot listener when the component unmounts
3131
+ }
3132
+ };
3133
+ // eslint-disable-next-line react-hooks/exhaustive-deps
3134
+ }, [queryConstraints]);
3135
+ const onScrollBottom = () => {
3136
+ if (!loading) {
3137
+ setLoading(true);
3138
+ loadListings();
3139
+ }
3140
+ };
3141
+ return { placements: Object.fromEntries(placements), onScrollBottom, loading, changeQueryConstraints };
3142
+ }
3143
+ function useLoadApplications({ user, applicationType, listingId, queryConstraint }) {
3144
+ const [applications, setApplications] = (0, react_1.useState)([]);
3145
+ const [lastDoc, setLastDoc] = (0, react_1.useState)(null);
3146
+ const [loading, setLoading] = (0, react_1.useState)(false);
3147
+ const [type, setType] = (0, react_1.useState)(applicationType || "all");
3148
+ const firebaseQuery = new firebaseQuery_1.default();
3149
+ const [queryConstraints, setQueryConstraints] = (0, react_1.useState)(queryConstraint || []);
3150
+ const changeQueryConstraints = (e) => {
3151
+ setQueryConstraints([...(queryConstraint || []), ...e]);
3152
+ };
3153
+ const loadApplications = () => {
3154
+ var _a, _b;
3155
+ const constraints = [(0, firestore_1.where)("providerId", "==", user.oId), (0, firestore_1.limit)(10), (0, firestore_1.orderBy)((0, firestore_1.documentId)())];
3156
+ if (lastDoc === null || lastDoc === void 0 ? void 0 : lastDoc.id) {
3157
+ constraints.push((0, firestore_1.startAfter)(lastDoc));
3158
+ }
3159
+ switch (type) {
3160
+ case "actionRequired":
3161
+ constraints.push((0, firestore_1.where)("status", "==", "submitted"), (0, firestore_1.where)("reqUserType", "==", "Staff"));
3162
+ break;
3163
+ case "awaitingStudent":
3164
+ constraints.push((0, firestore_1.where)("status", "==", "submitted"), (0, firestore_1.where)("reqUserType", "==", "Students"));
3165
+ break;
3166
+ case "closed":
3167
+ constraints.push((0, firestore_1.where)("status", "in", ["approved", "declined"]));
3168
+ break;
3169
+ default:
3170
+ constraints.push((0, firestore_1.where)("status", "==", "submitted"));
3171
+ }
3172
+ if (listingId) {
3173
+ constraints.push((0, firestore_1.where)("listingId", "==", listingId));
3174
+ }
3175
+ console.log("Constraints before user group check", constraints);
3176
+ if (user.viewAddresses !== "all" && user.userGroup !== "admin") {
3177
+ if (user.viewPlacementListings === "all") {
3178
+ if (!((_a = user.visibleAddresses) === null || _a === void 0 ? void 0 : _a.length))
3179
+ return;
3180
+ constraints.push((0, firestore_1.where)('addressId', 'in', user.visibleAddresses));
3181
+ }
3182
+ else {
3183
+ if (!((_b = user.visibleListings) === null || _b === void 0 ? void 0 : _b.length))
3184
+ return;
3185
+ constraints.push((0, firestore_1.where)('placementId', 'in', user.visibleListings));
3186
+ }
3187
+ }
3188
+ queryConstraints && constraints.unshift(...queryConstraints);
3189
+ console.log("Constraints after user group check", constraints);
3190
+ return firebaseQuery.collectionSnapshot((async (snapshot) => {
3191
+ const deletedApplications = snapshot.docChanges().map((change) => {
3192
+ if (change.type === "removed") {
3193
+ return change.doc.id;
3194
+ }
3195
+ return;
3196
+ });
3197
+ console.log("applicantCount", snapshot.size);
3198
+ setApplications((prev) => prev.filter(([k]) => !deletedApplications.includes(k)));
3199
+ if (!snapshot.empty) {
3200
+ const newApplications = snapshot.docs.map(doc => ([doc.id, { id: doc.id, ...doc.data() }])).filter(([, v]) => v.status !== "draft");
3201
+ setApplications(prev => ([...prev, ...newApplications]));
3202
+ setLastDoc(snapshot.docs[snapshot.docs.length - 1]);
3203
+ }
3204
+ else {
3205
+ setApplications([]);
3206
+ setLastDoc(null);
3207
+ }
3208
+ setLoading(false);
3209
+ }), "applications", constraints, undefined, true);
3210
+ };
3211
+ (0, react_1.useEffect)(() => {
3212
+ let unsubscribe;
3213
+ loadApplications();
3214
+ return () => {
3215
+ if (unsubscribe) {
3216
+ unsubscribe(); // Unsubscribe from the snapshot listener when the component unmounts
3217
+ }
3218
+ };
3219
+ // eslint-disable-next-line react-hooks/exhaustive-deps
3220
+ }, [type, queryConstraints]);
3221
+ const onScrollBottom = () => {
3222
+ if (!loading) {
3223
+ setLoading(true);
3224
+ loadApplications();
3225
+ }
3226
+ };
3227
+ return { applications, type, setType, onScrollBottom, loading, changeQueryConstraints };
3228
+ }
3229
+ function useDataViewerPaginator({ view: initialView, sorts, queryLimit, additionalEntryProcessing, formatItems, snapshot, filters: initialFilters, onSearch, data }) {
3230
+ const [tableData, setTableData] = (0, react_1.useState)(Array.isArray(data) ? Object.fromEntries(Object.entries(data).slice(0, queryLimit)) : {});
3231
+ const [page, setPage] = (0, react_1.useState)([1, 0]);
3232
+ const [view, setView] = (0, react_1.useState)(initialView);
3233
+ const [filters, setFilters] = (0, react_1.useState)(initialFilters);
3234
+ const [queryAnchor, setQueryAnchor] = (0, react_1.useState)({ startKey: "", endKey: "", startQueryPos: 0, endQueryPos: 0 });
3235
+ const [prevEntryIds, setPrevEntryIds] = (0, react_1.useState)({});
3236
+ const [dataListenerUnsubscribe, setDataListenerUnsubscribe] = (0, react_1.useState)();
3237
+ const [loading, setLoading] = (0, react_1.useState)(true);
3238
+ const [searchString, setSearchString] = (0, react_1.useState)();
3239
+ const [sort, setSort] = (0, react_1.useState)();
3240
+ const processedData = async (k, v) => additionalEntryProcessing ? await additionalEntryProcessing(k, v) : v;
3241
+ const setTableDataFromDefinedData = async () => {
3242
+ if (!data || Array.isArray(data))
3243
+ return;
3244
+ const dataWithAdditionalProcessingPossibleNulls = (await Promise.all(Object.entries(data).map(async ([k, v]) => [k, await processedData(k, v)])));
3245
+ const dataWithAdditionalProcessing = dataWithAdditionalProcessingPossibleNulls.filter(([k, v]) => v);
3246
+ const searchedData = searchString ? dataWithAdditionalProcessing.filter(([, v]) => {
3247
+ const values = Object.values(v).join(", ");
3248
+ console.log("VALUESTRING", v);
3249
+ return values.includes(searchString);
3250
+ }) : dataWithAdditionalProcessing;
3251
+ const filteredData = filters && Object.keys(filters).length > 0 ? searchedData.filter(([, dataValue]) => Object.entries(filters).every(([filterKey, filterValue]) => {
3252
+ const value = dataValue[filterKey];
3253
+ if ((typeof value === "number") && value === parseInt(filterValue.value))
3254
+ return true;
3255
+ if ((typeof value === "boolean") && value === (filterValue.value === "true"))
3256
+ return true;
3257
+ if ((typeof value === "boolean") && value === (filterValue.value === "false"))
3258
+ return true;
3259
+ if ((typeof value === "string" || Array.isArray(value)) && value.includes(filterValue.value))
3260
+ return true;
3261
+ return false;
3262
+ })) : searchedData;
3263
+ if (view === "table") {
3264
+ if (!queryLimit)
3265
+ throw new Error("Tables must have a limit defined.");
3266
+ const newData = filteredData.slice((page[0] - 1) * queryLimit, page[0] * queryLimit);
3267
+ setTableData(Object.fromEntries(newData));
3268
+ if (Object.keys(Object.fromEntries(newData)).pop() === Object.keys(data).pop()) {
3269
+ setLoading("loaded");
3270
+ }
3271
+ else {
3272
+ setLoading(false);
3273
+ }
3274
+ return;
3275
+ }
3276
+ if (view === "list") {
3277
+ setTableData(Object.fromEntries(filteredData));
3278
+ setLoading("loaded");
3279
+ }
3280
+ };
3281
+ const getDataFromQuery = async (itemList = {}, currentQueryAnchor = queryAnchor, cursorDirection, prevEntries = prevEntryIds, loadMoreFromQuery = false) => {
3282
+ if (!filters)
3283
+ return;
3284
+ setLoading(true);
3285
+ if (!Array.isArray(data)) {
3286
+ setTableDataFromDefinedData();
3287
+ return;
3288
+ }
3289
+ if (!queryLimit)
3290
+ throw new Error("Firestore queries must have a limit defined.");
3291
+ if (onSearch && (searchString || sort)) {
3292
+ if (typeof onSearch === "boolean")
3293
+ 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.");
3294
+ const data = await onSearch(searchString, sort, page[0], filters, queryLimit);
3295
+ const dataWithAdditionalProcessing = await Promise.all(Object.entries(data).map(async ([k, v]) => [k, await processedData(k, v)]));
3296
+ setTableData((old) => {
3297
+ if (view === "table") {
3298
+ return { ...Object.fromEntries(dataWithAdditionalProcessing) };
3299
+ }
3300
+ return { ...old, ...Object.fromEntries(dataWithAdditionalProcessing) };
3301
+ });
3302
+ if (dataWithAdditionalProcessing.length < queryLimit) {
3303
+ setLoading("loaded");
3304
+ }
3305
+ else {
3306
+ setLoading(false);
3307
+ }
3308
+ return;
3309
+ }
3310
+ let cursorPos;
3311
+ if (page[0] > page[1]) {
3312
+ cursorPos = currentQueryAnchor.endQueryPos;
3313
+ }
3314
+ else {
3315
+ cursorPos = currentQueryAnchor.startQueryPos;
3316
+ }
3317
+ const querySchema = data[cursorPos];
3318
+ const createQuery = (queryData) => {
3319
+ const constraints = [];
3320
+ queryData.where && queryData.where.forEach((w) => {
3321
+ constraints.push((0, firestore_1.where)(...w));
3322
+ });
3323
+ filters && Object.entries(filters).filter(([, value]) => value.value).forEach(([key, value]) => {
3324
+ const filterValue = (value.type === "number" || value.type === "dropdown") ? parseInt(value.value) || value.value : value.value;
3325
+ constraints.push((0, firestore_1.where)(key, "==", filterValue));
3326
+ });
3327
+ constraints.push((0, firestore_1.orderBy)(queryData.orderBy ? queryData.orderBy === "documentId" ? (0, firestore_1.documentId)() : queryData.orderBy : (0, firestore_1.documentId)()));
3328
+ if (page[0] > page[1] && !cursorDirection) { // Going up
3329
+ currentQueryAnchor.endKey && constraints.push((0, firestore_1.startAfter)(currentQueryAnchor.endKey));
3330
+ constraints.push((0, firestore_1.limit)(queryLimit));
3331
+ if (!loadMoreFromQuery) {
3332
+ currentQueryAnchor = { ...currentQueryAnchor, startQueryPos: currentQueryAnchor.endQueryPos };
3333
+ }
3334
+ }
3335
+ else if (page[0] < page[1] && !cursorDirection) { // Going down
3336
+ if (!loadMoreFromQuery) {
3337
+ currentQueryAnchor = { ...currentQueryAnchor, endQueryPos: currentQueryAnchor.startQueryPos };
3338
+ }
3339
+ constraints.push((0, firestore_1.limitToLast)(queryLimit));
3340
+ if (currentQueryAnchor.startKey) {
3341
+ currentQueryAnchor.startKey && constraints.push((0, firestore_1.endBefore)(currentQueryAnchor.startKey));
3342
+ }
3343
+ else {
3344
+ currentQueryAnchor.startKey && constraints.push((0, firestore_1.endAt)(currentQueryAnchor.startKey));
3345
+ }
3346
+ }
3347
+ else {
3348
+ if (cursorDirection === "decrease") {
3349
+ constraints.push((0, firestore_1.limitToLast)(queryLimit));
3350
+ }
3351
+ else {
3352
+ constraints.push((0, firestore_1.limit)(queryLimit));
3353
+ }
3354
+ }
3355
+ return constraints;
3356
+ };
3357
+ const constraints = createQuery(querySchema);
3358
+ const q = (0, firestore_1.query)((0, firestore_1.collection)(firebaseConfig_1.db, ...querySchema.path), ...(constraints));
3359
+ console.log("Fetching docs", constraints);
3360
+ if (snapshot) {
3361
+ // Use onSnapshot to get real-time updates
3362
+ const unsubscribe = (0, firestore_1.onSnapshot)(q, (querySnapshot) => {
3363
+ handleQuerySnapshot(querySnapshot);
3364
+ });
3365
+ // Save the unsubscribe function to state so we can dispose of it later
3366
+ setDataListenerUnsubscribe((d) => ({ ...(d || {}), [cursorPos]: unsubscribe }));
3367
+ return;
3368
+ }
3369
+ else {
3370
+ // Just get the docs without setting up a listener
3371
+ const queryData = await (0, firestore_1.getDocs)(q);
3372
+ handleQuerySnapshot(queryData);
3373
+ }
3374
+ // Function to handle query snapshot
3375
+ async function handleQuerySnapshot(querySnapshot) {
3376
+ if (!Array.isArray(data))
3377
+ throw new Error("Called querySnapshot but data is defined.");
3378
+ if (!queryLimit)
3379
+ throw new Error("Firestore queries must have a limit defined.");
3380
+ const queryResults = {};
3381
+ let index = 0; // Declare the index variable
3382
+ const reverseIfBack = (docs) => page[0] < page[1] ? docs.reverse() : docs;
3383
+ // Process each document in the querySnapshot
3384
+ for (const doc of reverseIfBack(querySnapshot.docs)) {
3385
+ if ((Object.keys(queryResults).length + Object.keys(itemList).length) === queryLimit) {
3386
+ break;
3387
+ }
3388
+ let position = Object.keys(itemList).length + (page[0] - 1) * queryLimit + index + 1;
3389
+ if (page[0] < page[1]) {
3390
+ position = (page[0]) * queryLimit - index - Object.keys(itemList).length;
3391
+ }
3392
+ if (itemList[doc.id] || (prevEntries[doc.id] && prevEntries[doc.id] !== position)) {
3393
+ console.log("Removing ", doc.id, ": E=", prevEntries[doc.id], ", G=", position);
3394
+ continue;
3395
+ }
3396
+ let item = doc.data();
3397
+ item.id = doc.id;
3398
+ // Apply additionalEntryProcessing if provided
3399
+ if (additionalEntryProcessing) {
3400
+ item = await additionalEntryProcessing(doc.id, item);
3401
+ }
3402
+ if (!item)
3403
+ continue;
3404
+ queryResults[doc.id] = item;
3405
+ index += 1;
3406
+ if (prevEntries[doc.id])
3407
+ continue;
3408
+ prevEntries[doc.id] = position;
3409
+ }
3410
+ if (cursorDirection === "decrease" || page[0] < page[1]) {
3411
+ itemList = { ...Object.fromEntries(Object.entries(queryResults).reverse()), ...itemList };
3412
+ }
3413
+ else {
3414
+ itemList = { ...itemList, ...queryResults };
3415
+ }
3416
+ // Updating state with the new data and query anchors
3417
+ setPrevEntryIds(prevEntries);
3418
+ if (querySnapshot.size < queryLimit && Object.keys(itemList).length < queryLimit) {
3419
+ // If we have ran out of entries, increase or decrease the index.
3420
+ if (page[0] > page[1] && cursorPos + 1 < data.length) {
3421
+ return getDataFromQuery(itemList, { ...currentQueryAnchor, endQueryPos: currentQueryAnchor.endQueryPos + 1 }, "increase", prevEntries);
3422
+ }
3423
+ else if (page[0] < page[1] && cursorPos > 0) {
3424
+ return getDataFromQuery(itemList, { ...currentQueryAnchor, startQueryPos: currentQueryAnchor.startQueryPos - 1 }, "decrease", prevEntries);
3425
+ }
3426
+ }
3427
+ if (Object.keys(itemList).length < queryLimit && querySnapshot.size === queryLimit) {
3428
+ console.log("Shorter than ten");
3429
+ return getDataFromQuery(itemList, { ...currentQueryAnchor, startKey: Object.keys(itemList)[0], endKey: Object.keys(itemList).slice(-1)[0] }, undefined, prevEntries, true);
3430
+ }
3431
+ if (querySnapshot.size === 0 &&
3432
+ Object.keys(itemList).length === 0 &&
3433
+ currentQueryAnchor.endQueryPos + 1 === data.length &&
3434
+ page[0] > 1) {
3435
+ setTableData({});
3436
+ setQueryAnchor((a) => ({ ...a, startKey: "" }));
3437
+ return;
3438
+ }
3439
+ if (querySnapshot.size < queryLimit) {
3440
+ setLoading("loaded");
3441
+ }
3442
+ else {
3443
+ setLoading(false);
3444
+ }
3445
+ setQueryAnchor({ ...currentQueryAnchor, startKey: Object.keys(itemList)[0], endKey: Object.keys(itemList).slice(-1)[0] });
3446
+ setTableData((old) => {
3447
+ if (view === "table") {
3448
+ return { ...itemList };
3449
+ }
3450
+ return { ...old, ...itemList };
3451
+ });
3452
+ }
3453
+ };
3454
+ const reset = () => {
3455
+ console.log("Resetting after filters?");
3456
+ setPage([1, 0]);
3457
+ setTableData({});
3458
+ setQueryAnchor({ startKey: "", endKey: "", startQueryPos: 0, endQueryPos: 0 });
3459
+ setPrevEntryIds({});
3460
+ dataListenerUnsubscribe && Object.values(dataListenerUnsubscribe).map((u) => u());
3461
+ setDataListenerUnsubscribe(undefined);
3462
+ };
3463
+ (0, react_1.useEffect)(() => {
3464
+ console.log("Filters updates", filters);
3465
+ if (!filters)
3466
+ return;
3467
+ console.log("Resetting cus filters");
3468
+ reset();
3469
+ }, [filters]);
3470
+ (0, react_1.useEffect)(() => {
3471
+ reset();
3472
+ }, [view, searchString, data, sort]);
3473
+ // Fetch new data when queries or page change
3474
+ (0, react_1.useEffect)(() => {
3475
+ getDataFromQuery();
3476
+ dataListenerUnsubscribe && Object.values(dataListenerUnsubscribe).map((u) => u());
3477
+ }, [page]);
3478
+ const pageUp = () => {
3479
+ setPage((p) => ([p[0] + 1, p[0]]));
3480
+ };
3481
+ const pageDown = () => {
3482
+ setPage((p) => ([p[0] - 1, p[0]]));
3483
+ };
3484
+ const updateSort = (sortLabel) => {
3485
+ if (!sorts || !sorts[sortLabel])
3486
+ return;
3487
+ setSort([sortLabel, sorts[sortLabel]]);
3488
+ };
3489
+ return ({ ...{ tableData, pageUp, pageDown, setFilters, page: page[0], sorts, loading, sort, updateSort: updateSort, setView, updateSearch: setSearchString } });
2699
3490
  }
3491
+ ;
2700
3492
  //# sourceMappingURL=hooks.js.map