placementt-core 11.0.803 → 11.0.892

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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";
@@ -405,6 +405,100 @@ export function useNewInstitutePlacementList({id, user, filters, view, cohort, q
405
405
  }
406
406
 
407
407
 
408
+
409
+ type AlumniPaginatorParams = {
410
+ user?: UserData,
411
+ alumniConvoUser?: AlumniConvoUser,
412
+ school?: string,
413
+ queryConstraints?: QueryObjectConstraint,
414
+ ql?: number,
415
+ view: "list"|"table",
416
+ filters?: FilterObject,
417
+ }
418
+
419
+
420
+
421
+ export function useAlumniPaginator({user, alumniConvoUser, filters, view, school, queryConstraints, ql=DEFAULTQUERYLIMIT}:AlumniPaginatorParams) {
422
+ const [query, setQuery] = useState<QueryObject[]>();
423
+
424
+ const sorts:Sorts = {}
425
+
426
+
427
+ const {tableData, pageUp, pageDown, setFilters, page, setView, loading} = useDataViewerPaginator({view, filters, sorts, queryLimit: ql, data: query})
428
+ const firebaseQuery = new FirebaseQuery();
429
+
430
+ useEffect(() => {
431
+ const createQuery = async () => {
432
+ // Sets the query of for the DataViewerPaginator
433
+
434
+
435
+ const getQueryAccess = async () => {
436
+ const constraints:QueryObjectConstraint = [];
437
+
438
+ if (user) {
439
+ constraints.push(["oId", "==", user.oId]);
440
+
441
+ if (user.userGroup === "admin" && user.userType === "Staff") return constraints;
442
+
443
+ if (user.userType === "Staff") {
444
+ if (user.viewSchools === "all") return constraints;
445
+
446
+ if (user.viewSchools === "none") return false;
447
+
448
+ if (user.viewSchools === "some") {
449
+ if (!school) return false;
450
+
451
+ if (user?.visibleSchools?.includes(school as string)) return constraints;
452
+ }
453
+ return false;
454
+ }
455
+ return false;
456
+ }
457
+
458
+ if (alumniConvoUser) {
459
+ constraints.push(["oId", "==", alumniConvoUser.oId]);
460
+ console.log("ALUMNI CONVO USER");
461
+
462
+ if ((school || alumniConvoUser.schoolId) && school === alumniConvoUser.schoolId) return constraints;
463
+ console.log("ALUMNI ACCESS TRUE");
464
+ if (alumniConvoUser.schoolId) {
465
+ const school = await firebaseQuery.getDocData(["schools", alumniConvoUser.schoolId]) as SchoolData;
466
+ console.log("SCHOOL ACCESS", school, school.alumniConversations);
467
+ return school.alumniConversations ? constraints : false;
468
+
469
+ } else {
470
+ const institute = await firebaseQuery.getDocData(["institutes", alumniConvoUser.oId]) as InstituteData;
471
+ return institute.alumniConversations ? constraints : false;
472
+ }
473
+ }
474
+ return false;
475
+ }
476
+ const constraints = await getQueryAccess();
477
+ console.log("CONSTRAINTS", constraints);
478
+ if (!constraints) return;
479
+
480
+ school && constraints.push(["schoolId", "==", school]);
481
+ queryConstraints && constraints.unshift(...queryConstraints);
482
+
483
+ return constraints;
484
+ }
485
+ console.log("Creating query");
486
+ createQuery().then((constraints) => {
487
+ setQuery([{
488
+ path: ["alumni"],
489
+ where: constraints
490
+ }])
491
+ })
492
+ }, [user, queryConstraints, school])
493
+
494
+ useEffect(() => {
495
+ console.log("Alumni data", query, tableData);
496
+ }, [tableData]);
497
+
498
+ return {tableData, page, loading, setFilters, setView, pageUp, pageDown, sorts}
499
+ }
500
+
501
+
408
502
  const algoliaPlacementSearch = async (user: UserData, query?: string, sort?: [string, {value: string, direction: "asc"|"desc"}], page?: number, filters?: FilterObject, limit?: number, cohort?: string, inProgress?: boolean) => {
409
503
  const algoliaClient = algoliasearch(process.env.NODE_ENV === "development" ? "A0ZB50I7VS" : "XMPXCMUUOJ", user.algoliaKey);
410
504
  const placementsIndex = algoliaClient.initIndex(sort ? Object.values(sort[1]).join("_") : "placements");
@@ -894,200 +988,36 @@ export function useFilterTablePaginator({data}:{data:{[key:string]:{[key:string]
894
988
  return ({...{tableData, setPage, setFilters, page}});
895
989
  }
896
990
 
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}>({});
991
+ export function useProviderContactPaginator({data, user, view, filters}:{data:QueryObject[], user: UserData, view: "list"|"table", filters?: FilterObject}) {
992
+ const [query, setQuery] = useState<QueryObject[]>();
903
993
  const firebaseQuery = new FirebaseQuery();
904
994
 
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;
912
- }
913
-
914
- const querySchema:QueryObject = data?.[cursorPos];
915
-
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
-
923
- if (user.userType === "Students") {
924
- constraints.push(where("listed", "==", true));
925
- }
926
-
927
- queryData?.where && queryData.where.forEach((w) => {
928
- constraints.push(where(...w));
929
- });
930
-
931
- filters && Object.entries(filters).forEach(([key, value]) => {
932
- constraints.push(where(key, "==", value));
933
- });
934
-
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
- }
944
-
945
-
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
- };
971
-
972
- const constraints = createQuery(querySchema);
973
- // console.log(queryId, "constraints", constraints)
974
-
975
- const q = query(collection(db, "savedPlacements"), ...(constraints));
976
- const queryResults:{[key:string]: unknown} = {};
977
-
978
- const queryData = await getDocs(q);
979
-
980
- // console.log("queryData.size", queryData.size)
981
-
982
-
983
- const reverseIfBack = (docs:QueryDocumentSnapshot<DocumentData>[]) => {
984
- if (page[0] < page[1]) {
985
- return docs.reverse();
986
- }
987
- return docs;
988
- };
989
-
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
-
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
- }
1000
-
1001
- // console.log(index, "doc.id", doc.id, position, "E", prevEntries[doc.id])
1002
-
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
- }
1007
-
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
- });
1015
-
1016
- if (cursorDirection === "decrease" || page[0] < page[1]) {
1017
- itemList = {...Object.fromEntries(Object.entries(queryResults).reverse()), ...itemList};
1018
- } else {
1019
- itemList = {...itemList, ...queryResults};
995
+ const getAdditionalData = async (k: string, v: ProviderContactData) => {
996
+ if (v.savedBy?.[user.oId].activities?.includes("workExperience")) {
997
+ const placementsCount = await firebaseQuery.getCount("placementListings", [where(`savedBy.${user.oId}.exists`, "==", true), where("providerContactId", "==", k)]);
998
+ return {...v, plcaements: placementsCount};
1020
999
  }
1000
+ return v;
1001
+ }
1021
1002
 
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);
1031
- }
1032
- }
1033
-
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
- }
1048
-
1049
- setQueryAnchor({...currentQueryAnchor, startKey: Object.keys(itemList)[0], endKey: Object.keys(itemList).slice(-1)[0]});
1050
-
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
- };
1060
-
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";
1064
-
1065
- if (user.product === "admin") {
1066
- if (placement.mapConsent === undefined) return "notReviewed";
1067
- if (placement.mapConsent === false) return "notPublic";
1068
- return "unknown";
1069
- };
1003
+ const {tableData, pageUp, pageDown, setFilters, page, setView, loading} = useDataViewerPaginator({view, filters, queryLimit: 20, data: query, additionalEntryProcessing: getAdditionalData})
1070
1004
 
1071
- if (!provider.insurance) return "awaitingProviderApproval";
1072
-
1073
- return "requiresApproval";
1074
- };
1075
1005
 
1076
1006
  useEffect(() => {
1077
- if (!filters) return;
1007
+ const constraints:QueryObjectConstraint = [
1008
+ [`savedBy.${user.oId}.exists`, "==", true],
1009
+ ]
1078
1010
 
1079
- setPage([1, 0]);
1080
- setTableData({});
1081
- setQueryAnchor({startKey: "", endKey: "", startQueryPos: 0, endQueryPos: 0});
1082
- setPrevEntryIds({});
1083
- }, [filters]);
1084
-
1085
- // Fetch new data when queries or page change
1086
- useEffect(() => {
1087
- getDataFromQuery();
1088
- }, [page]);
1011
+ if (user.userType === "Students") {
1012
+ constraints.push([`savedBy.${user.oId}.cohorts.${user.cohort}.listed`, "==", true]);
1013
+ }
1014
+ setQuery([{
1015
+ path: ["providerContacts"],
1016
+ where: constraints
1017
+ }])
1018
+ }, [user]);
1089
1019
 
1090
- return ({...{tableData, setPage, setFilters, page}});
1020
+ return ({...{tableData, pageUp, pageDown, setFilters, page, setView, loading}});
1091
1021
  }
1092
1022
 
1093
1023
  type UserPaginatorParams = {
@@ -1130,8 +1060,8 @@ export function useCohortUserPaginator({user, cohort, data, search, userType, so
1130
1060
  }
1131
1061
  if (
1132
1062
  (!user.viewCohorts && user.userGroup !== "admin") ||
1133
- user.viewCohorts === "none" ||
1134
- (user.viewCohorts === "some" && cohort !== "all" && !user.visibleCohorts?.includes(cohort || ""))) {
1063
+ (user.viewCohorts === "none" && user.userGroup !== "admin") ||
1064
+ (user.viewCohorts === "some" && user.userGroup !== "admin" && cohort !== "all" && !user.visibleCohorts?.includes(cohort || ""))) {
1135
1065
  setQueries(undefined);
1136
1066
  return;
1137
1067
  }
@@ -1476,514 +1406,514 @@ export function useLazyLoadQueryList({path, constraints, number, onItemFetched}:
1476
1406
  }
1477
1407
 
1478
1408
 
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;
1409
+ // type PublicPlacementListingLoaderParams = {
1410
+ // providerId?: string,
1411
+ // number: number,
1412
+ // }
1413
+
1414
+ // export function usePublicPlacementListingLoader({providerId, number=5}:PublicPlacementListingLoaderParams) {
1415
+ // const [items, setItems] = useState<{[key:string]:{[key:string]:unknown}}>({});
1416
+ // const [loadMoreIcon, setLoadMoreIcon] = useState<boolean>(false);
1417
+
1418
+ // const [lastItem, setLastItem] = useState<QueryDocumentSnapshot<DocumentData>>();
1419
+ // const firebaseQuery = new FirebaseQuery();
1420
+
1421
+ // const reset = () => {
1422
+ // setItems({});
1423
+ // setLastItem(undefined);
1424
+ // };
1425
+
1426
+ // const loadMore = async () => {
1427
+ // setLoadMoreIcon(true);
1428
+ // let formattedConstraints:QueryConstraint[] = [
1429
+ // where("status", "==", "listed"),
1430
+ // limit(number)
1431
+ // ];
1432
+
1433
+ // if (providerId) {
1434
+ // formattedConstraints.push(where("providerId", "==", providerId));
1435
+ // }
1436
+ // if (lastItem) {
1437
+ // formattedConstraints.push(startAfter(lastItem));
1438
+ // }
1439
+ // const documents = await firebaseQuery.getDocsWhere("placementListings", formattedConstraints, true) as QuerySnapshot<DocumentData>;
1440
+
1441
+ // console.log("docs", documents.docs);
1442
+ // setLastItem(documents.docs[documents.docs.length-1]);
1443
+
1444
+ // const processedItems = Object.fromEntries(await Promise.all(Object.values(documents.docs).map(async (doc) => {
1445
+ // let itemObj = {...doc.data(), id: doc.id} as PlacementListing;
1446
+
1447
+ // if (itemObj.addressId) {
1448
+ // const address = await firebaseQuery.getDocData(["addresses", itemObj.addressId]) as Address;
1449
+ // delete address.id;
1450
+ // itemObj = {...address, ...itemObj};
1451
+ // }
1452
+ // if (itemObj.applicantWorkflowId) {
1453
+ // const applicantWorkflow = (await firebaseQuery.getDocData(["applicantWorkflows", itemObj.applicantWorkflowId]) as ApplicantWorkflow).workflow.filter((i) => i.id === 1)[0];
1454
+ // const applicantFiles = applicantWorkflow.files ? Object.fromEntries(await Promise.all(applicantWorkflow.files?.map(async (fileId) => {
1455
+ // const file = await firebaseQuery.getDocData(["files", fileId]);
1456
+ // file.url = await getDownloadURL(ref(storage, `providers/${itemObj.providerId}/${file.fileName}`));
1457
+
1458
+ // return [fileId, file];
1459
+ // }))) : [];
1460
+ // const applicantForms = applicantWorkflow.forms ? Object.fromEntries(await Promise.all(applicantWorkflow.forms?.map(async (formId) => {
1461
+ // return [formId, await firebaseQuery.getDocData(["forms", formId])];
1462
+ // }))) : [];
1463
+
1464
+ // applicantWorkflow.viewableFiles = applicantFiles;
1465
+ // applicantWorkflow.formDetails = applicantForms;
1466
+ // itemObj = {...itemObj, applicantWorkflow: [applicantWorkflow]};
1467
+ // }
1468
+ // return [doc.id, itemObj];
1469
+ // })))
1470
+
1471
+ // setItems((i) => ({...i, ...processedItems}));
1472
+ // setLoadMoreIcon(false);
1473
+ // };
1474
+ // useEffect(() => {
1475
+ // loadMore();
1476
+ // }, []);
1477
+
1478
+ // return ({...{items, loadMore, loadMoreIcon, reset}});
1479
+ // }
1480
+
1481
+ // export type ApplicationHookParams = {
1482
+ // successText: {
1483
+ // submitted: {
1484
+ // title: string;
1485
+ // desc: string;
1486
+ // };
1487
+ // draftSaved: {
1488
+ // title: string;
1489
+ // desc: string;
1490
+ // };
1491
+ // stageComplete: {
1492
+ // title: string;
1493
+ // desc: string;
1494
+ // };
1495
+ // outcome: {
1496
+ // title: string;
1497
+ // desc: string;
1498
+ // };
1499
+ // };
1500
+ // setSuccessPopup: import("react").Dispatch<import("react").SetStateAction<"submitted" | "draftSaved" | "stageComplete" | "outcome" | undefined>>;
1501
+ // openSuccessPopup: (type: "submitted" | "draftSaved" | "stageComplete" | "outcome") => void;
1502
+ // setFApplication: import("react").Dispatch<import("react").SetStateAction<Partial<Application>>>;
1503
+ // fApplication: Partial<Application>;
1504
+ // draftSaved: boolean;
1505
+ // profileUrl: string | undefined;
1506
+ // successPopup: "submitted" | "draftSaved" | "stageComplete" | "outcome" | undefined;
1507
+ // fApplicationId: string | undefined;
1508
+ // fListing: PlacementListing | false | undefined;
1509
+ // student: UserData | undefined;
1510
+ // fProvider: {
1511
+ // details?: ProviderData;
1512
+ // profile?: string;
1513
+ // id?: string;
1514
+ // } | undefined;
1515
+ // onFApply: (draft?: boolean) => Promise<void>;
1516
+ // setFormComplete: (formId: string, e: {
1517
+ // [key: string]: unknown;
1518
+ // }) => void;
1519
+ // viewFile: (file: string, onOpen: (url: string) => void) => void
1520
+ // addFile: (files: string[], fileId: number) => void;
1521
+ // uploadedFiles?: {
1522
+ // [key: string]: FileItem;
1523
+ // };
1524
+ // getCurrentStage: (stage: number) => Promise<{
1525
+ // stage: ApplicantStage;
1526
+ // completedSections: {
1527
+ // submitted?: string | undefined;
1528
+ // filesViewed?: string[] | undefined;
1529
+ // formsCompleted?: {
1530
+ // [key: string]: unknown;
1531
+ // } | undefined;
1532
+ // filesUploaded?: {
1533
+ // [key: number]: string[];
1534
+ // } | undefined;
1535
+ // };
1536
+ // }>;
1537
+ // currentStageComplete?: boolean;
1538
+ // progressStage: (type: number | "accept" | "reject", e?: {
1539
+ // feedback?: string;
1540
+ // }) => Promise<void>;
1541
+ // };
1542
+
1543
+ // export function useCreateApplicationRenderer({user, listingId, listing, provider, application, applicationId, orgContext}:
1544
+ // {user:UserData, listingId:string, applicationId?: string, listing?: PlacementListing, application?: Partial<Application>,
1545
+ // orgContext?: {details: ProviderData, addresses: {[key: string]: OrganisationAddress}, applicantWorkflows: {[key: string]: ApplicantWorkflow}},
1546
+ // provider?: {details?: ProviderData, profile?: string, id?: string}}) {
1547
+
1548
+ // const firebaseQuery = new FirebaseQuery();
1549
+
1550
+ // let applicationWithoutAdditionalData = {...(application || {})} as any;
1551
+ // delete applicationWithoutAdditionalData.listing;
1552
+ // delete applicationWithoutAdditionalData.address;
1553
+ // delete applicationWithoutAdditionalData.provider;
1624
1554
 
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);
1555
+ // const [fApplication, setFApplication] = useState<Partial<Application>>(application ? applicationWithoutAdditionalData : {
1556
+ // uid: user.userType === "Students" ? user.id : undefined,
1557
+ // listingId: listingId,
1558
+ // addressId: listing?.addressId,
1559
+ // stage: 1,
1560
+ // reqUserType: "Students",
1561
+ // status: "draft"});
1562
+ // const [fApplicationId, setFApplicationId] = useState<string|undefined>(applicationId);
1563
+ // const [draftSaved, setDraftSaved] = useState(false);
1564
+ // const [fProvider, setFProvider] = useState<{details?: ProviderData, profile?: string, id?: string}|undefined>(provider);
1565
+ // const [fListing, setFListing] = useState<PlacementListing|false|undefined>(Object.keys(listing || {}).length > 5 ? listing : undefined);
1566
+ // const [student, setStudent] = useState<UserData|undefined>(user.userType === "Students" ? user : undefined);
1567
+ // const [profileUrl, setProfileUrl] = useState<string>();
1568
+ // const [successPopup, setSuccessPopup] = useState<"submitted"|"draftSaved"|"stageComplete"|"outcome">();
1569
+ // const [uploadedFiles, setUploadedFiles] = useState<{[key: string]: FileItem}>();
1570
+ // const [currentStageComplete, setCurrentStageComplete] = useState<boolean>();
1571
+
1572
+ // useEffect(() => {
1573
+ // const getListing = async () => {
1574
+ // console.log("Checking ID")
1575
+ // if (!listingId) return;
1576
+ // console.log("Getting listing")
1577
+ // console.log("LISTING PARAM", listing, Object.keys(listing || {}).length > 5);
1578
+
1579
+ // const listingData = (Object.keys(listing || {}).length > 5) ? listing : (await firebaseQuery.getDocData(["placementListings", listingId]).catch(() => false) as PlacementListing|false);
1650
1580
 
1651
- console.log("LISTINGDATA", listingData, Object.keys(listing || {}).length > 5 ? {a: "string"} : "AAA");
1581
+ // console.log("LISTINGDATA", listingData, Object.keys(listing || {}).length > 5 ? {a: "string"} : "AAA");
1652
1582
 
1653
1583
 
1654
1584
 
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;
1585
+ // const address = listingData ? (user.product === "providers" && orgContext) ? orgContext.addresses[listingData.addressId || ""] : await firebaseQuery.getDocData(["addresses", listingData.addressId as string]) as Address : undefined;
1586
+ // 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
1587
 
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}`));
1588
+ // if (workflow && listingData) {
1589
+ // workflow.workflow = await Promise.all(workflow.workflow.map(async (s) => {
1590
+ // const applicantFiles = s.files ? Object.fromEntries(await Promise.all(s.files?.map(async (fileId: string) => {
1591
+ // const file = await firebaseQuery.getDocData(["files", fileId]);
1592
+ // file.url = await getDownloadURL(ref(storage, `providers/${listingData?.providerId}/${file.fileName}`));
1663
1593
 
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
- }))) : [];
1594
+ // return [fileId, file];
1595
+ // }))) : [];
1596
+ // const applicantForms = s.forms ? Object.fromEntries(await Promise.all(s.forms?.map(async (formId: string) => {
1597
+ // return [formId, await firebaseQuery.getDocData(["forms", formId])];
1598
+ // }))) : [];
1669
1599
 
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]);
1600
+ // return {...s, viewableFiles: applicantFiles, formDetails: applicantForms};
1601
+ // }));
1602
+ // delete workflow.id;
1603
+ // }
1604
+ // if (address) {
1605
+ // delete address.id;
1606
+ // }
1607
+
1608
+ // console.log("Setting listing")
1609
+ // setFListing((listingData && workflow) ? {...listingData, ...address, applicantWorkflow: workflow.workflow} as PlacementListing : false);
1610
+
1611
+
1612
+ // if ((fProvider?.id === application?.providerId) && user.product === "providers") {
1613
+ // setFProvider({details: orgContext?.details, id: user.oId});
1614
+ // } else if (listingData && listingData?.providerId) {
1615
+ // console.log("Getting provider from DB");
1616
+ // const provider = await firebaseQuery.getDocData(["providers", listingData.providerId]) as ProviderData;
1617
+ // console.log("Provider", provider);
1618
+ // setFProvider({details: provider, id: listingData.providerId});
1619
+ // }
1620
+ // }
1621
+
1622
+ // getListing();
1623
+ // }, [listingId, listing]);
1694
1624
 
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
- }, []);
1625
+ // useEffect(() => {
1626
+ // if (student?.id !== application?.uid) {
1627
+ // if (user.userType === "Students") {
1628
+ // setStudent(user);
1629
+ // } else if (user.product === "providers" && application?.uid) {
1630
+ // firebaseQuery.getDocData(["users", application.uid]).then((s) => setStudent(s as UserData));
1631
+ // }
1632
+ // }
1633
+ // }, []);
1704
1634
 
1705
- useEffect(() => {
1706
- setFListing(Object.keys(listing || {}).length > 5 ? listing : undefined);
1707
- }, [listing]);
1635
+ // useEffect(() => {
1636
+ // setFListing(Object.keys(listing || {}).length > 5 ? listing : undefined);
1637
+ // }, [listing]);
1708
1638
 
1709
- useEffect(() => {
1710
- if (provider?.profile) return;
1711
- if (!provider?.id) return;
1639
+ // useEffect(() => {
1640
+ // if (provider?.profile) return;
1641
+ // if (!provider?.id) return;
1712
1642
 
1713
- getDownloadURL(ref(storage, `providers/${provider?.id}/profilePic.png`)).then(setProfileUrl).catch(() => null);
1714
- }, [provider]);
1643
+ // getDownloadURL(ref(storage, `providers/${provider?.id}/profilePic.png`)).then(setProfileUrl).catch(() => null);
1644
+ // }, [provider]);
1715
1645
 
1716
1646
 
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;
1647
+ // useEffect(() => {
1648
+ // console.log("APPLICATIONID", applicationId);
1649
+ // if (!applicationId) {
1650
+ // if (!listingId) return;
1651
+ // firebaseQuery.getDocsWhere("applications", [where("status", "not-in", ["approved", "declined"]), where("uid", "==", user.id), where("listingId", "==", listingId)]).then((existingApplication) => {
1652
+ // console.log("EXISTING", existingApplication);
1653
+ // // get uploaded files
1654
+ // if (existingApplication && Object.keys(existingApplication).length) {
1655
+ // setFApplication(Object.values(existingApplication)[0]);
1656
+ // setFApplicationId(Object.keys(existingApplication)[0]);
1657
+ // }
1658
+ // });
1659
+ // return;
1660
+ // }
1661
+ // if (applicationId) {
1662
+ // setFApplicationId(applicationId);
1663
+ // if (application) {
1664
+ // let applicationWithoutAdditionalData = {...(application || {})} as any;
1665
+ // delete applicationWithoutAdditionalData.listing;
1666
+ // delete applicationWithoutAdditionalData.address;
1667
+ // delete applicationWithoutAdditionalData.provider;
1668
+ // setFApplication(applicationWithoutAdditionalData);
1669
+ // } else {
1670
+ // firebaseQuery.getDocData(["applications", applicationId]).then(setFApplication);
1671
+ // }
1672
+ // }
1673
+ // }, [application, applicationId]);
1674
+
1675
+ // const getCurrentStage = async (stage: number): Promise<{
1676
+ // stage: ApplicantStage; completedSections: {
1677
+ // submitted?: string | undefined;
1678
+ // filesViewed?: string[] | undefined;
1679
+ // formsCompleted?: {
1680
+ // [key: string]: unknown;
1681
+ // } | undefined;
1682
+ // filesUploaded?: {
1683
+ // [key: number]: string[];
1684
+ // } | undefined;
1685
+ // };
1686
+ // }> => {
1687
+ // console.log("fLSITING CURRENT STAGE", fListing);
1688
+ // if (!fListing) throw new Error("Listing deleted");
1689
+ // if (!fListing?.applicantWorkflowId) throw new Error("No workflow stage");
1690
+
1691
+ // const mApplicantWorkflow = (await firebaseQuery.getDocData(["applicantWorkflows", fListing.applicantWorkflowId]) as ApplicantWorkflow);
1692
+
1693
+ // const stageObj = mApplicantWorkflow?.workflow?.find((s) => s.id === stage);
1694
+
1695
+ // if (!stageObj) throw new Error("Can't find stage.");
1696
+
1697
+ // const applicantFiles = stageObj.files ? Object.fromEntries(await Promise.all(stageObj.files?.map(async (fileId) => {
1698
+ // const file = await firebaseQuery.getDocData(["files", fileId]);
1699
+ // file.url = await getDownloadURL(ref(storage, `providers/${mApplicantWorkflow?.oId}/${file.fileName}`));
1700
+
1701
+ // return [fileId, file];
1702
+ // }))) : [];
1703
+ // const applicantForms = stageObj.forms ? Object.fromEntries(await Promise.all(stageObj.forms?.map(async (formId) => {
1704
+ // return [formId, await firebaseQuery.getDocData(["forms", formId])];
1705
+ // }))) : [];
1706
+
1707
+ // stageObj.viewableFiles = applicantFiles;
1708
+ // stageObj.formDetails = applicantForms;
1779
1709
 
1780
- return {stage: stageObj, completedSections: fApplication?.completedSections?.[stage] || {}};
1781
- };
1710
+ // return {stage: stageObj, completedSections: fApplication?.completedSections?.[stage] || {}};
1711
+ // };
1782
1712
 
1783
- useEffect(() => {
1784
- const getUploadedFiles = async () => {
1785
- if (!fApplication.completedSections) {
1786
- setUploadedFiles({});
1787
- return
1788
- };
1713
+ // useEffect(() => {
1714
+ // const getUploadedFiles = async () => {
1715
+ // if (!fApplication.completedSections) {
1716
+ // setUploadedFiles({});
1717
+ // return
1718
+ // };
1789
1719
 
1790
- const fileIds = Object.values(fApplication.completedSections)
1791
- .flatMap(stageData =>
1792
- Object.values(stageData.filesUploaded || {}).flatMap(fileIds => fileIds)
1793
- );
1720
+ // const fileIds = Object.values(fApplication.completedSections)
1721
+ // .flatMap(stageData =>
1722
+ // Object.values(stageData.filesUploaded || {}).flatMap(fileIds => fileIds)
1723
+ // );
1794
1724
 
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}`));
1725
+ // const fileDataPromises = fileIds.map(async (fileId) => {
1726
+ // const fileData = await firebaseQuery.getDocData(["files", fileId]) as FileItem;
1727
+ // fileData.url = await getDownloadURL(ref(storage, `userFiles/${fileData.fileName}`));
1798
1728
 
1799
- return [fileId, fileData] as [string, FileItem]
1800
- });
1729
+ // return [fileId, fileData] as [string, FileItem]
1730
+ // });
1801
1731
 
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]);
1732
+ // const fileDataArray = await Promise.all(fileDataPromises);
1733
+ // const fileDataObj = Object.fromEntries(fileDataArray)
1734
+ // setUploadedFiles(fileDataObj)
1735
+ // }
1736
+
1737
+ // const addApplication = async () => {
1738
+ // console.log("ADDING APPLICATION");
1739
+ // if (!fListing || !fListing?.id || !fProvider?.id || !student?.id) return;
1740
+
1741
+ // const applicationData = {
1742
+ // uid: student.id,
1743
+ // listingId: fListing?.id,
1744
+ // addressId: fListing.addressId,
1745
+ // applicantWorkflowId: fListing?.applicantWorkflowId,
1746
+ // providerId: fProvider.id,
1747
+ // stage: 1,
1748
+ // status: "draft",
1749
+ // created: (new Date()).toISOString(),
1750
+ // ...fApplication,
1751
+ // } as Partial<Application>;
1752
+ // const mApplicationId = (await firebaseQuery.add(["applications"], applicationData)).id;
1753
+ // console.log("APPLICATION ADDED");
1754
+ // setFApplicationId(mApplicationId);
1755
+ // setFApplication(applicationData);
1756
+ // setDraftSaved(true);
1757
+ // return;
1758
+ // };
1759
+ // getUploadedFiles();
1760
+
1761
+ // console.log("Checking IDs");
1762
+
1763
+ // if (!fListing || !fListing?.id || !fProvider?.id || !student?.id) return;
1764
+ // if (user.product === "providers") return;
1765
+
1766
+ // console.log("Checking dates and sections");
1767
+ // if (!fApplication.completedSections && !fApplication.startDate && !fApplication.endDate) return;
1768
+
1769
+ // console.log("Application updated");
1770
+ // if (!fApplicationId && !applicationId) {
1771
+ // // save new
1772
+ // console.log("Add application")
1773
+ // addApplication();
1774
+ // return;
1775
+ // }
1776
+ // // update
1777
+ // firebaseQuery.update(["applications", (fApplicationId || applicationId) as string], fApplication);
1778
+ // setDraftSaved(true);
1779
+ // }, [fApplication]);
1850
1780
 
1851
- const openSuccessPopup = (type: "submitted"|"draftSaved"|"stageComplete"|"outcome") => {
1852
- setSuccessPopup(type);
1853
- setTimeout(() => {
1854
- // onClose();
1855
- }, 1500);
1856
- };
1781
+ // const openSuccessPopup = (type: "submitted"|"draftSaved"|"stageComplete"|"outcome") => {
1782
+ // setSuccessPopup(type);
1783
+ // setTimeout(() => {
1784
+ // // onClose();
1785
+ // }, 1500);
1786
+ // };
1857
1787
 
1858
- useEffect(() => {
1788
+ // useEffect(() => {
1859
1789
 
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);
1790
+ // const areStagesCompleted = async ():Promise<boolean|undefined> => {
1791
+ // if (!fListing) return;
1792
+ // if (fApplication.stage === undefined) return undefined;
1793
+ // const currentStage = await getCurrentStage(fApplication.stage);
1864
1794
 
1865
- console.log("Checking current stage is complete");
1795
+ // console.log("Checking current stage is complete");
1866
1796
 
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
- }
1797
+ // for (const fileViewed of currentStage.stage?.files || []) {
1798
+ // console.log("Checking file viewed", fileViewed, "in", currentStage?.completedSections?.filesViewed);
1799
+ // if (!currentStage?.completedSections?.filesViewed?.includes(fileViewed)) {
1800
+ // console.log("File not viewed");
1801
+ // return false;
1802
+ // } else {
1803
+ // console.log("File viewed");
1804
+ // }
1805
+ // }
1806
+ // for (const formCompleted of currentStage?.stage?.forms || []) {
1807
+ // console.log("Checking form completed", formCompleted, "in", currentStage?.completedSections?.formsCompleted);
1808
+
1809
+ // if (!Object.keys(currentStage?.completedSections?.formsCompleted || {}).includes(formCompleted)) {
1810
+ // console.log("Form not completed");
1811
+ // return false;
1812
+ // } else {
1813
+ // console.log("Form completed")
1814
+ // }
1815
+ // }
1816
+ // for (let i = 0; i++; i < (currentStage?.stage?.requiredFiles || []).length) {
1817
+ // if (!Object.keys(currentStage?.completedSections?.filesUploaded || {}).includes(i.toString())) {
1818
+ // console.log("Form not uploaded");
1819
+ // return false;
1820
+ // } else {
1821
+ // console.log("Form uploaded");
1822
+ // }
1823
+ // }
1894
1824
 
1895
- return true;
1896
- };
1825
+ // return true;
1826
+ // };
1897
1827
 
1898
- areStagesCompleted().then(setCurrentStageComplete);
1899
- }, [fApplication, fListing])
1828
+ // areStagesCompleted().then(setCurrentStageComplete);
1829
+ // }, [fApplication, fListing])
1900
1830
 
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.");
1831
+ // const viewFile = (file: string, onOpen: (url: string) => void) => {
1832
+ // if (fApplication.reqUserType !== user.userType) return;
1833
+ // if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
1834
+ // if (!fListing) throw new Error("No associated listing.");
1905
1835
 
1906
- const viewableFiles = fListing?.applicantWorkflow?.find((stage) => stage.id === fApplication.stage)?.viewableFiles;
1836
+ // const viewableFiles = fListing?.applicantWorkflow?.find((stage) => stage.id === fApplication.stage)?.viewableFiles;
1907
1837
 
1908
- setFApplication((a) => {
1909
- const oldA = {...a};
1910
- const viewedFiles = a.completedSections?.[1]?.filesViewed || [];
1911
- if (viewedFiles?.includes(file)) return a;
1838
+ // setFApplication((a) => {
1839
+ // const oldA = {...a};
1840
+ // const viewedFiles = a.completedSections?.[1]?.filesViewed || [];
1841
+ // if (viewedFiles?.includes(file)) return a;
1912
1842
 
1913
- viewableFiles?.[file].url && onOpen(viewableFiles?.[file].url);
1914
- viewedFiles?.push(file);
1843
+ // viewableFiles?.[file].url && onOpen(viewableFiles?.[file].url);
1844
+ // viewedFiles?.push(file);
1915
1845
 
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
- };
1846
+ // const newA = editNestedObject(["completedSections", 1, "filesViewed"], oldA, viewedFiles) as Partial<Application>;
1847
+ // return newA;
1848
+ // });
1849
+ // };
1850
+
1851
+ // const addFile = (files: string[], fileId: number) => {
1852
+ // if (fApplication.reqUserType !== user.userType) throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
1853
+ // if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
1854
+
1855
+ // if (!files.length) throw new Error("No files to upload");
1856
+ // setFApplication((a) => editNestedObject(["completedSections", fApplication.stage as number, "filesUploaded", fileId], a, files) as Application);
1857
+ // };
1858
+
1859
+ // const setFormComplete = (formId: string, e: {[key: string]: unknown}) => {
1860
+ // if (fApplication.reqUserType !== user.userType) throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
1861
+ // if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
1862
+ // setFApplication((a) => editNestedObject(["completedSections", fApplication.stage as number, "formsCompleted", formId], a, e) as Application);
1863
+ // };
1934
1864
 
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;
1865
+ // const successText = {
1866
+ // submitted: {
1867
+ // title: "Application submitted",
1868
+ // desc: "We've sent your application to the placement provider. You will hear what the next steps are soon.",
1869
+ // },
1870
+ // draftSaved: {
1871
+ // title: "Draft saved",
1872
+ // desc: "Your draft has been saved. Go to the 'Applications' section from your home screen to edit.",
1873
+ // },
1874
+ // stageComplete: {
1875
+ // title: "Stage complete",
1876
+ // desc: "We have sent this to the next stage in the application process. We will update you with any progress.",
1877
+ // },
1878
+ // outcome: {
1879
+ // title: "Outcome submitted",
1880
+ // desc: "We have sent the student an email with the outcome of their application.",
1881
+ // },
1882
+ // };
1883
+
1884
+ // const onFApply = async (draft?: boolean) => {
1885
+ // if (draft) {
1886
+ // openSuccessPopup("draftSaved")
1887
+ // return;
1888
+ // }
1889
+
1890
+ // if (!fApplicationId) return;
1961
1891
 
1962
- // Check all items have been filled in.
1963
- if (!fApplication.startDate || !fApplication.endDate) throw new Error("Please select dates for your placement.");
1892
+ // // Check all items have been filled in.
1893
+ // if (!fApplication.startDate || !fApplication.endDate) throw new Error("Please select dates for your placement.");
1964
1894
 
1965
- await executeCallable("applications-submit", {applicationId: fApplicationId});
1895
+ // await executeCallable("applications-submit", {applicationId: fApplicationId});
1966
1896
 
1967
- const newApplication = await firebaseQuery.getDocData(["applications", fApplicationId]) as Application;
1968
- setFApplication(newApplication);
1969
- openSuccessPopup("submitted")
1970
- };
1897
+ // const newApplication = await firebaseQuery.getDocData(["applications", fApplicationId]) as Application;
1898
+ // setFApplication(newApplication);
1899
+ // openSuccessPopup("submitted")
1900
+ // };
1971
1901
 
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
- };
1902
+ // const progressStage = async (type: number|"accept"|"reject", e?: {feedback?: string}) => {
1903
+ // // Check all stages completed.
1904
+ // if (!fApplicationId) return;
1905
+ // if (!currentStageComplete) throw new Error("Complete all forms before submitting.");
1906
+ // if (fApplication.reqUserType !== user.userType) throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
1907
+ // if (fApplication.stage === undefined) throw new Error("Missing applciation stage.")
1908
+
1909
+ // await executeCallable("applications-changeStage", {applicationId: fApplicationId, type: type, feedback: e?.feedback});
1910
+ // const newApplication = await firebaseQuery.getDocData(["applications", fApplicationId]) as Application;
1911
+ // setFApplication(newApplication);
1912
+ // };
1983
1913
 
1984
1914
 
1985
- return {successText, onFApply, progressStage, currentStageComplete, uploadedFiles, getCurrentStage, setFormComplete, viewFile, addFile, setSuccessPopup, openSuccessPopup, setFApplication, fApplication, draftSaved, profileUrl, successPopup, fApplicationId, fListing, student, fProvider}
1986
- }
1915
+ // return {successText, onFApply, progressStage, currentStageComplete, uploadedFiles, getCurrentStage, setFormComplete, viewFile, addFile, setSuccessPopup, openSuccessPopup, setFApplication, fApplication, draftSaved, profileUrl, successPopup, fApplicationId, fListing, student, fProvider}
1916
+ // }
1987
1917
 
1988
1918
  export function useProposePlacementRenderer({user, orgContext, placement}:
1989
1919
  {user:UserData, orgContext?: {details: InstituteData, userGroups: {[key:string]: UserGroupData}, forms: {[key:string]: unknown}, cohorts: {[key:string]: CohortData}},
@@ -2046,11 +1976,9 @@ export function useProposePlacementRenderer({user, orgContext, placement}:
2046
1976
 
2047
1977
  const submitSection = (type:"dates"|"provider"|"address", data:{[key:string]:unknown}) => {
2048
1978
  setFormData((f) => {
2049
- const { id, ...values } = data
2050
1979
  return {
2051
1980
  ...f,
2052
- ...values,
2053
- id: (placement?.placementId || formData?.id) as string
1981
+ ...data
2054
1982
  } as StudentPlacementData;
2055
1983
  });
2056
1984
  if (placement?.placementId && type === "dates") {
@@ -3039,41 +2967,42 @@ function useGenericWorkflowEditor({user, initialData, defaultData, onSubmit}: Ge
3039
2967
  onDeleteArrow, fWorkflowNodes, containerRef, setError, setArrows, setFWorkflowNodes}});
3040
2968
  }
3041
2969
 
3042
- type InstitutePlacementListingUploadParams = {
2970
+ type InstituteProviderContactUploadParams = {
3043
2971
  user: UserData,
3044
2972
  onComplete?: () => void
3045
2973
  }
3046
2974
 
3047
- export type InstitutePlacementListingUpload = {
3048
- provider: string;
3049
- jobTitle: string;
2975
+ export type InstituteProviderContactUpload = {
2976
+ business: string;
2977
+ forename?: string;
2978
+ surname?: string;
3050
2979
  email: string;
3051
2980
  phone?: string;
3052
- addressOne: string;
3053
- addressTwo: string;
3054
- city: string;
3055
- postcode: string;
3056
- country: string;
2981
+ addressOne?: string;
2982
+ addressTwo?: string;
2983
+ city?: string;
2984
+ postcode?: string;
2985
+ country?: string;
3057
2986
  };
3058
2987
 
3059
- export function useInstitutePlacementListingHandler({user}: InstitutePlacementListingUploadParams) {
2988
+ export function useInstituteProviderContactsHandler({user}: InstituteProviderContactUploadParams) {
3060
2989
  const [emptyCellsWarning, setEmptyCellsWarning] = useState(false);
3061
2990
  const [alert, setAlert] = useState<{severity: "warning"|"error"|"success"|"info", msg: string}>();
3062
2991
 
3063
- const requiredFields = ["name", "jobTitle", "email", "addressOne", "city", "postCode", "country"];
2992
+ const requiredFields = ["business", "forename", "email"];
3064
2993
  const {execute} = useExecuteCallableJob({user: user});
3065
2994
 
3066
- const checkData = (placements: InstitutePlacementListingUpload[]) => {
2995
+ const checkData = (providerContacts: InstituteProviderContactUpload[]) => {
3067
2996
  setAlert(undefined);
3068
2997
 
3069
- placements = placements.filter((u) => Object.entries(u).some(([, v]) => v));
2998
+ providerContacts = providerContacts.filter((u) => Object.entries(u).some(([, v]) => v));
3070
2999
 
3071
- if (!Object.entries(placements)) {
3000
+ if (!Object.entries(providerContacts)) {
3072
3001
  return [];
3073
3002
  }
3074
- console.log("P", placements);
3003
+ console.log("P", providerContacts);
3075
3004
 
3076
- if (placements.filter((u) => u.email).length < placements.length) {
3005
+ if (providerContacts.filter((u) => u.email).length < providerContacts.length) {
3077
3006
  setAlert({msg: "Your data contains missing email addresses.", severity: "error"});
3078
3007
  return false;
3079
3008
  }
@@ -3081,18 +3010,18 @@ export function useInstitutePlacementListingHandler({user}: InstitutePlacementLi
3081
3010
  let emptyOptionalCell = false;
3082
3011
  let emptyRequiredCell = false;
3083
3012
 
3084
- for (const placement of placements ) {
3085
- if (!checkEmailValidity(placement)) {
3013
+ for (const providerContact of providerContacts ) {
3014
+ if (!checkEmailValidity(providerContact)) {
3086
3015
  return false;
3087
3016
  }
3088
3017
 
3089
- if (Object.keys(placement).includes("")) {
3018
+ if (Object.keys(providerContact).includes("")) {
3090
3019
  setAlert({msg: "Data cannot be uploaded in unnamed columns.", severity: "error"});
3091
3020
  return false;
3092
3021
  }
3093
3022
 
3094
- for (const field in placement) {
3095
- if (!placement[field]) {
3023
+ for (const field in providerContact) {
3024
+ if (!providerContact[field]) {
3096
3025
  if (requiredFields.includes(field)) {
3097
3026
  setAlert({msg: "All users must contain "+requiredFields.join(", "), severity: "error"});
3098
3027
  emptyRequiredCell = true;
@@ -3113,44 +3042,30 @@ export function useInstitutePlacementListingHandler({user}: InstitutePlacementLi
3113
3042
  } else {
3114
3043
  setEmptyCellsWarning(false);
3115
3044
  }
3116
- return placements;
3045
+ return providerContacts;
3117
3046
  };
3118
3047
 
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"});
3048
+ const checkEmailValidity = (providerContact: InstituteProviderContactUpload) => {
3049
+ if (!validateEmail(providerContact.email as string)) {
3050
+ setAlert({msg: `Error in email formatting: ${providerContact.email}. Amend errors and reupload.`, severity: "error"});
3122
3051
  return false;
3123
3052
  }
3124
3053
  return true;
3125
3054
  };
3126
3055
 
3127
- const uploadPlacements = async (placements: InstitutePlacementListingUpload[]) => {
3128
- let fPlacements:InstitutePlacementListingUpload[] = [];
3129
- console.log("PP", placements);
3056
+ const uploadProviderContacts = async (providers: InstituteProviderContactUpload[], schoolId?: string) => {
3057
+ let fProviders:InstituteProviderContactUpload[] = [];
3058
+ console.log("PP", providers);
3130
3059
 
3131
- const cleanUpload = checkData(placements);
3060
+ const cleanUpload = checkData(providers);
3132
3061
  if (!cleanUpload) {
3133
3062
  return false;
3134
3063
  }
3135
- fPlacements = cleanUpload;
3064
+ fProviders = cleanUpload;
3136
3065
 
3137
3066
  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});
3067
+ if (fProviders.length) {
3068
+ execute("providerContacts-add", {providerContacts: fProviders, instituteId: user.product === "admin" ? "admin" : user.oId, schoolId: schoolId});
3154
3069
  }
3155
3070
  return true;
3156
3071
  };
@@ -3160,7 +3075,7 @@ export function useInstitutePlacementListingHandler({user}: InstitutePlacementLi
3160
3075
  setEmptyCellsWarning(false);
3161
3076
  };
3162
3077
 
3163
- return ({...{uploadPlacements, alert, onChange}});
3078
+ return ({...{uploadProviderContacts, alert, onChange}});
3164
3079
  }
3165
3080
 
3166
3081
 
@@ -3175,7 +3090,7 @@ export function useGetIndividualPlacementForPlacementPage({user, placementId, or
3175
3090
  const [disableEmail, setDisableEmail] = useState({parent: false, provider: false});
3176
3091
  const [rejectELIPopup, setRejectELIPopup] = useState(false);
3177
3092
  const [eliPopupOpen, setEliPopupOpen] = useState(false);
3178
- const [eliURL, setELIURL] = useState("");
3093
+ const [eliData, setELIData] = useState<string>();
3179
3094
 
3180
3095
  const [rejectExternalDocPopup, setRejectExternalDocPopup] = useState<"riskAssessment"|"dbsCheck"|false>(false);
3181
3096
  const [externalDocPopupOpen, setExternalDocPopupOpen] = useState<"riskAssessment"|"dbsCheck"|false>(false);
@@ -3356,10 +3271,10 @@ export function useGetIndividualPlacementForPlacementPage({user, placementId, or
3356
3271
  setShareStudentRequestPopup(true);
3357
3272
  }
3358
3273
  if (e === "noInsurance") {
3359
- if (!eliURL) {
3274
+ if (!eliData) {
3360
3275
  const storageRef = ref(storage, `insurance/${placement.providerId}.pdf`);
3361
- const file = await getDownloadURL(storageRef);
3362
- setELIURL(file);
3276
+ const file = await getDownloadURL(storageRef).catch(() => placement.insuranceSkippedReason);
3277
+ setELIData(file);
3363
3278
  }
3364
3279
  setEliPopupOpen(true);
3365
3280
  }
@@ -3391,15 +3306,15 @@ export function useGetIndividualPlacementForPlacementPage({user, placementId, or
3391
3306
 
3392
3307
  const approveELI = async () => {
3393
3308
  if (!placement) return;
3394
- await executeCallable("insurance-approve", {oId: user.oId, providerId: placement.providerId});
3309
+ await executeCallable("insurance-approve", {oId: user.oId, providerContactId: placement.providerContactId});
3395
3310
  setEliPopupOpen(false);
3396
3311
  };
3397
3312
 
3398
3313
  const rejectELI = async ({reason}:{reason: string}) => {
3399
3314
  if (!placement || !institute) return;
3400
3315
 
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});
3316
+ console.log("Reject", {reason: reason, placement: placement, instituteName: institute.name});
3317
+ await executeCallable("insurance-reject", {reason: reason, placementId: placementId, instituteName: institute.name});
3403
3318
  setRejectELIPopup(false);
3404
3319
  setEliPopupOpen(false);
3405
3320
  };
@@ -3420,10 +3335,12 @@ export function useGetIndividualPlacementForPlacementPage({user, placementId, or
3420
3335
  const manuallyConfigureProvider = async () => {
3421
3336
  if (!placement) return;
3422
3337
  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,
3338
+ const res = await executeCallable("providerContacts-uploadProviderDetails", {
3339
+ placement: {
3340
+ id: placementId,
3341
+ data: Object.fromEntries(Object.entries(placement).filter(([k]) => k !== "contactId")),
3342
+ stage: wStage,
3343
+ },
3427
3344
  skipSearch: true}).catch((e) => {
3428
3345
  throw e;
3429
3346
  });
@@ -3447,7 +3364,7 @@ export function useGetIndividualPlacementForPlacementPage({user, placementId, or
3447
3364
  await executeCallable("placement-withdraw", {placementId: placementId});
3448
3365
  }
3449
3366
 
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}
3367
+ 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
3368
  }
3452
3369
 
3453
3370
  export function useOnboardingPopup({onboarding, providerId, placementId, user, onClose}:{onboarding: (
@@ -3810,17 +3727,8 @@ export function useLoadListings(user: UserData, queryConstraint?: QueryConstrain
3810
3727
  };
3811
3728
 
3812
3729
  useEffect(() => {
3813
- let unsubscribe: () => void;
3814
-
3815
-
3816
3730
 
3817
3731
  loadListings();
3818
-
3819
- return () => {
3820
- if (unsubscribe) {
3821
- unsubscribe(); // Unsubscribe from the snapshot listener when the component unmounts
3822
- }
3823
- };
3824
3732
  // eslint-disable-next-line react-hooks/exhaustive-deps
3825
3733
  }, [queryConstraints]);
3826
3734
 
@@ -3911,17 +3819,7 @@ export function useLoadProviderPlacements(user: UserData, queryConstraint?: Quer
3911
3819
  };
3912
3820
 
3913
3821
  useEffect(() => {
3914
- let unsubscribe: () => void;
3915
-
3916
-
3917
-
3918
3822
  loadListings();
3919
-
3920
- return () => {
3921
- if (unsubscribe) {
3922
- unsubscribe(); // Unsubscribe from the snapshot listener when the component unmounts
3923
- }
3924
- };
3925
3823
  // eslint-disable-next-line react-hooks/exhaustive-deps
3926
3824
  }, [queryConstraints]);
3927
3825
 
@@ -4016,14 +3914,7 @@ export function useLoadApplications({user, applicationType, listingId, queryCons
4016
3914
  };
4017
3915
 
4018
3916
  useEffect(() => {
4019
- let unsubscribe: () => void;
4020
-
4021
3917
  loadApplications();
4022
- return () => {
4023
- if (unsubscribe) {
4024
- unsubscribe(); // Unsubscribe from the snapshot listener when the component unmounts
4025
- }
4026
- };
4027
3918
  // eslint-disable-next-line react-hooks/exhaustive-deps
4028
3919
  }, [type, queryConstraints]);
4029
3920
 
@@ -4060,7 +3951,7 @@ export type DataViewerPaginater = {
4060
3951
  sorts?: Sorts
4061
3952
  }
4062
3953
 
4063
- export function useDataViewerPaginator({view: initialView, sorts, queryLimit, additionalEntryProcessing, formatItems, snapshot, filters: initialFilters, onSearch, data}:DataViewerPaginater) {
3954
+ export function useDataViewerPaginator({view: initialView, sorts, queryLimit=10, additionalEntryProcessing, formatItems, snapshot, filters: initialFilters, onSearch, data}:DataViewerPaginater) {
4064
3955
  const [tableData, setTableData] = useState<{[key:string]:{[key:string]: unknown}}>(Array.isArray(data) ? Object.fromEntries(Object.entries(data).slice(0, queryLimit)) : {});
4065
3956
  const [page, setPage] = useState([1, 0]);
4066
3957
  const [view, setView] = useState(initialView);
@@ -4117,7 +4008,7 @@ export function useDataViewerPaginator({view: initialView, sorts, queryLimit, ad
4117
4008
  const getDataFromQuery = async (
4118
4009
  itemList: {[key: string]: any} = {}, currentQueryAnchor=queryAnchor, cursorDirection?:"increase"|"decrease"|undefined, prevEntries=prevEntryIds, loadMoreFromQuery=false):Promise<any> => {
4119
4010
 
4120
- if (!filters) return;
4011
+ // if (!filters) return;
4121
4012
  setLoading(true);
4122
4013
  if (!Array.isArray(data)) {
4123
4014
  setTableDataFromDefinedData();
@@ -4287,8 +4178,11 @@ export function useDataViewerPaginator({view: initialView, sorts, queryLimit, ad
4287
4178
  Object.keys(itemList).length === 0 &&
4288
4179
  currentQueryAnchor.endQueryPos+1 === data.length &&
4289
4180
  page[0] > 1) {
4290
- setTableData({});
4181
+ if (view === "table") {
4182
+ setTableData({});
4183
+ }
4291
4184
  setQueryAnchor((a) => ({...a, startKey: ""}));
4185
+ setLoading("loaded");
4292
4186
  return;
4293
4187
  }
4294
4188
 
@@ -4327,8 +4221,25 @@ export function useDataViewerPaginator({view: initialView, sorts, queryLimit, ad
4327
4221
  }, [filters]);
4328
4222
 
4329
4223
  useEffect(() => {
4224
+ console.log("View reset.")
4225
+ reset();
4226
+ }, [view]);
4227
+
4228
+ useEffect(() => {
4229
+ console.log("search reset.")
4330
4230
  reset();
4331
- }, [view, searchString, data, sort]);
4231
+ }, [searchString]);
4232
+
4233
+ useEffect(() => {
4234
+ console.log("data reset.")
4235
+ reset();
4236
+ }, [data]);
4237
+
4238
+ useEffect(() => {
4239
+ console.log("sort reset.")
4240
+ reset();
4241
+ }, [sort]);
4242
+
4332
4243
 
4333
4244
  // Fetch new data when queries or page change
4334
4245
  useEffect(() => {