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/lib/firebase/firebase.d.ts +1 -1
- package/lib/firebase/firebase.js +8 -3
- package/lib/firebase/firebase.js.map +1 -1
- package/lib/firebase/readDatabase.js +7 -7
- package/lib/firebase/readDatabase.js.map +1 -1
- package/lib/hooks.d.ts +54 -179
- package/lib/hooks.js +581 -640
- package/lib/hooks.js.map +1 -1
- package/lib/reduxHooks.d.ts +66 -1
- package/lib/reduxHooks.js +70 -11
- package/lib/reduxHooks.js.map +1 -1
- package/lib/tasksAndTips.d.ts +14 -4
- package/lib/tasksAndTips.js +463 -454
- package/lib/tasksAndTips.js.map +1 -1
- package/lib/typeDefinitions.d.ts +181 -89
- package/lib/util.d.ts +8 -1
- package/lib/util.js +15 -1
- package/lib/util.js.map +1 -1
- package/package.json +7 -4
- package/src/firebase/firebase.tsx +8 -4
- package/src/firebase/readDatabase.tsx +7 -7
- package/src/hooks.tsx +662 -751
- package/src/reduxHooks.ts +76 -13
- package/src/tasksAndTips.ts +504 -446
- package/src/typeDefinitions.ts +241 -82
- package/src/util.ts +18 -1
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
|
-
|
|
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,
|
|
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
|
|
898
|
-
const [
|
|
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
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1007
|
+
const constraints:QueryObjectConstraint = [
|
|
1008
|
+
[`savedBy.${user.oId}.exists`, "==", true],
|
|
1009
|
+
]
|
|
1078
1010
|
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
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,
|
|
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
|
-
|
|
1481
|
-
|
|
1482
|
-
}
|
|
1483
|
-
|
|
1484
|
-
export function usePublicPlacementListingLoader({providerId, number=5}:PublicPlacementListingLoaderParams) {
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
}
|
|
1550
|
-
|
|
1551
|
-
export type ApplicationHookParams = {
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
};
|
|
1612
|
-
|
|
1613
|
-
export function useCreateApplicationRenderer({user, listingId, listing, provider, application, applicationId, orgContext}:
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
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
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
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
|
-
|
|
1581
|
+
// console.log("LISTINGDATA", listingData, Object.keys(listing || {}).length > 5 ? {a: "string"} : "AAA");
|
|
1652
1582
|
|
|
1653
1583
|
|
|
1654
1584
|
|
|
1655
|
-
|
|
1656
|
-
|
|
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
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
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
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
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
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
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
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
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
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1635
|
+
// useEffect(() => {
|
|
1636
|
+
// setFListing(Object.keys(listing || {}).length > 5 ? listing : undefined);
|
|
1637
|
+
// }, [listing]);
|
|
1708
1638
|
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1639
|
+
// useEffect(() => {
|
|
1640
|
+
// if (provider?.profile) return;
|
|
1641
|
+
// if (!provider?.id) return;
|
|
1712
1642
|
|
|
1713
|
-
|
|
1714
|
-
|
|
1643
|
+
// getDownloadURL(ref(storage, `providers/${provider?.id}/profilePic.png`)).then(setProfileUrl).catch(() => null);
|
|
1644
|
+
// }, [provider]);
|
|
1715
1645
|
|
|
1716
1646
|
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
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
|
-
|
|
1781
|
-
|
|
1710
|
+
// return {stage: stageObj, completedSections: fApplication?.completedSections?.[stage] || {}};
|
|
1711
|
+
// };
|
|
1782
1712
|
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1713
|
+
// useEffect(() => {
|
|
1714
|
+
// const getUploadedFiles = async () => {
|
|
1715
|
+
// if (!fApplication.completedSections) {
|
|
1716
|
+
// setUploadedFiles({});
|
|
1717
|
+
// return
|
|
1718
|
+
// };
|
|
1789
1719
|
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1720
|
+
// const fileIds = Object.values(fApplication.completedSections)
|
|
1721
|
+
// .flatMap(stageData =>
|
|
1722
|
+
// Object.values(stageData.filesUploaded || {}).flatMap(fileIds => fileIds)
|
|
1723
|
+
// );
|
|
1794
1724
|
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
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
|
-
|
|
1800
|
-
|
|
1729
|
+
// return [fileId, fileData] as [string, FileItem]
|
|
1730
|
+
// });
|
|
1801
1731
|
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
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
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1781
|
+
// const openSuccessPopup = (type: "submitted"|"draftSaved"|"stageComplete"|"outcome") => {
|
|
1782
|
+
// setSuccessPopup(type);
|
|
1783
|
+
// setTimeout(() => {
|
|
1784
|
+
// // onClose();
|
|
1785
|
+
// }, 1500);
|
|
1786
|
+
// };
|
|
1857
1787
|
|
|
1858
|
-
|
|
1788
|
+
// useEffect(() => {
|
|
1859
1789
|
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
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
|
-
|
|
1795
|
+
// console.log("Checking current stage is complete");
|
|
1866
1796
|
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
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
|
-
|
|
1896
|
-
|
|
1825
|
+
// return true;
|
|
1826
|
+
// };
|
|
1897
1827
|
|
|
1898
|
-
|
|
1899
|
-
|
|
1828
|
+
// areStagesCompleted().then(setCurrentStageComplete);
|
|
1829
|
+
// }, [fApplication, fListing])
|
|
1900
1830
|
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
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
|
-
|
|
1836
|
+
// const viewableFiles = fListing?.applicantWorkflow?.find((stage) => stage.id === fApplication.stage)?.viewableFiles;
|
|
1907
1837
|
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1838
|
+
// setFApplication((a) => {
|
|
1839
|
+
// const oldA = {...a};
|
|
1840
|
+
// const viewedFiles = a.completedSections?.[1]?.filesViewed || [];
|
|
1841
|
+
// if (viewedFiles?.includes(file)) return a;
|
|
1912
1842
|
|
|
1913
|
-
|
|
1914
|
-
|
|
1843
|
+
// viewableFiles?.[file].url && onOpen(viewableFiles?.[file].url);
|
|
1844
|
+
// viewedFiles?.push(file);
|
|
1915
1845
|
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
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
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
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
|
-
|
|
1963
|
-
|
|
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
|
-
|
|
1895
|
+
// await executeCallable("applications-submit", {applicationId: fApplicationId});
|
|
1966
1896
|
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1897
|
+
// const newApplication = await firebaseQuery.getDocData(["applications", fApplicationId]) as Application;
|
|
1898
|
+
// setFApplication(newApplication);
|
|
1899
|
+
// openSuccessPopup("submitted")
|
|
1900
|
+
// };
|
|
1971
1901
|
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
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
|
-
|
|
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
|
-
...
|
|
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
|
|
2970
|
+
type InstituteProviderContactUploadParams = {
|
|
3043
2971
|
user: UserData,
|
|
3044
2972
|
onComplete?: () => void
|
|
3045
2973
|
}
|
|
3046
2974
|
|
|
3047
|
-
export type
|
|
3048
|
-
|
|
3049
|
-
|
|
2975
|
+
export type InstituteProviderContactUpload = {
|
|
2976
|
+
business: string;
|
|
2977
|
+
forename?: string;
|
|
2978
|
+
surname?: string;
|
|
3050
2979
|
email: string;
|
|
3051
2980
|
phone?: string;
|
|
3052
|
-
addressOne
|
|
3053
|
-
addressTwo
|
|
3054
|
-
city
|
|
3055
|
-
postcode
|
|
3056
|
-
country
|
|
2981
|
+
addressOne?: string;
|
|
2982
|
+
addressTwo?: string;
|
|
2983
|
+
city?: string;
|
|
2984
|
+
postcode?: string;
|
|
2985
|
+
country?: string;
|
|
3057
2986
|
};
|
|
3058
2987
|
|
|
3059
|
-
export function
|
|
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 = ["
|
|
2992
|
+
const requiredFields = ["business", "forename", "email"];
|
|
3064
2993
|
const {execute} = useExecuteCallableJob({user: user});
|
|
3065
2994
|
|
|
3066
|
-
const checkData = (
|
|
2995
|
+
const checkData = (providerContacts: InstituteProviderContactUpload[]) => {
|
|
3067
2996
|
setAlert(undefined);
|
|
3068
2997
|
|
|
3069
|
-
|
|
2998
|
+
providerContacts = providerContacts.filter((u) => Object.entries(u).some(([, v]) => v));
|
|
3070
2999
|
|
|
3071
|
-
if (!Object.entries(
|
|
3000
|
+
if (!Object.entries(providerContacts)) {
|
|
3072
3001
|
return [];
|
|
3073
3002
|
}
|
|
3074
|
-
console.log("P",
|
|
3003
|
+
console.log("P", providerContacts);
|
|
3075
3004
|
|
|
3076
|
-
if (
|
|
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
|
|
3085
|
-
if (!checkEmailValidity(
|
|
3013
|
+
for (const providerContact of providerContacts ) {
|
|
3014
|
+
if (!checkEmailValidity(providerContact)) {
|
|
3086
3015
|
return false;
|
|
3087
3016
|
}
|
|
3088
3017
|
|
|
3089
|
-
if (Object.keys(
|
|
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
|
|
3095
|
-
if (!
|
|
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
|
|
3045
|
+
return providerContacts;
|
|
3117
3046
|
};
|
|
3118
3047
|
|
|
3119
|
-
const checkEmailValidity = (
|
|
3120
|
-
if (!validateEmail(
|
|
3121
|
-
setAlert({msg: `Error in email formatting: ${
|
|
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
|
|
3128
|
-
let
|
|
3129
|
-
console.log("PP",
|
|
3056
|
+
const uploadProviderContacts = async (providers: InstituteProviderContactUpload[], schoolId?: string) => {
|
|
3057
|
+
let fProviders:InstituteProviderContactUpload[] = [];
|
|
3058
|
+
console.log("PP", providers);
|
|
3130
3059
|
|
|
3131
|
-
const cleanUpload = checkData(
|
|
3060
|
+
const cleanUpload = checkData(providers);
|
|
3132
3061
|
if (!cleanUpload) {
|
|
3133
3062
|
return false;
|
|
3134
3063
|
}
|
|
3135
|
-
|
|
3064
|
+
fProviders = cleanUpload;
|
|
3136
3065
|
|
|
3137
3066
|
setAlert(undefined);
|
|
3138
|
-
if (
|
|
3139
|
-
|
|
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 ({...{
|
|
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 [
|
|
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 (!
|
|
3274
|
+
if (!eliData) {
|
|
3360
3275
|
const storageRef = ref(storage, `insurance/${placement.providerId}.pdf`);
|
|
3361
|
-
const file = await getDownloadURL(storageRef);
|
|
3362
|
-
|
|
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,
|
|
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
|
|
3402
|
-
await executeCallable("insurance-reject", {reason: reason, placementId: placementId, instituteName: institute.name
|
|
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("
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
}, [
|
|
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(() => {
|