placementt-core 1.20.232 → 1.300.4

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 (101) hide show
  1. package/.eslintrc.js +40 -40
  2. package/.gitattributes +2 -2
  3. package/deploy-all.js +75 -0
  4. package/lib/config.d.ts +0 -13
  5. package/lib/config.js +1 -3
  6. package/lib/config.js.map +1 -1
  7. package/lib/constants.d.ts +1 -0
  8. package/lib/constants.js +48 -1
  9. package/lib/constants.js.map +1 -1
  10. package/lib/features/config.d.ts +133 -133
  11. package/lib/features/config.js +35 -35
  12. package/lib/features/contacts/contacts.d.ts +75 -75
  13. package/lib/features/contacts/contacts.js +105 -105
  14. package/lib/features/downtime/useDowntime.d.ts +11 -11
  15. package/lib/features/downtime/useDowntime.js +22 -22
  16. package/lib/features/placements/studentPlacements/activePlacement.js +1 -1
  17. package/lib/features/placements/studentPlacements/activePlacement.js.map +1 -1
  18. package/lib/features/placements/studentPlacements/studentPlacementsSlice.d.ts +63 -63
  19. package/lib/features/placements/studentPlacements/studentPlacementsSlice.js +81 -81
  20. package/lib/features/providerPlacements/providerPlacementsSlice.d.ts +19 -19
  21. package/lib/features/providerPlacements/providerPlacementsSlice.js +24 -24
  22. package/lib/features/studentPlacements/studentPlacementsSlice.d.ts +62 -62
  23. package/lib/features/studentPlacements/studentPlacementsSlice.js +87 -87
  24. package/lib/features/studentPlacements/useStudentPlacements.d.ts +6 -6
  25. package/lib/features/studentPlacements/useStudentPlacements.js +18 -18
  26. package/lib/features/userSlice.d.ts +26 -26
  27. package/lib/features/userSlice.js +23 -23
  28. package/lib/features/users/useUserFunctions.d.ts +25 -25
  29. package/lib/features/users/useUserFunctions.js +124 -124
  30. package/lib/features/users/userSlice.d.ts +46 -46
  31. package/lib/features/users/userSlice.js +48 -48
  32. package/lib/firebase/firebase.d.ts +1 -1
  33. package/lib/firebase/firebase.js +8 -3
  34. package/lib/firebase/firebase.js.map +1 -1
  35. package/lib/firebase/firebaseConfig.js +1 -0
  36. package/lib/firebase/firebaseConfig.js.map +1 -1
  37. package/lib/firebase/readDatabase.js +7 -7
  38. package/lib/firebase/readDatabase.js.map +1 -1
  39. package/lib/hooks.d.ts +85 -192
  40. package/lib/hooks.js +731 -671
  41. package/lib/hooks.js.map +1 -1
  42. package/lib/images/GatsbyBenchmarks.d.ts +1 -2
  43. package/lib/index.d.ts +0 -1
  44. package/lib/index.js +0 -1
  45. package/lib/index.js.map +1 -1
  46. package/lib/reduxHooks.d.ts +9 -41
  47. package/lib/reduxHooks.js +1 -49
  48. package/lib/reduxHooks.js.map +1 -1
  49. package/lib/tasksAndTips.js +368 -418
  50. package/lib/tasksAndTips.js.map +1 -1
  51. package/lib/typeDefinitions.d.ts +162 -83
  52. package/lib/util.d.ts +25 -1
  53. package/lib/util.js +329 -2
  54. package/lib/util.js.map +1 -1
  55. package/package.json +56 -56
  56. package/src/DatabaseDefinitions.ts +18 -18
  57. package/src/apiCalls.ts +128 -128
  58. package/src/config.ts +50 -53
  59. package/src/constants.ts +846 -796
  60. package/src/databaseTypes.ts +42 -42
  61. package/src/features/analytics/useAnalytics.tsx +63 -63
  62. package/src/features/contacts/contactsSlice.ts +147 -147
  63. package/src/features/contacts/useContacts.tsx +73 -73
  64. package/src/features/dropdown/useDropdown.tsx +52 -52
  65. package/src/features/global/downtime/useDowntime.tsx +23 -23
  66. package/src/features/global/users/useUserFunctions.tsx +132 -132
  67. package/src/features/jobs/jobsSlice.ts +71 -71
  68. package/src/features/placements/studentPlacements/activePlacement.ts +68 -68
  69. package/src/features/placements/studentPlacements/completedStudentPlacementsSlice.ts +97 -97
  70. package/src/features/placements/studentPlacements/upcomingStudentPlacementsSlice.ts +108 -108
  71. package/src/features/placements/studentPlacements/useStudentPlacements.tsx +9 -9
  72. package/src/features/placements/types.ts +10 -10
  73. package/src/features/referrals/useReferrals.tsx +56 -56
  74. package/src/features/updates/useUpdates.tsx +38 -38
  75. package/src/firebase/firebase.tsx +158 -153
  76. package/src/firebase/firebaseConfig.tsx +47 -45
  77. package/src/firebase/firebaseQuery.tsx +151 -151
  78. package/src/firebase/persistence.ts +84 -84
  79. package/src/firebase/readDatabase.tsx +236 -236
  80. package/src/firebase/util.tsx +352 -352
  81. package/src/firebase/writeDatabase.tsx +77 -77
  82. package/src/hooks.tsx +4476 -4463
  83. package/src/images/GatsbyBenchmarks.tsx +711 -711
  84. package/src/images/LogFuturePlacement.jsx +64 -64
  85. package/src/images/LogPreviousPlacement.jsx +228 -228
  86. package/src/images/gatsby_benchmarks.svg +466 -466
  87. package/src/images/log_future_placement.svg +114 -114
  88. package/src/images/log_previous_placement.svg +199 -199
  89. package/src/index.ts +34 -35
  90. package/src/readDatabase.tsx +3 -3
  91. package/src/reduxHooks.ts +295 -352
  92. package/src/tasksAndTips.ts +1267 -1267
  93. package/src/tutorialTips.ts +58 -58
  94. package/src/typeDefinitions.ts +1260 -1129
  95. package/src/util.ts +523 -177
  96. package/tsconfig.dev.json +5 -5
  97. package/tsconfig.json +21 -21
  98. package/lib/features/logs/logsSlice.d.ts +0 -93
  99. package/lib/features/logs/logsSlice.js +0 -146
  100. package/lib/features/logs/logsSlice.js.map +0 -1
  101. package/src/features/logs/logsSlice.ts +0 -208
package/lib/hooks.js CHANGED
@@ -10,18 +10,17 @@ exports.useNewInstitutePlacementList = useNewInstitutePlacementList;
10
10
  exports.useAlumniPaginator = useAlumniPaginator;
11
11
  exports.useVeryOldInstitutePlacementList = useVeryOldInstitutePlacementList;
12
12
  exports.useFilterTablePaginator = useFilterTablePaginator;
13
- exports.usePlacementListingPaginator = usePlacementListingPaginator;
13
+ exports.useProviderContactPaginator = useProviderContactPaginator;
14
+ exports.useNewCohortUserPaginator = useNewCohortUserPaginator;
14
15
  exports.useCohortUserPaginator = useCohortUserPaginator;
15
16
  exports.useAdmissionsPaginator = useAdmissionsPaginator;
16
17
  exports.useLazyLoadQueryList = useLazyLoadQueryList;
17
- exports.usePublicPlacementListingLoader = usePublicPlacementListingLoader;
18
- exports.useCreateApplicationRenderer = useCreateApplicationRenderer;
19
18
  exports.useProposePlacementRenderer = useProposePlacementRenderer;
20
19
  exports.useCreateCohortRenderer = useCreateCohortRenderer;
21
20
  exports.useUserUploadHandler = useUserUploadHandler;
22
21
  exports.useWorkflowEditor = useWorkflowEditor;
23
22
  exports.useApplicantWorkflowEditor = useApplicantWorkflowEditor;
24
- exports.useInstitutePlacementListingHandler = useInstitutePlacementListingHandler;
23
+ exports.useInstituteProviderContactsHandler = useInstituteProviderContactsHandler;
25
24
  exports.useGetIndividualPlacementForPlacementPage = useGetIndividualPlacementForPlacementPage;
26
25
  exports.useOnboardingPopup = useOnboardingPopup;
27
26
  exports.useLoadAddresses = useLoadAddresses;
@@ -40,6 +39,7 @@ const util_1 = require("./firebase/util");
40
39
  const writeDatabase_1 = require("./firebase/writeDatabase");
41
40
  const algoliasearch_1 = __importDefault(require("algoliasearch"));
42
41
  const storage_1 = require("firebase/storage");
42
+ const util_2 = require("./util");
43
43
  const DEFAULTQUERYLIMIT = 5;
44
44
  function useStudentPlacementList({ user, student, queryConstraint, ql = DEFAULTQUERYLIMIT }) {
45
45
  const [loadMoreIcon, setLoadMoreIcon] = (0, react_1.useState)(true);
@@ -243,7 +243,7 @@ function useOldInstitutePlacementList({ id, user, cohort, queryConstraint, ql =
243
243
  };
244
244
  return ({ ...{ placements, loadMoreIcon, loadMorePlacements, setQuery, setInitialQueryLimit, reset, changeQueryConstraints } });
245
245
  }
246
- function useNewInstitutePlacementList({ id, user, filters, view, cohort, queryConstraints, ql = DEFAULTQUERYLIMIT, inProgress }) {
246
+ function useNewInstitutePlacementList({ id, user, uid, filters, initialSort, initialSearch, view, cohort, queryConstraints, ql = DEFAULTQUERYLIMIT, inProgress }) {
247
247
  const [query, setQuery] = (0, react_1.useState)();
248
248
  const sorts = {
249
249
  ["Student Forename - Asc"]: {
@@ -267,7 +267,7 @@ function useNewInstitutePlacementList({ id, user, filters, view, cohort, queryCo
267
267
  direction: "asc",
268
268
  },
269
269
  ["Student Email - Desc"]: {
270
- value: "studentEmaile",
270
+ value: "studentEmail",
271
271
  direction: "desc",
272
272
  },
273
273
  ["Provider email - Asc"]: {
@@ -284,27 +284,34 @@ function useNewInstitutePlacementList({ id, user, filters, view, cohort, queryCo
284
284
  if (!(user.studentFilter && user.studentFilterValues))
285
285
  return false;
286
286
  const student = await (0, readDatabase_1.getUserById)(placement.uid).catch(() => false);
287
- if (!student)
287
+ if (!student) {
288
+ console.log("No student");
288
289
  return;
290
+ }
291
+ ;
289
292
  if (!user.studentFilterValues.includes(student.details[user.studentFilter])) {
293
+ console.log("filter not included. Filteres: ", user.studentFilterValues, "value", user.studentFilter, "-", student.details[user.studentFilter]);
290
294
  return false;
291
295
  }
292
296
  }
293
297
  return { ...placement, id: k };
294
298
  };
295
- 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) });
299
+ const { tableData, pageUp, pageDown, setFilters, page, setView, loading, updateSearch, updateSort, sort } = useDataViewerPaginator({ view, filters, sorts, queryLimit: ql, initialSort, initialSearch, data: query, additionalEntryProcessing: additionalProcessing, onSearch: async (s, sort, page, filters, limit) => await algoliaPlacementSearch(query || [], user, s, sort, page, filters, limit, cohort, inProgress) });
296
300
  (0, react_1.useEffect)(() => {
297
301
  var _a;
302
+ console.log("SET QUERY", user, queryConstraints, cohort);
298
303
  // Sets the query of for the DataViewerPaginator
299
304
  if (user.product !== "institutes" || user.userType !== "Staff") {
300
305
  setQuery(undefined);
301
306
  return;
302
307
  }
303
- 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")))) {
308
+ 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 !== "none")))) {
304
309
  const constraints = [["oId", "==", user.oId], ["draft", "==", false]];
305
310
  cohort && constraints.push(["cohort", "==", cohort]);
311
+ uid && constraints.push(["uid", "==", uid]);
306
312
  queryConstraints && constraints.unshift(...queryConstraints);
307
313
  inProgress !== undefined && constraints.push(["inProgress", "==", inProgress]);
314
+ console.log("PLACEMENT CONSTRAINTS", constraints);
308
315
  setQuery([{
309
316
  path: ["placements"],
310
317
  where: constraints
@@ -384,7 +391,7 @@ function useAlumniPaginator({ user, alumniConvoUser, filters, view, school, quer
384
391
  }, [tableData]);
385
392
  return { tableData, page, loading, setFilters, setView, pageUp, pageDown, sorts };
386
393
  }
387
- const algoliaPlacementSearch = async (user, query, sort, page, filters, limit, cohort, inProgress) => {
394
+ const algoliaPlacementSearch = async (data, user, query, sort, page, filters, limit, cohort, inProgress) => {
388
395
  const algoliaClient = (0, algoliasearch_1.default)(process.env.NODE_ENV === "development" ? "A0ZB50I7VS" : "XMPXCMUUOJ", user.algoliaKey);
389
396
  const placementsIndex = algoliaClient.initIndex(sort ? Object.values(sort[1]).join("_") : "placements");
390
397
  // const usersIndex = algoliaClient.initIndex("users");
@@ -414,10 +421,34 @@ const algoliaPlacementSearch = async (user, query, sort, page, filters, limit, c
414
421
  // }))
415
422
  // }
416
423
  // }
417
- let placementSearchString = `oId:${user.oId} AND ` + (inProgress !== undefined ? (inProgress ? "inProgress:true" : "completed:true") : "");
418
- if (cohort) {
419
- placementSearchString = placementSearchString + ` AND cohort:${cohort}`;
420
- }
424
+ if (data.length === 0)
425
+ return {};
426
+ const constraints = data[0].where;
427
+ if (!(constraints === null || constraints === void 0 ? void 0 : constraints.length))
428
+ return {};
429
+ let placementSearchString = constraints.map(([k, e, v]) => {
430
+ if (e === "==")
431
+ return `${k}:${v}`; // Equality check
432
+ if (e === "!=")
433
+ return `${k}:-${v}`; // Not equal check
434
+ if (e === "<")
435
+ return `${k}:<${v}`; // Less than check
436
+ if (e === "<=")
437
+ return `${k}:<=${v}`; // Less than or equal check
438
+ if (e === ">")
439
+ return `${k}:>${v}`; // Greater than check
440
+ if (e === ">=")
441
+ return `${k}:>=${v}`; // Greater than or equal check
442
+ if (e === "array-contains")
443
+ return `${k}:${v}`; // Array contains check (string format)
444
+ if (e === "array-contains-any")
445
+ return `${k}:"${v.join('","')}"`; // Array contains any of the values (string format)
446
+ if (e === "in")
447
+ return `(${v.map((value) => `${k}:${value}`).join(' OR ')})`; // In check
448
+ if (e === "not-in")
449
+ return v.map((value) => `${k}:-${value}`).join(' AND '); // In check
450
+ return;
451
+ }).join(" AND ");
421
452
  filters && Object.entries(filters).filter(([, filter]) => filter.value).map(([id, filter]) => {
422
453
  placementSearchString = placementSearchString + ` AND ${id}:${filter.value}`;
423
454
  });
@@ -784,181 +815,183 @@ function useFilterTablePaginator({ data }) {
784
815
  }, [page]);
785
816
  return ({ ...{ tableData, setPage, setFilters, page } });
786
817
  }
787
- function usePlacementListingPaginator({ data, user }) {
788
- const [tableData, setTableData] = (0, react_1.useState)({});
789
- const [page, setPage] = (0, react_1.useState)([1, 0]);
790
- const [filters, setFilters] = (0, react_1.useState)();
791
- const [queryAnchor, setQueryAnchor] = (0, react_1.useState)({ startKey: "", endKey: "", startQueryPos: 0, endQueryPos: 0 });
792
- const [prevEntryIds, setPrevEntryIds] = (0, react_1.useState)({});
818
+ function useProviderContactPaginator({ data, user, view, filters }) {
819
+ const [query, setQuery] = (0, react_1.useState)();
793
820
  const firebaseQuery = new firebaseQuery_1.default();
794
- const getDataFromQuery = async (itemList = {}, currentQueryAnchor = queryAnchor, cursorDirection, prevEntries = prevEntryIds, loadMoreFromQuery = false) => {
795
- let cursorPos;
796
- if (page[0] > page[1]) {
797
- cursorPos = currentQueryAnchor.endQueryPos;
821
+ const getAdditionalData = async (k, v) => {
822
+ var _a, _b;
823
+ if ((_b = (_a = v.savedBy) === null || _a === void 0 ? void 0 : _a[user.oId].activities) === null || _b === void 0 ? void 0 : _b.includes("workExperience")) {
824
+ const placementsCount = await firebaseQuery.getCount("placementListings", [(0, firestore_1.where)(`savedBy.${user.oId}.exists`, "==", true), (0, firestore_1.where)("providerContactId", "==", k)]);
825
+ return { ...v, plcaements: placementsCount };
798
826
  }
799
- else {
800
- cursorPos = currentQueryAnchor.startQueryPos;
827
+ return v;
828
+ };
829
+ const { tableData, pageUp, pageDown, setFilters, page, setView, loading } = useDataViewerPaginator({ view, filters, queryLimit: 10, data: query, additionalEntryProcessing: getAdditionalData });
830
+ (0, react_1.useEffect)(() => {
831
+ const constraints = [
832
+ [`savedBy.${user.oId}.exists`, "==", true],
833
+ ];
834
+ if (user.userType === "Students") {
835
+ constraints.push([`savedBy.${user.oId}.cohorts.${user.cohort}.listed`, "==", true]);
801
836
  }
802
- const querySchema = data === null || data === void 0 ? void 0 : data[cursorPos];
803
- const createQuery = (queryData) => {
804
- const constraints = [
805
- (0, firestore_1.where)("savedById", "==", user.userType === "Staff" ? user.oId : user.id),
806
- (0, firestore_1.where)("savedByProduct", "==", user.product),
807
- (0, firestore_1.where)("savedByUserType", "==", user.userType === "Staff" ? "Organisation" : "Student"),
808
- ];
809
- if (user.userType === "Students") {
810
- constraints.push((0, firestore_1.where)("listed", "==", true));
811
- }
812
- (queryData === null || queryData === void 0 ? void 0 : queryData.where) && queryData.where.forEach((w) => {
813
- constraints.push((0, firestore_1.where)(...w));
814
- });
815
- filters && Object.entries(filters).forEach(([key, value]) => {
816
- constraints.push((0, firestore_1.where)(key, "==", value));
817
- });
818
- if (queryData === null || queryData === void 0 ? void 0 : queryData.orderBy) {
819
- if (queryData.orderBy === "documentId") {
820
- constraints.push((0, firestore_1.orderBy)((0, firestore_1.documentId)()));
821
- }
822
- else {
823
- constraints.push((0, firestore_1.orderBy)(queryData.orderBy));
824
- }
825
- }
826
- else {
827
- constraints.push((0, firestore_1.orderBy)((0, firestore_1.documentId)()));
828
- }
829
- if (page[0] > page[1] && !cursorDirection) { // Going up
830
- currentQueryAnchor.endKey && constraints.push((0, firestore_1.startAfter)(currentQueryAnchor.endKey));
831
- constraints.push((0, firestore_1.limit)(10));
832
- if (!loadMoreFromQuery) {
833
- currentQueryAnchor = { ...currentQueryAnchor, startQueryPos: currentQueryAnchor.endQueryPos };
834
- }
837
+ setQuery([{
838
+ path: ["providerContacts"],
839
+ where: constraints
840
+ }]);
841
+ }, [user]);
842
+ return ({ ...{ tableData, pageUp, pageDown, setFilters, page, setView, loading } });
843
+ }
844
+ const algoliaUsersSearch = async (data, user, query, sort, page, filters, limit, cohort) => {
845
+ const algoliaClient = (0, algoliasearch_1.default)(process.env.NODE_ENV === "development" ? "A0ZB50I7VS" : "XMPXCMUUOJ", user.algoliaKey);
846
+ const userIndex = algoliaClient.initIndex(sort ? `users_${Object.values(sort[1]).join("_")}` : "users");
847
+ const constraints = data[0].where;
848
+ if (!(constraints === null || constraints === void 0 ? void 0 : constraints.length))
849
+ return {};
850
+ let userSearchString = constraints.map(([k, e, v]) => {
851
+ if (e === "==")
852
+ return `${k}:${v}`; // Equality check
853
+ if (e === "!=")
854
+ return `${k}:-${v}`; // Not equal check
855
+ if (e === "<")
856
+ return `${k}:<${v}`; // Less than check
857
+ if (e === "<=")
858
+ return `${k}:<=${v}`; // Less than or equal check
859
+ if (e === ">")
860
+ return `${k}:>${v}`; // Greater than check
861
+ if (e === ">=")
862
+ return `${k}:>=${v}`; // Greater than or equal check
863
+ if (e === "array-contains")
864
+ return `${k}:${v}`; // Array contains check (string format)
865
+ if (e === "array-contains-any")
866
+ return `${k}:"${v.join('","')}"`; // Array contains any of the values (string format)
867
+ if (e === "in")
868
+ return `(${v.map((value) => `${k}:${value}`).join(' OR ')})`; // In check
869
+ if (e === "not-in")
870
+ return v.map((value) => `${k}:-${value}`).join(' AND '); // In check
871
+ return;
872
+ }).join(" AND ");
873
+ filters && Object.entries(filters).filter(([, filter]) => filter.value).map(([id, filter]) => {
874
+ userSearchString = userSearchString + ` AND ${id}:${filter.value}`;
875
+ });
876
+ console.log("QUERY", userSearchString);
877
+ const options = {
878
+ filters: userSearchString,
879
+ hitsPerPage: limit,
880
+ page: page ? page - 1 : undefined,
881
+ };
882
+ const searchUsersHits = await userIndex.search(query || "", options);
883
+ console.log(searchUsersHits.hits);
884
+ const i = (searchUsersHits ? (await Promise.all(searchUsersHits.hits.map(async (hit) => {
885
+ return [hit.objectID, hit];
886
+ }))) : []).filter((e) => e !== undefined);
887
+ return Object.fromEntries(i);
888
+ };
889
+ function useNewCohortUserPaginator({ user, institute, initialSort, filters, view, cohort, queryConstraints, ql = DEFAULTQUERYLIMIT, userType }) {
890
+ const [query, setQuery] = (0, react_1.useState)();
891
+ const firebaseQuery = new firebaseQuery_1.default();
892
+ const sorts = {
893
+ ["Student Forename - Asc"]: {
894
+ value: "details.forename",
895
+ direction: "asc",
896
+ },
897
+ ["Student Forename - Desc"]: {
898
+ value: "details.forename",
899
+ direction: "desc",
900
+ },
901
+ ["Student Surname - Asc"]: {
902
+ value: "details.surname",
903
+ direction: "asc",
904
+ },
905
+ ["Student Surname - Desc"]: {
906
+ value: "details.surname",
907
+ direction: "desc",
908
+ },
909
+ ["Student Email - Asc"]: {
910
+ value: "email",
911
+ direction: "asc",
912
+ },
913
+ ["Student Email - Desc"]: {
914
+ value: "email",
915
+ direction: "desc",
916
+ }
917
+ };
918
+ (0, react_1.useEffect)(() => {
919
+ const getAccess = async () => {
920
+ var _a, _b, _c, _d, _e, _f, _g, _h;
921
+ // Sets the query of for the DataViewerPaginator
922
+ if (user.product !== "institutes" || user.userType !== "Staff") {
923
+ setQuery(undefined);
924
+ return;
835
925
  }
836
- else if (page[0] < page[1] && !cursorDirection) { // Going down
837
- if (!loadMoreFromQuery) {
838
- currentQueryAnchor = { ...currentQueryAnchor, endQueryPos: currentQueryAnchor.startQueryPos };
926
+ const constraints = [["oId", "==", user.oId], ["userType", "==", userType]];
927
+ cohort && constraints.push(["cohort", "==", cohort]);
928
+ queryConstraints && constraints.unshift(...queryConstraints);
929
+ const mSetQuery = (clear) => {
930
+ setQuery(clear ? undefined : [{
931
+ path: ["users"],
932
+ where: constraints
933
+ }]);
934
+ return;
935
+ };
936
+ if (institute.package === "institutes-one") {
937
+ if (user.userGroup === "admin" || (user.viewCohorts === "all" && user.viewStudents === "all"))
938
+ return mSetQuery();
939
+ if (!user.viewCohorts || user.viewCohorts === "none" || !user.viewStudents || user.viewStudents === "none" || (user.viewCohorts === "some" && !((_a = user.visibleCohorts) === null || _a === void 0 ? void 0 : _a.length)) || (user.viewStudents === "some" && !((_b = user.studentFilterValues) === null || _b === void 0 ? void 0 : _b.length)))
940
+ return mSetQuery(true);
941
+ if (user.viewStudents === "some") {
942
+ constraints.push([`details.${user.studentFilter}`, "in", user.studentFilterValues]);
839
943
  }
840
- constraints.push((0, firestore_1.limitToLast)(10));
841
- if (currentQueryAnchor.startKey) {
842
- currentQueryAnchor.startKey && constraints.push((0, firestore_1.endBefore)(currentQueryAnchor.startKey));
944
+ if (cohort) {
945
+ const canViewCohort = user.viewCohorts === "all" || (user.viewCohorts === "some" && ((_c = user.visibleCohorts) === null || _c === void 0 ? void 0 : _c.includes("cohort")));
946
+ return mSetQuery(canViewCohort);
843
947
  }
844
948
  else {
845
- currentQueryAnchor.startKey && constraints.push((0, firestore_1.endAt)(currentQueryAnchor.startKey));
949
+ // No cohort.
950
+ if (user.viewCohorts === "all")
951
+ return mSetQuery();
952
+ if (user.viewCohorts === "some" && user.visibleCohorts) {
953
+ constraints.push(["cohort", "in", user.visibleCohorts]);
954
+ return mSetQuery();
955
+ }
956
+ return mSetQuery(true);
846
957
  }
847
958
  }
848
- else {
849
- if (cursorDirection === "decrease") {
850
- constraints.push((0, firestore_1.limitToLast)(10));
959
+ if (institute.package === "institutes-two") {
960
+ if (user.userGroup === "admin" || (user.viewSchools === "all" && user.viewCohorts === "all" && user.viewStudents === "all"))
961
+ return mSetQuery();
962
+ if (!user.viewCohorts || !user.viewSchools || user.viewSchools === "none" || user.viewCohorts === "none")
963
+ return mSetQuery(true);
964
+ if (!user.viewStudents || user.viewStudents === "none" || (user.viewStudents === "some" && !((_d = user.studentFilterValues) === null || _d === void 0 ? void 0 : _d.length)) || (user.viewCohorts === "some" && !((_e = user.visibleCohorts) === null || _e === void 0 ? void 0 : _e.length)) || (user.viewSchools === "some" && !((_f = user.visibleSchools) === null || _f === void 0 ? void 0 : _f.length)))
965
+ return mSetQuery(true);
966
+ if (user.viewStudents === "some") {
967
+ constraints.push([`details.${user.studentFilter}`, "in", user.studentFilterValues]);
968
+ }
969
+ if (cohort) {
970
+ if (user.viewCohorts === "some" && !((_g = user.visibleCohorts) === null || _g === void 0 ? void 0 : _g.includes(cohort)))
971
+ return mSetQuery(true);
972
+ if (user.viewSchools === "some") {
973
+ const cohortData = await firebaseQuery.getDocData(["cohorts", cohort]);
974
+ if (!cohortData.schoolId || !((_h = user.visibleSchools) === null || _h === void 0 ? void 0 : _h.includes(cohortData.schoolId)))
975
+ return mSetQuery(true);
976
+ }
851
977
  }
852
978
  else {
853
- constraints.push((0, firestore_1.limit)(10));
979
+ if (user.viewCohorts === "some" && user.visibleCohorts) {
980
+ constraints.push(["cohort", "in", user.visibleCohorts]);
981
+ }
982
+ else if (user.viewSchools === "some" && user.visibleSchools) {
983
+ const cohorts = await firebaseQuery.getDocsWhere("cohorts", [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("schoolId", "in", user.visibleSchools)]);
984
+ constraints.push(["cohort", "in", Object.keys(cohorts || {})]);
985
+ }
854
986
  }
987
+ return mSetQuery();
855
988
  }
856
- return constraints;
857
- };
858
- const constraints = createQuery(querySchema);
859
- // console.log(queryId, "constraints", constraints)
860
- const q = (0, firestore_1.query)((0, firestore_1.collection)(firebaseConfig_1.db, "savedPlacements"), ...(constraints));
861
- const queryResults = {};
862
- const queryData = await (0, firestore_1.getDocs)(q);
863
- // console.log("queryData.size", queryData.size)
864
- const reverseIfBack = (docs) => {
865
- if (page[0] < page[1]) {
866
- return docs.reverse();
867
- }
868
- return docs;
989
+ setQuery(undefined);
869
990
  };
870
- let index = 0;
871
- reverseIfBack(queryData.docs).forEach(async (doc) => {
872
- if (Object.keys(queryResults).length + Object.keys(itemList).length === 10) {
873
- return;
874
- }
875
- let position = Object.keys(itemList).length + (page[0] - 1) * 10 + index + 1;
876
- if (page[0] < page[1]) {
877
- position = (page[0]) * 10 - index - Object.keys(itemList).length;
878
- }
879
- // console.log(index, "doc.id", doc.id, position, "E", prevEntries[doc.id])
880
- if (itemList[doc.id] || (prevEntries[doc.id] && prevEntries[doc.id] !== position)) {
881
- console.log("Removing ", doc.id, ": E=", prevEntries[doc.id], ", G=", position);
882
- return;
883
- }
884
- const item = doc.data();
885
- item.id = doc.id;
886
- queryResults[doc.id] = item;
887
- index = index + 1;
888
- if (prevEntries[doc.id])
889
- return;
890
- prevEntries[doc.id] = position;
891
- });
892
- if (cursorDirection === "decrease" || page[0] < page[1]) {
893
- itemList = { ...Object.fromEntries(Object.entries(queryResults).reverse()), ...itemList };
894
- }
895
- else {
896
- itemList = { ...itemList, ...queryResults };
897
- }
898
- setPrevEntryIds(prevEntries);
899
- if (queryData.size < 10 && Object.keys(itemList).length < 10) {
900
- if (page[0] > page[1] && cursorPos + 1 < data.length) {
901
- console.log("Increase query index");
902
- return getDataFromQuery(itemList, { ...currentQueryAnchor, endQueryPos: currentQueryAnchor.endQueryPos + 1 }, "increase", prevEntries);
903
- }
904
- else if (page[0] < page[1] && cursorPos > 0) {
905
- console.log("Decrease query index");
906
- return getDataFromQuery(itemList, { ...currentQueryAnchor, startQueryPos: currentQueryAnchor.startQueryPos - 1 }, "decrease", prevEntries);
907
- }
908
- }
909
- if (Object.keys(itemList).length < 10 && queryData.size === 10) {
910
- console.log("Shorter than ten");
911
- // if(loadMoreFromQuery){return}
912
- return getDataFromQuery(itemList, { ...currentQueryAnchor, startKey: Object.keys(itemList)[0], endKey: Object.keys(itemList).slice(-1)[0] }, undefined, prevEntries, true);
913
- }
914
- if (queryData.size === 0 &&
915
- Object.keys(itemList).length === 0 &&
916
- currentQueryAnchor.endQueryPos + 1 === data.length &&
917
- page[0] > 1) {
918
- setTableData({});
919
- setQueryAnchor((a) => ({ ...a, startKey: "" }));
920
- return;
921
- }
922
- setQueryAnchor({ ...currentQueryAnchor, startKey: Object.keys(itemList)[0], endKey: Object.keys(itemList).slice(-1)[0] });
923
- const finalData = Object.fromEntries(await Promise.all(Object.entries(itemList).map(async ([k, v]) => {
924
- const placement = await firebaseQuery.getDocData(["placementListings", v.placementId || ""]);
925
- const address = await firebaseQuery.getDocData(["addresses", placement.addressId || ""]).catch(() => ({ ["address-line1"]: "Unknown address" }));
926
- const provider = await firebaseQuery.getDocData(["providers", placement.providerId || ""]).catch(() => ({ name: "Unknown" }));
927
- const status = provider.name !== "Unknown" ? getPlacementStatus(provider, placement, v) : "Deleted";
928
- return [k, { ...address, ...provider, ...placement, email: placement.providerEmail, status: status, savedPlacement: v }];
929
- })));
930
- setTableData(finalData);
931
- };
932
- const getPlacementStatus = (provider, placement, savedPlacement) => {
933
- if (savedPlacement.status === "Blocked")
934
- return "blocked";
935
- if (savedPlacement.status === "Accepted")
936
- return "active";
937
- if (user.product === "admin") {
938
- if (placement.mapConsent === undefined)
939
- return "notReviewed";
940
- if (placement.mapConsent === false)
941
- return "notPublic";
942
- return "unknown";
943
- }
944
- ;
945
- if (!provider.insurance)
946
- return "awaitingProviderApproval";
947
- return "requiresApproval";
948
- };
949
- (0, react_1.useEffect)(() => {
950
- if (!filters)
951
- return;
952
- setPage([1, 0]);
953
- setTableData({});
954
- setQueryAnchor({ startKey: "", endKey: "", startQueryPos: 0, endQueryPos: 0 });
955
- setPrevEntryIds({});
956
- }, [filters]);
957
- // Fetch new data when queries or page change
958
- (0, react_1.useEffect)(() => {
959
- getDataFromQuery();
960
- }, [page]);
961
- return ({ ...{ tableData, setPage, setFilters, page } });
991
+ getAccess();
992
+ }, [user, queryConstraints, cohort]);
993
+ const { tableData, pageUp, pageDown, setFilters, page, setView, loading, updateSearch, updateSort, sort } = useDataViewerPaginator({ view, filters, initialSort, sorts, queryLimit: ql, data: query, onSearch: async (s, sort, page, filters, limit) => await algoliaUsersSearch(query || [], user, s, sort, page, filters, limit, cohort) });
994
+ return { tableData, page, loading, updateSearch, setFilters, setView, pageUp, pageDown, sorts, updateSort, sort };
962
995
  }
963
996
  function useCohortUserPaginator({ user, cohort, data, search, userType, sort }) {
964
997
  const [tableData, setTableData] = (0, react_1.useState)({});
@@ -1281,394 +1314,433 @@ function useLazyLoadQueryList({ path, constraints, number, onItemFetched }) {
1281
1314
  }, []);
1282
1315
  return ({ ...{ items, loadMore, loadMoreIcon, reset } });
1283
1316
  }
1284
- function usePublicPlacementListingLoader({ providerId, number = 5 }) {
1285
- const [items, setItems] = (0, react_1.useState)({});
1286
- const [loadMoreIcon, setLoadMoreIcon] = (0, react_1.useState)(false);
1287
- const [lastItem, setLastItem] = (0, react_1.useState)();
1288
- const firebaseQuery = new firebaseQuery_1.default();
1289
- const reset = () => {
1290
- setItems({});
1291
- setLastItem(undefined);
1292
- };
1293
- const loadMore = async () => {
1294
- setLoadMoreIcon(true);
1295
- let formattedConstraints = [
1296
- (0, firestore_1.where)("status", "==", "listed"),
1297
- (0, firestore_1.limit)(number)
1298
- ];
1299
- if (providerId) {
1300
- formattedConstraints.push((0, firestore_1.where)("providerId", "==", providerId));
1301
- }
1302
- if (lastItem) {
1303
- formattedConstraints.push((0, firestore_1.startAfter)(lastItem));
1304
- }
1305
- const documents = await firebaseQuery.getDocsWhere("placementListings", formattedConstraints, true);
1306
- console.log("docs", documents.docs);
1307
- setLastItem(documents.docs[documents.docs.length - 1]);
1308
- const processedItems = Object.fromEntries(await Promise.all(Object.values(documents.docs).map(async (doc) => {
1309
- var _a, _b;
1310
- let itemObj = { ...doc.data(), id: doc.id };
1311
- if (itemObj.addressId) {
1312
- const address = await firebaseQuery.getDocData(["addresses", itemObj.addressId]);
1313
- delete address.id;
1314
- itemObj = { ...address, ...itemObj };
1315
- }
1316
- if (itemObj.applicantWorkflowId) {
1317
- const applicantWorkflow = (await firebaseQuery.getDocData(["applicantWorkflows", itemObj.applicantWorkflowId])).workflow.filter((i) => i.id === 1)[0];
1318
- const applicantFiles = applicantWorkflow.files ? Object.fromEntries(await Promise.all((_a = applicantWorkflow.files) === null || _a === void 0 ? void 0 : _a.map(async (fileId) => {
1319
- const file = await firebaseQuery.getDocData(["files", fileId]);
1320
- file.url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `providers/${itemObj.providerId}/${file.fileName}`));
1321
- return [fileId, file];
1322
- }))) : [];
1323
- const applicantForms = applicantWorkflow.forms ? Object.fromEntries(await Promise.all((_b = applicantWorkflow.forms) === null || _b === void 0 ? void 0 : _b.map(async (formId) => {
1324
- return [formId, await firebaseQuery.getDocData(["forms", formId])];
1325
- }))) : [];
1326
- applicantWorkflow.viewableFiles = applicantFiles;
1327
- applicantWorkflow.formDetails = applicantForms;
1328
- itemObj = { ...itemObj, applicantWorkflow: [applicantWorkflow] };
1329
- }
1330
- return [doc.id, itemObj];
1331
- })));
1332
- setItems((i) => ({ ...i, ...processedItems }));
1333
- setLoadMoreIcon(false);
1334
- };
1335
- (0, react_1.useEffect)(() => {
1336
- loadMore();
1337
- }, []);
1338
- return ({ ...{ items, loadMore, loadMoreIcon, reset } });
1339
- }
1340
- function useCreateApplicationRenderer({ user, listingId, listing, provider, application, applicationId, orgContext }) {
1341
- const firebaseQuery = new firebaseQuery_1.default();
1342
- let applicationWithoutAdditionalData = { ...(application || {}) };
1343
- delete applicationWithoutAdditionalData.listing;
1344
- delete applicationWithoutAdditionalData.address;
1345
- delete applicationWithoutAdditionalData.provider;
1346
- const [fApplication, setFApplication] = (0, react_1.useState)(application ? applicationWithoutAdditionalData : {
1347
- uid: user.userType === "Students" ? user.id : undefined,
1348
- listingId: listingId,
1349
- addressId: listing === null || listing === void 0 ? void 0 : listing.addressId,
1350
- stage: 1,
1351
- reqUserType: "Students",
1352
- status: "draft"
1353
- });
1354
- const [fApplicationId, setFApplicationId] = (0, react_1.useState)(applicationId);
1355
- const [draftSaved, setDraftSaved] = (0, react_1.useState)(false);
1356
- const [fProvider, setFProvider] = (0, react_1.useState)(provider);
1357
- const [fListing, setFListing] = (0, react_1.useState)(Object.keys(listing || {}).length > 5 ? listing : undefined);
1358
- const [student, setStudent] = (0, react_1.useState)(user.userType === "Students" ? user : undefined);
1359
- const [profileUrl, setProfileUrl] = (0, react_1.useState)();
1360
- const [successPopup, setSuccessPopup] = (0, react_1.useState)();
1361
- const [uploadedFiles, setUploadedFiles] = (0, react_1.useState)();
1362
- const [currentStageComplete, setCurrentStageComplete] = (0, react_1.useState)();
1363
- (0, react_1.useEffect)(() => {
1364
- const getListing = async () => {
1365
- console.log("Checking ID");
1366
- if (!listingId)
1367
- return;
1368
- console.log("Getting listing");
1369
- console.log("LISTING PARAM", listing, Object.keys(listing || {}).length > 5);
1370
- const listingData = (Object.keys(listing || {}).length > 5) ? listing : await firebaseQuery.getDocData(["placementListings", listingId]).catch(() => false);
1371
- console.log("LISTINGDATA", listingData, Object.keys(listing || {}).length > 5 ? { a: "string" } : "AAA");
1372
- const address = listingData ? (user.product === "providers" && orgContext) ? orgContext.addresses[listingData.addressId || ""] : await firebaseQuery.getDocData(["addresses", listingData.addressId]) : undefined;
1373
- const workflow = listingData ? (user.product === "providers" && orgContext) ? orgContext.applicantWorkflows[listingData.applicantWorkflowId || ""] : await firebaseQuery.getDocData(["applicantWorkflows", listingData.applicantWorkflowId]) : undefined;
1374
- if (workflow && listingData) {
1375
- workflow.workflow = await Promise.all(workflow.workflow.map(async (s) => {
1376
- var _a, _b;
1377
- const applicantFiles = s.files ? Object.fromEntries(await Promise.all((_a = s.files) === null || _a === void 0 ? void 0 : _a.map(async (fileId) => {
1378
- const file = await firebaseQuery.getDocData(["files", fileId]);
1379
- 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}`));
1380
- return [fileId, file];
1381
- }))) : [];
1382
- const applicantForms = s.forms ? Object.fromEntries(await Promise.all((_b = s.forms) === null || _b === void 0 ? void 0 : _b.map(async (formId) => {
1383
- return [formId, await firebaseQuery.getDocData(["forms", formId])];
1384
- }))) : [];
1385
- return { ...s, viewableFiles: applicantFiles, formDetails: applicantForms };
1386
- }));
1387
- delete workflow.id;
1388
- }
1389
- if (address) {
1390
- delete address.id;
1391
- }
1392
- console.log("Setting listing");
1393
- setFListing((listingData && workflow) ? { ...listingData, ...address, applicantWorkflow: workflow.workflow } : false);
1394
- if (((fProvider === null || fProvider === void 0 ? void 0 : fProvider.id) === (application === null || application === void 0 ? void 0 : application.providerId)) && user.product === "providers") {
1395
- setFProvider({ details: orgContext === null || orgContext === void 0 ? void 0 : orgContext.details, id: user.oId });
1396
- }
1397
- else if (listingData && (listingData === null || listingData === void 0 ? void 0 : listingData.providerId)) {
1398
- console.log("Getting provider from DB");
1399
- const provider = await firebaseQuery.getDocData(["providers", listingData.providerId]);
1400
- console.log("Provider", provider);
1401
- setFProvider({ details: provider, id: listingData.providerId });
1402
- }
1403
- };
1404
- getListing();
1405
- }, [listingId, listing]);
1406
- (0, react_1.useEffect)(() => {
1407
- if ((student === null || student === void 0 ? void 0 : student.id) !== (application === null || application === void 0 ? void 0 : application.uid)) {
1408
- if (user.userType === "Students") {
1409
- setStudent(user);
1410
- }
1411
- else if (user.product === "providers" && (application === null || application === void 0 ? void 0 : application.uid)) {
1412
- firebaseQuery.getDocData(["users", application.uid]).then((s) => setStudent(s));
1413
- }
1414
- }
1415
- }, []);
1416
- (0, react_1.useEffect)(() => {
1417
- setFListing(Object.keys(listing || {}).length > 5 ? listing : undefined);
1418
- }, [listing]);
1419
- (0, react_1.useEffect)(() => {
1420
- if (provider === null || provider === void 0 ? void 0 : provider.profile)
1421
- return;
1422
- if (!(provider === null || provider === void 0 ? void 0 : provider.id))
1423
- return;
1424
- (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `providers/${provider === null || provider === void 0 ? void 0 : provider.id}/profilePic.png`)).then(setProfileUrl).catch(() => null);
1425
- }, [provider]);
1426
- (0, react_1.useEffect)(() => {
1427
- console.log("APPLICATIONID", applicationId);
1428
- if (!applicationId) {
1429
- if (!listingId)
1430
- return;
1431
- firebaseQuery.getDocsWhere("applications", [(0, firestore_1.where)("status", "not-in", ["approved", "declined"]), (0, firestore_1.where)("uid", "==", user.id), (0, firestore_1.where)("listingId", "==", listingId)]).then((existingApplication) => {
1432
- console.log("EXISTING", existingApplication);
1433
- // get uploaded files
1434
- if (existingApplication && Object.keys(existingApplication).length) {
1435
- setFApplication(Object.values(existingApplication)[0]);
1436
- setFApplicationId(Object.keys(existingApplication)[0]);
1437
- }
1438
- });
1439
- return;
1440
- }
1441
- if (applicationId) {
1442
- setFApplicationId(applicationId);
1443
- if (application) {
1444
- let applicationWithoutAdditionalData = { ...(application || {}) };
1445
- delete applicationWithoutAdditionalData.listing;
1446
- delete applicationWithoutAdditionalData.address;
1447
- delete applicationWithoutAdditionalData.provider;
1448
- setFApplication(applicationWithoutAdditionalData);
1449
- }
1450
- else {
1451
- firebaseQuery.getDocData(["applications", applicationId]).then(setFApplication);
1452
- }
1453
- }
1454
- }, [application, applicationId]);
1455
- const getCurrentStage = async (stage) => {
1456
- var _a, _b, _c, _d;
1457
- console.log("fLSITING CURRENT STAGE", fListing);
1458
- if (!fListing)
1459
- throw new Error("Listing deleted");
1460
- if (!(fListing === null || fListing === void 0 ? void 0 : fListing.applicantWorkflowId))
1461
- throw new Error("No workflow stage");
1462
- const mApplicantWorkflow = await firebaseQuery.getDocData(["applicantWorkflows", fListing.applicantWorkflowId]);
1463
- const stageObj = (_a = mApplicantWorkflow === null || mApplicantWorkflow === void 0 ? void 0 : mApplicantWorkflow.workflow) === null || _a === void 0 ? void 0 : _a.find((s) => s.id === stage);
1464
- if (!stageObj)
1465
- throw new Error("Can't find stage.");
1466
- const applicantFiles = stageObj.files ? Object.fromEntries(await Promise.all((_b = stageObj.files) === null || _b === void 0 ? void 0 : _b.map(async (fileId) => {
1467
- const file = await firebaseQuery.getDocData(["files", fileId]);
1468
- 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}`));
1469
- return [fileId, file];
1470
- }))) : [];
1471
- const applicantForms = stageObj.forms ? Object.fromEntries(await Promise.all((_c = stageObj.forms) === null || _c === void 0 ? void 0 : _c.map(async (formId) => {
1472
- return [formId, await firebaseQuery.getDocData(["forms", formId])];
1473
- }))) : [];
1474
- stageObj.viewableFiles = applicantFiles;
1475
- stageObj.formDetails = applicantForms;
1476
- return { stage: stageObj, completedSections: ((_d = fApplication === null || fApplication === void 0 ? void 0 : fApplication.completedSections) === null || _d === void 0 ? void 0 : _d[stage]) || {} };
1477
- };
1478
- (0, react_1.useEffect)(() => {
1479
- const getUploadedFiles = async () => {
1480
- if (!fApplication.completedSections) {
1481
- setUploadedFiles({});
1482
- return;
1483
- }
1484
- ;
1485
- const fileIds = Object.values(fApplication.completedSections)
1486
- .flatMap(stageData => Object.values(stageData.filesUploaded || {}).flatMap(fileIds => fileIds));
1487
- const fileDataPromises = fileIds.map(async (fileId) => {
1488
- const fileData = await firebaseQuery.getDocData(["files", fileId]);
1489
- fileData.url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `userFiles/${fileData.fileName}`));
1490
- return [fileId, fileData];
1491
- });
1492
- const fileDataArray = await Promise.all(fileDataPromises);
1493
- const fileDataObj = Object.fromEntries(fileDataArray);
1494
- setUploadedFiles(fileDataObj);
1495
- };
1496
- const addApplication = async () => {
1497
- console.log("ADDING APPLICATION");
1498
- 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))
1499
- return;
1500
- const applicationData = {
1501
- uid: student.id,
1502
- listingId: fListing === null || fListing === void 0 ? void 0 : fListing.id,
1503
- addressId: fListing.addressId,
1504
- applicantWorkflowId: fListing === null || fListing === void 0 ? void 0 : fListing.applicantWorkflowId,
1505
- providerId: fProvider.id,
1506
- stage: 1,
1507
- status: "draft",
1508
- created: (new Date()).toISOString(),
1509
- ...fApplication,
1510
- };
1511
- const mApplicationId = (await firebaseQuery.add(["applications"], applicationData)).id;
1512
- console.log("APPLICATION ADDED");
1513
- setFApplicationId(mApplicationId);
1514
- setFApplication(applicationData);
1515
- setDraftSaved(true);
1516
- return;
1517
- };
1518
- getUploadedFiles();
1519
- console.log("Checking IDs");
1520
- 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))
1521
- return;
1522
- if (user.product === "providers")
1523
- return;
1524
- console.log("Checking dates and sections");
1525
- if (!fApplication.completedSections && !fApplication.startDate && !fApplication.endDate)
1526
- return;
1527
- console.log("Application updated");
1528
- if (!fApplicationId && !applicationId) {
1529
- // save new
1530
- console.log("Add application");
1531
- addApplication();
1532
- return;
1533
- }
1534
- // update
1535
- firebaseQuery.update(["applications", (fApplicationId || applicationId)], fApplication);
1536
- setDraftSaved(true);
1537
- }, [fApplication]);
1538
- const openSuccessPopup = (type) => {
1539
- setSuccessPopup(type);
1540
- setTimeout(() => {
1541
- // onClose();
1542
- }, 1500);
1543
- };
1544
- (0, react_1.useEffect)(() => {
1545
- const areStagesCompleted = async () => {
1546
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
1547
- if (!fListing)
1548
- return;
1549
- if (fApplication.stage === undefined)
1550
- return undefined;
1551
- const currentStage = await getCurrentStage(fApplication.stage);
1552
- console.log("Checking current stage is complete");
1553
- for (const fileViewed of ((_a = currentStage.stage) === null || _a === void 0 ? void 0 : _a.files) || []) {
1554
- console.log("Checking file viewed", fileViewed, "in", (_b = currentStage === null || currentStage === void 0 ? void 0 : currentStage.completedSections) === null || _b === void 0 ? void 0 : _b.filesViewed);
1555
- if (!((_d = (_c = currentStage === null || currentStage === void 0 ? void 0 : currentStage.completedSections) === null || _c === void 0 ? void 0 : _c.filesViewed) === null || _d === void 0 ? void 0 : _d.includes(fileViewed))) {
1556
- console.log("File not viewed");
1557
- return false;
1558
- }
1559
- else {
1560
- console.log("File viewed");
1561
- }
1562
- }
1563
- for (const formCompleted of ((_e = currentStage === null || currentStage === void 0 ? void 0 : currentStage.stage) === null || _e === void 0 ? void 0 : _e.forms) || []) {
1564
- console.log("Checking form completed", formCompleted, "in", (_f = currentStage === null || currentStage === void 0 ? void 0 : currentStage.completedSections) === null || _f === void 0 ? void 0 : _f.formsCompleted);
1565
- if (!Object.keys(((_g = currentStage === null || currentStage === void 0 ? void 0 : currentStage.completedSections) === null || _g === void 0 ? void 0 : _g.formsCompleted) || {}).includes(formCompleted)) {
1566
- console.log("Form not completed");
1567
- return false;
1568
- }
1569
- else {
1570
- console.log("Form completed");
1571
- }
1572
- }
1573
- for (let i = 0; i++; i < (((_h = currentStage === null || currentStage === void 0 ? void 0 : currentStage.stage) === null || _h === void 0 ? void 0 : _h.requiredFiles) || []).length) {
1574
- if (!Object.keys(((_j = currentStage === null || currentStage === void 0 ? void 0 : currentStage.completedSections) === null || _j === void 0 ? void 0 : _j.filesUploaded) || {}).includes(i.toString())) {
1575
- console.log("Form not uploaded");
1576
- return false;
1577
- }
1578
- else {
1579
- console.log("Form uploaded");
1580
- }
1581
- }
1582
- return true;
1583
- };
1584
- areStagesCompleted().then(setCurrentStageComplete);
1585
- }, [fApplication, fListing]);
1586
- const viewFile = (file, onOpen) => {
1587
- var _a, _b;
1588
- if (fApplication.reqUserType !== user.userType)
1589
- return;
1590
- if (fApplication.stage === undefined)
1591
- throw new Error("Missing applciation stage.");
1592
- if (!fListing)
1593
- throw new Error("No associated listing.");
1594
- 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;
1595
- setFApplication((a) => {
1596
- var _a, _b;
1597
- const oldA = { ...a };
1598
- const viewedFiles = ((_b = (_a = a.completedSections) === null || _a === void 0 ? void 0 : _a[1]) === null || _b === void 0 ? void 0 : _b.filesViewed) || [];
1599
- if (viewedFiles === null || viewedFiles === void 0 ? void 0 : viewedFiles.includes(file))
1600
- return a;
1601
- (viewableFiles === null || viewableFiles === void 0 ? void 0 : viewableFiles[file].url) && onOpen(viewableFiles === null || viewableFiles === void 0 ? void 0 : viewableFiles[file].url);
1602
- viewedFiles === null || viewedFiles === void 0 ? void 0 : viewedFiles.push(file);
1603
- const newA = (0, util_1.editNestedObject)(["completedSections", 1, "filesViewed"], oldA, viewedFiles);
1604
- return newA;
1605
- });
1606
- };
1607
- const addFile = (files, fileId) => {
1608
- if (fApplication.reqUserType !== user.userType)
1609
- throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
1610
- if (fApplication.stage === undefined)
1611
- throw new Error("Missing applciation stage.");
1612
- if (!files.length)
1613
- throw new Error("No files to upload");
1614
- setFApplication((a) => (0, util_1.editNestedObject)(["completedSections", fApplication.stage, "filesUploaded", fileId], a, files));
1615
- };
1616
- const setFormComplete = (formId, e) => {
1617
- if (fApplication.reqUserType !== user.userType)
1618
- throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
1619
- if (fApplication.stage === undefined)
1620
- throw new Error("Missing applciation stage.");
1621
- setFApplication((a) => (0, util_1.editNestedObject)(["completedSections", fApplication.stage, "formsCompleted", formId], a, e));
1622
- };
1623
- const successText = {
1624
- submitted: {
1625
- title: "Application submitted",
1626
- desc: "We've sent your application to the placement provider. You will hear what the next steps are soon.",
1627
- },
1628
- draftSaved: {
1629
- title: "Draft saved",
1630
- desc: "Your draft has been saved. Go to the 'Applications' section from your home screen to edit.",
1631
- },
1632
- stageComplete: {
1633
- title: "Stage complete",
1634
- desc: "We have sent this to the next stage in the application process. We will update you with any progress.",
1635
- },
1636
- outcome: {
1637
- title: "Outcome submitted",
1638
- desc: "We have sent the student an email with the outcome of their application.",
1639
- },
1640
- };
1641
- const onFApply = async (draft) => {
1642
- if (draft) {
1643
- openSuccessPopup("draftSaved");
1644
- return;
1645
- }
1646
- if (!fApplicationId)
1647
- return;
1648
- // Check all items have been filled in.
1649
- if (!fApplication.startDate || !fApplication.endDate)
1650
- throw new Error("Please select dates for your placement.");
1651
- await (0, firebase_1.executeCallable)("applications-submit", { applicationId: fApplicationId });
1652
- const newApplication = await firebaseQuery.getDocData(["applications", fApplicationId]);
1653
- setFApplication(newApplication);
1654
- openSuccessPopup("submitted");
1655
- };
1656
- const progressStage = async (type, e) => {
1657
- // Check all stages completed.
1658
- if (!fApplicationId)
1659
- return;
1660
- if (!currentStageComplete)
1661
- throw new Error("Complete all forms before submitting.");
1662
- if (fApplication.reqUserType !== user.userType)
1663
- throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
1664
- if (fApplication.stage === undefined)
1665
- throw new Error("Missing applciation stage.");
1666
- await (0, firebase_1.executeCallable)("applications-changeStage", { applicationId: fApplicationId, type: type, feedback: e === null || e === void 0 ? void 0 : e.feedback });
1667
- const newApplication = await firebaseQuery.getDocData(["applications", fApplicationId]);
1668
- setFApplication(newApplication);
1669
- };
1670
- return { successText, onFApply, progressStage, currentStageComplete, uploadedFiles, getCurrentStage, setFormComplete, viewFile, addFile, setSuccessPopup, openSuccessPopup, setFApplication, fApplication, draftSaved, profileUrl, successPopup, fApplicationId, fListing, student, fProvider };
1671
- }
1317
+ // type PublicPlacementListingLoaderParams = {
1318
+ // providerId?: string,
1319
+ // number: number,
1320
+ // }
1321
+ // export function usePublicPlacementListingLoader({providerId, number=5}:PublicPlacementListingLoaderParams) {
1322
+ // const [items, setItems] = useState<{[key:string]:{[key:string]:unknown}}>({});
1323
+ // const [loadMoreIcon, setLoadMoreIcon] = useState<boolean>(false);
1324
+ // const [lastItem, setLastItem] = useState<QueryDocumentSnapshot<DocumentData>>();
1325
+ // const firebaseQuery = new FirebaseQuery();
1326
+ // const reset = () => {
1327
+ // setItems({});
1328
+ // setLastItem(undefined);
1329
+ // };
1330
+ // const loadMore = async () => {
1331
+ // setLoadMoreIcon(true);
1332
+ // let formattedConstraints:QueryConstraint[] = [
1333
+ // where("status", "==", "listed"),
1334
+ // limit(number)
1335
+ // ];
1336
+ // if (providerId) {
1337
+ // formattedConstraints.push(where("providerId", "==", providerId));
1338
+ // }
1339
+ // if (lastItem) {
1340
+ // formattedConstraints.push(startAfter(lastItem));
1341
+ // }
1342
+ // const documents = await firebaseQuery.getDocsWhere("placementListings", formattedConstraints, true) as QuerySnapshot<DocumentData>;
1343
+ // console.log("docs", documents.docs);
1344
+ // setLastItem(documents.docs[documents.docs.length-1]);
1345
+ // const processedItems = Object.fromEntries(await Promise.all(Object.values(documents.docs).map(async (doc) => {
1346
+ // let itemObj = {...doc.data(), id: doc.id} as PlacementListing;
1347
+ // if (itemObj.addressId) {
1348
+ // const address = await firebaseQuery.getDocData(["addresses", itemObj.addressId]) as Address;
1349
+ // delete address.id;
1350
+ // itemObj = {...address, ...itemObj};
1351
+ // }
1352
+ // if (itemObj.applicantWorkflowId) {
1353
+ // const applicantWorkflow = (await firebaseQuery.getDocData(["applicantWorkflows", itemObj.applicantWorkflowId]) as ApplicantWorkflow).workflow.filter((i) => i.id === 1)[0];
1354
+ // const applicantFiles = applicantWorkflow.files ? Object.fromEntries(await Promise.all(applicantWorkflow.files?.map(async (fileId) => {
1355
+ // const file = await firebaseQuery.getDocData(["files", fileId]);
1356
+ // file.url = await getDownloadURL(ref(storage, `providers/${itemObj.providerId}/${file.fileName}`));
1357
+ // return [fileId, file];
1358
+ // }))) : [];
1359
+ // const applicantForms = applicantWorkflow.forms ? Object.fromEntries(await Promise.all(applicantWorkflow.forms?.map(async (formId) => {
1360
+ // return [formId, await firebaseQuery.getDocData(["forms", formId])];
1361
+ // }))) : [];
1362
+ // applicantWorkflow.viewableFiles = applicantFiles;
1363
+ // applicantWorkflow.formDetails = applicantForms;
1364
+ // itemObj = {...itemObj, applicantWorkflow: [applicantWorkflow]};
1365
+ // }
1366
+ // return [doc.id, itemObj];
1367
+ // })))
1368
+ // setItems((i) => ({...i, ...processedItems}));
1369
+ // setLoadMoreIcon(false);
1370
+ // };
1371
+ // useEffect(() => {
1372
+ // loadMore();
1373
+ // }, []);
1374
+ // return ({...{items, loadMore, loadMoreIcon, reset}});
1375
+ // }
1376
+ // export type ApplicationHookParams = {
1377
+ // successText: {
1378
+ // submitted: {
1379
+ // title: string;
1380
+ // desc: string;
1381
+ // };
1382
+ // draftSaved: {
1383
+ // title: string;
1384
+ // desc: string;
1385
+ // };
1386
+ // stageComplete: {
1387
+ // title: string;
1388
+ // desc: string;
1389
+ // };
1390
+ // outcome: {
1391
+ // title: string;
1392
+ // desc: string;
1393
+ // };
1394
+ // };
1395
+ // setSuccessPopup: import("react").Dispatch<import("react").SetStateAction<"submitted" | "draftSaved" | "stageComplete" | "outcome" | undefined>>;
1396
+ // openSuccessPopup: (type: "submitted" | "draftSaved" | "stageComplete" | "outcome") => void;
1397
+ // setFApplication: import("react").Dispatch<import("react").SetStateAction<Partial<Application>>>;
1398
+ // fApplication: Partial<Application>;
1399
+ // draftSaved: boolean;
1400
+ // profileUrl: string | undefined;
1401
+ // successPopup: "submitted" | "draftSaved" | "stageComplete" | "outcome" | undefined;
1402
+ // fApplicationId: string | undefined;
1403
+ // fListing: PlacementListing | false | undefined;
1404
+ // student: UserData | undefined;
1405
+ // fProvider: {
1406
+ // details?: ProviderData;
1407
+ // profile?: string;
1408
+ // id?: string;
1409
+ // } | undefined;
1410
+ // onFApply: (draft?: boolean) => Promise<void>;
1411
+ // setFormComplete: (formId: string, e: {
1412
+ // [key: string]: unknown;
1413
+ // }) => void;
1414
+ // viewFile: (file: string, onOpen: (url: string) => void) => void
1415
+ // addFile: (files: string[], fileId: number) => void;
1416
+ // uploadedFiles?: {
1417
+ // [key: string]: FileItem;
1418
+ // };
1419
+ // getCurrentStage: (stage: number) => Promise<{
1420
+ // stage: ApplicantStage;
1421
+ // completedSections: {
1422
+ // submitted?: string | undefined;
1423
+ // filesViewed?: string[] | undefined;
1424
+ // formsCompleted?: {
1425
+ // [key: string]: unknown;
1426
+ // } | undefined;
1427
+ // filesUploaded?: {
1428
+ // [key: number]: string[];
1429
+ // } | undefined;
1430
+ // };
1431
+ // }>;
1432
+ // currentStageComplete?: boolean;
1433
+ // progressStage: (type: number | "accept" | "reject", e?: {
1434
+ // feedback?: string;
1435
+ // }) => Promise<void>;
1436
+ // };
1437
+ // export function useCreateApplicationRenderer({user, listingId, listing, provider, application, applicationId, orgContext}:
1438
+ // {user:UserData, listingId:string, applicationId?: string, listing?: PlacementListing, application?: Partial<Application>,
1439
+ // orgContext?: {details: ProviderData, addresses: {[key: string]: OrganisationAddress}, applicantWorkflows: {[key: string]: ApplicantWorkflow}},
1440
+ // provider?: {details?: ProviderData, profile?: string, id?: string}}) {
1441
+ // const firebaseQuery = new FirebaseQuery();
1442
+ // let applicationWithoutAdditionalData = {...(application || {})} as any;
1443
+ // delete applicationWithoutAdditionalData.listing;
1444
+ // delete applicationWithoutAdditionalData.address;
1445
+ // delete applicationWithoutAdditionalData.provider;
1446
+ // const [fApplication, setFApplication] = useState<Partial<Application>>(application ? applicationWithoutAdditionalData : {
1447
+ // uid: user.userType === "Students" ? user.id : undefined,
1448
+ // listingId: listingId,
1449
+ // addressId: listing?.addressId,
1450
+ // stage: 1,
1451
+ // reqUserType: "Students",
1452
+ // status: "draft"});
1453
+ // const [fApplicationId, setFApplicationId] = useState<string|undefined>(applicationId);
1454
+ // const [draftSaved, setDraftSaved] = useState(false);
1455
+ // const [fProvider, setFProvider] = useState<{details?: ProviderData, profile?: string, id?: string}|undefined>(provider);
1456
+ // const [fListing, setFListing] = useState<PlacementListing|false|undefined>(Object.keys(listing || {}).length > 5 ? listing : undefined);
1457
+ // const [student, setStudent] = useState<UserData|undefined>(user.userType === "Students" ? user : undefined);
1458
+ // const [profileUrl, setProfileUrl] = useState<string>();
1459
+ // const [successPopup, setSuccessPopup] = useState<"submitted"|"draftSaved"|"stageComplete"|"outcome">();
1460
+ // const [uploadedFiles, setUploadedFiles] = useState<{[key: string]: FileItem}>();
1461
+ // const [currentStageComplete, setCurrentStageComplete] = useState<boolean>();
1462
+ // useEffect(() => {
1463
+ // const getListing = async () => {
1464
+ // console.log("Checking ID")
1465
+ // if (!listingId) return;
1466
+ // console.log("Getting listing")
1467
+ // console.log("LISTING PARAM", listing, Object.keys(listing || {}).length > 5);
1468
+ // const listingData = (Object.keys(listing || {}).length > 5) ? listing : (await firebaseQuery.getDocData(["placementListings", listingId]).catch(() => false) as PlacementListing|false);
1469
+ // console.log("LISTINGDATA", listingData, Object.keys(listing || {}).length > 5 ? {a: "string"} : "AAA");
1470
+ // const address = listingData ? (user.product === "providers" && orgContext) ? orgContext.addresses[listingData.addressId || ""] : await firebaseQuery.getDocData(["addresses", listingData.addressId as string]) as Address : undefined;
1471
+ // const workflow = listingData ? (user.product === "providers" && orgContext) ? orgContext.applicantWorkflows[listingData.applicantWorkflowId || ""] as ApplicantWorkflow : await firebaseQuery.getDocData(["applicantWorkflows", listingData.applicantWorkflowId as string]) as ApplicantWorkflow : undefined;
1472
+ // if (workflow && listingData) {
1473
+ // workflow.workflow = await Promise.all(workflow.workflow.map(async (s) => {
1474
+ // const applicantFiles = s.files ? Object.fromEntries(await Promise.all(s.files?.map(async (fileId: string) => {
1475
+ // const file = await firebaseQuery.getDocData(["files", fileId]);
1476
+ // file.url = await getDownloadURL(ref(storage, `providers/${listingData?.providerId}/${file.fileName}`));
1477
+ // return [fileId, file];
1478
+ // }))) : [];
1479
+ // const applicantForms = s.forms ? Object.fromEntries(await Promise.all(s.forms?.map(async (formId: string) => {
1480
+ // return [formId, await firebaseQuery.getDocData(["forms", formId])];
1481
+ // }))) : [];
1482
+ // return {...s, viewableFiles: applicantFiles, formDetails: applicantForms};
1483
+ // }));
1484
+ // delete workflow.id;
1485
+ // }
1486
+ // if (address) {
1487
+ // delete address.id;
1488
+ // }
1489
+ // console.log("Setting listing")
1490
+ // setFListing((listingData && workflow) ? {...listingData, ...address, applicantWorkflow: workflow.workflow} as PlacementListing : false);
1491
+ // if ((fProvider?.id === application?.providerId) && user.product === "providers") {
1492
+ // setFProvider({details: orgContext?.details, id: user.oId});
1493
+ // } else if (listingData && listingData?.providerId) {
1494
+ // console.log("Getting provider from DB");
1495
+ // const provider = await firebaseQuery.getDocData(["providers", listingData.providerId]) as ProviderData;
1496
+ // console.log("Provider", provider);
1497
+ // setFProvider({details: provider, id: listingData.providerId});
1498
+ // }
1499
+ // }
1500
+ // getListing();
1501
+ // }, [listingId, listing]);
1502
+ // useEffect(() => {
1503
+ // if (student?.id !== application?.uid) {
1504
+ // if (user.userType === "Students") {
1505
+ // setStudent(user);
1506
+ // } else if (user.product === "providers" && application?.uid) {
1507
+ // firebaseQuery.getDocData(["users", application.uid]).then((s) => setStudent(s as UserData));
1508
+ // }
1509
+ // }
1510
+ // }, []);
1511
+ // useEffect(() => {
1512
+ // setFListing(Object.keys(listing || {}).length > 5 ? listing : undefined);
1513
+ // }, [listing]);
1514
+ // useEffect(() => {
1515
+ // if (provider?.profile) return;
1516
+ // if (!provider?.id) return;
1517
+ // getDownloadURL(ref(storage, `providers/${provider?.id}/profilePic.png`)).then(setProfileUrl).catch(() => null);
1518
+ // }, [provider]);
1519
+ // useEffect(() => {
1520
+ // console.log("APPLICATIONID", applicationId);
1521
+ // if (!applicationId) {
1522
+ // if (!listingId) return;
1523
+ // firebaseQuery.getDocsWhere("applications", [where("status", "not-in", ["approved", "declined"]), where("uid", "==", user.id), where("listingId", "==", listingId)]).then((existingApplication) => {
1524
+ // console.log("EXISTING", existingApplication);
1525
+ // // get uploaded files
1526
+ // if (existingApplication && Object.keys(existingApplication).length) {
1527
+ // setFApplication(Object.values(existingApplication)[0]);
1528
+ // setFApplicationId(Object.keys(existingApplication)[0]);
1529
+ // }
1530
+ // });
1531
+ // return;
1532
+ // }
1533
+ // if (applicationId) {
1534
+ // setFApplicationId(applicationId);
1535
+ // if (application) {
1536
+ // let applicationWithoutAdditionalData = {...(application || {})} as any;
1537
+ // delete applicationWithoutAdditionalData.listing;
1538
+ // delete applicationWithoutAdditionalData.address;
1539
+ // delete applicationWithoutAdditionalData.provider;
1540
+ // setFApplication(applicationWithoutAdditionalData);
1541
+ // } else {
1542
+ // firebaseQuery.getDocData(["applications", applicationId]).then(setFApplication);
1543
+ // }
1544
+ // }
1545
+ // }, [application, applicationId]);
1546
+ // const getCurrentStage = async (stage: number): Promise<{
1547
+ // stage: ApplicantStage; completedSections: {
1548
+ // submitted?: string | undefined;
1549
+ // filesViewed?: string[] | undefined;
1550
+ // formsCompleted?: {
1551
+ // [key: string]: unknown;
1552
+ // } | undefined;
1553
+ // filesUploaded?: {
1554
+ // [key: number]: string[];
1555
+ // } | undefined;
1556
+ // };
1557
+ // }> => {
1558
+ // console.log("fLSITING CURRENT STAGE", fListing);
1559
+ // if (!fListing) throw new Error("Listing deleted");
1560
+ // if (!fListing?.applicantWorkflowId) throw new Error("No workflow stage");
1561
+ // const mApplicantWorkflow = (await firebaseQuery.getDocData(["applicantWorkflows", fListing.applicantWorkflowId]) as ApplicantWorkflow);
1562
+ // const stageObj = mApplicantWorkflow?.workflow?.find((s) => s.id === stage);
1563
+ // if (!stageObj) throw new Error("Can't find stage.");
1564
+ // const applicantFiles = stageObj.files ? Object.fromEntries(await Promise.all(stageObj.files?.map(async (fileId) => {
1565
+ // const file = await firebaseQuery.getDocData(["files", fileId]);
1566
+ // file.url = await getDownloadURL(ref(storage, `providers/${mApplicantWorkflow?.oId}/${file.fileName}`));
1567
+ // return [fileId, file];
1568
+ // }))) : [];
1569
+ // const applicantForms = stageObj.forms ? Object.fromEntries(await Promise.all(stageObj.forms?.map(async (formId) => {
1570
+ // return [formId, await firebaseQuery.getDocData(["forms", formId])];
1571
+ // }))) : [];
1572
+ // stageObj.viewableFiles = applicantFiles;
1573
+ // stageObj.formDetails = applicantForms;
1574
+ // return {stage: stageObj, completedSections: fApplication?.completedSections?.[stage] || {}};
1575
+ // };
1576
+ // useEffect(() => {
1577
+ // const getUploadedFiles = async () => {
1578
+ // if (!fApplication.completedSections) {
1579
+ // setUploadedFiles({});
1580
+ // return
1581
+ // };
1582
+ // const fileIds = Object.values(fApplication.completedSections)
1583
+ // .flatMap(stageData =>
1584
+ // Object.values(stageData.filesUploaded || {}).flatMap(fileIds => fileIds)
1585
+ // );
1586
+ // const fileDataPromises = fileIds.map(async (fileId) => {
1587
+ // const fileData = await firebaseQuery.getDocData(["files", fileId]) as FileItem;
1588
+ // fileData.url = await getDownloadURL(ref(storage, `userFiles/${fileData.fileName}`));
1589
+ // return [fileId, fileData] as [string, FileItem]
1590
+ // });
1591
+ // const fileDataArray = await Promise.all(fileDataPromises);
1592
+ // const fileDataObj = Object.fromEntries(fileDataArray)
1593
+ // setUploadedFiles(fileDataObj)
1594
+ // }
1595
+ // const addApplication = async () => {
1596
+ // console.log("ADDING APPLICATION");
1597
+ // if (!fListing || !fListing?.id || !fProvider?.id || !student?.id) return;
1598
+ // const applicationData = {
1599
+ // uid: student.id,
1600
+ // listingId: fListing?.id,
1601
+ // addressId: fListing.addressId,
1602
+ // applicantWorkflowId: fListing?.applicantWorkflowId,
1603
+ // providerId: fProvider.id,
1604
+ // stage: 1,
1605
+ // status: "draft",
1606
+ // created: (new Date()).toISOString(),
1607
+ // ...fApplication,
1608
+ // } as Partial<Application>;
1609
+ // const mApplicationId = (await firebaseQuery.add(["applications"], applicationData)).id;
1610
+ // console.log("APPLICATION ADDED");
1611
+ // setFApplicationId(mApplicationId);
1612
+ // setFApplication(applicationData);
1613
+ // setDraftSaved(true);
1614
+ // return;
1615
+ // };
1616
+ // getUploadedFiles();
1617
+ // console.log("Checking IDs");
1618
+ // if (!fListing || !fListing?.id || !fProvider?.id || !student?.id) return;
1619
+ // if (user.product === "providers") return;
1620
+ // console.log("Checking dates and sections");
1621
+ // if (!fApplication.completedSections && !fApplication.startDate && !fApplication.endDate) return;
1622
+ // console.log("Application updated");
1623
+ // if (!fApplicationId && !applicationId) {
1624
+ // // save new
1625
+ // console.log("Add application")
1626
+ // addApplication();
1627
+ // return;
1628
+ // }
1629
+ // // update
1630
+ // firebaseQuery.update(["applications", (fApplicationId || applicationId) as string], fApplication);
1631
+ // setDraftSaved(true);
1632
+ // }, [fApplication]);
1633
+ // const openSuccessPopup = (type: "submitted"|"draftSaved"|"stageComplete"|"outcome") => {
1634
+ // setSuccessPopup(type);
1635
+ // setTimeout(() => {
1636
+ // // onClose();
1637
+ // }, 1500);
1638
+ // };
1639
+ // useEffect(() => {
1640
+ // const areStagesCompleted = async ():Promise<boolean|undefined> => {
1641
+ // if (!fListing) return;
1642
+ // if (fApplication.stage === undefined) return undefined;
1643
+ // const currentStage = await getCurrentStage(fApplication.stage);
1644
+ // console.log("Checking current stage is complete");
1645
+ // for (const fileViewed of currentStage.stage?.files || []) {
1646
+ // console.log("Checking file viewed", fileViewed, "in", currentStage?.completedSections?.filesViewed);
1647
+ // if (!currentStage?.completedSections?.filesViewed?.includes(fileViewed)) {
1648
+ // console.log("File not viewed");
1649
+ // return false;
1650
+ // } else {
1651
+ // console.log("File viewed");
1652
+ // }
1653
+ // }
1654
+ // for (const formCompleted of currentStage?.stage?.forms || []) {
1655
+ // console.log("Checking form completed", formCompleted, "in", currentStage?.completedSections?.formsCompleted);
1656
+ // if (!Object.keys(currentStage?.completedSections?.formsCompleted || {}).includes(formCompleted)) {
1657
+ // console.log("Form not completed");
1658
+ // return false;
1659
+ // } else {
1660
+ // console.log("Form completed")
1661
+ // }
1662
+ // }
1663
+ // for (let i = 0; i++; i < (currentStage?.stage?.requiredFiles || []).length) {
1664
+ // if (!Object.keys(currentStage?.completedSections?.filesUploaded || {}).includes(i.toString())) {
1665
+ // console.log("Form not uploaded");
1666
+ // return false;
1667
+ // } else {
1668
+ // console.log("Form uploaded");
1669
+ // }
1670
+ // }
1671
+ // return true;
1672
+ // };
1673
+ // areStagesCompleted().then(setCurrentStageComplete);
1674
+ // }, [fApplication, fListing])
1675
+ // const viewFile = (file: string, onOpen: (url: string) => void) => {
1676
+ // if (fApplication.reqUserType !== user.userType) return;
1677
+ // if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
1678
+ // if (!fListing) throw new Error("No associated listing.");
1679
+ // const viewableFiles = fListing?.applicantWorkflow?.find((stage) => stage.id === fApplication.stage)?.viewableFiles;
1680
+ // setFApplication((a) => {
1681
+ // const oldA = {...a};
1682
+ // const viewedFiles = a.completedSections?.[1]?.filesViewed || [];
1683
+ // if (viewedFiles?.includes(file)) return a;
1684
+ // viewableFiles?.[file].url && onOpen(viewableFiles?.[file].url);
1685
+ // viewedFiles?.push(file);
1686
+ // const newA = editNestedObject(["completedSections", 1, "filesViewed"], oldA, viewedFiles) as Partial<Application>;
1687
+ // return newA;
1688
+ // });
1689
+ // };
1690
+ // const addFile = (files: string[], fileId: number) => {
1691
+ // if (fApplication.reqUserType !== user.userType) throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
1692
+ // if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
1693
+ // if (!files.length) throw new Error("No files to upload");
1694
+ // setFApplication((a) => editNestedObject(["completedSections", fApplication.stage as number, "filesUploaded", fileId], a, files) as Application);
1695
+ // };
1696
+ // const setFormComplete = (formId: string, e: {[key: string]: unknown}) => {
1697
+ // if (fApplication.reqUserType !== user.userType) throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
1698
+ // if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
1699
+ // setFApplication((a) => editNestedObject(["completedSections", fApplication.stage as number, "formsCompleted", formId], a, e) as Application);
1700
+ // };
1701
+ // const successText = {
1702
+ // submitted: {
1703
+ // title: "Application submitted",
1704
+ // desc: "We've sent your application to the placement provider. You will hear what the next steps are soon.",
1705
+ // },
1706
+ // draftSaved: {
1707
+ // title: "Draft saved",
1708
+ // desc: "Your draft has been saved. Go to the 'Applications' section from your home screen to edit.",
1709
+ // },
1710
+ // stageComplete: {
1711
+ // title: "Stage complete",
1712
+ // desc: "We have sent this to the next stage in the application process. We will update you with any progress.",
1713
+ // },
1714
+ // outcome: {
1715
+ // title: "Outcome submitted",
1716
+ // desc: "We have sent the student an email with the outcome of their application.",
1717
+ // },
1718
+ // };
1719
+ // const onFApply = async (draft?: boolean) => {
1720
+ // if (draft) {
1721
+ // openSuccessPopup("draftSaved")
1722
+ // return;
1723
+ // }
1724
+ // if (!fApplicationId) return;
1725
+ // // Check all items have been filled in.
1726
+ // if (!fApplication.startDate || !fApplication.endDate) throw new Error("Please select dates for your placement.");
1727
+ // await executeCallable("applications-submit", {applicationId: fApplicationId});
1728
+ // const newApplication = await firebaseQuery.getDocData(["applications", fApplicationId]) as Application;
1729
+ // setFApplication(newApplication);
1730
+ // openSuccessPopup("submitted")
1731
+ // };
1732
+ // const progressStage = async (type: number|"accept"|"reject", e?: {feedback?: string}) => {
1733
+ // // Check all stages completed.
1734
+ // if (!fApplicationId) return;
1735
+ // if (!currentStageComplete) throw new Error("Complete all forms before submitting.");
1736
+ // if (fApplication.reqUserType !== user.userType) throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
1737
+ // if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
1738
+ // await executeCallable("applications-changeStage", {applicationId: fApplicationId, type: type, feedback: e?.feedback});
1739
+ // const newApplication = await firebaseQuery.getDocData(["applications", fApplicationId]) as Application;
1740
+ // setFApplication(newApplication);
1741
+ // };
1742
+ // return {successText, onFApply, progressStage, currentStageComplete, uploadedFiles, getCurrentStage, setFormComplete, viewFile, addFile, setSuccessPopup, openSuccessPopup, setFApplication, fApplication, draftSaved, profileUrl, successPopup, fApplicationId, fListing, student, fProvider}
1743
+ // }
1672
1744
  function useProposePlacementRenderer({ user, orgContext, placement }) {
1673
1745
  const [businessSectionComplete, setBusinessSectionComplete] = (0, react_1.useState)(false);
1674
1746
  const [addressSectionComplete, setAddressSectionComplete] = (0, react_1.useState)(false);
@@ -1734,22 +1806,27 @@ function useProposePlacementRenderer({ user, orgContext, placement }) {
1734
1806
  setFormData(undefined);
1735
1807
  };
1736
1808
  const proposePlacement = async (draft = false) => {
1737
- // const getPlacementStatus = (startDate: Date, endDate: Date) => {
1738
- // const today = new Date()
1739
- // if (startDate <= today && endDate >= today) return { active: !draft ? true : false, inProgress: true, completed: false};
1740
- // else if (endDate <= today) return { completed: true, inProgress: false, active: false};
1741
- // return { completed: false, inProgress: true, active: false };
1742
- // }
1809
+ const getPlacementStatus = (startDate, endDate) => {
1810
+ const today = new Date();
1811
+ if (startDate <= today && endDate >= today)
1812
+ return { active: !draft ? true : false, inProgress: true, completed: false };
1813
+ else if (endDate <= today)
1814
+ return { completed: true, inProgress: false, active: false };
1815
+ return { completed: false, inProgress: true, active: false };
1816
+ };
1743
1817
  if (!formData || !student) {
1744
1818
  throw new Error("Cannot find placement details.");
1745
1819
  }
1746
1820
  try {
1747
1821
  console.log("formData", formData);
1748
- if (formData.id && formData.uid && draft === formData.draft)
1749
- await firebaseQuery.update(["placements", formData.id], formData);
1750
- const response = await (0, writeDatabase_1.addPlacement)(formData, student.id, draft);
1822
+ const status = getPlacementStatus(new Date(formData.startDate), new Date(formData.endDate));
1823
+ const newFormData = { ...formData, ...status };
1824
+ if (newFormData.id && newFormData.uid && draft === newFormData.draft)
1825
+ await firebaseQuery.update(["placements", newFormData.id], newFormData);
1826
+ else
1827
+ await (0, writeDatabase_1.addPlacement)(newFormData, student.id, draft);
1751
1828
  setComplete(true);
1752
- return response;
1829
+ return { status };
1753
1830
  }
1754
1831
  catch (error) {
1755
1832
  console.log("Error:", error);
@@ -1791,7 +1868,7 @@ const useRefDimensions = () => {
1791
1868
  return { dimensions, refCallback };
1792
1869
  };
1793
1870
  exports.useRefDimensions = useRefDimensions;
1794
- const cohortStages = ["info", "name", "placementType", "review", "created"];
1871
+ const cohortStages = ["info", "name", "placementType", "database", "review", "created"];
1795
1872
  const defaultCohortData = {
1796
1873
  name: "",
1797
1874
  stage: "info",
@@ -2485,34 +2562,34 @@ function useGenericWorkflowEditor({ user, initialData, defaultData, onSubmit })
2485
2562
  includedForms, fSubmitWorkflow, openPopup, snackbar, setSnackbar, setMousePosFunc, mousePos, tutorialActive,
2486
2563
  onDeleteArrow, fWorkflowNodes, containerRef, setError, setArrows, setFWorkflowNodes } });
2487
2564
  }
2488
- function useInstitutePlacementListingHandler({ user }) {
2565
+ function useInstituteProviderContactsHandler({ user }) {
2489
2566
  const [emptyCellsWarning, setEmptyCellsWarning] = (0, react_1.useState)(false);
2490
2567
  const [alert, setAlert] = (0, react_1.useState)();
2491
- const requiredFields = ["name", "jobTitle", "email", "addressOne", "city", "postCode", "country"];
2568
+ const requiredFields = ["business", "forename", "email"];
2492
2569
  const { execute } = (0, firebase_1.useExecuteCallableJob)({ user: user });
2493
- const checkData = (placements) => {
2570
+ const checkData = (providerContacts) => {
2494
2571
  setAlert(undefined);
2495
- placements = placements.filter((u) => Object.entries(u).some(([, v]) => v));
2496
- if (!Object.entries(placements)) {
2572
+ providerContacts = providerContacts.filter((u) => Object.entries(u).some(([, v]) => v));
2573
+ if (!Object.entries(providerContacts)) {
2497
2574
  return [];
2498
2575
  }
2499
- console.log("P", placements);
2500
- if (placements.filter((u) => u.email).length < placements.length) {
2576
+ console.log("P", providerContacts);
2577
+ if (providerContacts.filter((u) => u.email).length < providerContacts.length) {
2501
2578
  setAlert({ msg: "Your data contains missing email addresses.", severity: "error" });
2502
2579
  return false;
2503
2580
  }
2504
2581
  let emptyOptionalCell = false;
2505
2582
  let emptyRequiredCell = false;
2506
- for (const placement of placements) {
2507
- if (!checkEmailValidity(placement)) {
2583
+ for (const providerContact of providerContacts) {
2584
+ if (!checkEmailValidity(providerContact)) {
2508
2585
  return false;
2509
2586
  }
2510
- if (Object.keys(placement).includes("")) {
2587
+ if (Object.keys(providerContact).includes("")) {
2511
2588
  setAlert({ msg: "Data cannot be uploaded in unnamed columns.", severity: "error" });
2512
2589
  return false;
2513
2590
  }
2514
- for (const field in placement) {
2515
- if (!placement[field]) {
2591
+ for (const field in providerContact) {
2592
+ if (!providerContact[field]) {
2516
2593
  if (requiredFields.includes(field)) {
2517
2594
  setAlert({ msg: "All users must contain " + requiredFields.join(", "), severity: "error" });
2518
2595
  emptyRequiredCell = true;
@@ -2532,39 +2609,26 @@ function useInstitutePlacementListingHandler({ user }) {
2532
2609
  else {
2533
2610
  setEmptyCellsWarning(false);
2534
2611
  }
2535
- return placements;
2612
+ return providerContacts;
2536
2613
  };
2537
- const checkEmailValidity = (placement) => {
2538
- if (!(0, util_1.validateEmail)(placement.email)) {
2539
- setAlert({ msg: `Error in email formatting: ${placement.email}. Amend errors and reupload.`, severity: "error" });
2614
+ const checkEmailValidity = (providerContact) => {
2615
+ if (!(0, util_1.validateEmail)(providerContact.email)) {
2616
+ setAlert({ msg: `Error in email formatting: ${providerContact.email}. Amend errors and reupload.`, severity: "error" });
2540
2617
  return false;
2541
2618
  }
2542
2619
  return true;
2543
2620
  };
2544
- const uploadPlacements = async (placements) => {
2545
- let fPlacements = [];
2546
- console.log("PP", placements);
2547
- const cleanUpload = checkData(placements);
2621
+ const uploadProviderContacts = async (providers, schoolId) => {
2622
+ let fProviders = [];
2623
+ console.log("PP", providers);
2624
+ const cleanUpload = checkData(providers);
2548
2625
  if (!cleanUpload) {
2549
2626
  return false;
2550
2627
  }
2551
- fPlacements = cleanUpload;
2628
+ fProviders = cleanUpload;
2552
2629
  setAlert(undefined);
2553
- if (fPlacements.length) {
2554
- const formattedPlacements = fPlacements.map((v) => ({
2555
- name: v.provider,
2556
- title: v.jobTitle,
2557
- providerEmail: v.email,
2558
- providerPhone: v.phone,
2559
- ["address-line1"]: v.addressOne,
2560
- ["address-line2"]: v.addressTwo,
2561
- locality: v.city,
2562
- postal_code: v.postcode,
2563
- country: v.country,
2564
- }));
2565
- console.log("P", placements);
2566
- console.log("callable params", { placements: formattedPlacements, instituteId: user.product === "admin" ? "admin" : user.oId });
2567
- execute("placementListing-add", { data: formattedPlacements, instituteId: user.product === "admin" ? "admin" : user.oId });
2630
+ if (fProviders.length) {
2631
+ execute("providerContacts-add", { providerContacts: fProviders, instituteId: user.product === "admin" ? "admin" : user.oId, schoolId: schoolId });
2568
2632
  }
2569
2633
  return true;
2570
2634
  };
@@ -2572,7 +2636,7 @@ function useInstitutePlacementListingHandler({ user }) {
2572
2636
  setAlert(undefined);
2573
2637
  setEmptyCellsWarning(false);
2574
2638
  };
2575
- return ({ ...{ uploadPlacements, alert, onChange } });
2639
+ return ({ ...{ uploadProviderContacts, alert, onChange } });
2576
2640
  }
2577
2641
  function useGetIndividualPlacementForPlacementPage({ user, placementId, organisation }) {
2578
2642
  var _a;
@@ -2738,7 +2802,7 @@ function useGetIndividualPlacementForPlacementPage({ user, placementId, organisa
2738
2802
  }
2739
2803
  if (e === "noInsurance") {
2740
2804
  if (!eliData) {
2741
- const storageRef = (0, storage_1.ref)(firebaseConfig_1.storage, `insurance/${placement.providerId}.pdf`);
2805
+ const storageRef = (0, storage_1.ref)(firebaseConfig_1.storage, `insurance/${placement.providerContactId}.pdf`);
2742
2806
  const file = await (0, storage_1.getDownloadURL)(storageRef).catch(() => placement.insuranceSkippedReason);
2743
2807
  setELIData(file);
2744
2808
  }
@@ -2773,14 +2837,14 @@ function useGetIndividualPlacementForPlacementPage({ user, placementId, organisa
2773
2837
  const approveELI = async () => {
2774
2838
  if (!placement)
2775
2839
  return;
2776
- await (0, firebase_1.executeCallable)("insurance-approve", { oId: user.oId, providerId: placement.providerId });
2840
+ await (0, firebase_1.executeCallable)("insurance-approve", { oId: user.oId, providerContactId: placement.providerContactId });
2777
2841
  setEliPopupOpen(false);
2778
2842
  };
2779
2843
  const rejectELI = async ({ reason }) => {
2780
2844
  if (!placement || !institute)
2781
2845
  return;
2782
- console.log("Reject", { reason: reason, placement: placement, instituteName: institute.name, staffEmail: user.email });
2783
- await (0, firebase_1.executeCallable)("insurance-reject", { reason: reason, placementId: placementId, instituteName: institute.name, staffEmail: user.email });
2846
+ console.log("Reject", { reason: reason, placement: placement, instituteName: institute.name });
2847
+ await (0, firebase_1.executeCallable)("insurance-reject", { reason: reason, placementId: placementId, instituteName: institute.name });
2784
2848
  setRejectELIPopup(false);
2785
2849
  setEliPopupOpen(false);
2786
2850
  };
@@ -2799,10 +2863,12 @@ function useGetIndividualPlacementForPlacementPage({ user, placementId, organisa
2799
2863
  if (!placement)
2800
2864
  return;
2801
2865
  if (!placement.providerId) {
2802
- const res = await (0, firebase_1.executeCallable)("placement-uploadProviderDetails", {
2803
- pId: placementId,
2804
- placement: Object.fromEntries(Object.entries(placement).filter(([k]) => k !== "contactId")),
2805
- stage: wStage,
2866
+ const res = await (0, firebase_1.executeCallable)("providerContacts-uploadProviderDetails", {
2867
+ placement: {
2868
+ id: placementId,
2869
+ data: Object.fromEntries(Object.entries(placement).filter(([k]) => k !== "contactId")),
2870
+ stage: wStage,
2871
+ },
2806
2872
  skipSearch: true
2807
2873
  }).catch((e) => {
2808
2874
  throw e;
@@ -3104,13 +3170,7 @@ function useLoadListings(user, queryConstraint, request) {
3104
3170
  }), "placementListings", constraints, undefined, true);
3105
3171
  };
3106
3172
  (0, react_1.useEffect)(() => {
3107
- let unsubscribe;
3108
3173
  loadListings();
3109
- return () => {
3110
- if (unsubscribe) {
3111
- unsubscribe(); // Unsubscribe from the snapshot listener when the component unmounts
3112
- }
3113
- };
3114
3174
  // eslint-disable-next-line react-hooks/exhaustive-deps
3115
3175
  }, [queryConstraints]);
3116
3176
  const onScrollBottom = () => {
@@ -3186,13 +3246,7 @@ function useLoadProviderPlacements(user, queryConstraint, placementId) {
3186
3246
  }), "placements", constraints, undefined, true);
3187
3247
  };
3188
3248
  (0, react_1.useEffect)(() => {
3189
- let unsubscribe;
3190
3249
  loadListings();
3191
- return () => {
3192
- if (unsubscribe) {
3193
- unsubscribe(); // Unsubscribe from the snapshot listener when the component unmounts
3194
- }
3195
- };
3196
3250
  // eslint-disable-next-line react-hooks/exhaustive-deps
3197
3251
  }, [queryConstraints]);
3198
3252
  const onScrollBottom = () => {
@@ -3272,13 +3326,7 @@ function useLoadApplications({ user, applicationType, listingId, queryConstraint
3272
3326
  }), "applications", constraints, undefined, true);
3273
3327
  };
3274
3328
  (0, react_1.useEffect)(() => {
3275
- let unsubscribe;
3276
3329
  loadApplications();
3277
- return () => {
3278
- if (unsubscribe) {
3279
- unsubscribe(); // Unsubscribe from the snapshot listener when the component unmounts
3280
- }
3281
- };
3282
3330
  // eslint-disable-next-line react-hooks/exhaustive-deps
3283
3331
  }, [type, queryConstraints]);
3284
3332
  const onScrollBottom = () => {
@@ -3289,7 +3337,7 @@ function useLoadApplications({ user, applicationType, listingId, queryConstraint
3289
3337
  };
3290
3338
  return { applications, type, setType, onScrollBottom, loading, changeQueryConstraints };
3291
3339
  }
3292
- function useDataViewerPaginator({ view: initialView, sorts, queryLimit = 10, additionalEntryProcessing, formatItems, snapshot, filters: initialFilters, onSearch, data }) {
3340
+ function useDataViewerPaginator({ view: initialView, sorts, queryLimit = 10, additionalEntryProcessing, formatItems, snapshot, filters: initialFilters, initialSort, initialSearch, onSearch, data }) {
3293
3341
  const [tableData, setTableData] = (0, react_1.useState)(Array.isArray(data) ? Object.fromEntries(Object.entries(data).slice(0, queryLimit)) : {});
3294
3342
  const [page, setPage] = (0, react_1.useState)([1, 0]);
3295
3343
  const [view, setView] = (0, react_1.useState)(initialView);
@@ -3299,12 +3347,13 @@ function useDataViewerPaginator({ view: initialView, sorts, queryLimit = 10, add
3299
3347
  const [dataListenerUnsubscribe, setDataListenerUnsubscribe] = (0, react_1.useState)();
3300
3348
  const [loading, setLoading] = (0, react_1.useState)(true);
3301
3349
  const [searchString, setSearchString] = (0, react_1.useState)();
3302
- const [sort, setSort] = (0, react_1.useState)();
3350
+ const [sort, setSort] = (0, react_1.useState)((initialSort && sorts && sorts[initialSort]) ? [initialSort, sorts[initialSort]] : undefined);
3351
+ const [fData, setFData] = (0, react_1.useState)(data);
3303
3352
  const processedData = async (k, v) => additionalEntryProcessing ? await additionalEntryProcessing(k, v) : v;
3304
3353
  const setTableDataFromDefinedData = async () => {
3305
- if (!data || Array.isArray(data))
3354
+ if (!fData || Array.isArray(fData))
3306
3355
  return;
3307
- const dataWithAdditionalProcessingPossibleNulls = (await Promise.all(Object.entries(data).map(async ([k, v]) => [k, await processedData(k, v)])));
3356
+ const dataWithAdditionalProcessingPossibleNulls = (await Promise.all(Object.entries(fData).map(async ([k, v]) => [k, await processedData(k, v)])));
3308
3357
  const dataWithAdditionalProcessing = dataWithAdditionalProcessingPossibleNulls.filter(([k, v]) => v);
3309
3358
  const searchedData = searchString ? dataWithAdditionalProcessing.filter(([, v]) => {
3310
3359
  const values = Object.values(v).join(", ");
@@ -3328,7 +3377,7 @@ function useDataViewerPaginator({ view: initialView, sorts, queryLimit = 10, add
3328
3377
  throw new Error("Tables must have a limit defined.");
3329
3378
  const newData = filteredData.slice((page[0] - 1) * queryLimit, page[0] * queryLimit);
3330
3379
  setTableData(Object.fromEntries(newData));
3331
- if (Object.keys(Object.fromEntries(newData)).pop() === Object.keys(data).pop()) {
3380
+ if (Object.keys(Object.fromEntries(newData)).pop() === Object.keys(fData).pop()) {
3332
3381
  setLoading("loaded");
3333
3382
  }
3334
3383
  else {
@@ -3344,7 +3393,7 @@ function useDataViewerPaginator({ view: initialView, sorts, queryLimit = 10, add
3344
3393
  const getDataFromQuery = async (itemList = {}, currentQueryAnchor = queryAnchor, cursorDirection, prevEntries = prevEntryIds, loadMoreFromQuery = false) => {
3345
3394
  // if (!filters) return;
3346
3395
  setLoading(true);
3347
- if (!Array.isArray(data)) {
3396
+ if (!Array.isArray(fData)) {
3348
3397
  setTableDataFromDefinedData();
3349
3398
  return;
3350
3399
  }
@@ -3353,8 +3402,8 @@ function useDataViewerPaginator({ view: initialView, sorts, queryLimit = 10, add
3353
3402
  if (onSearch && (searchString || sort)) {
3354
3403
  if (typeof onSearch === "boolean")
3355
3404
  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.");
3356
- const data = await onSearch(searchString, sort, page[0], filters, queryLimit);
3357
- const dataWithAdditionalProcessing = await Promise.all(Object.entries(data).map(async ([k, v]) => [k, await processedData(k, v)]));
3405
+ const searchData = await onSearch(searchString, sort, page[0], filters, queryLimit);
3406
+ const dataWithAdditionalProcessing = await Promise.all(Object.entries(searchData).map(async ([k, v]) => [k, await processedData(k, v)]));
3358
3407
  setTableData((old) => {
3359
3408
  if (view === "table") {
3360
3409
  return { ...Object.fromEntries(dataWithAdditionalProcessing) };
@@ -3376,7 +3425,7 @@ function useDataViewerPaginator({ view: initialView, sorts, queryLimit = 10, add
3376
3425
  else {
3377
3426
  cursorPos = currentQueryAnchor.startQueryPos;
3378
3427
  }
3379
- const querySchema = data[cursorPos];
3428
+ const querySchema = fData[cursorPos];
3380
3429
  const createQuery = (queryData) => {
3381
3430
  const constraints = [];
3382
3431
  queryData.where && queryData.where.forEach((w) => {
@@ -3435,7 +3484,7 @@ function useDataViewerPaginator({ view: initialView, sorts, queryLimit = 10, add
3435
3484
  }
3436
3485
  // Function to handle query snapshot
3437
3486
  async function handleQuerySnapshot(querySnapshot) {
3438
- if (!Array.isArray(data))
3487
+ if (!Array.isArray(fData))
3439
3488
  throw new Error("Called querySnapshot but data is defined.");
3440
3489
  if (!queryLimit)
3441
3490
  throw new Error("Firestore queries must have a limit defined.");
@@ -3479,7 +3528,7 @@ function useDataViewerPaginator({ view: initialView, sorts, queryLimit = 10, add
3479
3528
  setPrevEntryIds(prevEntries);
3480
3529
  if (querySnapshot.size < queryLimit && Object.keys(itemList).length < queryLimit) {
3481
3530
  // If we have ran out of entries, increase or decrease the index.
3482
- if (page[0] > page[1] && cursorPos + 1 < data.length) {
3531
+ if (page[0] > page[1] && cursorPos + 1 < fData.length) {
3483
3532
  return getDataFromQuery(itemList, { ...currentQueryAnchor, endQueryPos: currentQueryAnchor.endQueryPos + 1 }, "increase", prevEntries);
3484
3533
  }
3485
3534
  else if (page[0] < page[1] && cursorPos > 0) {
@@ -3492,7 +3541,7 @@ function useDataViewerPaginator({ view: initialView, sorts, queryLimit = 10, add
3492
3541
  }
3493
3542
  if (querySnapshot.size === 0 &&
3494
3543
  Object.keys(itemList).length === 0 &&
3495
- currentQueryAnchor.endQueryPos + 1 === data.length &&
3544
+ currentQueryAnchor.endQueryPos + 1 === fData.length &&
3496
3545
  page[0] > 1) {
3497
3546
  if (view === "table") {
3498
3547
  setTableData({});
@@ -3526,28 +3575,33 @@ function useDataViewerPaginator({ view: initialView, sorts, queryLimit = 10, add
3526
3575
  setDataListenerUnsubscribe(undefined);
3527
3576
  };
3528
3577
  (0, react_1.useEffect)(() => {
3529
- console.log("Filters updates", filters);
3530
- if (!filters)
3578
+ if ((0, util_2.objectsEqualNew)(fData, data))
3531
3579
  return;
3532
- console.log("Resetting cus filters");
3533
- reset();
3534
- }, [filters]);
3535
- (0, react_1.useEffect)(() => {
3536
- console.log("View reset.");
3537
- reset();
3538
- }, [view]);
3539
- (0, react_1.useEffect)(() => {
3540
- console.log("search reset.");
3541
- reset();
3542
- }, [searchString]);
3543
- (0, react_1.useEffect)(() => {
3544
- console.log("data reset.");
3580
+ console.log("data reset.", fData, data);
3581
+ setFData(data);
3545
3582
  reset();
3546
3583
  }, [data]);
3547
- (0, react_1.useEffect)(() => {
3548
- console.log("sort reset.");
3584
+ const updateFilters = (fFilters) => {
3585
+ if (!(0, util_2.objectsEqualNew)(fFilters, filters)) {
3586
+ console.log("FILTER RESET", fFilters, filters);
3587
+ setFilters(fFilters);
3588
+ reset();
3589
+ }
3590
+ };
3591
+ const updateSearch = (search) => {
3592
+ if (searchString === search)
3593
+ return;
3594
+ console.log("SEARCH RESET", searchString, search);
3595
+ setSearchString(search);
3549
3596
  reset();
3550
- }, [sort]);
3597
+ };
3598
+ const updateView = (v) => {
3599
+ if (v === view)
3600
+ return;
3601
+ console.log("View reset", view, v);
3602
+ setView(v);
3603
+ reset();
3604
+ };
3551
3605
  // Fetch new data when queries or page change
3552
3606
  (0, react_1.useEffect)(() => {
3553
3607
  getDataFromQuery();
@@ -3560,11 +3614,17 @@ function useDataViewerPaginator({ view: initialView, sorts, queryLimit = 10, add
3560
3614
  setPage((p) => ([p[0] - 1, p[0]]));
3561
3615
  };
3562
3616
  const updateSort = (sortLabel) => {
3563
- if (!sorts || !sorts[sortLabel])
3564
- return;
3565
- setSort([sortLabel, sorts[sortLabel]]);
3617
+ if (!sortLabel) {
3618
+ setSort(undefined);
3619
+ }
3620
+ else {
3621
+ if (!sorts || !sorts[sortLabel])
3622
+ return;
3623
+ setSort([sortLabel, sorts[sortLabel]]);
3624
+ }
3625
+ reset();
3566
3626
  };
3567
- return ({ ...{ tableData, pageUp, pageDown, setFilters, page: page[0], sorts, loading, sort, updateSort: updateSort, setView, updateSearch: setSearchString } });
3627
+ return ({ ...{ tableData, pageUp, pageDown, search: searchString, setFilters: updateFilters, page: page[0], sorts, loading, sort, updateSort: updateSort, setView: updateView, updateSearch } });
3568
3628
  }
3569
3629
  ;
3570
3630
  //# sourceMappingURL=hooks.js.map