placementt-core 11.0.803 → 11.0.914

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/hooks.tsx CHANGED
@@ -11,13 +11,13 @@ import { getFiles, getFormsFromId, getPlacementbyId, getPlacementsWhere, getUser
11
11
  import { arrayUniqueValues, arraysEqual, convertDate, editNestedObject, getAccess, getDateDiff, getUniqueId, objectsEqual, validateEmail } from "./firebase/util";
12
12
  import { addPlacement, editPlacementStage, uploadFiles } from "./firebase/writeDatabase";
13
13
  import {
14
- Address,
14
+ AlumniConvoUser,
15
15
  ApplicantStage,
16
- ApplicantWorkflow,
17
16
  Application,
18
17
  ArrowObject, CohortData, CustomFormSchema, FileItem, FlagCodes, InstituteData, OnboardingDocs, PlacementListing, Products,
18
+ ProviderContactData,
19
19
  ProviderData,
20
- QueryObject, QueryObjectConstraint, SavedPlacement, Sorts, StudentPlacementData, UserData, UserGroupData, WorkflowStage
20
+ QueryObject, QueryObjectConstraint, SchoolData, Sorts, StudentPlacementData, UserData, UserGroupData, WorkflowStage
21
21
  } from "./typeDefinitions";
22
22
  import algoliasearch from "algoliasearch";
23
23
  import {getDownloadURL, ref} from "firebase/storage";
@@ -348,7 +348,7 @@ export function useNewInstitutePlacementList({id, user, filters, view, cohort, q
348
348
  direction: "asc",
349
349
  },
350
350
  ["Student Email - Desc"]: {
351
- value: "studentEmaile",
351
+ value: "studentEmail",
352
352
  direction: "desc",
353
353
  },
354
354
  ["Provider email - Asc"]: {
@@ -367,17 +367,22 @@ export function useNewInstitutePlacementList({id, user, filters, view, cohort, q
367
367
 
368
368
  const student = await getUserById(placement.uid).catch(() => false) as UserData|false;
369
369
 
370
- if (!student) return;
370
+ if (!student) {
371
+ console.log("No student");
372
+ return
373
+ };
371
374
 
372
375
  if (!user.studentFilterValues.includes(student.details[user.studentFilter])) {
376
+ console.log("filter not included. Filteres: ", user.studentFilterValues, "value", user.studentFilter, "-", student.details[user.studentFilter]);
373
377
  return false;
374
378
  }
375
379
  }
380
+ console.log("Valid placement", k);
376
381
  return {...placement, id: k};
377
382
  }
378
383
 
379
384
 
380
- 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)})
385
+ 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(query || [], user, s, sort, page, filters, limit, cohort, inProgress)})
381
386
 
382
387
  useEffect(() => {
383
388
  // Sets the query of for the DataViewerPaginator
@@ -385,7 +390,7 @@ export function useNewInstitutePlacementList({id, user, filters, view, cohort, q
385
390
  setQuery(undefined);
386
391
  return;
387
392
  }
388
- if (((user.userGroup === "admin" || (cohort && user.viewCohorts === "some" && user?.visibleCohorts?.includes(cohort as string)) || (user.viewCohorts === "all" && user.viewStudents === "all")))) {
393
+ if (((user.userGroup === "admin" || (cohort && user.viewCohorts === "some" && user?.visibleCohorts?.includes(cohort as string)) || (user.viewCohorts === "all" && user.viewStudents !== "none")))) {
389
394
  const constraints:QueryObjectConstraint = [["oId", "==", user.oId], ["draft", "==", false]];
390
395
 
391
396
  cohort && constraints.push(["cohort", "==", cohort]);
@@ -405,7 +410,101 @@ export function useNewInstitutePlacementList({id, user, filters, view, cohort, q
405
410
  }
406
411
 
407
412
 
408
- const algoliaPlacementSearch = async (user: UserData, query?: string, sort?: [string, {value: string, direction: "asc"|"desc"}], page?: number, filters?: FilterObject, limit?: number, cohort?: string, inProgress?: boolean) => {
413
+
414
+ type AlumniPaginatorParams = {
415
+ user?: UserData,
416
+ alumniConvoUser?: AlumniConvoUser,
417
+ school?: string,
418
+ queryConstraints?: QueryObjectConstraint,
419
+ ql?: number,
420
+ view: "list"|"table",
421
+ filters?: FilterObject,
422
+ }
423
+
424
+
425
+
426
+ export function useAlumniPaginator({user, alumniConvoUser, filters, view, school, queryConstraints, ql=DEFAULTQUERYLIMIT}:AlumniPaginatorParams) {
427
+ const [query, setQuery] = useState<QueryObject[]>();
428
+
429
+ const sorts:Sorts = {}
430
+
431
+
432
+ const {tableData, pageUp, pageDown, setFilters, page, setView, loading} = useDataViewerPaginator({view, filters, sorts, queryLimit: ql, data: query})
433
+ const firebaseQuery = new FirebaseQuery();
434
+
435
+ useEffect(() => {
436
+ const createQuery = async () => {
437
+ // Sets the query of for the DataViewerPaginator
438
+
439
+
440
+ const getQueryAccess = async () => {
441
+ const constraints:QueryObjectConstraint = [];
442
+
443
+ if (user) {
444
+ constraints.push(["oId", "==", user.oId]);
445
+
446
+ if (user.userGroup === "admin" && user.userType === "Staff") return constraints;
447
+
448
+ if (user.userType === "Staff") {
449
+ if (user.viewSchools === "all") return constraints;
450
+
451
+ if (user.viewSchools === "none") return false;
452
+
453
+ if (user.viewSchools === "some") {
454
+ if (!school) return false;
455
+
456
+ if (user?.visibleSchools?.includes(school as string)) return constraints;
457
+ }
458
+ return false;
459
+ }
460
+ return false;
461
+ }
462
+
463
+ if (alumniConvoUser) {
464
+ constraints.push(["oId", "==", alumniConvoUser.oId]);
465
+ console.log("ALUMNI CONVO USER");
466
+
467
+ if ((school || alumniConvoUser.schoolId) && school === alumniConvoUser.schoolId) return constraints;
468
+ console.log("ALUMNI ACCESS TRUE");
469
+ if (alumniConvoUser.schoolId) {
470
+ const school = await firebaseQuery.getDocData(["schools", alumniConvoUser.schoolId]) as SchoolData;
471
+ console.log("SCHOOL ACCESS", school, school.alumniConversations);
472
+ return school.alumniConversations ? constraints : false;
473
+
474
+ } else {
475
+ const institute = await firebaseQuery.getDocData(["institutes", alumniConvoUser.oId]) as InstituteData;
476
+ return institute.alumniConversations ? constraints : false;
477
+ }
478
+ }
479
+ return false;
480
+ }
481
+ const constraints = await getQueryAccess();
482
+ console.log("CONSTRAINTS", constraints);
483
+ if (!constraints) return;
484
+
485
+ school && constraints.push(["schoolId", "==", school]);
486
+ queryConstraints && constraints.unshift(...queryConstraints);
487
+
488
+ return constraints;
489
+ }
490
+ console.log("Creating query");
491
+ createQuery().then((constraints) => {
492
+ setQuery([{
493
+ path: ["alumni"],
494
+ where: constraints
495
+ }])
496
+ })
497
+ }, [user, queryConstraints, school])
498
+
499
+ useEffect(() => {
500
+ console.log("Alumni data", query, tableData);
501
+ }, [tableData]);
502
+
503
+ return {tableData, page, loading, setFilters, setView, pageUp, pageDown, sorts}
504
+ }
505
+
506
+
507
+ const algoliaPlacementSearch = async (data: QueryObject[], user: UserData, query?: string, sort?: [string, {value: string, direction: "asc"|"desc"}], page?: number, filters?: FilterObject, limit?: number, cohort?: string, inProgress?: boolean) => {
409
508
  const algoliaClient = algoliasearch(process.env.NODE_ENV === "development" ? "A0ZB50I7VS" : "XMPXCMUUOJ", user.algoliaKey);
410
509
  const placementsIndex = algoliaClient.initIndex(sort ? Object.values(sort[1]).join("_") : "placements");
411
510
  // const usersIndex = algoliaClient.initIndex("users");
@@ -894,210 +993,222 @@ export function useFilterTablePaginator({data}:{data:{[key:string]:{[key:string]
894
993
  return ({...{tableData, setPage, setFilters, page}});
895
994
  }
896
995
 
897
- export function usePlacementListingPaginator({data, user}:{data:QueryObject[], user: UserData}) {
898
- const [tableData, setTableData] = useState<{[key:string]:PlacementListing&{savedPlacement: SavedPlacement}}>({});
899
- const [page, setPage] = useState([1, 0]);
900
- const [filters, setFilters] = useState<{[key:string]: unknown}>();
901
- const [queryAnchor, setQueryAnchor] = useState<{startKey: string, endKey: string, startQueryPos: number, endQueryPos: number}>({startKey: "", endKey: "", startQueryPos: 0, endQueryPos: 0});
902
- const [prevEntryIds, setPrevEntryIds] = useState<{[key:string]:number}>({});
996
+ export function useProviderContactPaginator({data, user, view, filters}:{data:QueryObject[], user: UserData, view: "list"|"table", filters?: FilterObject}) {
997
+ const [query, setQuery] = useState<QueryObject[]>();
903
998
  const firebaseQuery = new FirebaseQuery();
904
999
 
905
- const getDataFromQuery = async (
906
- itemList: {[key: string]: any} = {}, currentQueryAnchor=queryAnchor, cursorDirection?:"increase"|"decrease"|undefined, prevEntries=prevEntryIds, loadMoreFromQuery=false):Promise<any> => {
907
- let cursorPos:number;
908
- if (page[0] > page[1]) {
909
- cursorPos = currentQueryAnchor.endQueryPos;
910
- } else {
911
- cursorPos = currentQueryAnchor.startQueryPos;
1000
+ const getAdditionalData = async (k: string, v: ProviderContactData) => {
1001
+ if (v.savedBy?.[user.oId].activities?.includes("workExperience")) {
1002
+ const placementsCount = await firebaseQuery.getCount("placementListings", [where(`savedBy.${user.oId}.exists`, "==", true), where("providerContactId", "==", k)]);
1003
+ return {...v, plcaements: placementsCount};
912
1004
  }
1005
+ return v;
1006
+ }
913
1007
 
914
- const querySchema:QueryObject = data?.[cursorPos];
1008
+ const {tableData, pageUp, pageDown, setFilters, page, setView, loading} = useDataViewerPaginator({view, filters, queryLimit: 10, data: query, additionalEntryProcessing: getAdditionalData})
915
1009
 
916
- const createQuery = (queryData?:QueryObject) => {
917
- const constraints:any[] = [
918
- where("savedById", "==", user.userType === "Staff" ? user.oId : user.id),
919
- where("savedByProduct", "==", user.product),
920
- where("savedByUserType", "==", user.userType === "Staff" ? "Organisation" : "Student"),
921
- ]
922
1010
 
923
- if (user.userType === "Students") {
924
- constraints.push(where("listed", "==", true));
925
- }
1011
+ useEffect(() => {
1012
+ const constraints:QueryObjectConstraint = [
1013
+ [`savedBy.${user.oId}.exists`, "==", true],
1014
+ ]
926
1015
 
927
- queryData?.where && queryData.where.forEach((w) => {
928
- constraints.push(where(...w));
929
- });
1016
+ if (user.userType === "Students") {
1017
+ constraints.push([`savedBy.${user.oId}.cohorts.${user.cohort}.listed`, "==", true]);
1018
+ }
1019
+ setQuery([{
1020
+ path: ["providerContacts"],
1021
+ where: constraints
1022
+ }])
1023
+ }, [user]);
930
1024
 
931
- filters && Object.entries(filters).forEach(([key, value]) => {
932
- constraints.push(where(key, "==", value));
933
- });
1025
+ return ({...{tableData, pageUp, pageDown, setFilters, page, setView, loading}});
1026
+ }
934
1027
 
935
- if (queryData?.orderBy) {
936
- if (queryData.orderBy === "documentId") {
937
- constraints.push(orderBy(documentId()));
938
- } else {
939
- constraints.push(orderBy(queryData.orderBy));
940
- }
941
- } else {
942
- constraints.push(orderBy(documentId()));
943
- }
1028
+ type UserPaginatorParams = {
1029
+ user: UserData,
1030
+ cohort?: string,
1031
+ data: QueryObject[],
1032
+ search?: string,
1033
+ userType: "Staff"|"Students",
1034
+ sort?: string
1035
+ }
944
1036
 
945
1037
 
946
- if (page[0] > page[1] && !cursorDirection) { // Going up
947
- currentQueryAnchor.endKey && constraints.push(startAfter(currentQueryAnchor.endKey));
948
- constraints.push(limit(10));
949
- if (!loadMoreFromQuery) {
950
- currentQueryAnchor = {...currentQueryAnchor, startQueryPos: currentQueryAnchor.endQueryPos};
951
- }
952
- } else if (page[0] < page[1] && !cursorDirection) { // Going down
953
- if (!loadMoreFromQuery) {
954
- currentQueryAnchor = {...currentQueryAnchor, endQueryPos: currentQueryAnchor.startQueryPos};
955
- }
956
- constraints.push(limitToLast(10));
957
- if (currentQueryAnchor.startKey) {
958
- currentQueryAnchor.startKey && constraints.push(endBefore(currentQueryAnchor.startKey));
959
- } else {
960
- currentQueryAnchor.startKey && constraints.push(endAt(currentQueryAnchor.startKey));
961
- }
962
- } else {
963
- if (cursorDirection === "decrease") {
964
- constraints.push(limitToLast(10));
965
- } else {
966
- constraints.push(limit(10));
967
- }
968
- }
969
- return constraints;
970
- };
1038
+ const algoliaUsersSearch = async (data: QueryObject[], user: UserData, query?: string, sort?: [string, {value: string, direction: "asc"|"desc"}], page?: number, filters?: FilterObject, limit?: number, cohort?: string) => {
1039
+ const algoliaClient = algoliasearch(process.env.NODE_ENV === "development" ? "A0ZB50I7VS" : "XMPXCMUUOJ", user.algoliaKey);
1040
+ console.log("SORT", sort);
1041
+ const userIndex = algoliaClient.initIndex(sort ? `users_${Object.values(sort[1]).join("_")}` : "users");
1042
+ const constraints = data[0].where;
1043
+
1044
+ if (!constraints?.length) return {};
1045
+
1046
+ let userSearchString = constraints.map(([k, e, v]) => {
1047
+ if (e === "==") return `${k}:"${v}"`; // Equality check
1048
+ if (e === "!=") return `${k}:-"${v}"`; // Not equal check
1049
+ if (e === "<") return `${k}:<${v}`; // Less than check
1050
+ if (e === "<=") return `${k}:<=${v}`; // Less than or equal check
1051
+ if (e === ">") return `${k}:>${v}`; // Greater than check
1052
+ if (e === ">=") return `${k}:>=${v}`; // Greater than or equal check
1053
+ if (e === "array-contains") return `${k}:"${v}"`; // Array contains check (string format)
1054
+ if (e === "array-contains-any") return `${k}:"${(v as string[]).join('","')}"`; // Array contains any of the values (string format)
1055
+ if (e === "in") return `${k}:(${(v as string[]).join('","')})`; // In check
1056
+ if (e === "not-in") return `${k}:(-${(v as string[]).join('","')})`; // Not in check
1057
+ return;
1058
+ }).join(" AND ");
971
1059
 
972
- const constraints = createQuery(querySchema);
973
- // console.log(queryId, "constraints", constraints)
1060
+ console.log("QUERY", userSearchString);
974
1061
 
975
- const q = query(collection(db, "savedPlacements"), ...(constraints));
976
- const queryResults:{[key:string]: unknown} = {};
1062
+ filters && Object.entries(filters).filter(([, filter]) => filter.value).map(([id, filter]) => {
1063
+ userSearchString = userSearchString + ` AND ${id}:${filter.value}`;
1064
+ });
977
1065
 
978
- const queryData = await getDocs(q);
1066
+ const options = {
1067
+ filters: userSearchString,
1068
+ hitsPerPage: limit,
1069
+ page: page ? page - 1 : undefined,
1070
+ }
979
1071
 
980
- // console.log("queryData.size", queryData.size)
1072
+ const searchUsersHits = await userIndex.search<UserData>(query || "", options);
981
1073
 
1074
+ console.log(searchUsersHits.hits);
1075
+
1076
+ const i = (searchUsersHits ? (await Promise.all(searchUsersHits.hits.map(async (hit) => {
1077
+ return [hit.objectID, hit];
1078
+ }))) : []).filter((e) => e !== undefined) as [string, UserData][];
982
1079
 
983
- const reverseIfBack = (docs:QueryDocumentSnapshot<DocumentData>[]) => {
984
- if (page[0] < page[1]) {
985
- return docs.reverse();
986
- }
987
- return docs;
988
- };
1080
+ return Object.fromEntries(i)
1081
+ }
989
1082
 
990
- let index = 0;
991
- reverseIfBack(queryData.docs).forEach(async (doc: QueryDocumentSnapshot) => {
992
- if (Object.keys(queryResults).length + Object.keys(itemList).length === 10) {
993
- return;
994
- }
995
1083
 
996
- let position = Object.keys(itemList).length+(page[0]-1)*10+index+1;
997
- if (page[0] < page[1]) {
998
- position = (page[0])*10-index-Object.keys(itemList).length;
999
- }
1084
+ type NewUserPaginatorParams = {
1085
+ user: UserData,
1086
+ cohort?: string,
1087
+ queryConstraints?: QueryObjectConstraint,
1088
+ ql?: number,
1089
+ view: "list"|"table",
1090
+ filters?: FilterObject,
1091
+ institute: InstituteData,
1092
+ userType: "Staff"|"Students"
1093
+ }
1000
1094
 
1001
- // console.log(index, "doc.id", doc.id, position, "E", prevEntries[doc.id])
1002
1095
 
1003
- if (itemList[doc.id] || (prevEntries[doc.id] && prevEntries[doc.id] !== position)) {
1004
- console.log("Removing ", doc.id, ": E=", prevEntries[doc.id], ", G=", position);
1005
- return;
1006
- }
1096
+ export function useNewCohortUserPaginator({user, institute, filters, view, cohort, queryConstraints, ql=DEFAULTQUERYLIMIT, userType}:NewUserPaginatorParams) {
1097
+ const [query, setQuery] = useState<QueryObject[]>();
1007
1098
 
1008
- const item = doc.data() as SavedPlacement;
1009
- item.id = doc.id;
1010
- queryResults[doc.id] = item;
1011
- index = index+1;
1012
- if (prevEntries[doc.id]) return;
1013
- prevEntries[doc.id] = position;
1014
- });
1099
+ const firebaseQuery = new FirebaseQuery();
1015
1100
 
1016
- if (cursorDirection === "decrease" || page[0] < page[1]) {
1017
- itemList = {...Object.fromEntries(Object.entries(queryResults).reverse()), ...itemList};
1018
- } else {
1019
- itemList = {...itemList, ...queryResults};
1101
+ const sorts:Sorts = {
1102
+ ["Student Forename - Asc"]: {
1103
+ value: "details.forename",
1104
+ direction: "asc",
1105
+ },
1106
+ ["Student Forename - Desc"]: {
1107
+ value: "details.forename",
1108
+ direction: "desc",
1109
+ },
1110
+ ["Student Surname - Asc"]: {
1111
+ value: "details.surname",
1112
+ direction: "asc",
1113
+ },
1114
+ ["Student Surname - Desc"]: {
1115
+ value: "details.surname",
1116
+ direction: "desc",
1117
+ },
1118
+ ["Student Email - Asc"]: {
1119
+ value: "email",
1120
+ direction: "asc",
1121
+ },
1122
+ ["Student Email - Desc"]: {
1123
+ value: "email",
1124
+ direction: "desc",
1020
1125
  }
1126
+ }
1127
+
1128
+ useEffect(() => {
1021
1129
 
1022
- setPrevEntryIds(prevEntries);
1023
-
1024
- if (queryData.size < 10 && Object.keys(itemList).length < 10) {
1025
- if (page[0] > page[1] && cursorPos+1 < data.length) {
1026
- console.log("Increase query index");
1027
- return getDataFromQuery(itemList, {...currentQueryAnchor, endQueryPos: currentQueryAnchor.endQueryPos+1}, "increase", prevEntries);
1028
- } else if (page[0] < page[1] && cursorPos > 0) {
1029
- console.log("Decrease query index");
1030
- return getDataFromQuery(itemList, {...currentQueryAnchor, startQueryPos: currentQueryAnchor.startQueryPos-1}, "decrease", prevEntries);
1130
+ const getAccess = async () => {
1131
+ // Sets the query of for the DataViewerPaginator
1132
+ if(user.product !== "institutes" || user.userType !== "Staff") {
1133
+ setQuery(undefined);
1134
+ return;
1031
1135
  }
1032
- }
1033
1136
 
1034
- if (Object.keys(itemList).length < 10 && queryData.size === 10) {
1035
- console.log("Shorter than ten");
1036
- // if(loadMoreFromQuery){return}
1037
- return getDataFromQuery(itemList, {...currentQueryAnchor, startKey: Object.keys(itemList)[0], endKey: Object.keys(itemList).slice(-1)[0]}, undefined, prevEntries, true);
1038
- }
1039
-
1040
- if (queryData.size === 0 &&
1041
- Object.keys(itemList).length === 0 &&
1042
- currentQueryAnchor.endQueryPos+1 === data.length &&
1043
- page[0] > 1) {
1044
- setTableData({});
1045
- setQueryAnchor((a) => ({...a, startKey: ""}));
1046
- return;
1047
- }
1137
+ const constraints:QueryObjectConstraint = [["oId", "==", user.oId], ["userType", "==", userType]];
1138
+ cohort && constraints.push(["cohort", "==", cohort]);
1139
+ queryConstraints && constraints.unshift(...queryConstraints);
1048
1140
 
1049
- setQueryAnchor({...currentQueryAnchor, startKey: Object.keys(itemList)[0], endKey: Object.keys(itemList).slice(-1)[0]});
1141
+ const mSetQuery = (clear?: boolean) => {
1142
+ setQuery(clear ? undefined : [{
1143
+ path: ["users"],
1144
+ where: constraints
1145
+ }]);
1146
+ return;
1147
+ }
1050
1148
 
1051
- const finalData = Object.fromEntries(await Promise.all(Object.entries(itemList).map(async ([k, v]:[string, SavedPlacement]) => {
1052
- const placement = await firebaseQuery.getDocData(["placementListings", v.placementId || ""]) as PlacementListing;
1053
- const address = await firebaseQuery.getDocData(["addresses", placement.addressId || ""]).catch(() => ({["address-line1"]: "Unknown address"}));
1054
- const provider = await firebaseQuery.getDocData(["providers", placement.providerId || ""]).catch(() => ({name: "Unknown"})) as ProviderData;
1055
- const status = provider.name !== "Unknown" ? getPlacementStatus(provider, placement, v) : "Deleted";
1056
- return [k, {...address, ...provider, ...placement, email: placement.providerEmail, status: status, savedPlacement: v}];
1057
- })));
1058
- setTableData(finalData);
1059
- };
1149
+ if (institute.package === "institutes-one") {
1150
+ if (user.userGroup === "admin" || (user.viewCohorts === "all" && user.viewStudents === "all")) return mSetQuery();
1151
+
1152
+ if (!user.viewCohorts || user.viewCohorts === "none" || !user.viewStudents || user.viewStudents === "none" || (user.viewCohorts === "some" && !user.visibleCohorts?.length) || (user.viewStudents === "some" && !user.studentFilterValues?.length)) return mSetQuery(true);
1153
+
1154
+ if (user.viewStudents === "some") {
1155
+ constraints.push([`details.${user.studentFilter}`, "in", user.studentFilterValues as string[]]);
1156
+ }
1060
1157
 
1061
- const getPlacementStatus = (provider: ProviderData, placement: PlacementListing, savedPlacement: SavedPlacement):"active"|"requiresApproval"|"awaitingProviderApproval"|"public"|"blocked"|"notReviewed"|"notPublic"|"unknown" => {
1062
- if (savedPlacement.status === "Blocked") return "blocked";
1063
- if (savedPlacement.status === "Accepted") return "active";
1158
+ if (cohort) {
1159
+ const canViewCohort = user.viewCohorts === "all" || (user.viewCohorts === "some" && user.visibleCohorts?.includes("cohort"));
1160
+ return mSetQuery(canViewCohort);
1161
+ } else {
1162
+ // No cohort.
1163
+ if (user.viewCohorts === "all") return mSetQuery();
1164
+ if (user.viewCohorts === "some" && user.visibleCohorts) {
1165
+ constraints.push(["cohort", "in", user.visibleCohorts]);
1166
+ return mSetQuery()
1167
+ }
1168
+ return mSetQuery(true);
1169
+ }
1170
+ }
1064
1171
 
1065
- if (user.product === "admin") {
1066
- if (placement.mapConsent === undefined) return "notReviewed";
1067
- if (placement.mapConsent === false) return "notPublic";
1068
- return "unknown";
1069
- };
1172
+ if (institute.package === "institutes-two") {
1173
+ if (user.userGroup === "admin" || (user.viewSchools === "all" && user.viewCohorts === "all" && user.viewStudents === "all")) return mSetQuery();
1070
1174
 
1071
- if (!provider.insurance) return "awaitingProviderApproval";
1072
-
1073
- return "requiresApproval";
1074
- };
1175
+ if (!user.viewCohorts || !user.viewSchools || user.viewSchools === "none" || user.viewCohorts === "none") return mSetQuery(true);
1176
+ if (!user.viewStudents || user.viewStudents === "none" || (user.viewStudents === "some" && !user.studentFilterValues?.length) || (user.viewCohorts === "some" && !user.visibleCohorts?.length) || (user.viewSchools === "some" && !user.visibleSchools?.length)) return mSetQuery(true);
1177
+
1178
+ if (user.viewStudents === "some") {
1179
+ constraints.push([`details.${user.studentFilter}`, "in", user.studentFilterValues as string[]]);
1180
+ }
1181
+
1182
+ if (cohort) {
1183
+ if (user.viewCohorts === "some" && !user.visibleCohorts?.includes(cohort)) return mSetQuery(true);
1184
+
1185
+ if (user.viewSchools === "some") {
1186
+ const cohortData = await firebaseQuery.getDocData(["cohorts", cohort]) as CohortData;
1187
+ if (!cohortData.schoolId || !user.visibleSchools?.includes(cohortData.schoolId)) return mSetQuery(true)
1188
+ }
1189
+ } else {
1190
+ if (user.viewCohorts === "some" && user.visibleCohorts) {
1191
+ constraints.push(["cohort", "in", user.visibleCohorts]);
1192
+ } else if (user.viewSchools === "some" && user.visibleSchools) {
1193
+ const cohorts = await firebaseQuery.getDocsWhere("cohorts", [where("oId", "==", user.oId), where("schoolId", "in", user.visibleSchools)]);
1194
+ constraints.push(["cohort", "in", Object.keys(cohorts || {})]);
1195
+ }
1196
+ }
1197
+ return mSetQuery();
1198
+ }
1199
+ setQuery(undefined)
1200
+ }
1201
+ getAccess();
1202
+ }, [user, queryConstraints, cohort])
1075
1203
 
1076
- useEffect(() => {
1077
- if (!filters) return;
1078
1204
 
1079
- setPage([1, 0]);
1080
- setTableData({});
1081
- setQueryAnchor({startKey: "", endKey: "", startQueryPos: 0, endQueryPos: 0});
1082
- setPrevEntryIds({});
1083
- }, [filters]);
1205
+ const {tableData, pageUp, pageDown, setFilters, page, setView, loading, updateSearch, updateSort, sort} = useDataViewerPaginator({view, filters, sorts, queryLimit: ql, data: query, onSearch: async (s, sort, page, filters, limit) => await algoliaUsersSearch(query || [], user, s, sort, page, filters, limit, cohort)})
1084
1206
 
1085
- // Fetch new data when queries or page change
1086
- useEffect(() => {
1087
- getDataFromQuery();
1088
- }, [page]);
1089
1207
 
1090
- return ({...{tableData, setPage, setFilters, page}});
1208
+ return {tableData, page, loading, updateSearch, setFilters, setView, pageUp, pageDown, sorts, updateSort, sort}
1091
1209
  }
1092
1210
 
1093
- type UserPaginatorParams = {
1094
- user: UserData,
1095
- cohort?: string,
1096
- data: QueryObject[],
1097
- search?: string,
1098
- userType: "Staff"|"Students",
1099
- sort?: string
1100
- }
1211
+
1101
1212
 
1102
1213
  export function useCohortUserPaginator({user, cohort, data, search, userType, sort}:UserPaginatorParams) {
1103
1214
  const [tableData, setTableData] = useState<{[key:string]:{[key:string]: unknown}}>({});
@@ -1130,8 +1241,8 @@ export function useCohortUserPaginator({user, cohort, data, search, userType, so
1130
1241
  }
1131
1242
  if (
1132
1243
  (!user.viewCohorts && user.userGroup !== "admin") ||
1133
- user.viewCohorts === "none" ||
1134
- (user.viewCohorts === "some" && cohort !== "all" && !user.visibleCohorts?.includes(cohort || ""))) {
1244
+ (user.viewCohorts === "none" && user.userGroup !== "admin") ||
1245
+ (user.viewCohorts === "some" && user.userGroup !== "admin" && cohort !== "all" && !user.visibleCohorts?.includes(cohort || ""))) {
1135
1246
  setQueries(undefined);
1136
1247
  return;
1137
1248
  }
@@ -1476,514 +1587,514 @@ export function useLazyLoadQueryList({path, constraints, number, onItemFetched}:
1476
1587
  }
1477
1588
 
1478
1589
 
1479
- type PublicPlacementListingLoaderParams = {
1480
- providerId?: string,
1481
- number: number,
1482
- }
1483
-
1484
- export function usePublicPlacementListingLoader({providerId, number=5}:PublicPlacementListingLoaderParams) {
1485
- const [items, setItems] = useState<{[key:string]:{[key:string]:unknown}}>({});
1486
- const [loadMoreIcon, setLoadMoreIcon] = useState<boolean>(false);
1487
-
1488
- const [lastItem, setLastItem] = useState<QueryDocumentSnapshot<DocumentData>>();
1489
- const firebaseQuery = new FirebaseQuery();
1490
-
1491
- const reset = () => {
1492
- setItems({});
1493
- setLastItem(undefined);
1494
- };
1495
-
1496
- const loadMore = async () => {
1497
- setLoadMoreIcon(true);
1498
- let formattedConstraints:QueryConstraint[] = [
1499
- where("status", "==", "listed"),
1500
- limit(number)
1501
- ];
1502
-
1503
- if (providerId) {
1504
- formattedConstraints.push(where("providerId", "==", providerId));
1505
- }
1506
- if (lastItem) {
1507
- formattedConstraints.push(startAfter(lastItem));
1508
- }
1509
- const documents = await firebaseQuery.getDocsWhere("placementListings", formattedConstraints, true) as QuerySnapshot<DocumentData>;
1510
-
1511
- console.log("docs", documents.docs);
1512
- setLastItem(documents.docs[documents.docs.length-1]);
1513
-
1514
- const processedItems = Object.fromEntries(await Promise.all(Object.values(documents.docs).map(async (doc) => {
1515
- let itemObj = {...doc.data(), id: doc.id} as PlacementListing;
1516
-
1517
- if (itemObj.addressId) {
1518
- const address = await firebaseQuery.getDocData(["addresses", itemObj.addressId]) as Address;
1519
- delete address.id;
1520
- itemObj = {...address, ...itemObj};
1521
- }
1522
- if (itemObj.applicantWorkflowId) {
1523
- const applicantWorkflow = (await firebaseQuery.getDocData(["applicantWorkflows", itemObj.applicantWorkflowId]) as ApplicantWorkflow).workflow.filter((i) => i.id === 1)[0];
1524
- const applicantFiles = applicantWorkflow.files ? Object.fromEntries(await Promise.all(applicantWorkflow.files?.map(async (fileId) => {
1525
- const file = await firebaseQuery.getDocData(["files", fileId]);
1526
- file.url = await getDownloadURL(ref(storage, `providers/${itemObj.providerId}/${file.fileName}`));
1527
-
1528
- return [fileId, file];
1529
- }))) : [];
1530
- const applicantForms = applicantWorkflow.forms ? Object.fromEntries(await Promise.all(applicantWorkflow.forms?.map(async (formId) => {
1531
- return [formId, await firebaseQuery.getDocData(["forms", formId])];
1532
- }))) : [];
1533
-
1534
- applicantWorkflow.viewableFiles = applicantFiles;
1535
- applicantWorkflow.formDetails = applicantForms;
1536
- itemObj = {...itemObj, applicantWorkflow: [applicantWorkflow]};
1537
- }
1538
- return [doc.id, itemObj];
1539
- })))
1540
-
1541
- setItems((i) => ({...i, ...processedItems}));
1542
- setLoadMoreIcon(false);
1543
- };
1544
- useEffect(() => {
1545
- loadMore();
1546
- }, []);
1547
-
1548
- return ({...{items, loadMore, loadMoreIcon, reset}});
1549
- }
1550
-
1551
- export type ApplicationHookParams = {
1552
- successText: {
1553
- submitted: {
1554
- title: string;
1555
- desc: string;
1556
- };
1557
- draftSaved: {
1558
- title: string;
1559
- desc: string;
1560
- };
1561
- stageComplete: {
1562
- title: string;
1563
- desc: string;
1564
- };
1565
- outcome: {
1566
- title: string;
1567
- desc: string;
1568
- };
1569
- };
1570
- setSuccessPopup: import("react").Dispatch<import("react").SetStateAction<"submitted" | "draftSaved" | "stageComplete" | "outcome" | undefined>>;
1571
- openSuccessPopup: (type: "submitted" | "draftSaved" | "stageComplete" | "outcome") => void;
1572
- setFApplication: import("react").Dispatch<import("react").SetStateAction<Partial<Application>>>;
1573
- fApplication: Partial<Application>;
1574
- draftSaved: boolean;
1575
- profileUrl: string | undefined;
1576
- successPopup: "submitted" | "draftSaved" | "stageComplete" | "outcome" | undefined;
1577
- fApplicationId: string | undefined;
1578
- fListing: PlacementListing | false | undefined;
1579
- student: UserData | undefined;
1580
- fProvider: {
1581
- details?: ProviderData;
1582
- profile?: string;
1583
- id?: string;
1584
- } | undefined;
1585
- onFApply: (draft?: boolean) => Promise<void>;
1586
- setFormComplete: (formId: string, e: {
1587
- [key: string]: unknown;
1588
- }) => void;
1589
- viewFile: (file: string, onOpen: (url: string) => void) => void
1590
- addFile: (files: string[], fileId: number) => void;
1591
- uploadedFiles?: {
1592
- [key: string]: FileItem;
1593
- };
1594
- getCurrentStage: (stage: number) => Promise<{
1595
- stage: ApplicantStage;
1596
- completedSections: {
1597
- submitted?: string | undefined;
1598
- filesViewed?: string[] | undefined;
1599
- formsCompleted?: {
1600
- [key: string]: unknown;
1601
- } | undefined;
1602
- filesUploaded?: {
1603
- [key: number]: string[];
1604
- } | undefined;
1605
- };
1606
- }>;
1607
- currentStageComplete?: boolean;
1608
- progressStage: (type: number | "accept" | "reject", e?: {
1609
- feedback?: string;
1610
- }) => Promise<void>;
1611
- };
1612
-
1613
- export function useCreateApplicationRenderer({user, listingId, listing, provider, application, applicationId, orgContext}:
1614
- {user:UserData, listingId:string, applicationId?: string, listing?: PlacementListing, application?: Partial<Application>,
1615
- orgContext?: {details: ProviderData, addresses: {[key: string]: OrganisationAddress}, applicantWorkflows: {[key: string]: ApplicantWorkflow}},
1616
- provider?: {details?: ProviderData, profile?: string, id?: string}}) {
1617
-
1618
- const firebaseQuery = new FirebaseQuery();
1619
-
1620
- let applicationWithoutAdditionalData = {...(application || {})} as any;
1621
- delete applicationWithoutAdditionalData.listing;
1622
- delete applicationWithoutAdditionalData.address;
1623
- delete applicationWithoutAdditionalData.provider;
1590
+ // type PublicPlacementListingLoaderParams = {
1591
+ // providerId?: string,
1592
+ // number: number,
1593
+ // }
1594
+
1595
+ // export function usePublicPlacementListingLoader({providerId, number=5}:PublicPlacementListingLoaderParams) {
1596
+ // const [items, setItems] = useState<{[key:string]:{[key:string]:unknown}}>({});
1597
+ // const [loadMoreIcon, setLoadMoreIcon] = useState<boolean>(false);
1598
+
1599
+ // const [lastItem, setLastItem] = useState<QueryDocumentSnapshot<DocumentData>>();
1600
+ // const firebaseQuery = new FirebaseQuery();
1601
+
1602
+ // const reset = () => {
1603
+ // setItems({});
1604
+ // setLastItem(undefined);
1605
+ // };
1606
+
1607
+ // const loadMore = async () => {
1608
+ // setLoadMoreIcon(true);
1609
+ // let formattedConstraints:QueryConstraint[] = [
1610
+ // where("status", "==", "listed"),
1611
+ // limit(number)
1612
+ // ];
1613
+
1614
+ // if (providerId) {
1615
+ // formattedConstraints.push(where("providerId", "==", providerId));
1616
+ // }
1617
+ // if (lastItem) {
1618
+ // formattedConstraints.push(startAfter(lastItem));
1619
+ // }
1620
+ // const documents = await firebaseQuery.getDocsWhere("placementListings", formattedConstraints, true) as QuerySnapshot<DocumentData>;
1621
+
1622
+ // console.log("docs", documents.docs);
1623
+ // setLastItem(documents.docs[documents.docs.length-1]);
1624
+
1625
+ // const processedItems = Object.fromEntries(await Promise.all(Object.values(documents.docs).map(async (doc) => {
1626
+ // let itemObj = {...doc.data(), id: doc.id} as PlacementListing;
1627
+
1628
+ // if (itemObj.addressId) {
1629
+ // const address = await firebaseQuery.getDocData(["addresses", itemObj.addressId]) as Address;
1630
+ // delete address.id;
1631
+ // itemObj = {...address, ...itemObj};
1632
+ // }
1633
+ // if (itemObj.applicantWorkflowId) {
1634
+ // const applicantWorkflow = (await firebaseQuery.getDocData(["applicantWorkflows", itemObj.applicantWorkflowId]) as ApplicantWorkflow).workflow.filter((i) => i.id === 1)[0];
1635
+ // const applicantFiles = applicantWorkflow.files ? Object.fromEntries(await Promise.all(applicantWorkflow.files?.map(async (fileId) => {
1636
+ // const file = await firebaseQuery.getDocData(["files", fileId]);
1637
+ // file.url = await getDownloadURL(ref(storage, `providers/${itemObj.providerId}/${file.fileName}`));
1638
+
1639
+ // return [fileId, file];
1640
+ // }))) : [];
1641
+ // const applicantForms = applicantWorkflow.forms ? Object.fromEntries(await Promise.all(applicantWorkflow.forms?.map(async (formId) => {
1642
+ // return [formId, await firebaseQuery.getDocData(["forms", formId])];
1643
+ // }))) : [];
1644
+
1645
+ // applicantWorkflow.viewableFiles = applicantFiles;
1646
+ // applicantWorkflow.formDetails = applicantForms;
1647
+ // itemObj = {...itemObj, applicantWorkflow: [applicantWorkflow]};
1648
+ // }
1649
+ // return [doc.id, itemObj];
1650
+ // })))
1651
+
1652
+ // setItems((i) => ({...i, ...processedItems}));
1653
+ // setLoadMoreIcon(false);
1654
+ // };
1655
+ // useEffect(() => {
1656
+ // loadMore();
1657
+ // }, []);
1658
+
1659
+ // return ({...{items, loadMore, loadMoreIcon, reset}});
1660
+ // }
1661
+
1662
+ // export type ApplicationHookParams = {
1663
+ // successText: {
1664
+ // submitted: {
1665
+ // title: string;
1666
+ // desc: string;
1667
+ // };
1668
+ // draftSaved: {
1669
+ // title: string;
1670
+ // desc: string;
1671
+ // };
1672
+ // stageComplete: {
1673
+ // title: string;
1674
+ // desc: string;
1675
+ // };
1676
+ // outcome: {
1677
+ // title: string;
1678
+ // desc: string;
1679
+ // };
1680
+ // };
1681
+ // setSuccessPopup: import("react").Dispatch<import("react").SetStateAction<"submitted" | "draftSaved" | "stageComplete" | "outcome" | undefined>>;
1682
+ // openSuccessPopup: (type: "submitted" | "draftSaved" | "stageComplete" | "outcome") => void;
1683
+ // setFApplication: import("react").Dispatch<import("react").SetStateAction<Partial<Application>>>;
1684
+ // fApplication: Partial<Application>;
1685
+ // draftSaved: boolean;
1686
+ // profileUrl: string | undefined;
1687
+ // successPopup: "submitted" | "draftSaved" | "stageComplete" | "outcome" | undefined;
1688
+ // fApplicationId: string | undefined;
1689
+ // fListing: PlacementListing | false | undefined;
1690
+ // student: UserData | undefined;
1691
+ // fProvider: {
1692
+ // details?: ProviderData;
1693
+ // profile?: string;
1694
+ // id?: string;
1695
+ // } | undefined;
1696
+ // onFApply: (draft?: boolean) => Promise<void>;
1697
+ // setFormComplete: (formId: string, e: {
1698
+ // [key: string]: unknown;
1699
+ // }) => void;
1700
+ // viewFile: (file: string, onOpen: (url: string) => void) => void
1701
+ // addFile: (files: string[], fileId: number) => void;
1702
+ // uploadedFiles?: {
1703
+ // [key: string]: FileItem;
1704
+ // };
1705
+ // getCurrentStage: (stage: number) => Promise<{
1706
+ // stage: ApplicantStage;
1707
+ // completedSections: {
1708
+ // submitted?: string | undefined;
1709
+ // filesViewed?: string[] | undefined;
1710
+ // formsCompleted?: {
1711
+ // [key: string]: unknown;
1712
+ // } | undefined;
1713
+ // filesUploaded?: {
1714
+ // [key: number]: string[];
1715
+ // } | undefined;
1716
+ // };
1717
+ // }>;
1718
+ // currentStageComplete?: boolean;
1719
+ // progressStage: (type: number | "accept" | "reject", e?: {
1720
+ // feedback?: string;
1721
+ // }) => Promise<void>;
1722
+ // };
1723
+
1724
+ // export function useCreateApplicationRenderer({user, listingId, listing, provider, application, applicationId, orgContext}:
1725
+ // {user:UserData, listingId:string, applicationId?: string, listing?: PlacementListing, application?: Partial<Application>,
1726
+ // orgContext?: {details: ProviderData, addresses: {[key: string]: OrganisationAddress}, applicantWorkflows: {[key: string]: ApplicantWorkflow}},
1727
+ // provider?: {details?: ProviderData, profile?: string, id?: string}}) {
1728
+
1729
+ // const firebaseQuery = new FirebaseQuery();
1730
+
1731
+ // let applicationWithoutAdditionalData = {...(application || {})} as any;
1732
+ // delete applicationWithoutAdditionalData.listing;
1733
+ // delete applicationWithoutAdditionalData.address;
1734
+ // delete applicationWithoutAdditionalData.provider;
1624
1735
 
1625
- const [fApplication, setFApplication] = useState<Partial<Application>>(application ? applicationWithoutAdditionalData : {
1626
- uid: user.userType === "Students" ? user.id : undefined,
1627
- listingId: listingId,
1628
- addressId: listing?.addressId,
1629
- stage: 1,
1630
- reqUserType: "Students",
1631
- status: "draft"});
1632
- const [fApplicationId, setFApplicationId] = useState<string|undefined>(applicationId);
1633
- const [draftSaved, setDraftSaved] = useState(false);
1634
- const [fProvider, setFProvider] = useState<{details?: ProviderData, profile?: string, id?: string}|undefined>(provider);
1635
- const [fListing, setFListing] = useState<PlacementListing|false|undefined>(Object.keys(listing || {}).length > 5 ? listing : undefined);
1636
- const [student, setStudent] = useState<UserData|undefined>(user.userType === "Students" ? user : undefined);
1637
- const [profileUrl, setProfileUrl] = useState<string>();
1638
- const [successPopup, setSuccessPopup] = useState<"submitted"|"draftSaved"|"stageComplete"|"outcome">();
1639
- const [uploadedFiles, setUploadedFiles] = useState<{[key: string]: FileItem}>();
1640
- const [currentStageComplete, setCurrentStageComplete] = useState<boolean>();
1641
-
1642
- useEffect(() => {
1643
- const getListing = async () => {
1644
- console.log("Checking ID")
1645
- if (!listingId) return;
1646
- console.log("Getting listing")
1647
- console.log("LISTING PARAM", listing, Object.keys(listing || {}).length > 5);
1648
-
1649
- const listingData = (Object.keys(listing || {}).length > 5) ? listing : (await firebaseQuery.getDocData(["placementListings", listingId]).catch(() => false) as PlacementListing|false);
1736
+ // const [fApplication, setFApplication] = useState<Partial<Application>>(application ? applicationWithoutAdditionalData : {
1737
+ // uid: user.userType === "Students" ? user.id : undefined,
1738
+ // listingId: listingId,
1739
+ // addressId: listing?.addressId,
1740
+ // stage: 1,
1741
+ // reqUserType: "Students",
1742
+ // status: "draft"});
1743
+ // const [fApplicationId, setFApplicationId] = useState<string|undefined>(applicationId);
1744
+ // const [draftSaved, setDraftSaved] = useState(false);
1745
+ // const [fProvider, setFProvider] = useState<{details?: ProviderData, profile?: string, id?: string}|undefined>(provider);
1746
+ // const [fListing, setFListing] = useState<PlacementListing|false|undefined>(Object.keys(listing || {}).length > 5 ? listing : undefined);
1747
+ // const [student, setStudent] = useState<UserData|undefined>(user.userType === "Students" ? user : undefined);
1748
+ // const [profileUrl, setProfileUrl] = useState<string>();
1749
+ // const [successPopup, setSuccessPopup] = useState<"submitted"|"draftSaved"|"stageComplete"|"outcome">();
1750
+ // const [uploadedFiles, setUploadedFiles] = useState<{[key: string]: FileItem}>();
1751
+ // const [currentStageComplete, setCurrentStageComplete] = useState<boolean>();
1752
+
1753
+ // useEffect(() => {
1754
+ // const getListing = async () => {
1755
+ // console.log("Checking ID")
1756
+ // if (!listingId) return;
1757
+ // console.log("Getting listing")
1758
+ // console.log("LISTING PARAM", listing, Object.keys(listing || {}).length > 5);
1759
+
1760
+ // const listingData = (Object.keys(listing || {}).length > 5) ? listing : (await firebaseQuery.getDocData(["placementListings", listingId]).catch(() => false) as PlacementListing|false);
1650
1761
 
1651
- console.log("LISTINGDATA", listingData, Object.keys(listing || {}).length > 5 ? {a: "string"} : "AAA");
1762
+ // console.log("LISTINGDATA", listingData, Object.keys(listing || {}).length > 5 ? {a: "string"} : "AAA");
1652
1763
 
1653
1764
 
1654
1765
 
1655
- const address = listingData ? (user.product === "providers" && orgContext) ? orgContext.addresses[listingData.addressId || ""] : await firebaseQuery.getDocData(["addresses", listingData.addressId as string]) as Address : undefined;
1656
- const workflow = listingData ? (user.product === "providers" && orgContext) ? orgContext.applicantWorkflows[listingData.applicantWorkflowId || ""] as ApplicantWorkflow : await firebaseQuery.getDocData(["applicantWorkflows", listingData.applicantWorkflowId as string]) as ApplicantWorkflow : undefined;
1766
+ // const address = listingData ? (user.product === "providers" && orgContext) ? orgContext.addresses[listingData.addressId || ""] : await firebaseQuery.getDocData(["addresses", listingData.addressId as string]) as Address : undefined;
1767
+ // const workflow = listingData ? (user.product === "providers" && orgContext) ? orgContext.applicantWorkflows[listingData.applicantWorkflowId || ""] as ApplicantWorkflow : await firebaseQuery.getDocData(["applicantWorkflows", listingData.applicantWorkflowId as string]) as ApplicantWorkflow : undefined;
1657
1768
 
1658
- if (workflow && listingData) {
1659
- workflow.workflow = await Promise.all(workflow.workflow.map(async (s) => {
1660
- const applicantFiles = s.files ? Object.fromEntries(await Promise.all(s.files?.map(async (fileId: string) => {
1661
- const file = await firebaseQuery.getDocData(["files", fileId]);
1662
- file.url = await getDownloadURL(ref(storage, `providers/${listingData?.providerId}/${file.fileName}`));
1769
+ // if (workflow && listingData) {
1770
+ // workflow.workflow = await Promise.all(workflow.workflow.map(async (s) => {
1771
+ // const applicantFiles = s.files ? Object.fromEntries(await Promise.all(s.files?.map(async (fileId: string) => {
1772
+ // const file = await firebaseQuery.getDocData(["files", fileId]);
1773
+ // file.url = await getDownloadURL(ref(storage, `providers/${listingData?.providerId}/${file.fileName}`));
1663
1774
 
1664
- return [fileId, file];
1665
- }))) : [];
1666
- const applicantForms = s.forms ? Object.fromEntries(await Promise.all(s.forms?.map(async (formId: string) => {
1667
- return [formId, await firebaseQuery.getDocData(["forms", formId])];
1668
- }))) : [];
1775
+ // return [fileId, file];
1776
+ // }))) : [];
1777
+ // const applicantForms = s.forms ? Object.fromEntries(await Promise.all(s.forms?.map(async (formId: string) => {
1778
+ // return [formId, await firebaseQuery.getDocData(["forms", formId])];
1779
+ // }))) : [];
1669
1780
 
1670
- return {...s, viewableFiles: applicantFiles, formDetails: applicantForms};
1671
- }));
1672
- delete workflow.id;
1673
- }
1674
- if (address) {
1675
- delete address.id;
1676
- }
1677
-
1678
- console.log("Setting listing")
1679
- setFListing((listingData && workflow) ? {...listingData, ...address, applicantWorkflow: workflow.workflow} as PlacementListing : false);
1680
-
1681
-
1682
- if ((fProvider?.id === application?.providerId) && user.product === "providers") {
1683
- setFProvider({details: orgContext?.details, id: user.oId});
1684
- } else if (listingData && listingData?.providerId) {
1685
- console.log("Getting provider from DB");
1686
- const provider = await firebaseQuery.getDocData(["providers", listingData.providerId]) as ProviderData;
1687
- console.log("Provider", provider);
1688
- setFProvider({details: provider, id: listingData.providerId});
1689
- }
1690
- }
1691
-
1692
- getListing();
1693
- }, [listingId, listing]);
1781
+ // return {...s, viewableFiles: applicantFiles, formDetails: applicantForms};
1782
+ // }));
1783
+ // delete workflow.id;
1784
+ // }
1785
+ // if (address) {
1786
+ // delete address.id;
1787
+ // }
1788
+
1789
+ // console.log("Setting listing")
1790
+ // setFListing((listingData && workflow) ? {...listingData, ...address, applicantWorkflow: workflow.workflow} as PlacementListing : false);
1791
+
1792
+
1793
+ // if ((fProvider?.id === application?.providerId) && user.product === "providers") {
1794
+ // setFProvider({details: orgContext?.details, id: user.oId});
1795
+ // } else if (listingData && listingData?.providerId) {
1796
+ // console.log("Getting provider from DB");
1797
+ // const provider = await firebaseQuery.getDocData(["providers", listingData.providerId]) as ProviderData;
1798
+ // console.log("Provider", provider);
1799
+ // setFProvider({details: provider, id: listingData.providerId});
1800
+ // }
1801
+ // }
1802
+
1803
+ // getListing();
1804
+ // }, [listingId, listing]);
1694
1805
 
1695
- useEffect(() => {
1696
- if (student?.id !== application?.uid) {
1697
- if (user.userType === "Students") {
1698
- setStudent(user);
1699
- } else if (user.product === "providers" && application?.uid) {
1700
- firebaseQuery.getDocData(["users", application.uid]).then((s) => setStudent(s as UserData));
1701
- }
1702
- }
1703
- }, []);
1806
+ // useEffect(() => {
1807
+ // if (student?.id !== application?.uid) {
1808
+ // if (user.userType === "Students") {
1809
+ // setStudent(user);
1810
+ // } else if (user.product === "providers" && application?.uid) {
1811
+ // firebaseQuery.getDocData(["users", application.uid]).then((s) => setStudent(s as UserData));
1812
+ // }
1813
+ // }
1814
+ // }, []);
1704
1815
 
1705
- useEffect(() => {
1706
- setFListing(Object.keys(listing || {}).length > 5 ? listing : undefined);
1707
- }, [listing]);
1816
+ // useEffect(() => {
1817
+ // setFListing(Object.keys(listing || {}).length > 5 ? listing : undefined);
1818
+ // }, [listing]);
1708
1819
 
1709
- useEffect(() => {
1710
- if (provider?.profile) return;
1711
- if (!provider?.id) return;
1820
+ // useEffect(() => {
1821
+ // if (provider?.profile) return;
1822
+ // if (!provider?.id) return;
1712
1823
 
1713
- getDownloadURL(ref(storage, `providers/${provider?.id}/profilePic.png`)).then(setProfileUrl).catch(() => null);
1714
- }, [provider]);
1824
+ // getDownloadURL(ref(storage, `providers/${provider?.id}/profilePic.png`)).then(setProfileUrl).catch(() => null);
1825
+ // }, [provider]);
1715
1826
 
1716
1827
 
1717
- useEffect(() => {
1718
- console.log("APPLICATIONID", applicationId);
1719
- if (!applicationId) {
1720
- if (!listingId) return;
1721
- firebaseQuery.getDocsWhere("applications", [where("status", "not-in", ["approved", "declined"]), where("uid", "==", user.id), where("listingId", "==", listingId)]).then((existingApplication) => {
1722
- console.log("EXISTING", existingApplication);
1723
- // get uploaded files
1724
- if (existingApplication && Object.keys(existingApplication).length) {
1725
- setFApplication(Object.values(existingApplication)[0]);
1726
- setFApplicationId(Object.keys(existingApplication)[0]);
1727
- }
1728
- });
1729
- return;
1730
- }
1731
- if (applicationId) {
1732
- setFApplicationId(applicationId);
1733
- if (application) {
1734
- let applicationWithoutAdditionalData = {...(application || {})} as any;
1735
- delete applicationWithoutAdditionalData.listing;
1736
- delete applicationWithoutAdditionalData.address;
1737
- delete applicationWithoutAdditionalData.provider;
1738
- setFApplication(applicationWithoutAdditionalData);
1739
- } else {
1740
- firebaseQuery.getDocData(["applications", applicationId]).then(setFApplication);
1741
- }
1742
- }
1743
- }, [application, applicationId]);
1744
-
1745
- const getCurrentStage = async (stage: number): Promise<{
1746
- stage: ApplicantStage; completedSections: {
1747
- submitted?: string | undefined;
1748
- filesViewed?: string[] | undefined;
1749
- formsCompleted?: {
1750
- [key: string]: unknown;
1751
- } | undefined;
1752
- filesUploaded?: {
1753
- [key: number]: string[];
1754
- } | undefined;
1755
- };
1756
- }> => {
1757
- console.log("fLSITING CURRENT STAGE", fListing);
1758
- if (!fListing) throw new Error("Listing deleted");
1759
- if (!fListing?.applicantWorkflowId) throw new Error("No workflow stage");
1760
-
1761
- const mApplicantWorkflow = (await firebaseQuery.getDocData(["applicantWorkflows", fListing.applicantWorkflowId]) as ApplicantWorkflow);
1762
-
1763
- const stageObj = mApplicantWorkflow?.workflow?.find((s) => s.id === stage);
1764
-
1765
- if (!stageObj) throw new Error("Can't find stage.");
1766
-
1767
- const applicantFiles = stageObj.files ? Object.fromEntries(await Promise.all(stageObj.files?.map(async (fileId) => {
1768
- const file = await firebaseQuery.getDocData(["files", fileId]);
1769
- file.url = await getDownloadURL(ref(storage, `providers/${mApplicantWorkflow?.oId}/${file.fileName}`));
1770
-
1771
- return [fileId, file];
1772
- }))) : [];
1773
- const applicantForms = stageObj.forms ? Object.fromEntries(await Promise.all(stageObj.forms?.map(async (formId) => {
1774
- return [formId, await firebaseQuery.getDocData(["forms", formId])];
1775
- }))) : [];
1776
-
1777
- stageObj.viewableFiles = applicantFiles;
1778
- stageObj.formDetails = applicantForms;
1828
+ // useEffect(() => {
1829
+ // console.log("APPLICATIONID", applicationId);
1830
+ // if (!applicationId) {
1831
+ // if (!listingId) return;
1832
+ // firebaseQuery.getDocsWhere("applications", [where("status", "not-in", ["approved", "declined"]), where("uid", "==", user.id), where("listingId", "==", listingId)]).then((existingApplication) => {
1833
+ // console.log("EXISTING", existingApplication);
1834
+ // // get uploaded files
1835
+ // if (existingApplication && Object.keys(existingApplication).length) {
1836
+ // setFApplication(Object.values(existingApplication)[0]);
1837
+ // setFApplicationId(Object.keys(existingApplication)[0]);
1838
+ // }
1839
+ // });
1840
+ // return;
1841
+ // }
1842
+ // if (applicationId) {
1843
+ // setFApplicationId(applicationId);
1844
+ // if (application) {
1845
+ // let applicationWithoutAdditionalData = {...(application || {})} as any;
1846
+ // delete applicationWithoutAdditionalData.listing;
1847
+ // delete applicationWithoutAdditionalData.address;
1848
+ // delete applicationWithoutAdditionalData.provider;
1849
+ // setFApplication(applicationWithoutAdditionalData);
1850
+ // } else {
1851
+ // firebaseQuery.getDocData(["applications", applicationId]).then(setFApplication);
1852
+ // }
1853
+ // }
1854
+ // }, [application, applicationId]);
1855
+
1856
+ // const getCurrentStage = async (stage: number): Promise<{
1857
+ // stage: ApplicantStage; completedSections: {
1858
+ // submitted?: string | undefined;
1859
+ // filesViewed?: string[] | undefined;
1860
+ // formsCompleted?: {
1861
+ // [key: string]: unknown;
1862
+ // } | undefined;
1863
+ // filesUploaded?: {
1864
+ // [key: number]: string[];
1865
+ // } | undefined;
1866
+ // };
1867
+ // }> => {
1868
+ // console.log("fLSITING CURRENT STAGE", fListing);
1869
+ // if (!fListing) throw new Error("Listing deleted");
1870
+ // if (!fListing?.applicantWorkflowId) throw new Error("No workflow stage");
1871
+
1872
+ // const mApplicantWorkflow = (await firebaseQuery.getDocData(["applicantWorkflows", fListing.applicantWorkflowId]) as ApplicantWorkflow);
1873
+
1874
+ // const stageObj = mApplicantWorkflow?.workflow?.find((s) => s.id === stage);
1875
+
1876
+ // if (!stageObj) throw new Error("Can't find stage.");
1877
+
1878
+ // const applicantFiles = stageObj.files ? Object.fromEntries(await Promise.all(stageObj.files?.map(async (fileId) => {
1879
+ // const file = await firebaseQuery.getDocData(["files", fileId]);
1880
+ // file.url = await getDownloadURL(ref(storage, `providers/${mApplicantWorkflow?.oId}/${file.fileName}`));
1881
+
1882
+ // return [fileId, file];
1883
+ // }))) : [];
1884
+ // const applicantForms = stageObj.forms ? Object.fromEntries(await Promise.all(stageObj.forms?.map(async (formId) => {
1885
+ // return [formId, await firebaseQuery.getDocData(["forms", formId])];
1886
+ // }))) : [];
1887
+
1888
+ // stageObj.viewableFiles = applicantFiles;
1889
+ // stageObj.formDetails = applicantForms;
1779
1890
 
1780
- return {stage: stageObj, completedSections: fApplication?.completedSections?.[stage] || {}};
1781
- };
1891
+ // return {stage: stageObj, completedSections: fApplication?.completedSections?.[stage] || {}};
1892
+ // };
1782
1893
 
1783
- useEffect(() => {
1784
- const getUploadedFiles = async () => {
1785
- if (!fApplication.completedSections) {
1786
- setUploadedFiles({});
1787
- return
1788
- };
1894
+ // useEffect(() => {
1895
+ // const getUploadedFiles = async () => {
1896
+ // if (!fApplication.completedSections) {
1897
+ // setUploadedFiles({});
1898
+ // return
1899
+ // };
1789
1900
 
1790
- const fileIds = Object.values(fApplication.completedSections)
1791
- .flatMap(stageData =>
1792
- Object.values(stageData.filesUploaded || {}).flatMap(fileIds => fileIds)
1793
- );
1901
+ // const fileIds = Object.values(fApplication.completedSections)
1902
+ // .flatMap(stageData =>
1903
+ // Object.values(stageData.filesUploaded || {}).flatMap(fileIds => fileIds)
1904
+ // );
1794
1905
 
1795
- const fileDataPromises = fileIds.map(async (fileId) => {
1796
- const fileData = await firebaseQuery.getDocData(["files", fileId]) as FileItem;
1797
- fileData.url = await getDownloadURL(ref(storage, `userFiles/${fileData.fileName}`));
1906
+ // const fileDataPromises = fileIds.map(async (fileId) => {
1907
+ // const fileData = await firebaseQuery.getDocData(["files", fileId]) as FileItem;
1908
+ // fileData.url = await getDownloadURL(ref(storage, `userFiles/${fileData.fileName}`));
1798
1909
 
1799
- return [fileId, fileData] as [string, FileItem]
1800
- });
1910
+ // return [fileId, fileData] as [string, FileItem]
1911
+ // });
1801
1912
 
1802
- const fileDataArray = await Promise.all(fileDataPromises);
1803
- const fileDataObj = Object.fromEntries(fileDataArray)
1804
- setUploadedFiles(fileDataObj)
1805
- }
1806
-
1807
- const addApplication = async () => {
1808
- console.log("ADDING APPLICATION");
1809
- if (!fListing || !fListing?.id || !fProvider?.id || !student?.id) return;
1810
-
1811
- const applicationData = {
1812
- uid: student.id,
1813
- listingId: fListing?.id,
1814
- addressId: fListing.addressId,
1815
- applicantWorkflowId: fListing?.applicantWorkflowId,
1816
- providerId: fProvider.id,
1817
- stage: 1,
1818
- status: "draft",
1819
- created: (new Date()).toISOString(),
1820
- ...fApplication,
1821
- } as Partial<Application>;
1822
- const mApplicationId = (await firebaseQuery.add(["applications"], applicationData)).id;
1823
- console.log("APPLICATION ADDED");
1824
- setFApplicationId(mApplicationId);
1825
- setFApplication(applicationData);
1826
- setDraftSaved(true);
1827
- return;
1828
- };
1829
- getUploadedFiles();
1830
-
1831
- console.log("Checking IDs");
1832
-
1833
- if (!fListing || !fListing?.id || !fProvider?.id || !student?.id) return;
1834
- if (user.product === "providers") return;
1835
-
1836
- console.log("Checking dates and sections");
1837
- if (!fApplication.completedSections && !fApplication.startDate && !fApplication.endDate) return;
1838
-
1839
- console.log("Application updated");
1840
- if (!fApplicationId && !applicationId) {
1841
- // save new
1842
- console.log("Add application")
1843
- addApplication();
1844
- return;
1845
- }
1846
- // update
1847
- firebaseQuery.update(["applications", (fApplicationId || applicationId) as string], fApplication);
1848
- setDraftSaved(true);
1849
- }, [fApplication]);
1913
+ // const fileDataArray = await Promise.all(fileDataPromises);
1914
+ // const fileDataObj = Object.fromEntries(fileDataArray)
1915
+ // setUploadedFiles(fileDataObj)
1916
+ // }
1917
+
1918
+ // const addApplication = async () => {
1919
+ // console.log("ADDING APPLICATION");
1920
+ // if (!fListing || !fListing?.id || !fProvider?.id || !student?.id) return;
1921
+
1922
+ // const applicationData = {
1923
+ // uid: student.id,
1924
+ // listingId: fListing?.id,
1925
+ // addressId: fListing.addressId,
1926
+ // applicantWorkflowId: fListing?.applicantWorkflowId,
1927
+ // providerId: fProvider.id,
1928
+ // stage: 1,
1929
+ // status: "draft",
1930
+ // created: (new Date()).toISOString(),
1931
+ // ...fApplication,
1932
+ // } as Partial<Application>;
1933
+ // const mApplicationId = (await firebaseQuery.add(["applications"], applicationData)).id;
1934
+ // console.log("APPLICATION ADDED");
1935
+ // setFApplicationId(mApplicationId);
1936
+ // setFApplication(applicationData);
1937
+ // setDraftSaved(true);
1938
+ // return;
1939
+ // };
1940
+ // getUploadedFiles();
1941
+
1942
+ // console.log("Checking IDs");
1943
+
1944
+ // if (!fListing || !fListing?.id || !fProvider?.id || !student?.id) return;
1945
+ // if (user.product === "providers") return;
1946
+
1947
+ // console.log("Checking dates and sections");
1948
+ // if (!fApplication.completedSections && !fApplication.startDate && !fApplication.endDate) return;
1949
+
1950
+ // console.log("Application updated");
1951
+ // if (!fApplicationId && !applicationId) {
1952
+ // // save new
1953
+ // console.log("Add application")
1954
+ // addApplication();
1955
+ // return;
1956
+ // }
1957
+ // // update
1958
+ // firebaseQuery.update(["applications", (fApplicationId || applicationId) as string], fApplication);
1959
+ // setDraftSaved(true);
1960
+ // }, [fApplication]);
1850
1961
 
1851
- const openSuccessPopup = (type: "submitted"|"draftSaved"|"stageComplete"|"outcome") => {
1852
- setSuccessPopup(type);
1853
- setTimeout(() => {
1854
- // onClose();
1855
- }, 1500);
1856
- };
1962
+ // const openSuccessPopup = (type: "submitted"|"draftSaved"|"stageComplete"|"outcome") => {
1963
+ // setSuccessPopup(type);
1964
+ // setTimeout(() => {
1965
+ // // onClose();
1966
+ // }, 1500);
1967
+ // };
1857
1968
 
1858
- useEffect(() => {
1969
+ // useEffect(() => {
1859
1970
 
1860
- const areStagesCompleted = async ():Promise<boolean|undefined> => {
1861
- if (!fListing) return;
1862
- if (fApplication.stage === undefined) return undefined;
1863
- const currentStage = await getCurrentStage(fApplication.stage);
1971
+ // const areStagesCompleted = async ():Promise<boolean|undefined> => {
1972
+ // if (!fListing) return;
1973
+ // if (fApplication.stage === undefined) return undefined;
1974
+ // const currentStage = await getCurrentStage(fApplication.stage);
1864
1975
 
1865
- console.log("Checking current stage is complete");
1976
+ // console.log("Checking current stage is complete");
1866
1977
 
1867
- for (const fileViewed of currentStage.stage?.files || []) {
1868
- console.log("Checking file viewed", fileViewed, "in", currentStage?.completedSections?.filesViewed);
1869
- if (!currentStage?.completedSections?.filesViewed?.includes(fileViewed)) {
1870
- console.log("File not viewed");
1871
- return false;
1872
- } else {
1873
- console.log("File viewed");
1874
- }
1875
- }
1876
- for (const formCompleted of currentStage?.stage?.forms || []) {
1877
- console.log("Checking form completed", formCompleted, "in", currentStage?.completedSections?.formsCompleted);
1878
-
1879
- if (!Object.keys(currentStage?.completedSections?.formsCompleted || {}).includes(formCompleted)) {
1880
- console.log("Form not completed");
1881
- return false;
1882
- } else {
1883
- console.log("Form completed")
1884
- }
1885
- }
1886
- for (let i = 0; i++; i < (currentStage?.stage?.requiredFiles || []).length) {
1887
- if (!Object.keys(currentStage?.completedSections?.filesUploaded || {}).includes(i.toString())) {
1888
- console.log("Form not uploaded");
1889
- return false;
1890
- } else {
1891
- console.log("Form uploaded");
1892
- }
1893
- }
1978
+ // for (const fileViewed of currentStage.stage?.files || []) {
1979
+ // console.log("Checking file viewed", fileViewed, "in", currentStage?.completedSections?.filesViewed);
1980
+ // if (!currentStage?.completedSections?.filesViewed?.includes(fileViewed)) {
1981
+ // console.log("File not viewed");
1982
+ // return false;
1983
+ // } else {
1984
+ // console.log("File viewed");
1985
+ // }
1986
+ // }
1987
+ // for (const formCompleted of currentStage?.stage?.forms || []) {
1988
+ // console.log("Checking form completed", formCompleted, "in", currentStage?.completedSections?.formsCompleted);
1989
+
1990
+ // if (!Object.keys(currentStage?.completedSections?.formsCompleted || {}).includes(formCompleted)) {
1991
+ // console.log("Form not completed");
1992
+ // return false;
1993
+ // } else {
1994
+ // console.log("Form completed")
1995
+ // }
1996
+ // }
1997
+ // for (let i = 0; i++; i < (currentStage?.stage?.requiredFiles || []).length) {
1998
+ // if (!Object.keys(currentStage?.completedSections?.filesUploaded || {}).includes(i.toString())) {
1999
+ // console.log("Form not uploaded");
2000
+ // return false;
2001
+ // } else {
2002
+ // console.log("Form uploaded");
2003
+ // }
2004
+ // }
1894
2005
 
1895
- return true;
1896
- };
2006
+ // return true;
2007
+ // };
1897
2008
 
1898
- areStagesCompleted().then(setCurrentStageComplete);
1899
- }, [fApplication, fListing])
2009
+ // areStagesCompleted().then(setCurrentStageComplete);
2010
+ // }, [fApplication, fListing])
1900
2011
 
1901
- const viewFile = (file: string, onOpen: (url: string) => void) => {
1902
- if (fApplication.reqUserType !== user.userType) return;
1903
- if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
1904
- if (!fListing) throw new Error("No associated listing.");
2012
+ // const viewFile = (file: string, onOpen: (url: string) => void) => {
2013
+ // if (fApplication.reqUserType !== user.userType) return;
2014
+ // if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
2015
+ // if (!fListing) throw new Error("No associated listing.");
1905
2016
 
1906
- const viewableFiles = fListing?.applicantWorkflow?.find((stage) => stage.id === fApplication.stage)?.viewableFiles;
2017
+ // const viewableFiles = fListing?.applicantWorkflow?.find((stage) => stage.id === fApplication.stage)?.viewableFiles;
1907
2018
 
1908
- setFApplication((a) => {
1909
- const oldA = {...a};
1910
- const viewedFiles = a.completedSections?.[1]?.filesViewed || [];
1911
- if (viewedFiles?.includes(file)) return a;
2019
+ // setFApplication((a) => {
2020
+ // const oldA = {...a};
2021
+ // const viewedFiles = a.completedSections?.[1]?.filesViewed || [];
2022
+ // if (viewedFiles?.includes(file)) return a;
1912
2023
 
1913
- viewableFiles?.[file].url && onOpen(viewableFiles?.[file].url);
1914
- viewedFiles?.push(file);
2024
+ // viewableFiles?.[file].url && onOpen(viewableFiles?.[file].url);
2025
+ // viewedFiles?.push(file);
1915
2026
 
1916
- const newA = editNestedObject(["completedSections", 1, "filesViewed"], oldA, viewedFiles) as Partial<Application>;
1917
- return newA;
1918
- });
1919
- };
1920
-
1921
- const addFile = (files: string[], fileId: number) => {
1922
- if (fApplication.reqUserType !== user.userType) throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
1923
- if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
1924
-
1925
- if (!files.length) throw new Error("No files to upload");
1926
- setFApplication((a) => editNestedObject(["completedSections", fApplication.stage as number, "filesUploaded", fileId], a, files) as Application);
1927
- };
1928
-
1929
- const setFormComplete = (formId: string, e: {[key: string]: unknown}) => {
1930
- if (fApplication.reqUserType !== user.userType) throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
1931
- if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
1932
- setFApplication((a) => editNestedObject(["completedSections", fApplication.stage as number, "formsCompleted", formId], a, e) as Application);
1933
- };
2027
+ // const newA = editNestedObject(["completedSections", 1, "filesViewed"], oldA, viewedFiles) as Partial<Application>;
2028
+ // return newA;
2029
+ // });
2030
+ // };
2031
+
2032
+ // const addFile = (files: string[], fileId: number) => {
2033
+ // if (fApplication.reqUserType !== user.userType) throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
2034
+ // if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
2035
+
2036
+ // if (!files.length) throw new Error("No files to upload");
2037
+ // setFApplication((a) => editNestedObject(["completedSections", fApplication.stage as number, "filesUploaded", fileId], a, files) as Application);
2038
+ // };
2039
+
2040
+ // const setFormComplete = (formId: string, e: {[key: string]: unknown}) => {
2041
+ // if (fApplication.reqUserType !== user.userType) throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
2042
+ // if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
2043
+ // setFApplication((a) => editNestedObject(["completedSections", fApplication.stage as number, "formsCompleted", formId], a, e) as Application);
2044
+ // };
1934
2045
 
1935
- const successText = {
1936
- submitted: {
1937
- title: "Application submitted",
1938
- desc: "We've sent your application to the placement provider. You will hear what the next steps are soon.",
1939
- },
1940
- draftSaved: {
1941
- title: "Draft saved",
1942
- desc: "Your draft has been saved. Go to the 'Applications' section from your home screen to edit.",
1943
- },
1944
- stageComplete: {
1945
- title: "Stage complete",
1946
- desc: "We have sent this to the next stage in the application process. We will update you with any progress.",
1947
- },
1948
- outcome: {
1949
- title: "Outcome submitted",
1950
- desc: "We have sent the student an email with the outcome of their application.",
1951
- },
1952
- };
1953
-
1954
- const onFApply = async (draft?: boolean) => {
1955
- if (draft) {
1956
- openSuccessPopup("draftSaved")
1957
- return;
1958
- }
1959
-
1960
- if (!fApplicationId) return;
2046
+ // const successText = {
2047
+ // submitted: {
2048
+ // title: "Application submitted",
2049
+ // desc: "We've sent your application to the placement provider. You will hear what the next steps are soon.",
2050
+ // },
2051
+ // draftSaved: {
2052
+ // title: "Draft saved",
2053
+ // desc: "Your draft has been saved. Go to the 'Applications' section from your home screen to edit.",
2054
+ // },
2055
+ // stageComplete: {
2056
+ // title: "Stage complete",
2057
+ // desc: "We have sent this to the next stage in the application process. We will update you with any progress.",
2058
+ // },
2059
+ // outcome: {
2060
+ // title: "Outcome submitted",
2061
+ // desc: "We have sent the student an email with the outcome of their application.",
2062
+ // },
2063
+ // };
2064
+
2065
+ // const onFApply = async (draft?: boolean) => {
2066
+ // if (draft) {
2067
+ // openSuccessPopup("draftSaved")
2068
+ // return;
2069
+ // }
2070
+
2071
+ // if (!fApplicationId) return;
1961
2072
 
1962
- // Check all items have been filled in.
1963
- if (!fApplication.startDate || !fApplication.endDate) throw new Error("Please select dates for your placement.");
2073
+ // // Check all items have been filled in.
2074
+ // if (!fApplication.startDate || !fApplication.endDate) throw new Error("Please select dates for your placement.");
1964
2075
 
1965
- await executeCallable("applications-submit", {applicationId: fApplicationId});
2076
+ // await executeCallable("applications-submit", {applicationId: fApplicationId});
1966
2077
 
1967
- const newApplication = await firebaseQuery.getDocData(["applications", fApplicationId]) as Application;
1968
- setFApplication(newApplication);
1969
- openSuccessPopup("submitted")
1970
- };
2078
+ // const newApplication = await firebaseQuery.getDocData(["applications", fApplicationId]) as Application;
2079
+ // setFApplication(newApplication);
2080
+ // openSuccessPopup("submitted")
2081
+ // };
1971
2082
 
1972
- const progressStage = async (type: number|"accept"|"reject", e?: {feedback?: string}) => {
1973
- // Check all stages completed.
1974
- if (!fApplicationId) return;
1975
- if (!currentStageComplete) throw new Error("Complete all forms before submitting.");
1976
- if (fApplication.reqUserType !== user.userType) throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
1977
- if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
1978
-
1979
- await executeCallable("applications-changeStage", {applicationId: fApplicationId, type: type, feedback: e?.feedback});
1980
- const newApplication = await firebaseQuery.getDocData(["applications", fApplicationId]) as Application;
1981
- setFApplication(newApplication);
1982
- };
2083
+ // const progressStage = async (type: number|"accept"|"reject", e?: {feedback?: string}) => {
2084
+ // // Check all stages completed.
2085
+ // if (!fApplicationId) return;
2086
+ // if (!currentStageComplete) throw new Error("Complete all forms before submitting.");
2087
+ // if (fApplication.reqUserType !== user.userType) throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
2088
+ // if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
2089
+
2090
+ // await executeCallable("applications-changeStage", {applicationId: fApplicationId, type: type, feedback: e?.feedback});
2091
+ // const newApplication = await firebaseQuery.getDocData(["applications", fApplicationId]) as Application;
2092
+ // setFApplication(newApplication);
2093
+ // };
1983
2094
 
1984
2095
 
1985
- return {successText, onFApply, progressStage, currentStageComplete, uploadedFiles, getCurrentStage, setFormComplete, viewFile, addFile, setSuccessPopup, openSuccessPopup, setFApplication, fApplication, draftSaved, profileUrl, successPopup, fApplicationId, fListing, student, fProvider}
1986
- }
2096
+ // return {successText, onFApply, progressStage, currentStageComplete, uploadedFiles, getCurrentStage, setFormComplete, viewFile, addFile, setSuccessPopup, openSuccessPopup, setFApplication, fApplication, draftSaved, profileUrl, successPopup, fApplicationId, fListing, student, fProvider}
2097
+ // }
1987
2098
 
1988
2099
  export function useProposePlacementRenderer({user, orgContext, placement}:
1989
2100
  {user:UserData, orgContext?: {details: InstituteData, userGroups: {[key:string]: UserGroupData}, forms: {[key:string]: unknown}, cohorts: {[key:string]: CohortData}},
@@ -2046,11 +2157,9 @@ export function useProposePlacementRenderer({user, orgContext, placement}:
2046
2157
 
2047
2158
  const submitSection = (type:"dates"|"provider"|"address", data:{[key:string]:unknown}) => {
2048
2159
  setFormData((f) => {
2049
- const { id, ...values } = data
2050
2160
  return {
2051
2161
  ...f,
2052
- ...values,
2053
- id: (placement?.placementId || formData?.id) as string
2162
+ ...data
2054
2163
  } as StudentPlacementData;
2055
2164
  });
2056
2165
  if (placement?.placementId && type === "dates") {
@@ -2137,8 +2246,8 @@ type CreateCohortRendererParams = {
2137
2246
  initialData ?: CohortData
2138
2247
  }
2139
2248
 
2140
- export type CreateCohortStages = "info"|"name"|"placementType"|"review";
2141
- const cohortStages = ["info", "name", "placementType", "review", "created"];
2249
+ export type CreateCohortStages = "info"|"name"|"placementType"|"database"|"review";
2250
+ const cohortStages = ["info", "name", "placementType", "database", "review", "created"];
2142
2251
 
2143
2252
  const defaultCohortData:CohortData = {
2144
2253
  name: "",
@@ -3039,41 +3148,42 @@ function useGenericWorkflowEditor({user, initialData, defaultData, onSubmit}: Ge
3039
3148
  onDeleteArrow, fWorkflowNodes, containerRef, setError, setArrows, setFWorkflowNodes}});
3040
3149
  }
3041
3150
 
3042
- type InstitutePlacementListingUploadParams = {
3151
+ type InstituteProviderContactUploadParams = {
3043
3152
  user: UserData,
3044
3153
  onComplete?: () => void
3045
3154
  }
3046
3155
 
3047
- export type InstitutePlacementListingUpload = {
3048
- provider: string;
3049
- jobTitle: string;
3156
+ export type InstituteProviderContactUpload = {
3157
+ business: string;
3158
+ forename?: string;
3159
+ surname?: string;
3050
3160
  email: string;
3051
3161
  phone?: string;
3052
- addressOne: string;
3053
- addressTwo: string;
3054
- city: string;
3055
- postcode: string;
3056
- country: string;
3162
+ addressOne?: string;
3163
+ addressTwo?: string;
3164
+ city?: string;
3165
+ postcode?: string;
3166
+ country?: string;
3057
3167
  };
3058
3168
 
3059
- export function useInstitutePlacementListingHandler({user}: InstitutePlacementListingUploadParams) {
3169
+ export function useInstituteProviderContactsHandler({user}: InstituteProviderContactUploadParams) {
3060
3170
  const [emptyCellsWarning, setEmptyCellsWarning] = useState(false);
3061
3171
  const [alert, setAlert] = useState<{severity: "warning"|"error"|"success"|"info", msg: string}>();
3062
3172
 
3063
- const requiredFields = ["name", "jobTitle", "email", "addressOne", "city", "postCode", "country"];
3173
+ const requiredFields = ["business", "forename", "email"];
3064
3174
  const {execute} = useExecuteCallableJob({user: user});
3065
3175
 
3066
- const checkData = (placements: InstitutePlacementListingUpload[]) => {
3176
+ const checkData = (providerContacts: InstituteProviderContactUpload[]) => {
3067
3177
  setAlert(undefined);
3068
3178
 
3069
- placements = placements.filter((u) => Object.entries(u).some(([, v]) => v));
3179
+ providerContacts = providerContacts.filter((u) => Object.entries(u).some(([, v]) => v));
3070
3180
 
3071
- if (!Object.entries(placements)) {
3181
+ if (!Object.entries(providerContacts)) {
3072
3182
  return [];
3073
3183
  }
3074
- console.log("P", placements);
3184
+ console.log("P", providerContacts);
3075
3185
 
3076
- if (placements.filter((u) => u.email).length < placements.length) {
3186
+ if (providerContacts.filter((u) => u.email).length < providerContacts.length) {
3077
3187
  setAlert({msg: "Your data contains missing email addresses.", severity: "error"});
3078
3188
  return false;
3079
3189
  }
@@ -3081,18 +3191,18 @@ export function useInstitutePlacementListingHandler({user}: InstitutePlacementLi
3081
3191
  let emptyOptionalCell = false;
3082
3192
  let emptyRequiredCell = false;
3083
3193
 
3084
- for (const placement of placements ) {
3085
- if (!checkEmailValidity(placement)) {
3194
+ for (const providerContact of providerContacts ) {
3195
+ if (!checkEmailValidity(providerContact)) {
3086
3196
  return false;
3087
3197
  }
3088
3198
 
3089
- if (Object.keys(placement).includes("")) {
3199
+ if (Object.keys(providerContact).includes("")) {
3090
3200
  setAlert({msg: "Data cannot be uploaded in unnamed columns.", severity: "error"});
3091
3201
  return false;
3092
3202
  }
3093
3203
 
3094
- for (const field in placement) {
3095
- if (!placement[field]) {
3204
+ for (const field in providerContact) {
3205
+ if (!providerContact[field]) {
3096
3206
  if (requiredFields.includes(field)) {
3097
3207
  setAlert({msg: "All users must contain "+requiredFields.join(", "), severity: "error"});
3098
3208
  emptyRequiredCell = true;
@@ -3113,44 +3223,30 @@ export function useInstitutePlacementListingHandler({user}: InstitutePlacementLi
3113
3223
  } else {
3114
3224
  setEmptyCellsWarning(false);
3115
3225
  }
3116
- return placements;
3226
+ return providerContacts;
3117
3227
  };
3118
3228
 
3119
- const checkEmailValidity = (placement: InstitutePlacementListingUpload) => {
3120
- if (!validateEmail(placement.email as string)) {
3121
- setAlert({msg: `Error in email formatting: ${placement.email}. Amend errors and reupload.`, severity: "error"});
3229
+ const checkEmailValidity = (providerContact: InstituteProviderContactUpload) => {
3230
+ if (!validateEmail(providerContact.email as string)) {
3231
+ setAlert({msg: `Error in email formatting: ${providerContact.email}. Amend errors and reupload.`, severity: "error"});
3122
3232
  return false;
3123
3233
  }
3124
3234
  return true;
3125
3235
  };
3126
3236
 
3127
- const uploadPlacements = async (placements: InstitutePlacementListingUpload[]) => {
3128
- let fPlacements:InstitutePlacementListingUpload[] = [];
3129
- console.log("PP", placements);
3237
+ const uploadProviderContacts = async (providers: InstituteProviderContactUpload[], schoolId?: string) => {
3238
+ let fProviders:InstituteProviderContactUpload[] = [];
3239
+ console.log("PP", providers);
3130
3240
 
3131
- const cleanUpload = checkData(placements);
3241
+ const cleanUpload = checkData(providers);
3132
3242
  if (!cleanUpload) {
3133
3243
  return false;
3134
3244
  }
3135
- fPlacements = cleanUpload;
3245
+ fProviders = cleanUpload;
3136
3246
 
3137
3247
  setAlert(undefined);
3138
- if (fPlacements.length) {
3139
- const formattedPlacements = fPlacements.map((v) =>
3140
- ({
3141
- name: v.provider,
3142
- title: v.jobTitle,
3143
- providerEmail: v.email,
3144
- providerPhone: v.phone,
3145
- ["address-line1"]: v.addressOne,
3146
- ["address-line2"]: v.addressTwo,
3147
- locality: v.city,
3148
- postal_code: v.postcode,
3149
- country: v.country,
3150
- }));
3151
- console.log("P", placements);
3152
- console.log("callable params", {placements: formattedPlacements, instituteId: user.product === "admin" ? "admin" : user.oId});
3153
- execute("placementListing-add", {data: formattedPlacements, instituteId: user.product === "admin" ? "admin" : user.oId});
3248
+ if (fProviders.length) {
3249
+ execute("providerContacts-add", {providerContacts: fProviders, instituteId: user.product === "admin" ? "admin" : user.oId, schoolId: schoolId});
3154
3250
  }
3155
3251
  return true;
3156
3252
  };
@@ -3160,7 +3256,7 @@ export function useInstitutePlacementListingHandler({user}: InstitutePlacementLi
3160
3256
  setEmptyCellsWarning(false);
3161
3257
  };
3162
3258
 
3163
- return ({...{uploadPlacements, alert, onChange}});
3259
+ return ({...{uploadProviderContacts, alert, onChange}});
3164
3260
  }
3165
3261
 
3166
3262
 
@@ -3175,7 +3271,7 @@ export function useGetIndividualPlacementForPlacementPage({user, placementId, or
3175
3271
  const [disableEmail, setDisableEmail] = useState({parent: false, provider: false});
3176
3272
  const [rejectELIPopup, setRejectELIPopup] = useState(false);
3177
3273
  const [eliPopupOpen, setEliPopupOpen] = useState(false);
3178
- const [eliURL, setELIURL] = useState("");
3274
+ const [eliData, setELIData] = useState<string>();
3179
3275
 
3180
3276
  const [rejectExternalDocPopup, setRejectExternalDocPopup] = useState<"riskAssessment"|"dbsCheck"|false>(false);
3181
3277
  const [externalDocPopupOpen, setExternalDocPopupOpen] = useState<"riskAssessment"|"dbsCheck"|false>(false);
@@ -3356,10 +3452,10 @@ export function useGetIndividualPlacementForPlacementPage({user, placementId, or
3356
3452
  setShareStudentRequestPopup(true);
3357
3453
  }
3358
3454
  if (e === "noInsurance") {
3359
- if (!eliURL) {
3360
- const storageRef = ref(storage, `insurance/${placement.providerId}.pdf`);
3361
- const file = await getDownloadURL(storageRef);
3362
- setELIURL(file);
3455
+ if (!eliData) {
3456
+ const storageRef = ref(storage, `insurance/${placement.providerContactId}.pdf`);
3457
+ const file = await getDownloadURL(storageRef).catch(() => placement.insuranceSkippedReason);
3458
+ setELIData(file);
3363
3459
  }
3364
3460
  setEliPopupOpen(true);
3365
3461
  }
@@ -3391,15 +3487,15 @@ export function useGetIndividualPlacementForPlacementPage({user, placementId, or
3391
3487
 
3392
3488
  const approveELI = async () => {
3393
3489
  if (!placement) return;
3394
- await executeCallable("insurance-approve", {oId: user.oId, providerId: placement.providerId});
3490
+ await executeCallable("insurance-approve", {oId: user.oId, providerContactId: placement.providerContactId});
3395
3491
  setEliPopupOpen(false);
3396
3492
  };
3397
3493
 
3398
3494
  const rejectELI = async ({reason}:{reason: string}) => {
3399
3495
  if (!placement || !institute) return;
3400
3496
 
3401
- console.log("Reject", {reason: reason, placement: placement, instituteName: institute.name, staffEmail: user.email});
3402
- await executeCallable("insurance-reject", {reason: reason, placementId: placementId, instituteName: institute.name, staffEmail: user.email});
3497
+ console.log("Reject", {reason: reason, placement: placement, instituteName: institute.name});
3498
+ await executeCallable("insurance-reject", {reason: reason, placementId: placementId, instituteName: institute.name});
3403
3499
  setRejectELIPopup(false);
3404
3500
  setEliPopupOpen(false);
3405
3501
  };
@@ -3420,10 +3516,12 @@ export function useGetIndividualPlacementForPlacementPage({user, placementId, or
3420
3516
  const manuallyConfigureProvider = async () => {
3421
3517
  if (!placement) return;
3422
3518
  if (!placement.providerId) {
3423
- const res = await executeCallable("placement-uploadProviderDetails", {
3424
- pId: placementId,
3425
- placement: Object.fromEntries(Object.entries(placement).filter(([k]) => k !== "contactId")),
3426
- stage: wStage,
3519
+ const res = await executeCallable("providerContacts-uploadProviderDetails", {
3520
+ placement: {
3521
+ id: placementId,
3522
+ data: Object.fromEntries(Object.entries(placement).filter(([k]) => k !== "contactId")),
3523
+ stage: wStage,
3524
+ },
3427
3525
  skipSearch: true}).catch((e) => {
3428
3526
  throw e;
3429
3527
  });
@@ -3447,7 +3545,7 @@ export function useGetIndividualPlacementForPlacementPage({user, placementId, or
3447
3545
  await executeCallable("placement-withdraw", {placementId: placementId});
3448
3546
  }
3449
3547
 
3450
- return {placement, wStage, student, workflow, editable, withdrawFromPlacementPopup, addOnboardingDocsPopup, setAddOnboardingDocsPopup, dismissOnboardingPopup, setDismissOnboardingPopup, setWithdrawFromPlacementPopup, withdrawFromPlacement, onFlagClick, setUploadInsurance, setUploadProviderDocPopup, setUploadRA, setUploadDBS, onboardingStatus, setSkipStagePopup, onboardingPopup, setViewExternalLinkPopup, setOnboardingPopup, setRejectELIPopup, eliURL, riskAssessmentURL, dbsCheckURL, setExternalLinkCopied, skipStagePopup, snackbar, setSnackbar, cohort, disableEmail, rejectELIPopup, eliPopupOpen, rejectExternalDocPopup, externalDocPopupOpen, viewExternalLinkPopup, externalLinkCopied, uploadInsurance, uploadRA, uploadDBS, editStage, sendEmail, canEdit, approveELI, setEliPopupOpen, uploadProviderDocPopup, rejectELI, setRejectExternalDocPopup, setExternalDocPopupOpen, approveProviderDoc, rejectProviderDoc, manuallyConfigureProvider, institute, shareStudentRequestPopup, setShareStudentRequestPopup}
3548
+ return {placement, wStage, student, workflow, editable, withdrawFromPlacementPopup, addOnboardingDocsPopup, setAddOnboardingDocsPopup, dismissOnboardingPopup, setDismissOnboardingPopup, setWithdrawFromPlacementPopup, withdrawFromPlacement, onFlagClick, setUploadInsurance, setUploadProviderDocPopup, setUploadRA, setUploadDBS, onboardingStatus, setSkipStagePopup, onboardingPopup, setViewExternalLinkPopup, setOnboardingPopup, setRejectELIPopup, eliData, riskAssessmentURL, dbsCheckURL, setExternalLinkCopied, skipStagePopup, snackbar, setSnackbar, cohort, disableEmail, rejectELIPopup, eliPopupOpen, rejectExternalDocPopup, externalDocPopupOpen, viewExternalLinkPopup, externalLinkCopied, uploadInsurance, uploadRA, uploadDBS, editStage, sendEmail, canEdit, approveELI, setEliPopupOpen, uploadProviderDocPopup, rejectELI, setRejectExternalDocPopup, setExternalDocPopupOpen, approveProviderDoc, rejectProviderDoc, manuallyConfigureProvider, institute, shareStudentRequestPopup, setShareStudentRequestPopup}
3451
3549
  }
3452
3550
 
3453
3551
  export function useOnboardingPopup({onboarding, providerId, placementId, user, onClose}:{onboarding: (
@@ -3810,17 +3908,8 @@ export function useLoadListings(user: UserData, queryConstraint?: QueryConstrain
3810
3908
  };
3811
3909
 
3812
3910
  useEffect(() => {
3813
- let unsubscribe: () => void;
3814
-
3815
-
3816
3911
 
3817
3912
  loadListings();
3818
-
3819
- return () => {
3820
- if (unsubscribe) {
3821
- unsubscribe(); // Unsubscribe from the snapshot listener when the component unmounts
3822
- }
3823
- };
3824
3913
  // eslint-disable-next-line react-hooks/exhaustive-deps
3825
3914
  }, [queryConstraints]);
3826
3915
 
@@ -3911,17 +4000,7 @@ export function useLoadProviderPlacements(user: UserData, queryConstraint?: Quer
3911
4000
  };
3912
4001
 
3913
4002
  useEffect(() => {
3914
- let unsubscribe: () => void;
3915
-
3916
-
3917
-
3918
4003
  loadListings();
3919
-
3920
- return () => {
3921
- if (unsubscribe) {
3922
- unsubscribe(); // Unsubscribe from the snapshot listener when the component unmounts
3923
- }
3924
- };
3925
4004
  // eslint-disable-next-line react-hooks/exhaustive-deps
3926
4005
  }, [queryConstraints]);
3927
4006
 
@@ -4016,14 +4095,7 @@ export function useLoadApplications({user, applicationType, listingId, queryCons
4016
4095
  };
4017
4096
 
4018
4097
  useEffect(() => {
4019
- let unsubscribe: () => void;
4020
-
4021
4098
  loadApplications();
4022
- return () => {
4023
- if (unsubscribe) {
4024
- unsubscribe(); // Unsubscribe from the snapshot listener when the component unmounts
4025
- }
4026
- };
4027
4099
  // eslint-disable-next-line react-hooks/exhaustive-deps
4028
4100
  }, [type, queryConstraints]);
4029
4101
 
@@ -4060,7 +4132,7 @@ export type DataViewerPaginater = {
4060
4132
  sorts?: Sorts
4061
4133
  }
4062
4134
 
4063
- export function useDataViewerPaginator({view: initialView, sorts, queryLimit, additionalEntryProcessing, formatItems, snapshot, filters: initialFilters, onSearch, data}:DataViewerPaginater) {
4135
+ export function useDataViewerPaginator({view: initialView, sorts, queryLimit=10, additionalEntryProcessing, formatItems, snapshot, filters: initialFilters, onSearch, data}:DataViewerPaginater) {
4064
4136
  const [tableData, setTableData] = useState<{[key:string]:{[key:string]: unknown}}>(Array.isArray(data) ? Object.fromEntries(Object.entries(data).slice(0, queryLimit)) : {});
4065
4137
  const [page, setPage] = useState([1, 0]);
4066
4138
  const [view, setView] = useState(initialView);
@@ -4117,7 +4189,7 @@ export function useDataViewerPaginator({view: initialView, sorts, queryLimit, ad
4117
4189
  const getDataFromQuery = async (
4118
4190
  itemList: {[key: string]: any} = {}, currentQueryAnchor=queryAnchor, cursorDirection?:"increase"|"decrease"|undefined, prevEntries=prevEntryIds, loadMoreFromQuery=false):Promise<any> => {
4119
4191
 
4120
- if (!filters) return;
4192
+ // if (!filters) return;
4121
4193
  setLoading(true);
4122
4194
  if (!Array.isArray(data)) {
4123
4195
  setTableDataFromDefinedData();
@@ -4127,8 +4199,8 @@ export function useDataViewerPaginator({view: initialView, sorts, queryLimit, ad
4127
4199
 
4128
4200
  if (onSearch && (searchString || sort)) {
4129
4201
  if (typeof onSearch === "boolean") 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.");
4130
- const data = await onSearch(searchString, sort, page[0], filters, queryLimit);
4131
- const dataWithAdditionalProcessing: [string, any][] = await Promise.all(Object.entries(data).map(async ([k, v]) => [k, await processedData(k, v)]));
4202
+ const searchData = await onSearch(searchString, sort, page[0], filters, queryLimit);
4203
+ const dataWithAdditionalProcessing: [string, any][] = await Promise.all(Object.entries(searchData).map(async ([k, v]) => [k, await processedData(k, v)]));
4132
4204
 
4133
4205
  setTableData((old) => {
4134
4206
  if (view === "table") {
@@ -4287,8 +4359,11 @@ export function useDataViewerPaginator({view: initialView, sorts, queryLimit, ad
4287
4359
  Object.keys(itemList).length === 0 &&
4288
4360
  currentQueryAnchor.endQueryPos+1 === data.length &&
4289
4361
  page[0] > 1) {
4290
- setTableData({});
4362
+ if (view === "table") {
4363
+ setTableData({});
4364
+ }
4291
4365
  setQueryAnchor((a) => ({...a, startKey: ""}));
4366
+ setLoading("loaded");
4292
4367
  return;
4293
4368
  }
4294
4369
 
@@ -4327,8 +4402,25 @@ export function useDataViewerPaginator({view: initialView, sorts, queryLimit, ad
4327
4402
  }, [filters]);
4328
4403
 
4329
4404
  useEffect(() => {
4405
+ console.log("View reset.")
4330
4406
  reset();
4331
- }, [view, searchString, data, sort]);
4407
+ }, [view]);
4408
+
4409
+ useEffect(() => {
4410
+ console.log("search reset.")
4411
+ reset();
4412
+ }, [searchString]);
4413
+
4414
+ useEffect(() => {
4415
+ console.log("data reset.")
4416
+ reset();
4417
+ }, [data]);
4418
+
4419
+ useEffect(() => {
4420
+ console.log("sort reset.")
4421
+ reset();
4422
+ }, [sort]);
4423
+
4332
4424
 
4333
4425
  // Fetch new data when queries or page change
4334
4426
  useEffect(() => {