placementt-core 1.20.197 → 11.0.533
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/.eslintrc.js +40 -40
- package/.gitattributes +2 -2
- package/lib/config.d.ts +0 -1
- package/lib/constants.d.ts +5 -2
- package/lib/constants.js +130 -136
- package/lib/constants.js.map +1 -1
- package/lib/features/analytics/useAnalytics.d.ts +0 -1
- package/lib/features/analytics/useAnalytics.js +3 -4
- package/lib/features/analytics/useAnalytics.js.map +1 -1
- package/lib/features/config.d.ts +133 -133
- package/lib/features/config.js +35 -35
- package/lib/features/contacts/contacts.d.ts +75 -75
- package/lib/features/contacts/contacts.js +105 -105
- package/lib/features/contacts/contactsSlice.d.ts +5 -5
- package/lib/features/contacts/useContacts.js +1 -2
- package/lib/features/contacts/useContacts.js.map +1 -1
- package/lib/features/downtime/useDowntime.d.ts +11 -11
- package/lib/features/downtime/useDowntime.js +22 -22
- package/lib/features/dropdown/useDropdown.d.ts +2 -3
- package/lib/features/dropdown/useDropdown.js +1 -2
- package/lib/features/dropdown/useDropdown.js.map +1 -1
- package/lib/features/global/downtime/useDowntime.d.ts +0 -1
- package/lib/features/global/downtime/useDowntime.js +3 -2
- package/lib/features/global/downtime/useDowntime.js.map +1 -1
- package/lib/features/global/users/useUserFunctions.d.ts +0 -1
- package/lib/features/global/users/useUserFunctions.js +6 -7
- package/lib/features/global/users/useUserFunctions.js.map +1 -1
- package/lib/features/placements/studentPlacements/activePlacement.d.ts +1 -1
- package/lib/features/placements/studentPlacements/activePlacement.js +1 -1
- package/lib/features/placements/studentPlacements/activePlacement.js.map +1 -1
- package/lib/features/placements/studentPlacements/completedStudentPlacementsSlice.d.ts +4 -5
- package/lib/features/placements/studentPlacements/completedStudentPlacementsSlice.js +1 -4
- package/lib/features/placements/studentPlacements/completedStudentPlacementsSlice.js.map +1 -1
- package/lib/features/placements/studentPlacements/studentPlacementsSlice.d.ts +63 -63
- package/lib/features/placements/studentPlacements/studentPlacementsSlice.js +81 -81
- package/lib/features/placements/studentPlacements/upcomingStudentPlacementsSlice.d.ts +4 -4
- package/lib/features/placements/studentPlacements/upcomingStudentPlacementsSlice.js +1 -1
- package/lib/features/placements/studentPlacements/upcomingStudentPlacementsSlice.js.map +1 -1
- package/lib/features/placements/studentPlacements/useStudentPlacements.d.ts +0 -1
- package/lib/features/placements/studentPlacements/useStudentPlacements.js +1 -2
- package/lib/features/placements/studentPlacements/useStudentPlacements.js.map +1 -1
- package/lib/features/providerPlacements/providerPlacementsSlice.d.ts +19 -19
- package/lib/features/providerPlacements/providerPlacementsSlice.js +24 -24
- package/lib/features/referrals/useReferrals.d.ts +0 -1
- package/lib/features/referrals/useReferrals.js +1 -2
- package/lib/features/referrals/useReferrals.js.map +1 -1
- package/lib/features/studentPlacements/studentPlacementsSlice.d.ts +62 -62
- package/lib/features/studentPlacements/studentPlacementsSlice.js +87 -87
- package/lib/features/studentPlacements/useStudentPlacements.d.ts +6 -6
- package/lib/features/studentPlacements/useStudentPlacements.js +18 -18
- package/lib/features/updates/useUpdates.js +1 -2
- package/lib/features/updates/useUpdates.js.map +1 -1
- package/lib/features/userSlice.d.ts +26 -26
- package/lib/features/userSlice.js +23 -23
- package/lib/features/users/useUserFunctions.d.ts +25 -25
- package/lib/features/users/useUserFunctions.js +124 -124
- package/lib/features/users/userSlice.d.ts +46 -46
- package/lib/features/users/userSlice.js +48 -48
- package/lib/firebase/firebase.d.ts +1 -1
- package/lib/firebase/firebase.js +9 -4
- package/lib/firebase/firebase.js.map +1 -1
- package/lib/firebase/firebaseConfig.js +3 -0
- package/lib/firebase/firebaseConfig.js.map +1 -1
- package/lib/firebase/firebaseQuery.js +3 -0
- package/lib/firebase/firebaseQuery.js.map +1 -1
- package/lib/firebase/persistence.js +2 -2
- package/lib/firebase/persistence.js.map +1 -1
- package/lib/firebase/readDatabase.d.ts +9 -6
- package/lib/firebase/readDatabase.js +16 -6
- package/lib/firebase/readDatabase.js.map +1 -1
- package/lib/firebase/util.d.ts +3 -4
- package/lib/firebase/util.js +49 -4
- package/lib/firebase/util.js.map +1 -1
- package/lib/firebase/writeDatabase.d.ts +3 -3
- package/lib/firebase/writeDatabase.js +7 -1
- package/lib/firebase/writeDatabase.js.map +1 -1
- package/lib/hooks.d.ts +384 -23
- package/lib/hooks.js +1342 -223
- package/lib/hooks.js.map +1 -1
- package/lib/images/GatsbyBenchmarks.d.ts +0 -1
- package/lib/images/GatsbyBenchmarks.js +1 -1
- package/lib/images/GatsbyBenchmarks.js.map +1 -1
- package/lib/reduxHooks.d.ts +11 -20
- package/lib/reduxHooks.js +28 -18
- package/lib/reduxHooks.js.map +1 -1
- package/lib/tasksAndTips.d.ts +25 -5
- package/lib/tasksAndTips.js +346 -48
- package/lib/tasksAndTips.js.map +1 -1
- package/lib/typeDefinitions.d.ts +478 -53
- package/lib/util.d.ts +1 -0
- package/lib/util.js +78 -6
- package/lib/util.js.map +1 -1
- package/package.json +52 -49
- package/src/DatabaseDefinitions.ts +18 -18
- package/src/apiCalls.ts +128 -128
- package/src/config.ts +50 -50
- package/src/constants.ts +708 -707
- package/src/databaseTypes.ts +42 -42
- package/src/features/analytics/useAnalytics.tsx +55 -55
- package/src/features/contacts/contactsSlice.ts +147 -147
- package/src/features/contacts/useContacts.tsx +73 -73
- package/src/features/dropdown/useDropdown.tsx +52 -52
- package/src/features/global/downtime/useDowntime.tsx +19 -18
- package/src/features/global/users/useUserFunctions.tsx +132 -132
- package/src/features/jobs/jobsSlice.ts +65 -65
- package/src/features/placements/studentPlacements/activePlacement.ts +63 -63
- package/src/features/placements/studentPlacements/completedStudentPlacementsSlice.ts +94 -97
- package/src/features/placements/studentPlacements/upcomingStudentPlacementsSlice.ts +108 -108
- package/src/features/placements/studentPlacements/useStudentPlacements.tsx +33 -33
- package/src/features/placements/types.ts +10 -10
- package/src/features/referrals/useReferrals.tsx +56 -56
- package/src/features/updates/useUpdates.tsx +36 -36
- package/src/firebase/firebase.tsx +142 -138
- package/src/firebase/firebaseConfig.tsx +45 -42
- package/src/firebase/firebaseQuery.tsx +143 -140
- package/src/firebase/persistence.ts +84 -84
- package/src/firebase/readDatabase.tsx +208 -197
- package/src/firebase/util.tsx +352 -308
- package/src/firebase/writeDatabase.tsx +75 -68
- package/src/hooks.tsx +3395 -1943
- package/src/images/GatsbyBenchmarks.tsx +711 -711
- package/src/images/LogFuturePlacement.jsx +64 -64
- package/src/images/LogPreviousPlacement.jsx +228 -228
- package/src/images/gatsby_benchmarks.svg +466 -466
- package/src/images/log_future_placement.svg +114 -114
- package/src/images/log_previous_placement.svg +199 -199
- package/src/index.ts +34 -34
- package/src/readDatabase.tsx +3 -3
- package/src/reduxHooks.ts +183 -170
- package/src/tasksAndTips.ts +744 -410
- package/src/tutorialTips.ts +58 -58
- package/src/typeDefinitions.ts +899 -503
- package/src/util.ts +132 -47
- package/tsconfig.dev.json +5 -5
- package/tsconfig.json +21 -21
package/lib/hooks.js
CHANGED
|
@@ -3,7 +3,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.useRefDimensions = void 0;
|
|
7
|
+
exports.useStudentPlacementList = useStudentPlacementList;
|
|
8
|
+
exports.useNewInstitutePlacementList = useNewInstitutePlacementList;
|
|
9
|
+
exports.useOldInstitutePlacementList = useOldInstitutePlacementList;
|
|
10
|
+
exports.useFilterTablePaginator = useFilterTablePaginator;
|
|
11
|
+
exports.usePlacementListingPaginator = usePlacementListingPaginator;
|
|
12
|
+
exports.useCohortUserPaginator = useCohortUserPaginator;
|
|
13
|
+
exports.useAdmissionsPaginator = useAdmissionsPaginator;
|
|
14
|
+
exports.useLazyLoadQueryList = useLazyLoadQueryList;
|
|
15
|
+
exports.usePublicPlacementListingLoader = usePublicPlacementListingLoader;
|
|
16
|
+
exports.useCreateApplicationRenderer = useCreateApplicationRenderer;
|
|
17
|
+
exports.useProposePlacementRenderer = useProposePlacementRenderer;
|
|
18
|
+
exports.useCreateCohortRenderer = useCreateCohortRenderer;
|
|
19
|
+
exports.useUserUploadHandler = useUserUploadHandler;
|
|
20
|
+
exports.useWorkflowEditor = useWorkflowEditor;
|
|
21
|
+
exports.useApplicantWorkflowEditor = useApplicantWorkflowEditor;
|
|
22
|
+
exports.useInstitutePlacementListingHandler = useInstitutePlacementListingHandler;
|
|
23
|
+
exports.useGetIndividualPlacementForPlacementPage = useGetIndividualPlacementForPlacementPage;
|
|
24
|
+
exports.useOnboardingPopup = useOnboardingPopup;
|
|
7
25
|
const firestore_1 = require("firebase/firestore");
|
|
8
26
|
const react_1 = require("react");
|
|
9
27
|
const constants_1 = require("./constants");
|
|
@@ -13,6 +31,8 @@ const firebaseQuery_1 = __importDefault(require("./firebase/firebaseQuery"));
|
|
|
13
31
|
const readDatabase_1 = require("./firebase/readDatabase");
|
|
14
32
|
const util_1 = require("./firebase/util");
|
|
15
33
|
const writeDatabase_1 = require("./firebase/writeDatabase");
|
|
34
|
+
const algoliasearch_1 = __importDefault(require("algoliasearch"));
|
|
35
|
+
const storage_1 = require("firebase/storage");
|
|
16
36
|
const DEFAULTQUERYLIMIT = 5;
|
|
17
37
|
function useStudentPlacementList({ user, student, queryConstraint, ql = DEFAULTQUERYLIMIT }) {
|
|
18
38
|
const [loadMoreIcon, setLoadMoreIcon] = (0, react_1.useState)(true);
|
|
@@ -101,21 +121,81 @@ function useStudentPlacementList({ user, student, queryConstraint, ql = DEFAULTQ
|
|
|
101
121
|
};
|
|
102
122
|
return ({ ...{ placements, loadMoreIcon, loadMorePlacements, setQuery, setInitialQueryLimit, reset, changeQueryConstraints } });
|
|
103
123
|
}
|
|
104
|
-
|
|
105
|
-
function useNewInstitutePlacementList({ id, user, cohort, queryConstraint, ql = DEFAULTQUERYLIMIT }) {
|
|
124
|
+
function useNewInstitutePlacementList({ id, user, cohort, queryConstraint, ql = DEFAULTQUERYLIMIT, inProgress }) {
|
|
106
125
|
const [loadMoreIcon, setLoadMoreIcon] = (0, react_1.useState)(true);
|
|
107
|
-
const [query, setQuery] = (0, react_1.useState)(
|
|
126
|
+
const [query, setQuery] = (0, react_1.useState)();
|
|
108
127
|
const [initialQueryLimit, setInitialQueryLimit] = (0, react_1.useState)(ql);
|
|
109
128
|
const [queryConstraints, setQueryConstraints] = (0, react_1.useState)(queryConstraint || []);
|
|
110
129
|
const [oId, setOId] = (0, react_1.useState)();
|
|
111
130
|
const [placements, setPlacements] = (0, react_1.useState)();
|
|
112
131
|
const [startPlacementAfter, setStartPlacementAfter] = (0, react_1.useState)(); // uid, pId
|
|
132
|
+
const algoliaClient = (0, algoliasearch_1.default)(process.env.NODE_ENV === "development" ? "A0ZB50I7VS" : "XMPXCMUUOJ", user.algoliaKey);
|
|
133
|
+
const placementsIndex = algoliaClient.initIndex("placements");
|
|
134
|
+
const usersIndex = algoliaClient.initIndex("users");
|
|
113
135
|
(0, react_1.useEffect)(() => {
|
|
114
136
|
if (user.product !== "institutes" || user.userType !== "Staff") {
|
|
115
137
|
setOId(undefined);
|
|
116
138
|
}
|
|
117
139
|
setOId(user.oId);
|
|
118
140
|
}, [user]);
|
|
141
|
+
(0, react_1.useEffect)(() => {
|
|
142
|
+
if (query === undefined)
|
|
143
|
+
return;
|
|
144
|
+
if (!query) {
|
|
145
|
+
reset();
|
|
146
|
+
loadMorePlacements([undefined, 0]);
|
|
147
|
+
}
|
|
148
|
+
const searchPlacements = async () => {
|
|
149
|
+
let placementsFound = {};
|
|
150
|
+
let userSearchString = `userType:Students AND status:active AND oId:${user.oId} AND product:${user.product}`;
|
|
151
|
+
if (cohort) {
|
|
152
|
+
userSearchString = userSearchString + ` AND cohort:${cohort}`;
|
|
153
|
+
}
|
|
154
|
+
if (user.product === "institutes" && user.userType === "Staff") {
|
|
155
|
+
const searchStudentHits = await usersIndex.search(query, {
|
|
156
|
+
filters: userSearchString
|
|
157
|
+
});
|
|
158
|
+
if (searchStudentHits) {
|
|
159
|
+
console.log("FOUND", searchStudentHits.hits.length, "students");
|
|
160
|
+
await Promise.all(searchStudentHits.hits.map(async (hit) => {
|
|
161
|
+
console.log("STUDENT", hit.objectID);
|
|
162
|
+
const constraints = [...(cohort ? [(0, firestore_1.where)("cohort", "==", cohort)] : [])];
|
|
163
|
+
if (inProgress !== undefined) {
|
|
164
|
+
constraints.push(inProgress ? (0, firestore_1.where)("inProgress", "==", true) : (0, firestore_1.where)("completed", "==", true));
|
|
165
|
+
}
|
|
166
|
+
const fPlacements = await (0, readDatabase_1.getPlacementsWhere)({ w: constraints, uid: hit.objectID, oId: hit.oId });
|
|
167
|
+
console.log("PLACEMENTS", fPlacements);
|
|
168
|
+
Object.entries(fPlacements).forEach(([k, v]) => {
|
|
169
|
+
placementsFound[k] = { ...v, student: hit };
|
|
170
|
+
});
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
let placementSearchString = `oId:${user.oId} AND ` + (inProgress !== undefined ? (inProgress ? "inProgress:true" : "completed:true") : "");
|
|
175
|
+
if (cohort) {
|
|
176
|
+
placementSearchString = placementSearchString + ` AND cohort:${cohort}`;
|
|
177
|
+
}
|
|
178
|
+
const searchPlacementHits = await placementsIndex.search(query, {
|
|
179
|
+
filters: placementSearchString
|
|
180
|
+
});
|
|
181
|
+
const i = (searchPlacementHits ? (await Promise.all(searchPlacementHits.hits.map(async (hit) => {
|
|
182
|
+
const student = hit.uid === user.id ?
|
|
183
|
+
user : (await (0, readDatabase_1.getUserById)(hit.uid)
|
|
184
|
+
.catch(() => false));
|
|
185
|
+
if (!student)
|
|
186
|
+
return;
|
|
187
|
+
console.log("STUDENNT", hit.objectID, student);
|
|
188
|
+
const finalData = { ...hit, student: student };
|
|
189
|
+
return [hit.objectID, finalData];
|
|
190
|
+
}))) : []).filter((e) => e !== undefined);
|
|
191
|
+
console.log("FOUND", i.length, "placement");
|
|
192
|
+
placementsFound = { ...Object.fromEntries(i), ...placementsFound };
|
|
193
|
+
console.log("found", placementsFound);
|
|
194
|
+
setPlacements(placementsFound);
|
|
195
|
+
setLoadMoreIcon(false);
|
|
196
|
+
};
|
|
197
|
+
searchPlacements();
|
|
198
|
+
}, [query]);
|
|
119
199
|
const reset = () => {
|
|
120
200
|
setPlacements(undefined);
|
|
121
201
|
setStartPlacementAfter([undefined, 0]);
|
|
@@ -127,10 +207,10 @@ function useNewInstitutePlacementList({ id, user, cohort, queryConstraint, ql =
|
|
|
127
207
|
setPlacements(undefined);
|
|
128
208
|
setStartPlacementAfter([undefined, 0]);
|
|
129
209
|
loadMorePlacements([undefined, 0]);
|
|
130
|
-
}, [
|
|
210
|
+
}, [queryConstraints]);
|
|
131
211
|
const loadMorePlacements = async (fStartPlacementAfter = startPlacementAfter) => {
|
|
132
212
|
var _a;
|
|
133
|
-
if (user.viewCohorts === "none" || !oId) {
|
|
213
|
+
if (query || user.viewCohorts === "none" || !oId) {
|
|
134
214
|
setLoadMoreIcon(false);
|
|
135
215
|
return;
|
|
136
216
|
}
|
|
@@ -144,7 +224,7 @@ function useNewInstitutePlacementList({ id, user, cohort, queryConstraint, ql =
|
|
|
144
224
|
(0, firestore_1.startAfter)(fStartPlacementAfter[0])] :
|
|
145
225
|
[(0, firestore_1.limit)(placements ? DEFAULTQUERYLIMIT : initialQueryLimit), ...(queryConstraintOrdered ? [] : [(0, firestore_1.orderBy)((0, firestore_1.documentId)())])];
|
|
146
226
|
queryConstraints && constraints.unshift(...queryConstraints);
|
|
147
|
-
query
|
|
227
|
+
// query && constraints.unshift(where("name", "==", query));
|
|
148
228
|
cohort && constraints.unshift((0, firestore_1.where)("cohort", "==", cohort));
|
|
149
229
|
const placementsQuery = await (0, readDatabase_1.getPlacementsWhere)({ w: constraints, oId: oId, raw: true });
|
|
150
230
|
const placementsWithStudentData = placementsQuery.empty ? [] : await Promise.all(placementsQuery.docs.map(async (placement) => {
|
|
@@ -178,7 +258,6 @@ function useNewInstitutePlacementList({ id, user, cohort, queryConstraint, ql =
|
|
|
178
258
|
};
|
|
179
259
|
return ({ ...{ placements, loadMoreIcon, loadMorePlacements, setQuery, setInitialQueryLimit, reset, changeQueryConstraints } });
|
|
180
260
|
}
|
|
181
|
-
exports.useNewInstitutePlacementList = useNewInstitutePlacementList;
|
|
182
261
|
function useOldInstitutePlacementList({ user, cohort, queryConstraint, ql = DEFAULTQUERYLIMIT }) {
|
|
183
262
|
const [loadMoreIcon, setLoadMoreIcon] = (0, react_1.useState)(true);
|
|
184
263
|
const [query, setQuery] = (0, react_1.useState)("");
|
|
@@ -372,7 +451,6 @@ function useOldInstitutePlacementList({ user, cohort, queryConstraint, ql = DEFA
|
|
|
372
451
|
};
|
|
373
452
|
return ({ ...{ placements, loadMoreIcon, loadMorePlacements, setQuery, setInitialQueryLimit, reset, changeQueryConstraints } });
|
|
374
453
|
}
|
|
375
|
-
exports.useOldInstitutePlacementList = useOldInstitutePlacementList;
|
|
376
454
|
function useFilterTablePaginator({ data }) {
|
|
377
455
|
const [tableData, setTableData] = (0, react_1.useState)(Array.isArray(data) ? Object.fromEntries(Object.entries(data).slice(0, 10)) : {});
|
|
378
456
|
const [page, setPage] = (0, react_1.useState)([1, 0]);
|
|
@@ -401,14 +479,7 @@ function useFilterTablePaginator({ data }) {
|
|
|
401
479
|
filters && Object.entries(filters).forEach(([key, value]) => {
|
|
402
480
|
constraints.push((0, firestore_1.where)(key, "==", value));
|
|
403
481
|
});
|
|
404
|
-
|
|
405
|
-
if (queryData.orderBy === "documentId") {
|
|
406
|
-
constraints.push((0, firestore_1.orderBy)((0, firestore_1.documentId)()));
|
|
407
|
-
}
|
|
408
|
-
else {
|
|
409
|
-
constraints.push((0, firestore_1.orderBy)(queryData.orderBy));
|
|
410
|
-
}
|
|
411
|
-
}
|
|
482
|
+
constraints.push((0, firestore_1.orderBy)(queryData.orderBy ? queryData.orderBy === "documentId" ? (0, firestore_1.documentId)() : queryData.orderBy : (0, firestore_1.documentId)()));
|
|
412
483
|
if (page[0] > page[1] && !cursorDirection) { // Going up
|
|
413
484
|
currentQueryAnchor.endKey && constraints.push((0, firestore_1.startAfter)(currentQueryAnchor.endKey));
|
|
414
485
|
constraints.push((0, firestore_1.limit)(10));
|
|
@@ -505,6 +576,7 @@ function useFilterTablePaginator({ data }) {
|
|
|
505
576
|
const listenForUpdates = () => {
|
|
506
577
|
if (!Object.keys(itemList).length)
|
|
507
578
|
return;
|
|
579
|
+
console.log("Fetching filter table updates");
|
|
508
580
|
const itemListUpdateQuery = (0, firestore_1.query)((0, firestore_1.collection)(firebaseConfig_1.db, "users"), (0, firestore_1.where)((0, firestore_1.documentId)(), "in", Object.keys(itemList)));
|
|
509
581
|
const itemUpdateSnapshot = (0, firestore_1.onSnapshot)(itemListUpdateQuery, (querySnapshot) => {
|
|
510
582
|
querySnapshot.docs.forEach((doc) => {
|
|
@@ -535,9 +607,8 @@ function useFilterTablePaginator({ data }) {
|
|
|
535
607
|
getDataFromQuery();
|
|
536
608
|
dataListenerUnsubscribe && dataListenerUnsubscribe();
|
|
537
609
|
}, [page]);
|
|
538
|
-
return ({ ...{ tableData, setPage, setFilters } });
|
|
610
|
+
return ({ ...{ tableData, setPage, setFilters, page } });
|
|
539
611
|
}
|
|
540
|
-
exports.useFilterTablePaginator = useFilterTablePaginator;
|
|
541
612
|
function usePlacementListingPaginator({ data, user }) {
|
|
542
613
|
const [tableData, setTableData] = (0, react_1.useState)({});
|
|
543
614
|
const [page, setPage] = (0, react_1.useState)([1, 0]);
|
|
@@ -553,16 +624,23 @@ function usePlacementListingPaginator({ data, user }) {
|
|
|
553
624
|
else {
|
|
554
625
|
cursorPos = currentQueryAnchor.startQueryPos;
|
|
555
626
|
}
|
|
556
|
-
const querySchema = data[cursorPos];
|
|
627
|
+
const querySchema = data === null || data === void 0 ? void 0 : data[cursorPos];
|
|
557
628
|
const createQuery = (queryData) => {
|
|
558
|
-
const constraints = [
|
|
559
|
-
|
|
629
|
+
const constraints = [
|
|
630
|
+
(0, firestore_1.where)("savedById", "==", user.userType === "Staff" ? user.oId : user.id),
|
|
631
|
+
(0, firestore_1.where)("savedByProduct", "==", user.product),
|
|
632
|
+
(0, firestore_1.where)("savedByUserType", "==", user.userType === "Staff" ? "Organisation" : "Student"),
|
|
633
|
+
];
|
|
634
|
+
if (user.userType === "Students") {
|
|
635
|
+
constraints.push((0, firestore_1.where)("listed", "==", true));
|
|
636
|
+
}
|
|
637
|
+
(queryData === null || queryData === void 0 ? void 0 : queryData.where) && queryData.where.forEach((w) => {
|
|
560
638
|
constraints.push((0, firestore_1.where)(...w));
|
|
561
639
|
});
|
|
562
640
|
filters && Object.entries(filters).forEach(([key, value]) => {
|
|
563
641
|
constraints.push((0, firestore_1.where)(key, "==", value));
|
|
564
642
|
});
|
|
565
|
-
if (queryData.orderBy) {
|
|
643
|
+
if (queryData === null || queryData === void 0 ? void 0 : queryData.orderBy) {
|
|
566
644
|
if (queryData.orderBy === "documentId") {
|
|
567
645
|
constraints.push((0, firestore_1.orderBy)((0, firestore_1.documentId)()));
|
|
568
646
|
}
|
|
@@ -570,6 +648,9 @@ function usePlacementListingPaginator({ data, user }) {
|
|
|
570
648
|
constraints.push((0, firestore_1.orderBy)(queryData.orderBy));
|
|
571
649
|
}
|
|
572
650
|
}
|
|
651
|
+
else {
|
|
652
|
+
constraints.push((0, firestore_1.orderBy)((0, firestore_1.documentId)()));
|
|
653
|
+
}
|
|
573
654
|
if (page[0] > page[1] && !cursorDirection) { // Going up
|
|
574
655
|
currentQueryAnchor.endKey && constraints.push((0, firestore_1.startAfter)(currentQueryAnchor.endKey));
|
|
575
656
|
constraints.push((0, firestore_1.limit)(10));
|
|
@@ -601,7 +682,7 @@ function usePlacementListingPaginator({ data, user }) {
|
|
|
601
682
|
};
|
|
602
683
|
const constraints = createQuery(querySchema);
|
|
603
684
|
// console.log(queryId, "constraints", constraints)
|
|
604
|
-
const q = (0, firestore_1.query)((0, firestore_1.collection)(firebaseConfig_1.db,
|
|
685
|
+
const q = (0, firestore_1.query)((0, firestore_1.collection)(firebaseConfig_1.db, "savedPlacements"), ...(constraints));
|
|
605
686
|
const queryResults = {};
|
|
606
687
|
const queryData = await (0, firestore_1.getDocs)(q);
|
|
607
688
|
// console.log("queryData.size", queryData.size)
|
|
@@ -665,17 +746,19 @@ function usePlacementListingPaginator({ data, user }) {
|
|
|
665
746
|
}
|
|
666
747
|
setQueryAnchor({ ...currentQueryAnchor, startKey: Object.keys(itemList)[0], endKey: Object.keys(itemList).slice(-1)[0] });
|
|
667
748
|
const finalData = Object.fromEntries(await Promise.all(Object.entries(itemList).map(async ([k, v]) => {
|
|
668
|
-
const
|
|
669
|
-
const
|
|
670
|
-
const
|
|
671
|
-
|
|
749
|
+
const placement = await firebaseQuery.getDocData(["placementListings", v.placementId || ""]);
|
|
750
|
+
const address = await firebaseQuery.getDocData(["addresses", placement.addressId || ""]);
|
|
751
|
+
const provider = await firebaseQuery.getDocData(["providers", placement.providerId || ""]);
|
|
752
|
+
const status = getPlacementStatus(provider, placement, v);
|
|
753
|
+
return [k, { ...address, ...provider, ...placement, email: placement.providerEmail, status: status, savedPlacement: v }];
|
|
672
754
|
})));
|
|
673
755
|
setTableData(finalData);
|
|
674
756
|
};
|
|
675
|
-
const getPlacementStatus = (placement) => {
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
757
|
+
const getPlacementStatus = (provider, placement, savedPlacement) => {
|
|
758
|
+
if (savedPlacement.status === "Blocked")
|
|
759
|
+
return "blocked";
|
|
760
|
+
if (savedPlacement.status === "Accepted")
|
|
761
|
+
return "active";
|
|
679
762
|
if (user.product === "admin") {
|
|
680
763
|
if (placement.mapConsent === undefined)
|
|
681
764
|
return "notReviewed";
|
|
@@ -684,13 +767,7 @@ function usePlacementListingPaginator({ data, user }) {
|
|
|
684
767
|
return "unknown";
|
|
685
768
|
}
|
|
686
769
|
;
|
|
687
|
-
if (!
|
|
688
|
-
return "awaitingProviderApproval";
|
|
689
|
-
if (placement.savedBy[user.oId].status === "approved")
|
|
690
|
-
return "active";
|
|
691
|
-
if (placement.savedBy[user.oId].status === "blocked")
|
|
692
|
-
return "blocked";
|
|
693
|
-
if (placement.savedBy[user.oId].status === "rejected")
|
|
770
|
+
if (!provider.insurance)
|
|
694
771
|
return "awaitingProviderApproval";
|
|
695
772
|
return "requiresApproval";
|
|
696
773
|
};
|
|
@@ -706,10 +783,9 @@ function usePlacementListingPaginator({ data, user }) {
|
|
|
706
783
|
(0, react_1.useEffect)(() => {
|
|
707
784
|
getDataFromQuery();
|
|
708
785
|
}, [page]);
|
|
709
|
-
return ({ ...{ tableData, setPage, setFilters } });
|
|
786
|
+
return ({ ...{ tableData, setPage, setFilters, page } });
|
|
710
787
|
}
|
|
711
|
-
|
|
712
|
-
function useCohortUserPaginator({ user, cohort, data }) {
|
|
788
|
+
function useCohortUserPaginator({ user, cohort, data, search, userType }) {
|
|
713
789
|
const [tableData, setTableData] = (0, react_1.useState)({});
|
|
714
790
|
const [queryAnchor, setQueryAnchor] = (0, react_1.useState)({ startKey: "", endKey: "", startQueryPos: 0, endQueryPos: 0 });
|
|
715
791
|
const [filters, setFilters] = (0, react_1.useState)();
|
|
@@ -717,13 +793,19 @@ function useCohortUserPaginator({ user, cohort, data }) {
|
|
|
717
793
|
const [page, setPage] = (0, react_1.useState)([1, 0]);
|
|
718
794
|
const [dataListenerUnsubscribe, setDataListenerUnsubscribe] = (0, react_1.useState)();
|
|
719
795
|
const [queries, setQueries] = (0, react_1.useState)();
|
|
796
|
+
const [prevSearch, setPrevSearch] = (0, react_1.useState)();
|
|
797
|
+
const algoliaClient = (0, algoliasearch_1.default)(process.env.NODE_ENV === "development" ? "A0ZB50I7VS" : "XMPXCMUUOJ", user.algoliaKey);
|
|
798
|
+
const usersIndex = algoliaClient.initIndex("users");
|
|
720
799
|
(0, react_1.useEffect)(() => {
|
|
721
800
|
var _a;
|
|
722
801
|
if (user.userType !== "Staff") {
|
|
802
|
+
console.log("Not a staff member", user);
|
|
723
803
|
setQueries(undefined);
|
|
724
804
|
return;
|
|
725
805
|
}
|
|
726
|
-
if ((!user.viewCohorts && user.userGroup !== "admin") ||
|
|
806
|
+
if ((!user.viewCohorts && user.userGroup !== "admin") ||
|
|
807
|
+
user.viewCohorts === "none" ||
|
|
808
|
+
(user.viewCohorts === "some" && cohort !== "all" && !((_a = user.visibleCohorts) === null || _a === void 0 ? void 0 : _a.split(",").includes(cohort || "")))) {
|
|
727
809
|
setQueries(undefined);
|
|
728
810
|
return;
|
|
729
811
|
}
|
|
@@ -754,9 +836,6 @@ function useCohortUserPaginator({ user, cohort, data }) {
|
|
|
754
836
|
return finalConstraints;
|
|
755
837
|
});
|
|
756
838
|
}, []);
|
|
757
|
-
(0, react_1.useEffect)(() => {
|
|
758
|
-
console.log("TD", tableData);
|
|
759
|
-
}, [tableData]);
|
|
760
839
|
const getDataFromQuery = async (itemList = {}, currentQueryAnchor = queryAnchor, cursorDirection, prevEntries = prevEntryIds, loadMoreFromQuery = false) => {
|
|
761
840
|
if (!queries) {
|
|
762
841
|
setTableData({});
|
|
@@ -776,7 +855,12 @@ function useCohortUserPaginator({ user, cohort, data }) {
|
|
|
776
855
|
console.log("mConstraints", mConstraints);
|
|
777
856
|
const fConstraints = [...mConstraints];
|
|
778
857
|
filters && Object.entries(filters).forEach(([key, value]) => {
|
|
779
|
-
|
|
858
|
+
if (typeof value === "object") {
|
|
859
|
+
fConstraints.push(value);
|
|
860
|
+
}
|
|
861
|
+
else {
|
|
862
|
+
fConstraints.push((0, firestore_1.where)(key, "==", value));
|
|
863
|
+
}
|
|
780
864
|
});
|
|
781
865
|
fConstraints.push((0, firestore_1.orderBy)((0, firestore_1.documentId)()));
|
|
782
866
|
if (page[0] > page[1] && !cursorDirection) { // Going up
|
|
@@ -871,6 +955,7 @@ function useCohortUserPaginator({ user, cohort, data }) {
|
|
|
871
955
|
const listenForUpdates = () => {
|
|
872
956
|
if (!Object.keys(itemList).length)
|
|
873
957
|
return;
|
|
958
|
+
console.log("Fetching cohort user data");
|
|
874
959
|
const itemListUpdateQuery = (0, firestore_1.query)((0, firestore_1.collection)(firebaseConfig_1.db, "users"), (0, firestore_1.where)((0, firestore_1.documentId)(), "in", Object.keys(itemList)));
|
|
875
960
|
const itemUpdateSnapshot = (0, firestore_1.onSnapshot)(itemListUpdateQuery, (querySnapshot) => {
|
|
876
961
|
querySnapshot.docs.forEach((doc) => {
|
|
@@ -886,23 +971,57 @@ function useCohortUserPaginator({ user, cohort, data }) {
|
|
|
886
971
|
setQueryAnchor({ ...currentQueryAnchor, startKey: Object.keys(itemList)[0], endKey: Object.keys(itemList).slice(-1)[0] });
|
|
887
972
|
setTableData(itemList);
|
|
888
973
|
};
|
|
974
|
+
const searchUsers = async () => {
|
|
975
|
+
if (!search)
|
|
976
|
+
return;
|
|
977
|
+
let userSearchString = `userType:${userType} AND oId:${user.oId} AND product:${user.product}`;
|
|
978
|
+
if (cohort && cohort !== "all") {
|
|
979
|
+
userSearchString = userSearchString + ` AND cohort:${cohort}`;
|
|
980
|
+
}
|
|
981
|
+
Object.entries(filters || {}).forEach(([field, value]) => {
|
|
982
|
+
userSearchString = userSearchString + ` AND ${field}:${value}`;
|
|
983
|
+
});
|
|
984
|
+
console.log("Going", page[0] > page[1] ? "up" : "down");
|
|
985
|
+
console.log("Start at", page[0] > page[1] ? page[1] : page[1] - 1);
|
|
986
|
+
const searchStudentHits = await usersIndex.search(search, {
|
|
987
|
+
filters: userSearchString,
|
|
988
|
+
length: 10,
|
|
989
|
+
offset: 10 * (page[0] > page[1] ? page[1] : (page[0] - 1))
|
|
990
|
+
});
|
|
991
|
+
const results = Object.fromEntries(await Promise.all(searchStudentHits.hits.map(async (hit) => {
|
|
992
|
+
return [hit.objectID, hit];
|
|
993
|
+
})));
|
|
994
|
+
setPrevSearch(search);
|
|
995
|
+
setTableData(results);
|
|
996
|
+
};
|
|
889
997
|
(0, react_1.useEffect)(() => {
|
|
890
|
-
if (!filters)
|
|
998
|
+
if (!filters && !prevSearch && !search)
|
|
999
|
+
return;
|
|
1000
|
+
if (search && prevSearch) {
|
|
1001
|
+
console.log("New search");
|
|
1002
|
+
setPrevSearch(search);
|
|
891
1003
|
return;
|
|
1004
|
+
}
|
|
1005
|
+
console.log("Setting page");
|
|
892
1006
|
setPage([1, 0]);
|
|
1007
|
+
console.log("Set page");
|
|
893
1008
|
setTableData({});
|
|
894
1009
|
setQueryAnchor({ startKey: "", endKey: "", startQueryPos: 0, endQueryPos: 0 });
|
|
895
1010
|
setPrevEntryIds({});
|
|
896
1011
|
dataListenerUnsubscribe && dataListenerUnsubscribe();
|
|
897
|
-
}, [filters]);
|
|
1012
|
+
}, [filters, search]);
|
|
898
1013
|
// Fetch new data when queries or page change
|
|
899
1014
|
(0, react_1.useEffect)(() => {
|
|
1015
|
+
if (search) {
|
|
1016
|
+
console.log("PAGE", page);
|
|
1017
|
+
searchUsers();
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
900
1020
|
getDataFromQuery();
|
|
901
1021
|
dataListenerUnsubscribe && dataListenerUnsubscribe();
|
|
902
|
-
}, [page]);
|
|
903
|
-
return ({ ...{ tableData, setPage, setFilters } });
|
|
1022
|
+
}, [page, queries, prevSearch]);
|
|
1023
|
+
return ({ ...{ tableData, setPage, page, setFilters } });
|
|
904
1024
|
}
|
|
905
|
-
exports.useCohortUserPaginator = useCohortUserPaginator;
|
|
906
1025
|
function useAdmissionsPaginator({ data }) {
|
|
907
1026
|
const [tableData, setTableData] = (0, react_1.useState)({});
|
|
908
1027
|
const [page, setPage] = (0, react_1.useState)([1, 0]);
|
|
@@ -916,8 +1035,7 @@ function useAdmissionsPaginator({ data }) {
|
|
|
916
1035
|
}, [filters]);
|
|
917
1036
|
return ({ ...{ tableData, setPage, setFilters } });
|
|
918
1037
|
}
|
|
919
|
-
|
|
920
|
-
function useLazyLoadQueryList({ path, constraints, number }) {
|
|
1038
|
+
function useLazyLoadQueryList({ path, constraints, number, onItemFetched }) {
|
|
921
1039
|
const [items, setItems] = (0, react_1.useState)({});
|
|
922
1040
|
const [loadMoreIcon, setLoadMoreIcon] = (0, react_1.useState)(false);
|
|
923
1041
|
const [lastItem, setLastItem] = (0, react_1.useState)();
|
|
@@ -927,6 +1045,7 @@ function useLazyLoadQueryList({ path, constraints, number }) {
|
|
|
927
1045
|
setLastItem(undefined);
|
|
928
1046
|
};
|
|
929
1047
|
const loadMore = async () => {
|
|
1048
|
+
var _a;
|
|
930
1049
|
setLoadMoreIcon(true);
|
|
931
1050
|
let formattedConstraints = [];
|
|
932
1051
|
if (constraints) {
|
|
@@ -936,8 +1055,73 @@ function useLazyLoadQueryList({ path, constraints, number }) {
|
|
|
936
1055
|
formattedConstraints.push((0, firestore_1.startAfter)(lastItem));
|
|
937
1056
|
}
|
|
938
1057
|
const documents = await firebaseQuery.getDocsWhere(path, formattedConstraints, true);
|
|
1058
|
+
console.log("docs", documents);
|
|
1059
|
+
if (documents === null || documents === void 0 ? void 0 : documents.empty) {
|
|
1060
|
+
setLoadMoreIcon(false);
|
|
1061
|
+
return;
|
|
1062
|
+
}
|
|
1063
|
+
setLastItem(documents === null || documents === void 0 ? void 0 : documents.docs[((_a = documents === null || documents === void 0 ? void 0 : documents.docs) === null || _a === void 0 ? void 0 : _a.length) - 1]);
|
|
1064
|
+
const processedItems = Object.fromEntries(await Promise.all(Object.values((documents === null || documents === void 0 ? void 0 : documents.docs) || {}).map(async (doc) => {
|
|
1065
|
+
const itemObj = { ...doc.data(), id: doc.id, docPath: doc.ref };
|
|
1066
|
+
return [doc.id, onItemFetched ? await onItemFetched(itemObj) : itemObj];
|
|
1067
|
+
})));
|
|
1068
|
+
setItems((i) => ({ ...i, ...processedItems }));
|
|
1069
|
+
setLoadMoreIcon(false);
|
|
1070
|
+
};
|
|
1071
|
+
(0, react_1.useEffect)(() => {
|
|
1072
|
+
loadMore();
|
|
1073
|
+
}, []);
|
|
1074
|
+
return ({ ...{ items, loadMore, loadMoreIcon, reset } });
|
|
1075
|
+
}
|
|
1076
|
+
function usePublicPlacementListingLoader({ providerId, number = 5 }) {
|
|
1077
|
+
const [items, setItems] = (0, react_1.useState)({});
|
|
1078
|
+
const [loadMoreIcon, setLoadMoreIcon] = (0, react_1.useState)(false);
|
|
1079
|
+
const [lastItem, setLastItem] = (0, react_1.useState)();
|
|
1080
|
+
const firebaseQuery = new firebaseQuery_1.default();
|
|
1081
|
+
const reset = () => {
|
|
1082
|
+
setItems({});
|
|
1083
|
+
setLastItem(undefined);
|
|
1084
|
+
};
|
|
1085
|
+
const loadMore = async () => {
|
|
1086
|
+
setLoadMoreIcon(true);
|
|
1087
|
+
let formattedConstraints = [
|
|
1088
|
+
(0, firestore_1.where)("status", "==", "listed"),
|
|
1089
|
+
(0, firestore_1.limit)(number)
|
|
1090
|
+
];
|
|
1091
|
+
if (providerId) {
|
|
1092
|
+
formattedConstraints.push((0, firestore_1.where)("providerId", "==", providerId));
|
|
1093
|
+
}
|
|
1094
|
+
if (lastItem) {
|
|
1095
|
+
formattedConstraints.push((0, firestore_1.startAfter)(lastItem));
|
|
1096
|
+
}
|
|
1097
|
+
const documents = await firebaseQuery.getDocsWhere("placementListings", formattedConstraints, true);
|
|
1098
|
+
console.log("docs", documents.docs);
|
|
939
1099
|
setLastItem(documents.docs[documents.docs.length - 1]);
|
|
940
|
-
|
|
1100
|
+
const processedItems = Object.fromEntries(await Promise.all(Object.values(documents.docs).map(async (doc) => {
|
|
1101
|
+
var _a, _b;
|
|
1102
|
+
let itemObj = { ...doc.data(), id: doc.id };
|
|
1103
|
+
if (itemObj.addressId) {
|
|
1104
|
+
const address = await firebaseQuery.getDocData(["addresses", itemObj.addressId]);
|
|
1105
|
+
delete address.id;
|
|
1106
|
+
itemObj = { ...address, ...itemObj };
|
|
1107
|
+
}
|
|
1108
|
+
if (itemObj.applicantWorkflowId) {
|
|
1109
|
+
const applicantWorkflow = (await firebaseQuery.getDocData(["applicantWorkflows", itemObj.applicantWorkflowId])).workflow.filter((i) => i.id === 1)[0];
|
|
1110
|
+
const applicantFiles = applicantWorkflow.files ? Object.fromEntries(await Promise.all((_a = applicantWorkflow.files) === null || _a === void 0 ? void 0 : _a.map(async (fileId) => {
|
|
1111
|
+
const file = await firebaseQuery.getDocData(["files", fileId]);
|
|
1112
|
+
file.url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `userFiles/${file.fileName}`));
|
|
1113
|
+
return [fileId, file];
|
|
1114
|
+
}))) : [];
|
|
1115
|
+
const applicantForms = applicantWorkflow.forms ? Object.fromEntries(await Promise.all((_b = applicantWorkflow.forms) === null || _b === void 0 ? void 0 : _b.map(async (formId) => {
|
|
1116
|
+
return [formId, await firebaseQuery.getDocData(["forms", formId])];
|
|
1117
|
+
}))) : [];
|
|
1118
|
+
applicantWorkflow.viewableFiles = applicantFiles;
|
|
1119
|
+
applicantWorkflow.formDetails = applicantForms;
|
|
1120
|
+
itemObj = { ...itemObj, applicantWorkflow: [applicantWorkflow] };
|
|
1121
|
+
}
|
|
1122
|
+
return [doc.id, itemObj];
|
|
1123
|
+
})));
|
|
1124
|
+
setItems((i) => ({ ...i, ...processedItems }));
|
|
941
1125
|
setLoadMoreIcon(false);
|
|
942
1126
|
};
|
|
943
1127
|
(0, react_1.useEffect)(() => {
|
|
@@ -945,7 +1129,308 @@ function useLazyLoadQueryList({ path, constraints, number }) {
|
|
|
945
1129
|
}, []);
|
|
946
1130
|
return ({ ...{ items, loadMore, loadMoreIcon, reset } });
|
|
947
1131
|
}
|
|
948
|
-
|
|
1132
|
+
function useCreateApplicationRenderer({ user, listingId, listing, provider, application, applicationId, orgContext }) {
|
|
1133
|
+
const firebaseQuery = new firebaseQuery_1.default();
|
|
1134
|
+
let applicationWithoutAdditionalData = { ...(application || {}) };
|
|
1135
|
+
delete applicationWithoutAdditionalData.listing;
|
|
1136
|
+
delete applicationWithoutAdditionalData.address;
|
|
1137
|
+
delete applicationWithoutAdditionalData.provider;
|
|
1138
|
+
const [fApplication, setFApplication] = (0, react_1.useState)(application ? applicationWithoutAdditionalData : {
|
|
1139
|
+
uid: user.userType === "Students" ? user.id : undefined,
|
|
1140
|
+
listingId: listingId,
|
|
1141
|
+
stage: 1,
|
|
1142
|
+
reqUserType: "Students",
|
|
1143
|
+
status: "draft"
|
|
1144
|
+
});
|
|
1145
|
+
const [fApplicationId, setFApplicationId] = (0, react_1.useState)(applicationId);
|
|
1146
|
+
const [draftSaved, setDraftSaved] = (0, react_1.useState)(false);
|
|
1147
|
+
const [fProvider, setFProvider] = (0, react_1.useState)(provider);
|
|
1148
|
+
const [fListing, setFListing] = (0, react_1.useState)(listing);
|
|
1149
|
+
const [student, setStudent] = (0, react_1.useState)(user.userType === "Students" ? user : undefined);
|
|
1150
|
+
const [profileUrl, setProfileUrl] = (0, react_1.useState)();
|
|
1151
|
+
const [successPopup, setSuccessPopup] = (0, react_1.useState)();
|
|
1152
|
+
const [uploadedFiles, setUploadedFiles] = (0, react_1.useState)();
|
|
1153
|
+
const [currentStageComplete, setCurrentStageComplete] = (0, react_1.useState)();
|
|
1154
|
+
(0, react_1.useEffect)(() => {
|
|
1155
|
+
const getListing = async () => {
|
|
1156
|
+
console.log("Checking ID");
|
|
1157
|
+
if (!listingId)
|
|
1158
|
+
return;
|
|
1159
|
+
console.log("Getting listing");
|
|
1160
|
+
const listingData = listing || await firebaseQuery.getDocData(["placementListings", listingId]);
|
|
1161
|
+
const address = (user.product === "providers" && orgContext) ? orgContext.addresses[listingData.addressId || ""] : await firebaseQuery.getDocData(["addresses", listingData.addressId]);
|
|
1162
|
+
const workflow = (user.product === "providers" && orgContext) ? orgContext.applicantWorkflows[listingData.applicantWorkflowId || ""] : await firebaseQuery.getDocData(["applicantWorkflows", listingData.applicantWorkflowId]);
|
|
1163
|
+
workflow.workflow = await Promise.all(workflow.workflow.map(async (s) => {
|
|
1164
|
+
var _a, _b;
|
|
1165
|
+
const applicantFiles = s.files ? Object.fromEntries(await Promise.all((_a = s.files) === null || _a === void 0 ? void 0 : _a.map(async (fileId) => {
|
|
1166
|
+
const file = await firebaseQuery.getDocData(["files", fileId]);
|
|
1167
|
+
file.url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `userFiles/${file.fileName}`));
|
|
1168
|
+
return [fileId, file];
|
|
1169
|
+
}))) : [];
|
|
1170
|
+
const applicantForms = s.forms ? Object.fromEntries(await Promise.all((_b = s.forms) === null || _b === void 0 ? void 0 : _b.map(async (formId) => {
|
|
1171
|
+
return [formId, await firebaseQuery.getDocData(["forms", formId])];
|
|
1172
|
+
}))) : [];
|
|
1173
|
+
return { ...s, viewableFiles: applicantFiles, formDetails: applicantForms };
|
|
1174
|
+
}));
|
|
1175
|
+
delete address.id;
|
|
1176
|
+
delete workflow.id;
|
|
1177
|
+
console.log("Setting listing");
|
|
1178
|
+
setFListing({ ...listingData, ...address, applicantWorkflow: workflow.workflow });
|
|
1179
|
+
console.log("Getting provider", listingData === null || listingData === void 0 ? void 0 : listingData.providerId);
|
|
1180
|
+
if (((fProvider === null || fProvider === void 0 ? void 0 : fProvider.id) === (application === null || application === void 0 ? void 0 : application.providerId)) && user.product === "providers") {
|
|
1181
|
+
setFProvider({ details: orgContext === null || orgContext === void 0 ? void 0 : orgContext.details, id: user.oId });
|
|
1182
|
+
}
|
|
1183
|
+
else if (listingData === null || listingData === void 0 ? void 0 : listingData.providerId) {
|
|
1184
|
+
console.log("Getting provider from DB");
|
|
1185
|
+
const provider = await firebaseQuery.getDocData(["providers", listingData.providerId]);
|
|
1186
|
+
console.log("Provider", provider);
|
|
1187
|
+
setFProvider({ details: provider, id: listingData.providerId });
|
|
1188
|
+
}
|
|
1189
|
+
};
|
|
1190
|
+
getListing();
|
|
1191
|
+
}, [listingId, listing]);
|
|
1192
|
+
(0, react_1.useEffect)(() => {
|
|
1193
|
+
if ((student === null || student === void 0 ? void 0 : student.id) !== (application === null || application === void 0 ? void 0 : application.uid)) {
|
|
1194
|
+
if (user.userType === "Students") {
|
|
1195
|
+
setStudent(user);
|
|
1196
|
+
}
|
|
1197
|
+
else if (user.product === "providers" && (application === null || application === void 0 ? void 0 : application.uid)) {
|
|
1198
|
+
firebaseQuery.getDocData(["users", application.uid]).then((s) => setStudent(s));
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
}, []);
|
|
1202
|
+
(0, react_1.useEffect)(() => {
|
|
1203
|
+
setFListing(listing);
|
|
1204
|
+
}, [listing]);
|
|
1205
|
+
(0, react_1.useEffect)(() => {
|
|
1206
|
+
if (provider === null || provider === void 0 ? void 0 : provider.profile)
|
|
1207
|
+
return;
|
|
1208
|
+
if (!(provider === null || provider === void 0 ? void 0 : provider.id))
|
|
1209
|
+
return;
|
|
1210
|
+
(0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `providers/${provider === null || provider === void 0 ? void 0 : provider.id}/profilePic.png`)).then(setProfileUrl).catch(() => null);
|
|
1211
|
+
}, [provider]);
|
|
1212
|
+
(0, react_1.useEffect)(() => {
|
|
1213
|
+
console.log("APPLICATIONID", applicationId);
|
|
1214
|
+
if (!applicationId) {
|
|
1215
|
+
if (!listingId)
|
|
1216
|
+
return;
|
|
1217
|
+
firebaseQuery.getDocsWhere("applications", [(0, firestore_1.where)("status", "not-in", ["approved", "declined"]), (0, firestore_1.where)("uid", "==", user.id), (0, firestore_1.where)("listingId", "==", listingId)]).then((existingApplication) => {
|
|
1218
|
+
console.log("EXISTING", existingApplication);
|
|
1219
|
+
// get uploaded files
|
|
1220
|
+
if (existingApplication && Object.keys(existingApplication).length) {
|
|
1221
|
+
setFApplication(Object.values(existingApplication)[0]);
|
|
1222
|
+
setFApplicationId(Object.keys(existingApplication)[0]);
|
|
1223
|
+
}
|
|
1224
|
+
});
|
|
1225
|
+
return;
|
|
1226
|
+
}
|
|
1227
|
+
if (applicationId)
|
|
1228
|
+
setFApplicationId(applicationId);
|
|
1229
|
+
}, [application, applicationId]);
|
|
1230
|
+
const getCurrentStage = async (stage) => {
|
|
1231
|
+
var _a, _b, _c, _d;
|
|
1232
|
+
if (!(fListing === null || fListing === void 0 ? void 0 : fListing.applicantWorkflowId))
|
|
1233
|
+
throw new Error("No workflow stage");
|
|
1234
|
+
const mApplicantWorkflow = await firebaseQuery.getDocData(["applicantWorkflows", fListing.applicantWorkflowId]);
|
|
1235
|
+
const stageObj = (_a = mApplicantWorkflow === null || mApplicantWorkflow === void 0 ? void 0 : mApplicantWorkflow.workflow) === null || _a === void 0 ? void 0 : _a.find((s) => s.id === stage);
|
|
1236
|
+
if (!stageObj)
|
|
1237
|
+
throw new Error("Can't find stage.");
|
|
1238
|
+
const applicantFiles = stageObj.files ? Object.fromEntries(await Promise.all((_b = stageObj.files) === null || _b === void 0 ? void 0 : _b.map(async (fileId) => {
|
|
1239
|
+
const file = await firebaseQuery.getDocData(["files", fileId]);
|
|
1240
|
+
file.url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `userFiles/${file.fileName}`));
|
|
1241
|
+
return [fileId, file];
|
|
1242
|
+
}))) : [];
|
|
1243
|
+
const applicantForms = stageObj.forms ? Object.fromEntries(await Promise.all((_c = stageObj.forms) === null || _c === void 0 ? void 0 : _c.map(async (formId) => {
|
|
1244
|
+
return [formId, await firebaseQuery.getDocData(["forms", formId])];
|
|
1245
|
+
}))) : [];
|
|
1246
|
+
stageObj.viewableFiles = applicantFiles;
|
|
1247
|
+
stageObj.formDetails = applicantForms;
|
|
1248
|
+
return { stage: stageObj, completedSections: ((_d = fApplication === null || fApplication === void 0 ? void 0 : fApplication.completedSections) === null || _d === void 0 ? void 0 : _d[stage]) || {} };
|
|
1249
|
+
};
|
|
1250
|
+
(0, react_1.useEffect)(() => {
|
|
1251
|
+
const getUploadedFiles = async () => {
|
|
1252
|
+
if (!fApplication.completedSections) {
|
|
1253
|
+
setUploadedFiles({});
|
|
1254
|
+
return;
|
|
1255
|
+
}
|
|
1256
|
+
;
|
|
1257
|
+
const fileIds = Object.values(fApplication.completedSections)
|
|
1258
|
+
.flatMap(stageData => Object.values(stageData.filesUploaded || {}).flatMap(fileIds => fileIds));
|
|
1259
|
+
const fileDataPromises = fileIds.map(async (fileId) => {
|
|
1260
|
+
const fileData = await firebaseQuery.getDocData(["files", fileId]);
|
|
1261
|
+
fileData.url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `userFiles/${fileData.fileName}`));
|
|
1262
|
+
return [fileId, fileData];
|
|
1263
|
+
});
|
|
1264
|
+
const fileDataArray = await Promise.all(fileDataPromises);
|
|
1265
|
+
const fileDataObj = Object.fromEntries(fileDataArray);
|
|
1266
|
+
setUploadedFiles(fileDataObj);
|
|
1267
|
+
};
|
|
1268
|
+
const addApplication = async () => {
|
|
1269
|
+
console.log("ADDING APPLICATION");
|
|
1270
|
+
if (!(fListing === null || fListing === void 0 ? void 0 : fListing.id) || !(fProvider === null || fProvider === void 0 ? void 0 : fProvider.id) || !(student === null || student === void 0 ? void 0 : student.id))
|
|
1271
|
+
return;
|
|
1272
|
+
const applicationData = {
|
|
1273
|
+
uid: student.id,
|
|
1274
|
+
listingId: fListing === null || fListing === void 0 ? void 0 : fListing.id,
|
|
1275
|
+
applicantWorkflowId: fListing === null || fListing === void 0 ? void 0 : fListing.applicantWorkflowId,
|
|
1276
|
+
providerId: fProvider.id,
|
|
1277
|
+
stage: 1,
|
|
1278
|
+
status: "draft",
|
|
1279
|
+
created: (new Date()).toISOString(),
|
|
1280
|
+
...fApplication,
|
|
1281
|
+
};
|
|
1282
|
+
const mApplicationId = (await firebaseQuery.add(["applications"], applicationData)).id;
|
|
1283
|
+
console.log("APPLICATION ADDED");
|
|
1284
|
+
setFApplicationId(mApplicationId);
|
|
1285
|
+
setFApplication(applicationData);
|
|
1286
|
+
setDraftSaved(true);
|
|
1287
|
+
return;
|
|
1288
|
+
};
|
|
1289
|
+
getUploadedFiles();
|
|
1290
|
+
console.log("Checking IDs");
|
|
1291
|
+
console.log(fListing === null || fListing === void 0 ? void 0 : fListing.id, fProvider === null || fProvider === void 0 ? void 0 : fProvider.id, student === null || student === void 0 ? void 0 : student.id);
|
|
1292
|
+
if (!(fListing === null || fListing === void 0 ? void 0 : fListing.id) || !(fProvider === null || fProvider === void 0 ? void 0 : fProvider.id) || !(student === null || student === void 0 ? void 0 : student.id))
|
|
1293
|
+
return;
|
|
1294
|
+
if (user.product === "providers")
|
|
1295
|
+
throw new Error("Providers cannot create applications");
|
|
1296
|
+
console.log("Checking dates and sections");
|
|
1297
|
+
if (!fApplication.completedSections && !fApplication.startDate && !fApplication.endDate)
|
|
1298
|
+
return;
|
|
1299
|
+
console.log("Application updated");
|
|
1300
|
+
if (!fApplicationId && !applicationId) {
|
|
1301
|
+
// save new
|
|
1302
|
+
console.log("Add application");
|
|
1303
|
+
addApplication();
|
|
1304
|
+
return;
|
|
1305
|
+
}
|
|
1306
|
+
// update
|
|
1307
|
+
firebaseQuery.update(["applications", (fApplicationId || applicationId)], fApplication);
|
|
1308
|
+
setDraftSaved(true);
|
|
1309
|
+
}, [fApplication]);
|
|
1310
|
+
const openSuccessPopup = (type) => {
|
|
1311
|
+
setSuccessPopup(type);
|
|
1312
|
+
setTimeout(() => {
|
|
1313
|
+
// onClose();
|
|
1314
|
+
}, 1500);
|
|
1315
|
+
};
|
|
1316
|
+
(0, react_1.useEffect)(() => {
|
|
1317
|
+
const areStagesCompleted = async () => {
|
|
1318
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
1319
|
+
if (!fListing)
|
|
1320
|
+
return;
|
|
1321
|
+
if (fApplication.stage === undefined)
|
|
1322
|
+
return undefined;
|
|
1323
|
+
const currentStage = await getCurrentStage(fApplication.stage);
|
|
1324
|
+
console.log("Checking current stage is complete");
|
|
1325
|
+
for (const fileViewed of ((_a = currentStage.stage) === null || _a === void 0 ? void 0 : _a.files) || []) {
|
|
1326
|
+
console.log("Checking file viewed", fileViewed, "in", (_b = currentStage === null || currentStage === void 0 ? void 0 : currentStage.completedSections) === null || _b === void 0 ? void 0 : _b.filesViewed);
|
|
1327
|
+
if (!((_d = (_c = currentStage === null || currentStage === void 0 ? void 0 : currentStage.completedSections) === null || _c === void 0 ? void 0 : _c.filesViewed) === null || _d === void 0 ? void 0 : _d.includes(fileViewed))) {
|
|
1328
|
+
console.log("File not viewed");
|
|
1329
|
+
return false;
|
|
1330
|
+
}
|
|
1331
|
+
else {
|
|
1332
|
+
console.log("File viewed");
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
for (const formCompleted of ((_e = currentStage === null || currentStage === void 0 ? void 0 : currentStage.stage) === null || _e === void 0 ? void 0 : _e.forms) || []) {
|
|
1336
|
+
console.log("Checking form completed", formCompleted, "in", (_f = currentStage === null || currentStage === void 0 ? void 0 : currentStage.completedSections) === null || _f === void 0 ? void 0 : _f.formsCompleted);
|
|
1337
|
+
if (!Object.keys(((_g = currentStage === null || currentStage === void 0 ? void 0 : currentStage.completedSections) === null || _g === void 0 ? void 0 : _g.formsCompleted) || {}).includes(formCompleted)) {
|
|
1338
|
+
console.log("Form not completed");
|
|
1339
|
+
return false;
|
|
1340
|
+
}
|
|
1341
|
+
else {
|
|
1342
|
+
console.log("Form completed");
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
for (let i = 0; i++; i < (((_h = currentStage === null || currentStage === void 0 ? void 0 : currentStage.stage) === null || _h === void 0 ? void 0 : _h.requiredFiles) || []).length) {
|
|
1346
|
+
if (!Object.keys(((_j = currentStage === null || currentStage === void 0 ? void 0 : currentStage.completedSections) === null || _j === void 0 ? void 0 : _j.filesUploaded) || {}).includes(i.toString())) {
|
|
1347
|
+
console.log("Form not uploaded");
|
|
1348
|
+
return false;
|
|
1349
|
+
}
|
|
1350
|
+
else {
|
|
1351
|
+
console.log("Form uploaded");
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
return true;
|
|
1355
|
+
};
|
|
1356
|
+
areStagesCompleted().then(setCurrentStageComplete);
|
|
1357
|
+
}, [fApplication, fListing]);
|
|
1358
|
+
const viewFile = (file, onOpen) => {
|
|
1359
|
+
var _a, _b;
|
|
1360
|
+
if (fApplication.reqUserType !== user.userType)
|
|
1361
|
+
return;
|
|
1362
|
+
if (fApplication.stage === undefined)
|
|
1363
|
+
throw new Error("Missing applciation stage.");
|
|
1364
|
+
const viewableFiles = (_b = (_a = fListing === null || fListing === void 0 ? void 0 : fListing.applicantWorkflow) === null || _a === void 0 ? void 0 : _a.find((stage) => stage.id === fApplication.stage)) === null || _b === void 0 ? void 0 : _b.viewableFiles;
|
|
1365
|
+
setFApplication((a) => {
|
|
1366
|
+
var _a, _b;
|
|
1367
|
+
const oldA = { ...a };
|
|
1368
|
+
const viewedFiles = ((_b = (_a = a.completedSections) === null || _a === void 0 ? void 0 : _a[1]) === null || _b === void 0 ? void 0 : _b.filesViewed) || [];
|
|
1369
|
+
if (viewedFiles === null || viewedFiles === void 0 ? void 0 : viewedFiles.includes(file))
|
|
1370
|
+
return a;
|
|
1371
|
+
(viewableFiles === null || viewableFiles === void 0 ? void 0 : viewableFiles[file].url) && onOpen(viewableFiles === null || viewableFiles === void 0 ? void 0 : viewableFiles[file].url);
|
|
1372
|
+
viewedFiles === null || viewedFiles === void 0 ? void 0 : viewedFiles.push(file);
|
|
1373
|
+
const newA = (0, util_1.editNestedObject)(["completedSections", 1, "filesViewed"], oldA, viewedFiles);
|
|
1374
|
+
return newA;
|
|
1375
|
+
});
|
|
1376
|
+
};
|
|
1377
|
+
const addFile = (files, fileId) => {
|
|
1378
|
+
if (fApplication.reqUserType !== user.userType)
|
|
1379
|
+
throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
|
|
1380
|
+
if (fApplication.stage === undefined)
|
|
1381
|
+
throw new Error("Missing applciation stage.");
|
|
1382
|
+
if (!files.length)
|
|
1383
|
+
throw new Error("No files to upload");
|
|
1384
|
+
setFApplication((a) => (0, util_1.editNestedObject)(["completedSections", fApplication.stage, "filesUploaded", fileId], a, files));
|
|
1385
|
+
};
|
|
1386
|
+
const setFormComplete = (formId, e) => {
|
|
1387
|
+
if (fApplication.reqUserType !== user.userType)
|
|
1388
|
+
throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
|
|
1389
|
+
if (fApplication.stage === undefined)
|
|
1390
|
+
throw new Error("Missing applciation stage.");
|
|
1391
|
+
setFApplication((a) => (0, util_1.editNestedObject)(["completedSections", fApplication.stage, "formsCompleted", formId], a, e));
|
|
1392
|
+
};
|
|
1393
|
+
const successText = {
|
|
1394
|
+
submitted: {
|
|
1395
|
+
title: "Application submitted",
|
|
1396
|
+
desc: "We've sent your application to the placement provider. You will hear what the next steps are soon.",
|
|
1397
|
+
},
|
|
1398
|
+
draftSaved: {
|
|
1399
|
+
title: "Draft saved",
|
|
1400
|
+
desc: "Your draft has been saved. Go to the 'Applications' section from your home screen to edit.",
|
|
1401
|
+
},
|
|
1402
|
+
stageComplete: {
|
|
1403
|
+
title: "Stage complete",
|
|
1404
|
+
desc: "We have sent this to the next stage in the application process. We will update you with any progress.",
|
|
1405
|
+
},
|
|
1406
|
+
outcome: {
|
|
1407
|
+
title: "Outcome submitted",
|
|
1408
|
+
desc: "We have sent the student an email with the outcome of their application.",
|
|
1409
|
+
},
|
|
1410
|
+
};
|
|
1411
|
+
const onFApply = async (draft) => {
|
|
1412
|
+
if (draft) {
|
|
1413
|
+
openSuccessPopup("draftSaved");
|
|
1414
|
+
return;
|
|
1415
|
+
}
|
|
1416
|
+
// Check all items have been filled in.
|
|
1417
|
+
if (!fApplication.startDate || !fApplication.endDate)
|
|
1418
|
+
throw new Error("Please select dates for your placement.");
|
|
1419
|
+
await (0, firebase_1.executeCallable)("applications-submit", { applicationId: fApplicationId });
|
|
1420
|
+
openSuccessPopup("submitted");
|
|
1421
|
+
};
|
|
1422
|
+
const progressStage = async (type, e) => {
|
|
1423
|
+
// Check all stages completed.
|
|
1424
|
+
if (!currentStageComplete)
|
|
1425
|
+
throw new Error("Complete all forms before submitting.");
|
|
1426
|
+
if (fApplication.reqUserType !== user.userType)
|
|
1427
|
+
throw new Error(`Incorrect user type. Expected ${fApplication.reqUserType}, got: ${user.userType}`);
|
|
1428
|
+
if (fApplication.stage === undefined)
|
|
1429
|
+
throw new Error("Missing applciation stage.");
|
|
1430
|
+
await (0, firebase_1.executeCallable)("applications-changeStage", { applicationId: fApplicationId, type: type, feedback: e === null || e === void 0 ? void 0 : e.feedback });
|
|
1431
|
+
};
|
|
1432
|
+
return { successText, onFApply, progressStage, currentStageComplete, uploadedFiles, getCurrentStage, setFormComplete, viewFile, addFile, setSuccessPopup, openSuccessPopup, setFApplication, fApplication, draftSaved, profileUrl, successPopup, fApplicationId, fListing, student, fProvider };
|
|
1433
|
+
}
|
|
949
1434
|
function useProposePlacementRenderer({ user, orgContext, placement }) {
|
|
950
1435
|
const [businessSectionComplete, setBusinessSectionComplete] = (0, react_1.useState)(false);
|
|
951
1436
|
const [addressSectionComplete, setAddressSectionComplete] = (0, react_1.useState)(false);
|
|
@@ -1013,41 +1498,22 @@ function useProposePlacementRenderer({ user, orgContext, placement }) {
|
|
|
1013
1498
|
setFormData(undefined);
|
|
1014
1499
|
};
|
|
1015
1500
|
const proposePlacement = async (draft = false) => {
|
|
1016
|
-
const getPlacementStatus = (startDate, endDate, today) => {
|
|
1017
|
-
if (startDate <= today && endDate >= today)
|
|
1018
|
-
return { active: !draft ? true : false, inProgress: true, completed: false };
|
|
1019
|
-
else if (endDate <= today)
|
|
1020
|
-
return { completed: true, inProgress: false, active: false };
|
|
1021
|
-
return { completed: false, inProgress: true, active: false };
|
|
1022
|
-
};
|
|
1023
1501
|
if (!formData || !student) {
|
|
1024
1502
|
throw new Error("Cannot find placement details.");
|
|
1025
1503
|
}
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
}
|
|
1040
|
-
else if (status.completed) {
|
|
1041
|
-
return { screen: "Completed" };
|
|
1042
|
-
}
|
|
1043
|
-
else {
|
|
1044
|
-
return { screen: "Upcoming" };
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
catch (error) {
|
|
1048
|
-
console.log("Error:", error);
|
|
1049
|
-
throw error;
|
|
1050
|
-
}
|
|
1504
|
+
console.log("formData", formData);
|
|
1505
|
+
if (formData.id && formData.uid && formData.id && draft === formData.draft) {
|
|
1506
|
+
return await firebaseQuery.update(["placements", formData.id], formData);
|
|
1507
|
+
}
|
|
1508
|
+
console.log("STUDENTID", student.id);
|
|
1509
|
+
return await (0, writeDatabase_1.addPlacement)(formData, student.id, draft).catch((e) => {
|
|
1510
|
+
console.log("error");
|
|
1511
|
+
console.log(e);
|
|
1512
|
+
throw e;
|
|
1513
|
+
}).then((e) => {
|
|
1514
|
+
setComplete(true);
|
|
1515
|
+
return e;
|
|
1516
|
+
});
|
|
1051
1517
|
};
|
|
1052
1518
|
const deletePlacement = async (id) => {
|
|
1053
1519
|
return await firebaseQuery.delete(["placements", id]);
|
|
@@ -1057,7 +1523,6 @@ function useProposePlacementRenderer({ user, orgContext, placement }) {
|
|
|
1057
1523
|
setBusinessSectionComplete, setAddressSectionComplete, setPlacementSectionComplete,
|
|
1058
1524
|
proposePlacement, deletePlacement, setStudent, submitSection, setFormData, resetFormData, setStage, setComplete } });
|
|
1059
1525
|
}
|
|
1060
|
-
exports.useProposePlacementRenderer = useProposePlacementRenderer;
|
|
1061
1526
|
const useRefDimensions = () => {
|
|
1062
1527
|
const [dimensions, setDimensions] = (0, react_1.useState)({ width: 1, height: 2 });
|
|
1063
1528
|
const refCallback = (0, react_1.useCallback)((node) => {
|
|
@@ -1073,10 +1538,10 @@ const useRefDimensions = () => {
|
|
|
1073
1538
|
return { dimensions, refCallback };
|
|
1074
1539
|
};
|
|
1075
1540
|
exports.useRefDimensions = useRefDimensions;
|
|
1076
|
-
const cohortStages = ["
|
|
1541
|
+
const cohortStages = ["info", "name", "placementType", "review", "created"];
|
|
1077
1542
|
const defaultCohortData = {
|
|
1078
1543
|
name: "",
|
|
1079
|
-
stage: "
|
|
1544
|
+
stage: "info",
|
|
1080
1545
|
startSubmission: "",
|
|
1081
1546
|
endSubmission: "",
|
|
1082
1547
|
startPlacements: "",
|
|
@@ -1101,7 +1566,7 @@ function useCreateCohortRenderer({ oId, product, initialData = defaultCohortData
|
|
|
1101
1566
|
}
|
|
1102
1567
|
};
|
|
1103
1568
|
(0, react_1.useEffect)(() => {
|
|
1104
|
-
if (!Object.keys(cohortData).length || (0, util_1.objectsEqual)(initialData, cohortData))
|
|
1569
|
+
if (!Object.keys(cohortData).length || cohortData.stage === "name" || (0, util_1.objectsEqual)(initialData, cohortData))
|
|
1105
1570
|
return;
|
|
1106
1571
|
if (cohortId) {
|
|
1107
1572
|
console.log("update", cohortId, cohortData);
|
|
@@ -1128,7 +1593,6 @@ function useCreateCohortRenderer({ oId, product, initialData = defaultCohortData
|
|
|
1128
1593
|
};
|
|
1129
1594
|
return ({ ...{ submitCohort, submitSection, back, setCohortData, deleteCohort, cohortData, cohortId } });
|
|
1130
1595
|
}
|
|
1131
|
-
exports.useCreateCohortRenderer = useCreateCohortRenderer;
|
|
1132
1596
|
function useUserUploadHandler({ product, oId, userType, user, onComplete, userGroupId, cohortId }) {
|
|
1133
1597
|
const [emptyCellsWarning, setEmptyCellsWarning] = (0, react_1.useState)(false);
|
|
1134
1598
|
const [alert, setAlert] = (0, react_1.useState)();
|
|
@@ -1143,13 +1607,20 @@ function useUserUploadHandler({ product, oId, userType, user, onComplete, userGr
|
|
|
1143
1607
|
if (!Object.entries(userData)) {
|
|
1144
1608
|
return [];
|
|
1145
1609
|
}
|
|
1146
|
-
const
|
|
1610
|
+
const emailDuplicateLookup = userData.reduce((acc, e, index) => {
|
|
1611
|
+
if (!e.email)
|
|
1612
|
+
return acc;
|
|
1613
|
+
acc[e.email] = [...(acc[e.email] || []), index];
|
|
1614
|
+
return acc;
|
|
1615
|
+
}, {});
|
|
1616
|
+
const emailDuplicates = Object.entries(emailDuplicateLookup).filter(([_, ids]) => ids.length > 1).map(([email]) => email);
|
|
1147
1617
|
if (userData.filter((u) => u.email).length < userData.length) {
|
|
1148
1618
|
setAlert({ msg: "Your data contains missing email addresses.", severity: "error" });
|
|
1149
1619
|
return false;
|
|
1150
1620
|
}
|
|
1151
|
-
|
|
1152
|
-
|
|
1621
|
+
console.log("emailDuplicates", emailDuplicates);
|
|
1622
|
+
if (emailDuplicates.length) {
|
|
1623
|
+
setAlert({ msg: `Your data contains multiple rows with the same email address. Please remove these and reupload.\n\n Duplicate emails: ${emailDuplicates.join(", ")}`, severity: "error" });
|
|
1153
1624
|
return false;
|
|
1154
1625
|
}
|
|
1155
1626
|
let emptyOptionalCell = false;
|
|
@@ -1226,11 +1697,300 @@ function useUserUploadHandler({ product, oId, userType, user, onComplete, userGr
|
|
|
1226
1697
|
};
|
|
1227
1698
|
return ({ ...{ uploadUsers, alert, onChange } });
|
|
1228
1699
|
}
|
|
1229
|
-
|
|
1230
|
-
|
|
1700
|
+
function useWorkflowEditor({ user, initialData, onSubmit, cohortId }) {
|
|
1701
|
+
const firebaseQuery = new firebaseQuery_1.default();
|
|
1702
|
+
const { filePopupActive, files, includedFiles, includedForms, uploadFile, fAddNode, fOnDelete, arrows, onChange, error, onMoveEnd, addEdgePoint, fWorkflowNodes, newEdgePoint, setTutorialActive, setFilePopupActive, fSubmitWorkflow, openPopup, setSnackbar, snackbar, setMousePosFunc, mousePos, tutorialActive, onDeleteArrow, containerRef, setError, setArrows, setFWorkflowNodes } = useGenericWorkflowEditor({ ...{ user, initialData }, defaultData: constants_1.defaultInstituteWorkflow, onSubmit: onSubmit });
|
|
1703
|
+
const addNode = ({ userType, nextStage, prevStage } = {}) => {
|
|
1704
|
+
return fAddNode({ userType: userType }, `${userType} review`, nextStage, prevStage);
|
|
1705
|
+
};
|
|
1706
|
+
const onDelete = (0, react_1.useCallback)(async (id) => {
|
|
1707
|
+
if (!id) {
|
|
1708
|
+
return;
|
|
1709
|
+
}
|
|
1710
|
+
return fOnDelete(id, onDeleteValidator);
|
|
1711
|
+
}, []);
|
|
1712
|
+
const onDeleteValidator = async (id) => {
|
|
1713
|
+
const placementsOnStage = await firebaseQuery.getCount("placements", [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("cohort", "==", cohortId), (0, firestore_1.where)("status", "==", id)]);
|
|
1714
|
+
if (placementsOnStage > 0) {
|
|
1715
|
+
return { res: false, reason: "Cannot delete a stage with current active placements." };
|
|
1716
|
+
}
|
|
1717
|
+
if ([1, 6, 8, 11].includes(id)) {
|
|
1718
|
+
return { res: false, reason: "Cannot delete core workflow component." };
|
|
1719
|
+
}
|
|
1720
|
+
return { res: true };
|
|
1721
|
+
};
|
|
1722
|
+
const submitWorkflow = async (workflow, callOnComplete = true) => {
|
|
1723
|
+
const validatorTypeConversion = (newWorkflow, oldWorkflow) => {
|
|
1724
|
+
return validateWorkflow(newWorkflow, oldWorkflow);
|
|
1725
|
+
};
|
|
1726
|
+
return fSubmitWorkflow(validatorTypeConversion, workflow, callOnComplete);
|
|
1727
|
+
};
|
|
1728
|
+
const validateWorkflow = async (newWorkflow, oldWorkflow) => {
|
|
1729
|
+
const getStageById = (id, checkInitialData) => {
|
|
1730
|
+
let node;
|
|
1731
|
+
if (checkInitialData) {
|
|
1732
|
+
if (!(oldWorkflow === null || oldWorkflow === void 0 ? void 0 : oldWorkflow.length)) {
|
|
1733
|
+
throw new Error("Check initial data but no oldWorkflow");
|
|
1734
|
+
}
|
|
1735
|
+
node = (oldWorkflow).find((x) => x.id === id);
|
|
1736
|
+
}
|
|
1737
|
+
else {
|
|
1738
|
+
node = (newWorkflow).find((x) => x.id === id);
|
|
1739
|
+
}
|
|
1740
|
+
if (!node) {
|
|
1741
|
+
throw new Error("Error in configuration. Cannot find stage: " + id);
|
|
1742
|
+
}
|
|
1743
|
+
return node;
|
|
1744
|
+
};
|
|
1745
|
+
console.log("workflows, new, old", newWorkflow, oldWorkflow);
|
|
1746
|
+
// Steps:
|
|
1747
|
+
// Check if any deleted stages that have placements assigned to them
|
|
1748
|
+
const missingNodes = oldWorkflow && oldWorkflow.length ? oldWorkflow.reduce((acc, oldNode) => {
|
|
1749
|
+
const existsInNewWorkflow = Boolean(newWorkflow.find((newNode) => newNode.id === oldNode.id));
|
|
1750
|
+
if (!existsInNewWorkflow) {
|
|
1751
|
+
acc.push(oldNode.id);
|
|
1752
|
+
}
|
|
1753
|
+
return acc;
|
|
1754
|
+
}, []) : [];
|
|
1755
|
+
await Promise.all(missingNodes.map(async (nodeId) => {
|
|
1756
|
+
const placementsOnStage = await firebaseQuery.getCount("placements", [(0, firestore_1.where)("oId", "==", user.oId), (0, firestore_1.where)("cohort", "==", cohortId), (0, firestore_1.where)("status", "==", nodeId)]);
|
|
1757
|
+
if (placementsOnStage > 0) {
|
|
1758
|
+
throw new Error("Cannot delete a stage with current active placements.");
|
|
1759
|
+
}
|
|
1760
|
+
}));
|
|
1761
|
+
// After verifying, we have a list of stages that
|
|
1762
|
+
// Create paths with new workflow
|
|
1763
|
+
// Check cyclic
|
|
1764
|
+
// Check early termination
|
|
1765
|
+
// Check missed items
|
|
1766
|
+
// Create paths from old workflow
|
|
1767
|
+
// Check cyclic
|
|
1768
|
+
// Check early termination
|
|
1769
|
+
// Check missed items
|
|
1770
|
+
const paths = [];
|
|
1771
|
+
const createPaths = (stage, path, checkingInitialData) => {
|
|
1772
|
+
var _a, _b;
|
|
1773
|
+
if (!stage)
|
|
1774
|
+
return;
|
|
1775
|
+
const currentPath = [...(path || [])];
|
|
1776
|
+
// Check if infinite cycles
|
|
1777
|
+
if (currentPath.find((s) => s.id === stage.id)) {
|
|
1778
|
+
// ID must be already in it, so a loop has been formed.
|
|
1779
|
+
// Get just the elements in that cycle, such as [1, 2, 3, 4, 1]
|
|
1780
|
+
const cyclicPath = currentPath.slice(currentPath.findIndex((s) => s.id === stage.id));
|
|
1781
|
+
// If we have a cycle [1, 2, 3, 4, 1], check if any of them have a way out.
|
|
1782
|
+
const escapableCycle = cyclicPath.some((cycleStage, idx) => {
|
|
1783
|
+
let cyclicStageButtons = (cycleStage === null || cycleStage === void 0 ? void 0 : cycleStage.buttons) || [];
|
|
1784
|
+
// Keep only the arrows that don't go to the next one already documented, or the ID being checked.
|
|
1785
|
+
cyclicStageButtons = cyclicStageButtons.filter((button) => ![cyclicPath[idx + 1], stage.id].includes(button.id));
|
|
1786
|
+
return cyclicStageButtons.length > 0;
|
|
1787
|
+
});
|
|
1788
|
+
if (!escapableCycle) {
|
|
1789
|
+
throw new Error(`Inescapable cycle detected at ${stage.name}. Amend and resubmit.`);
|
|
1790
|
+
}
|
|
1791
|
+
return;
|
|
1792
|
+
}
|
|
1793
|
+
currentPath.push(stage);
|
|
1794
|
+
if (!((_a = stage === null || stage === void 0 ? void 0 : stage.buttons) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
1795
|
+
console.log("Final path", currentPath, checkingInitialData);
|
|
1796
|
+
// Check if in order and ends in 11
|
|
1797
|
+
if (stage.id !== 11) {
|
|
1798
|
+
throw new Error("All paths must end with the 'Workflow end' stage. Amend and reupload.");
|
|
1799
|
+
}
|
|
1800
|
+
//Check if a valid path.
|
|
1801
|
+
const validEssentialRoute = [1, "Provider", 6, 8, 11];
|
|
1802
|
+
const currentEssentialRoute = currentPath.reduce((acc, node) => {
|
|
1803
|
+
if ([1, 6, 8, 11].includes(node.id)) {
|
|
1804
|
+
acc.push(node.id);
|
|
1805
|
+
return acc;
|
|
1806
|
+
}
|
|
1807
|
+
if ((node === null || node === void 0 ? void 0 : node.userType) !== "Provider")
|
|
1808
|
+
return acc;
|
|
1809
|
+
if (!acc.includes(6) && !acc.includes("Provider")) {
|
|
1810
|
+
acc.push("Provider");
|
|
1811
|
+
}
|
|
1812
|
+
return acc;
|
|
1813
|
+
}, []);
|
|
1814
|
+
const valid = (0, util_1.arraysEqual)(currentEssentialRoute, validEssentialRoute);
|
|
1815
|
+
if (!valid) {
|
|
1816
|
+
console.log("Error in", currentEssentialRoute);
|
|
1817
|
+
throw new Error(checkingInitialData ?
|
|
1818
|
+
"Cannot submit. Changing workflow will cause current placements to skip core workflow components." :
|
|
1819
|
+
"Missing core workflow components. Ensure all placements have a provider review, start, end and workflow end in that order.");
|
|
1820
|
+
}
|
|
1821
|
+
paths.push(currentPath);
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
1824
|
+
if (checkingInitialData) {
|
|
1825
|
+
stage.buttons.forEach((button) => {
|
|
1826
|
+
createPaths(getStageById(button.id, true), currentPath, checkingInitialData);
|
|
1827
|
+
});
|
|
1828
|
+
}
|
|
1829
|
+
const newWorkflowStage = newWorkflow.find((newStage) => newStage.id === stage.id);
|
|
1830
|
+
if (!newWorkflowStage) {
|
|
1831
|
+
if (checkingInitialData) {
|
|
1832
|
+
return;
|
|
1833
|
+
}
|
|
1834
|
+
throw new Error("Cannot find node: " + stage.id);
|
|
1835
|
+
}
|
|
1836
|
+
(_b = newWorkflowStage.buttons) === null || _b === void 0 ? void 0 : _b.forEach((button) => {
|
|
1837
|
+
console.log("stage", stage, checkingInitialData);
|
|
1838
|
+
createPaths(getStageById(button.id), currentPath);
|
|
1839
|
+
});
|
|
1840
|
+
};
|
|
1841
|
+
createPaths(getStageById(1), []);
|
|
1842
|
+
if (oldWorkflow && oldWorkflow.length) {
|
|
1843
|
+
createPaths(getStageById(1, true), [], true);
|
|
1844
|
+
}
|
|
1845
|
+
return paths.every((x) => x);
|
|
1846
|
+
};
|
|
1847
|
+
const workflowNodes = fWorkflowNodes;
|
|
1848
|
+
const setWorkflowNodes = setFWorkflowNodes;
|
|
1849
|
+
return ({ ...{ filePopupActive, files, uploadFile, addNode, onDelete, arrows, onChange, error, includedFiles, onMoveEnd, addEdgePoint, newEdgePoint, setTutorialActive, setFilePopupActive,
|
|
1850
|
+
includedForms, submitWorkflow, openPopup, snackbar, setSnackbar, setMousePosFunc, mousePos, tutorialActive,
|
|
1851
|
+
onDeleteArrow, workflowNodes, containerRef, setError, setArrows, setWorkflowNodes } });
|
|
1852
|
+
}
|
|
1853
|
+
function useApplicantWorkflowEditor({ user, initialData, onSubmit, workflowId }) {
|
|
1854
|
+
const firebaseQuery = new firebaseQuery_1.default();
|
|
1855
|
+
const { filePopupActive, includedFiles, includedForms, uploadFile, fAddNode, fOnDelete, arrows, onChange, error, onMoveEnd, addEdgePoint, fWorkflowNodes, newEdgePoint, setTutorialActive, setFilePopupActive, fSubmitWorkflow, openPopup, setSnackbar, snackbar, setMousePosFunc, mousePos, tutorialActive, onDeleteArrow, containerRef, setError, setArrows, setFWorkflowNodes } = useGenericWorkflowEditor({ ...{ user, initialData }, defaultData: workflowId ? [] : constants_1.defaultApplicantWorkflow, onSubmit: onSubmit });
|
|
1856
|
+
(0, react_1.useEffect)(() => {
|
|
1857
|
+
if (!workflowId)
|
|
1858
|
+
return;
|
|
1859
|
+
firebaseQuery.getDocData(["applicantWorkflows", workflowId]).then((e) => setFWorkflowNodes(e.workflow));
|
|
1860
|
+
}, [workflowId]);
|
|
1861
|
+
const addNode = ({ userType, nextStage, prevStage } = {}) => {
|
|
1862
|
+
return fAddNode({ userType: userType, buttons: [{ name: "Reject", id: 12, required: true }] }, "", nextStage, prevStage);
|
|
1863
|
+
};
|
|
1864
|
+
const onDelete = (0, react_1.useCallback)(async (id) => {
|
|
1865
|
+
if (!id) {
|
|
1866
|
+
return;
|
|
1867
|
+
}
|
|
1868
|
+
return fOnDelete(id, onDeleteValidator);
|
|
1869
|
+
}, []);
|
|
1870
|
+
const onDeleteValidator = async (id) => {
|
|
1871
|
+
const placementsOnStage = await firebaseQuery.getCount("placement", [(0, firestore_1.where)("providerId", "==", user.oId), (0, firestore_1.where)("applicantWorkflowId", "==", workflowId), (0, firestore_1.where)("applicantStage", "==", id)]);
|
|
1872
|
+
if (placementsOnStage > 0) {
|
|
1873
|
+
return { res: false, reason: "Cannot delete a stage with current applicants." };
|
|
1874
|
+
}
|
|
1875
|
+
if ([1, 11, 12].includes(id)) {
|
|
1876
|
+
return { res: false, reason: "Cannot delete core workflow component." };
|
|
1877
|
+
}
|
|
1878
|
+
return { res: true };
|
|
1879
|
+
};
|
|
1880
|
+
const submitWorkflow = async (workflow, callOnComplete = true) => {
|
|
1881
|
+
const validatorTypeConversion = (newWorkflow, oldWorkflow) => {
|
|
1882
|
+
return validateWorkflow(newWorkflow, oldWorkflow);
|
|
1883
|
+
};
|
|
1884
|
+
return fSubmitWorkflow(validatorTypeConversion, workflow, callOnComplete);
|
|
1885
|
+
};
|
|
1886
|
+
// Change validator
|
|
1887
|
+
const validateWorkflow = async (newWorkflow, oldWorkflow) => {
|
|
1888
|
+
const getStageById = (id, checkInitialData) => {
|
|
1889
|
+
let node;
|
|
1890
|
+
if (checkInitialData) {
|
|
1891
|
+
if (!(oldWorkflow === null || oldWorkflow === void 0 ? void 0 : oldWorkflow.length)) {
|
|
1892
|
+
throw new Error("Check initial data but no oldWorkflow");
|
|
1893
|
+
}
|
|
1894
|
+
node = (oldWorkflow).find((x) => x.id === id);
|
|
1895
|
+
}
|
|
1896
|
+
else {
|
|
1897
|
+
node = (newWorkflow).find((x) => x.id === id);
|
|
1898
|
+
}
|
|
1899
|
+
if (!node) {
|
|
1900
|
+
throw new Error("Error in configuration. Cannot find stage: " + id);
|
|
1901
|
+
}
|
|
1902
|
+
return node;
|
|
1903
|
+
};
|
|
1904
|
+
console.log("workflows, new, old", newWorkflow, oldWorkflow);
|
|
1905
|
+
// Steps:
|
|
1906
|
+
// Check if any deleted stages that have placements assigned to them
|
|
1907
|
+
const missingNodes = oldWorkflow && oldWorkflow.length ? oldWorkflow.reduce((acc, oldNode) => {
|
|
1908
|
+
const existsInNewWorkflow = Boolean(newWorkflow.find((newNode) => newNode.id === oldNode.id));
|
|
1909
|
+
if (!existsInNewWorkflow) {
|
|
1910
|
+
acc.push(oldNode.id);
|
|
1911
|
+
}
|
|
1912
|
+
return acc;
|
|
1913
|
+
}, []) : [];
|
|
1914
|
+
await Promise.all(missingNodes.map(async (nodeId) => {
|
|
1915
|
+
const placementsOnStage = await firebaseQuery.getCount("placement", [(0, firestore_1.where)("providerId", "==", user.oId), (0, firestore_1.where)("applicantWorkflow", "==", workflowId), (0, firestore_1.where)("applicantStage", "==", nodeId)]);
|
|
1916
|
+
if (placementsOnStage > 0) {
|
|
1917
|
+
throw new Error("Cannot delete a stage with current active placements.");
|
|
1918
|
+
}
|
|
1919
|
+
}));
|
|
1920
|
+
// After verifying, we have a list of stages that
|
|
1921
|
+
// Create paths with new workflow
|
|
1922
|
+
// Check cyclic
|
|
1923
|
+
// Check early termination
|
|
1924
|
+
// Check missed items
|
|
1925
|
+
// Create paths from old workflow
|
|
1926
|
+
// Check cyclic
|
|
1927
|
+
// Check early termination
|
|
1928
|
+
// Check missed items
|
|
1929
|
+
const paths = [];
|
|
1930
|
+
const createPaths = (stage, path, checkingInitialData) => {
|
|
1931
|
+
var _a, _b;
|
|
1932
|
+
if (!stage)
|
|
1933
|
+
return;
|
|
1934
|
+
const currentPath = [...(path || [])];
|
|
1935
|
+
// Check if infinite cycles
|
|
1936
|
+
if (currentPath.find((s) => s.id === stage.id)) {
|
|
1937
|
+
// ID must be already in it, so a loop has been formed.
|
|
1938
|
+
// Get just the elements in that cycle, such as [1, 2, 3, 4, 1]
|
|
1939
|
+
const cyclicPath = currentPath.slice(currentPath.findIndex((s) => s.id === stage.id));
|
|
1940
|
+
// If we have a cycle [1, 2, 3, 4, 1], check if any of them have a way out.
|
|
1941
|
+
const escapableCycle = cyclicPath.some((cycleStage, idx) => {
|
|
1942
|
+
let cyclicStageButtons = (cycleStage === null || cycleStage === void 0 ? void 0 : cycleStage.buttons) || [];
|
|
1943
|
+
// Keep only the arrows that don't go to the next one already documented, or the ID being checked.
|
|
1944
|
+
cyclicStageButtons = cyclicStageButtons.filter((button) => ![cyclicPath[idx + 1], stage.id].includes(button.id));
|
|
1945
|
+
return cyclicStageButtons.length > 0;
|
|
1946
|
+
});
|
|
1947
|
+
if (!escapableCycle) {
|
|
1948
|
+
throw new Error(`Inescapable cycle detected at ${stage.name}. Amend and resubmit.`);
|
|
1949
|
+
}
|
|
1950
|
+
return;
|
|
1951
|
+
}
|
|
1952
|
+
currentPath.push(stage);
|
|
1953
|
+
if (!((_a = stage === null || stage === void 0 ? void 0 : stage.buttons) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
1954
|
+
console.log("Final path", currentPath, checkingInitialData);
|
|
1955
|
+
// Check if in order and ends in 11
|
|
1956
|
+
if (![11, 12].includes(stage.id)) {
|
|
1957
|
+
throw new Error("All paths must end with the 'Success' or 'Reject' stage. Amend and reupload.");
|
|
1958
|
+
}
|
|
1959
|
+
paths.push(currentPath);
|
|
1960
|
+
return;
|
|
1961
|
+
}
|
|
1962
|
+
if (checkingInitialData) {
|
|
1963
|
+
stage.buttons.forEach((button) => {
|
|
1964
|
+
createPaths(getStageById(button.id, true), currentPath, checkingInitialData);
|
|
1965
|
+
});
|
|
1966
|
+
}
|
|
1967
|
+
const newWorkflowStage = newWorkflow.find((newStage) => newStage.id === stage.id);
|
|
1968
|
+
if (!newWorkflowStage) {
|
|
1969
|
+
if (checkingInitialData) {
|
|
1970
|
+
return;
|
|
1971
|
+
}
|
|
1972
|
+
throw new Error("Cannot find node: " + stage.id);
|
|
1973
|
+
}
|
|
1974
|
+
(_b = newWorkflowStage.buttons) === null || _b === void 0 ? void 0 : _b.forEach((button) => {
|
|
1975
|
+
createPaths(getStageById(button.id), currentPath);
|
|
1976
|
+
});
|
|
1977
|
+
};
|
|
1978
|
+
createPaths(getStageById(1), []);
|
|
1979
|
+
if (oldWorkflow && oldWorkflow.length) {
|
|
1980
|
+
createPaths(getStageById(1, true), [], true);
|
|
1981
|
+
}
|
|
1982
|
+
return paths.every((x) => x);
|
|
1983
|
+
};
|
|
1984
|
+
const workflowNodes = fWorkflowNodes;
|
|
1985
|
+
const setWorkflowNodes = setFWorkflowNodes;
|
|
1986
|
+
return ({ ...{ filePopupActive, uploadFile, addNode, onDelete, arrows, onChange, error, includedFiles, onMoveEnd, addEdgePoint, newEdgePoint, setTutorialActive, setFilePopupActive,
|
|
1987
|
+
includedForms, submitWorkflow, openPopup, snackbar, setSnackbar, setMousePosFunc, mousePos, tutorialActive,
|
|
1988
|
+
onDeleteArrow, workflowNodes, containerRef, setError, setArrows, setWorkflowNodes } });
|
|
1989
|
+
}
|
|
1990
|
+
function useGenericWorkflowEditor({ user, initialData, defaultData, onSubmit }) {
|
|
1231
1991
|
const [filePopupActive, setFilePopupActive] = (0, react_1.useState)(false);
|
|
1232
1992
|
const [files, setFiles] = (0, react_1.useState)([]);
|
|
1233
|
-
const [
|
|
1993
|
+
const [fWorkflowNodes, setFWorkflowNodes] = (0, react_1.useState)([]); // Workflow data
|
|
1234
1994
|
const [arrows, setArrows] = (0, react_1.useState)([]);
|
|
1235
1995
|
const [includedForms, setIncludedForms] = (0, react_1.useState)([]);
|
|
1236
1996
|
const [includedFiles, setIncludedFiles] = (0, react_1.useState)([]);
|
|
@@ -1241,19 +2001,16 @@ function useWorkflowEditor({ user, initialData, onSubmit, cohortId, product, oId
|
|
|
1241
2001
|
const [tutorialActive, setTutorialActive] = (0, react_1.useState)(false);
|
|
1242
2002
|
const containerRef = (0, react_1.useRef)(null);
|
|
1243
2003
|
let ticking = false;
|
|
1244
|
-
const userProduct = user.product === "admin" ? product : user.product;
|
|
1245
|
-
const userOId = user.product === "admin" ? oId : user.oId;
|
|
1246
2004
|
(0, react_1.useEffect)(() => {
|
|
1247
2005
|
let newData = initialData;
|
|
1248
2006
|
if (initialData === undefined || initialData.length === 0) {
|
|
1249
|
-
newData =
|
|
2007
|
+
newData = defaultData;
|
|
1250
2008
|
setTimeout(() => {
|
|
1251
2009
|
setTutorialActive(false);
|
|
1252
2010
|
}, 1000);
|
|
1253
2011
|
}
|
|
1254
|
-
(0, readDatabase_1.getFiles)(`${
|
|
1255
|
-
|
|
1256
|
-
console.log("new data", newData);
|
|
2012
|
+
(0, readDatabase_1.getFiles)(`${user.product}/${user.oId}/files`).then(setFiles);
|
|
2013
|
+
setFWorkflowNodes(newData || []);
|
|
1257
2014
|
}, [initialData]);
|
|
1258
2015
|
(0, react_1.useEffect)(() => {
|
|
1259
2016
|
// New edge points
|
|
@@ -1283,38 +2040,76 @@ function useWorkflowEditor({ user, initialData, onSubmit, cohortId, product, oId
|
|
|
1283
2040
|
ticking = true;
|
|
1284
2041
|
};
|
|
1285
2042
|
const uploadFile = async (files) => {
|
|
1286
|
-
const res = await (0, writeDatabase_1.uploadFiles)(files, `${
|
|
2043
|
+
const res = await (0, writeDatabase_1.uploadFiles)(files, `${user.product}/${user.oId}/files/`);
|
|
1287
2044
|
if (res === 1) {
|
|
1288
2045
|
// change this
|
|
1289
2046
|
setFilePopupActive(false);
|
|
1290
|
-
(0, readDatabase_1.getFiles)(`${
|
|
2047
|
+
(0, readDatabase_1.getFiles)(`${user.product}/${user.oId}/files`).then(setFiles);
|
|
1291
2048
|
}
|
|
1292
2049
|
};
|
|
1293
|
-
const
|
|
1294
|
-
|
|
2050
|
+
const fAddNode = (additionalData, name, nextStage, prevStage) => {
|
|
2051
|
+
let nodeId = (0, util_1.getUniqueId)(fWorkflowNodes);
|
|
2052
|
+
// Add user type and name for institute placement workflow!
|
|
2053
|
+
setFWorkflowNodes((p) => {
|
|
2054
|
+
let newWorkflowNodes = ([...p, { id: nodeId, pos: { x: 10, y: 10 }, ...additionalData, name: name || `Stage ${nodeId}`, buttons: nextStage ? [...((additionalData === null || additionalData === void 0 ? void 0 : additionalData.buttons) || []), { required: true, name: "Accept", id: nextStage }] : [] }]);
|
|
2055
|
+
if (prevStage) {
|
|
2056
|
+
const prevStageIndex = p.findIndex((node) => node.id === prevStage);
|
|
2057
|
+
newWorkflowNodes[prevStageIndex] = { ...newWorkflowNodes[prevStageIndex], buttons: [{ required: true, name: "Accept", id: nodeId }] };
|
|
2058
|
+
}
|
|
2059
|
+
return newWorkflowNodes;
|
|
2060
|
+
});
|
|
2061
|
+
return nodeId;
|
|
1295
2062
|
};
|
|
1296
|
-
const
|
|
1297
|
-
if (
|
|
1298
|
-
alert("Cannot delete core workflow component.");
|
|
2063
|
+
const fOnDelete = (0, react_1.useCallback)(async (id, validation) => {
|
|
2064
|
+
if (!id) {
|
|
1299
2065
|
return;
|
|
1300
2066
|
}
|
|
1301
|
-
|
|
2067
|
+
if (validation) {
|
|
2068
|
+
// Add placementsOnStage to validation
|
|
2069
|
+
const validationResult = await validation(id);
|
|
2070
|
+
if (!validationResult.res) {
|
|
2071
|
+
setError(validationResult.reason);
|
|
2072
|
+
return;
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
setFWorkflowNodes((prev) => {
|
|
2076
|
+
var _a;
|
|
1302
2077
|
let oldMutable = [...prev];
|
|
2078
|
+
// Buttons going from deleted nodes to new node
|
|
2079
|
+
const deletedNodeButtons = (_a = oldMutable.find((node) => node.id === id)) === null || _a === void 0 ? void 0 : _a.buttons;
|
|
1303
2080
|
oldMutable = oldMutable.filter((e) => e.id.toString() !== id.toString());
|
|
1304
|
-
oldMutable.
|
|
1305
|
-
|
|
2081
|
+
const arrowsToDeletedNode = oldMutable.map((e, i) => {
|
|
2082
|
+
var _a;
|
|
2083
|
+
const node = { ...e };
|
|
1306
2084
|
// Remove any arrows to this node
|
|
1307
|
-
|
|
2085
|
+
const nodeFeedsToDeleted = Boolean((_a = node.buttons) === null || _a === void 0 ? void 0 : _a.find((destination) => destination.id === id));
|
|
2086
|
+
if (nodeFeedsToDeleted) {
|
|
2087
|
+
console.log("Delete line from node", node.id);
|
|
2088
|
+
}
|
|
2089
|
+
if (nodeFeedsToDeleted) {
|
|
2090
|
+
const newNodeButtons = node.buttons ? node.buttons.filter((button) => id.toString() !== button.id.toString()) : [];
|
|
2091
|
+
node.buttons = newNodeButtons;
|
|
2092
|
+
console.log("New node buttons", newNodeButtons, node.buttons);
|
|
2093
|
+
}
|
|
1308
2094
|
oldMutable[i] = node;
|
|
1309
|
-
|
|
1310
|
-
|
|
2095
|
+
return nodeFeedsToDeleted ? node : undefined;
|
|
2096
|
+
}).filter((i) => i);
|
|
2097
|
+
console.log("arrows to and destinations", arrowsToDeletedNode, deletedNodeButtons);
|
|
2098
|
+
if ((deletedNodeButtons === null || deletedNodeButtons === void 0 ? void 0 : deletedNodeButtons.length) && arrowsToDeletedNode.length) {
|
|
2099
|
+
const newNodeDestination = deletedNodeButtons[0].id;
|
|
2100
|
+
const newNodeOrigin = arrowsToDeletedNode[0].id;
|
|
2101
|
+
const indexOfOrigin = oldMutable.findIndex((node) => node.id === newNodeOrigin);
|
|
2102
|
+
oldMutable[indexOfOrigin] = { ...oldMutable[indexOfOrigin], buttons: [...(oldMutable[indexOfOrigin].buttons || []), { id: newNodeDestination, required: true, name: "Submit" }] };
|
|
2103
|
+
}
|
|
2104
|
+
return oldMutable;
|
|
1311
2105
|
});
|
|
1312
2106
|
}, []);
|
|
1313
2107
|
(0, react_1.useEffect)(() => {
|
|
1314
|
-
|
|
2108
|
+
error && setError(undefined);
|
|
2109
|
+
if (!fWorkflowNodes) {
|
|
1315
2110
|
return;
|
|
1316
2111
|
}
|
|
1317
|
-
setArrows(
|
|
2112
|
+
setArrows(fWorkflowNodes.reduce((acc, node) => {
|
|
1318
2113
|
if (node.buttons) {
|
|
1319
2114
|
node.buttons.forEach((buttonData) => {
|
|
1320
2115
|
acc.push({
|
|
@@ -1327,112 +2122,69 @@ function useWorkflowEditor({ user, initialData, onSubmit, cohortId, product, oId
|
|
|
1327
2122
|
}
|
|
1328
2123
|
return acc;
|
|
1329
2124
|
}, []));
|
|
1330
|
-
|
|
2125
|
+
const mIncludedFiles = fWorkflowNodes.reduce((acc, node) => {
|
|
2126
|
+
if (node.files) {
|
|
2127
|
+
acc.push(...node.files.map((f) => {
|
|
2128
|
+
try {
|
|
2129
|
+
return JSON.parse(f).name;
|
|
2130
|
+
}
|
|
2131
|
+
catch {
|
|
2132
|
+
return f;
|
|
2133
|
+
}
|
|
2134
|
+
}));
|
|
2135
|
+
}
|
|
2136
|
+
return (0, util_1.arrayUniqueValues)(acc);
|
|
2137
|
+
}, []);
|
|
2138
|
+
const mIncludedForms = fWorkflowNodes.reduce((acc, node) => {
|
|
2139
|
+
if (node.forms) {
|
|
2140
|
+
acc.push(...node.forms);
|
|
2141
|
+
}
|
|
2142
|
+
return (0, util_1.arrayUniqueValues)(acc);
|
|
2143
|
+
}, []);
|
|
2144
|
+
setIncludedFiles(mIncludedFiles);
|
|
2145
|
+
setIncludedForms(mIncludedForms);
|
|
2146
|
+
}, [fWorkflowNodes]);
|
|
1331
2147
|
const onChange = (0, react_1.useCallback)((path, value) => {
|
|
1332
|
-
|
|
2148
|
+
setFWorkflowNodes((prev) => (0, util_1.editNestedObject)(path, prev, value, true));
|
|
1333
2149
|
}, []);
|
|
1334
|
-
const
|
|
2150
|
+
const fSubmitWorkflow = async (validation, workflow, callOnComplete = true) => {
|
|
1335
2151
|
setError(undefined);
|
|
1336
|
-
|
|
2152
|
+
const fWorkflow = workflow || fWorkflowNodes;
|
|
2153
|
+
const mIncludedFiles = fWorkflow.reduce((acc, node) => {
|
|
1337
2154
|
if (node.files) {
|
|
1338
|
-
acc.push(...node.files.map((f) =>
|
|
2155
|
+
acc.push(...node.files.map((f) => {
|
|
2156
|
+
try {
|
|
2157
|
+
return JSON.parse(f).name;
|
|
2158
|
+
}
|
|
2159
|
+
catch {
|
|
2160
|
+
return f;
|
|
2161
|
+
}
|
|
2162
|
+
}));
|
|
1339
2163
|
}
|
|
1340
2164
|
return (0, util_1.arrayUniqueValues)(acc);
|
|
1341
|
-
}, [])
|
|
1342
|
-
|
|
2165
|
+
}, []);
|
|
2166
|
+
const mIncludedForms = fWorkflow.reduce((acc, node) => {
|
|
1343
2167
|
if (node.forms) {
|
|
1344
2168
|
acc.push(...node.forms);
|
|
1345
2169
|
}
|
|
1346
2170
|
return (0, util_1.arrayUniqueValues)(acc);
|
|
1347
|
-
}, [])
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
2171
|
+
}, []);
|
|
2172
|
+
setIncludedFiles(mIncludedFiles);
|
|
2173
|
+
setIncludedForms(mIncludedForms);
|
|
2174
|
+
if (initialData === fWorkflow) {
|
|
2175
|
+
return callOnComplete && onSubmit({ workflow: fWorkflow, includedFiles: mIncludedFiles, includedForms: mIncludedForms });
|
|
2176
|
+
}
|
|
2177
|
+
const validatedWorkflow = await validation(fWorkflow, initialData).catch((e) => {
|
|
2178
|
+
setError(e.message);
|
|
2179
|
+
throw e;
|
|
2180
|
+
});
|
|
2181
|
+
if (!validatedWorkflow) {
|
|
1354
2182
|
return;
|
|
1355
2183
|
}
|
|
1356
|
-
|
|
1357
|
-
const restrictedChanges = workflowNodes.map((currentNode) => {
|
|
1358
|
-
var _a, _b;
|
|
1359
|
-
const editedNode = initialData[currentNode.id];
|
|
1360
|
-
const editedButtons = ((_a = editedNode === null || editedNode === void 0 ? void 0 : editedNode.buttons) === null || _a === void 0 ? void 0 : _a.map((x) => x.id)) || [];
|
|
1361
|
-
const currentButtons = ((_b = currentNode === null || currentNode === void 0 ? void 0 : currentNode.buttons) === null || _b === void 0 ? void 0 : _b.map((x) => x.id)) || [];
|
|
1362
|
-
// Should check IDs rather than the entire thing.
|
|
1363
|
-
if (!editedButtons.every((v, i) => v === currentButtons[i])) {
|
|
1364
|
-
return true;
|
|
1365
|
-
}
|
|
1366
|
-
return false;
|
|
1367
|
-
});
|
|
1368
|
-
if (restrictedChanges.includes(true) && Boolean(cohortId)) {
|
|
1369
|
-
const conflicts = await (0, readDatabase_1.checkPlacementConflicts)(userOId, cohortId);
|
|
1370
|
-
if (conflicts > 0) {
|
|
1371
|
-
setError(`${conflicts} active placements are using this workflow. Complete these placements to edit workflow.`);
|
|
1372
|
-
return;
|
|
1373
|
-
}
|
|
1374
|
-
}
|
|
1375
|
-
}
|
|
1376
|
-
onSubmit({ workflow: workflowNodes, includedFiles: includedFiles, includedForms: includedForms });
|
|
1377
|
-
};
|
|
1378
|
-
const workflowConseq = () => {
|
|
1379
|
-
const getStageById = (id) => workflowNodes.find((x) => x.id === id);
|
|
1380
|
-
const paths = [];
|
|
1381
|
-
const createPaths = (stage, path) => {
|
|
1382
|
-
var _a;
|
|
1383
|
-
if (!stage)
|
|
1384
|
-
return;
|
|
1385
|
-
const currentPath = [...(path || [])];
|
|
1386
|
-
// Check if infinite cycles
|
|
1387
|
-
if (currentPath.includes(stage.id)) {
|
|
1388
|
-
// ID must be already in it, so a loop has been formed.
|
|
1389
|
-
// Get subpath from id onwards, inclusive.
|
|
1390
|
-
// Check if there are other ways out. If not, return false!
|
|
1391
|
-
const cyclicPath = currentPath.slice(currentPath.indexOf(stage.id));
|
|
1392
|
-
const escapableCycle = cyclicPath.some((id, idx) => {
|
|
1393
|
-
var _a;
|
|
1394
|
-
let cyclicStageButtons = ((_a = getStageById(id)) === null || _a === void 0 ? void 0 : _a.buttons) || [];
|
|
1395
|
-
cyclicStageButtons = cyclicStageButtons.filter((button) => ![cyclicPath[idx + 1], stage.id].includes(button.id));
|
|
1396
|
-
return cyclicStageButtons.length > 0;
|
|
1397
|
-
});
|
|
1398
|
-
if (!escapableCycle) {
|
|
1399
|
-
paths.push(false);
|
|
1400
|
-
}
|
|
1401
|
-
return;
|
|
1402
|
-
}
|
|
1403
|
-
currentPath.push(stage.id);
|
|
1404
|
-
if (!((_a = stage === null || stage === void 0 ? void 0 : stage.buttons) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
1405
|
-
// Check if in order and ends in 11
|
|
1406
|
-
if (stage.id !== 11) {
|
|
1407
|
-
paths.push(false);
|
|
1408
|
-
return;
|
|
1409
|
-
}
|
|
1410
|
-
const validEssentialRoute = [1, "Provider", 6, 8, 11];
|
|
1411
|
-
const currentEssentialRoute = currentPath.reduce((acc, x) => {
|
|
1412
|
-
if ([1, 6, 8, 11].includes(x)) {
|
|
1413
|
-
acc.push(x);
|
|
1414
|
-
}
|
|
1415
|
-
const node = getStageById(x);
|
|
1416
|
-
if ((node === null || node === void 0 ? void 0 : node.userType) !== "Provider")
|
|
1417
|
-
return acc;
|
|
1418
|
-
if (!acc.includes(6) && !acc.includes("Provider")) {
|
|
1419
|
-
acc.push("Provider");
|
|
1420
|
-
}
|
|
1421
|
-
return acc;
|
|
1422
|
-
}, []);
|
|
1423
|
-
const valid = (0, util_1.arraysEqual)(currentEssentialRoute, validEssentialRoute);
|
|
1424
|
-
paths.push(valid ? currentPath : false);
|
|
1425
|
-
return;
|
|
1426
|
-
}
|
|
1427
|
-
stage.buttons.forEach((button) => {
|
|
1428
|
-
createPaths(getStageById(button.id), currentPath);
|
|
1429
|
-
});
|
|
1430
|
-
};
|
|
1431
|
-
createPaths(getStageById(1));
|
|
1432
|
-
return paths.every((x) => x);
|
|
2184
|
+
return callOnComplete && onSubmit({ workflow: fWorkflow, includedFiles: includedFiles, includedForms: includedForms });
|
|
1433
2185
|
};
|
|
1434
2186
|
const deleteEdge = (0, react_1.useCallback)((originId, nodeId) => {
|
|
1435
|
-
|
|
2187
|
+
setFWorkflowNodes((prev) => (0, util_1.editNestedObject)([originId, "buttons", nodeId], prev, undefined, true));
|
|
1436
2188
|
}, []);
|
|
1437
2189
|
const onDeleteArrow = (0, react_1.useCallback)((data) => {
|
|
1438
2190
|
deleteEdge(data.start, data.end);
|
|
@@ -1446,7 +2198,7 @@ function useWorkflowEditor({ user, initialData, onSubmit, cohortId, product, oId
|
|
|
1446
2198
|
const y = containerRef.current.scrollTop + clientRect.y - top - 26;
|
|
1447
2199
|
// Make sure x and y are not negative. Contrains canvas by top and left
|
|
1448
2200
|
const pos = { x: x >= 0 ? x : 0, y: y >= 0 ? y : 0 };
|
|
1449
|
-
|
|
2201
|
+
setFWorkflowNodes((p) => (0, util_1.editNestedObject)([id, "pos"], p, pos));
|
|
1450
2202
|
}, []);
|
|
1451
2203
|
const addEdgePoint = (0, react_1.useCallback)((id, existingEdgePoint) => {
|
|
1452
2204
|
var _a;
|
|
@@ -1455,7 +2207,7 @@ function useWorkflowEditor({ user, initialData, onSubmit, cohortId, product, oId
|
|
|
1455
2207
|
setSnackbar("Cannot connect stages after workflow end.");
|
|
1456
2208
|
return;
|
|
1457
2209
|
}
|
|
1458
|
-
const buttons = (_a =
|
|
2210
|
+
const buttons = (_a = fWorkflowNodes.find((node) => node.id === id)) === null || _a === void 0 ? void 0 : _a.buttons;
|
|
1459
2211
|
if ([1, 11].includes(id) && buttons && buttons.length > 0) {
|
|
1460
2212
|
setSnackbar("Stage can only have one destination.");
|
|
1461
2213
|
return;
|
|
@@ -1468,8 +2220,8 @@ function useWorkflowEditor({ user, initialData, onSubmit, cohortId, product, oId
|
|
|
1468
2220
|
setNewEdgePoint(undefined);
|
|
1469
2221
|
return;
|
|
1470
2222
|
}
|
|
1471
|
-
const originPos =
|
|
1472
|
-
const buttons = [...(
|
|
2223
|
+
const originPos = fWorkflowNodes.findIndex((x) => x.id.toString() === existingEdgePoint.toString());
|
|
2224
|
+
const buttons = [...(fWorkflowNodes[originPos].buttons || [])];
|
|
1473
2225
|
if (!buttons.some((x) => x.id.toString() === id.toString())) {
|
|
1474
2226
|
buttons.push({
|
|
1475
2227
|
id: id,
|
|
@@ -1477,17 +2229,16 @@ function useWorkflowEditor({ user, initialData, onSubmit, cohortId, product, oId
|
|
|
1477
2229
|
name: [1, 6, 8].includes(existingEdgePoint) ? false : "",
|
|
1478
2230
|
});
|
|
1479
2231
|
}
|
|
1480
|
-
|
|
2232
|
+
setFWorkflowNodes((p) => (0, util_1.editNestedObject)([existingEdgePoint, "buttons"], p, buttons, true));
|
|
1481
2233
|
setNewEdgePoint(undefined);
|
|
1482
|
-
}, [
|
|
2234
|
+
}, [fWorkflowNodes]);
|
|
1483
2235
|
const openPopup = (0, react_1.useCallback)(() => {
|
|
1484
2236
|
setFilePopupActive(true);
|
|
1485
2237
|
}, []);
|
|
1486
|
-
return ({ ...{ filePopupActive, files, uploadFile,
|
|
1487
|
-
includedForms,
|
|
1488
|
-
onDeleteArrow,
|
|
2238
|
+
return ({ ...{ filePopupActive, files, uploadFile, fAddNode, fOnDelete, arrows, onChange, error, includedFiles, onMoveEnd, addEdgePoint, newEdgePoint, setTutorialActive, setFilePopupActive,
|
|
2239
|
+
includedForms, fSubmitWorkflow, openPopup, snackbar, setSnackbar, setMousePosFunc, mousePos, tutorialActive,
|
|
2240
|
+
onDeleteArrow, fWorkflowNodes, containerRef, setError, setArrows, setFWorkflowNodes } });
|
|
1489
2241
|
}
|
|
1490
|
-
exports.useWorkflowEditor = useWorkflowEditor;
|
|
1491
2242
|
function useInstitutePlacementListingHandler({ user }) {
|
|
1492
2243
|
const [emptyCellsWarning, setEmptyCellsWarning] = (0, react_1.useState)(false);
|
|
1493
2244
|
const [alert, setAlert] = (0, react_1.useState)();
|
|
@@ -1577,5 +2328,373 @@ function useInstitutePlacementListingHandler({ user }) {
|
|
|
1577
2328
|
};
|
|
1578
2329
|
return ({ ...{ uploadPlacements, alert, onChange } });
|
|
1579
2330
|
}
|
|
1580
|
-
|
|
2331
|
+
function useGetIndividualPlacementForPlacementPage({ user, placementId, organisation }) {
|
|
2332
|
+
var _a;
|
|
2333
|
+
const [placement, setPlacement] = (0, react_1.useState)();
|
|
2334
|
+
const [institute, setInstitute] = (0, react_1.useState)(user.product === "institutes" ? organisation === null || organisation === void 0 ? void 0 : organisation.details : undefined);
|
|
2335
|
+
const [workflow, setWorkflow] = (0, react_1.useState)();
|
|
2336
|
+
const [cohort, setCohort] = (0, react_1.useState)();
|
|
2337
|
+
const [student, setStudent] = (0, react_1.useState)();
|
|
2338
|
+
const [wStage, setWStage] = (0, react_1.useState)();
|
|
2339
|
+
const [snackbar, setSnackbar] = (0, react_1.useState)({ open: false });
|
|
2340
|
+
const [disableEmail, setDisableEmail] = (0, react_1.useState)({ parent: false, provider: false });
|
|
2341
|
+
const [rejectELIPopup, setRejectELIPopup] = (0, react_1.useState)(false);
|
|
2342
|
+
const [eliPopupOpen, setEliPopupOpen] = (0, react_1.useState)(false);
|
|
2343
|
+
const [eliURL, setELIURL] = (0, react_1.useState)("");
|
|
2344
|
+
const [rejectExternalDocPopup, setRejectExternalDocPopup] = (0, react_1.useState)(false);
|
|
2345
|
+
const [externalDocPopupOpen, setExternalDocPopupOpen] = (0, react_1.useState)(false);
|
|
2346
|
+
const [riskAssessmentURL, setRiskAssessmentURL] = (0, react_1.useState)("");
|
|
2347
|
+
const [dbsCheckURL, setDbsCheckURL] = (0, react_1.useState)("");
|
|
2348
|
+
const [uploadProviderDocPopup, setUploadProviderDocPopup] = (0, react_1.useState)();
|
|
2349
|
+
const [skipStagePopup, setSkipStagePopup] = (0, react_1.useState)(false);
|
|
2350
|
+
const [viewExternalLinkPopup, setViewExternalLinkPopup] = (0, react_1.useState)(false);
|
|
2351
|
+
const [externalLinkCopied, setExternalLinkCopied] = (0, react_1.useState)(false);
|
|
2352
|
+
const [uploadInsurance, setUploadInsurance] = (0, react_1.useState)(false);
|
|
2353
|
+
const [uploadRA, setUploadRA] = (0, react_1.useState)(false);
|
|
2354
|
+
const [uploadDBS, setUploadDBS] = (0, react_1.useState)(false);
|
|
2355
|
+
const [onboardingPopup, setOnboardingPopup] = (0, react_1.useState)(false);
|
|
2356
|
+
const [editable, setEditable] = (0, react_1.useState)(false);
|
|
2357
|
+
const [withdrawFromPlacementPopup, setWithdrawFromPlacementPopup] = (0, react_1.useState)(false);
|
|
2358
|
+
const firebaseQuery = new firebaseQuery_1.default();
|
|
2359
|
+
(0, react_1.useEffect)(() => {
|
|
2360
|
+
if (!placementId)
|
|
2361
|
+
return;
|
|
2362
|
+
(0, readDatabase_1.getPlacementbyId)(placementId, setPlacement);
|
|
2363
|
+
}, [placementId]);
|
|
2364
|
+
(0, react_1.useEffect)(() => {
|
|
2365
|
+
var _a;
|
|
2366
|
+
console.log("p", placement);
|
|
2367
|
+
if (!placement) {
|
|
2368
|
+
return;
|
|
2369
|
+
}
|
|
2370
|
+
setEditable(!((placement.providerCompleted && placement.providerCompleted.includes("details")) || placement.completed));
|
|
2371
|
+
if (placement.oId) {
|
|
2372
|
+
if (user.product === "institutes") {
|
|
2373
|
+
setInstitute(organisation === null || organisation === void 0 ? void 0 : organisation.details);
|
|
2374
|
+
}
|
|
2375
|
+
else if (user.product === "providers") {
|
|
2376
|
+
firebaseQuery.getDocData(["institutes", placement.oId]).then((i) => setInstitute(i));
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
if (placement.cohort) {
|
|
2380
|
+
if (user.product === "institutes" && user.oId === placement.oId) {
|
|
2381
|
+
setCohort(organisation === null || organisation === void 0 ? void 0 : organisation.cohorts[placement.cohort]);
|
|
2382
|
+
setWorkflow((_a = organisation === null || organisation === void 0 ? void 0 : organisation.cohorts[placement.cohort]) === null || _a === void 0 ? void 0 : _a.workflow);
|
|
2383
|
+
}
|
|
2384
|
+
else {
|
|
2385
|
+
firebaseQuery.getDocData(["cohorts", placement.cohort]).then((w) => {
|
|
2386
|
+
setWorkflow(w.workflow);
|
|
2387
|
+
setCohort(w);
|
|
2388
|
+
});
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
else {
|
|
2392
|
+
setWorkflow(constants_1.defaultStudentWorkflow);
|
|
2393
|
+
}
|
|
2394
|
+
if (user.userType === "Students") {
|
|
2395
|
+
setStudent(user);
|
|
2396
|
+
}
|
|
2397
|
+
else {
|
|
2398
|
+
(0, readDatabase_1.getUserById)(placement.uid).then(setStudent);
|
|
2399
|
+
}
|
|
2400
|
+
}, [placement]);
|
|
2401
|
+
(0, react_1.useEffect)(() => {
|
|
2402
|
+
if (!workflow || !placement)
|
|
2403
|
+
return;
|
|
2404
|
+
const currentWorkflowStage = { ...workflow.find((obj) => obj.id === placement.status) };
|
|
2405
|
+
// console.log("currentWorkflowStage", currentWorkflowStage)
|
|
2406
|
+
currentWorkflowStage.id = placement.status;
|
|
2407
|
+
// Get form data for current stage
|
|
2408
|
+
if (currentWorkflowStage.forms) {
|
|
2409
|
+
(0, readDatabase_1.getFormsFromId)(["forms"], currentWorkflowStage.forms).then((details) => {
|
|
2410
|
+
currentWorkflowStage.formDetails = details;
|
|
2411
|
+
setWStage(currentWorkflowStage);
|
|
2412
|
+
});
|
|
2413
|
+
}
|
|
2414
|
+
else {
|
|
2415
|
+
setWStage(currentWorkflowStage);
|
|
2416
|
+
}
|
|
2417
|
+
}, [placement, workflow]);
|
|
2418
|
+
const editStage = async (nextStageId) => {
|
|
2419
|
+
if (!placementId || !wStage)
|
|
2420
|
+
return;
|
|
2421
|
+
await (0, writeDatabase_1.editPlacementStage)(placementId, wStage.id, nextStageId);
|
|
2422
|
+
setSnackbar({ open: true, message: "Stage updated." });
|
|
2423
|
+
};
|
|
2424
|
+
const sendEmail = (type) => {
|
|
2425
|
+
if (!placement || !student)
|
|
2426
|
+
return undefined;
|
|
2427
|
+
const sendRequest = async () => {
|
|
2428
|
+
await (0, firebase_1.executeCallable)("placement-sendExternalEmail", { pId: placementId, userType: type });
|
|
2429
|
+
setSnackbar({ open: true, message: "Email sent." });
|
|
2430
|
+
return;
|
|
2431
|
+
};
|
|
2432
|
+
if ((type === "provider" && !placement.providerEmail) || (type === "parent" && !student.details.parentEmail)) {
|
|
2433
|
+
setSnackbar({ open: true, message: `Please add a ${type} email.` });
|
|
2434
|
+
return;
|
|
2435
|
+
}
|
|
2436
|
+
if (!placement[`${type}Emailed`]) {
|
|
2437
|
+
setDisableEmail((x) => ({ ...x, [type]: true }));
|
|
2438
|
+
sendRequest().then(() => setDisableEmail((x) => ({ ...x, [type.toLowerCase()]: false })));
|
|
2439
|
+
return;
|
|
2440
|
+
}
|
|
2441
|
+
const previousEmailTime = new Date(placement[`${type}Emailed`].seconds * 1000);
|
|
2442
|
+
const today = new Date();
|
|
2443
|
+
const timeSinceEmail = (0, util_1.getDateDiff)(previousEmailTime, today);
|
|
2444
|
+
if (timeSinceEmail === 0) {
|
|
2445
|
+
setSnackbar({ open: true, message: "Emails can only be sent after 1 day." });
|
|
2446
|
+
return;
|
|
2447
|
+
}
|
|
2448
|
+
setDisableEmail((x) => ({ ...x, [type.toLowerCase()]: true }));
|
|
2449
|
+
sendRequest().then(() => setDisableEmail((x) => ({ ...x, [type.toLowerCase()]: false })));
|
|
2450
|
+
};
|
|
2451
|
+
const onboardingStatus = (placement === null || placement === void 0 ? void 0 : placement.onboarding) ? ((_a = placement.onboarding.completed) === null || _a === void 0 ? void 0 : _a.submitted) ? placement.onboarding.completed.accepted ? "Onboarding docs approved" : "Onboarding docs completed" : (user.userType === "Staff" ? "Onboarding sent" : "Complete onboarding") : "Add onboarding documents";
|
|
2452
|
+
const signOffPlacements = (0, util_1.getAccess)(user, "signOffPlacements");
|
|
2453
|
+
let canEdit = false;
|
|
2454
|
+
if (((wStage === null || wStage === void 0 ? void 0 : wStage.userType) === "Staff" && user.product === "providers") && user.userGroup === "admin") {
|
|
2455
|
+
canEdit = true;
|
|
2456
|
+
}
|
|
2457
|
+
else if (((wStage === null || wStage === void 0 ? void 0 : wStage.userType) === "Staff" && user.userType === "Staff" && user.product === "institutes") || (user.product === "providers" && (wStage === null || wStage === void 0 ? void 0 : wStage.userType) === "Provider") || user.userType === "Students" && (wStage === null || wStage === void 0 ? void 0 : wStage.userType) === "Students") {
|
|
2458
|
+
console.log("ALMOST CAN EDIT");
|
|
2459
|
+
if (user.userType === "Staff" && !signOffPlacements) {
|
|
2460
|
+
canEdit = false;
|
|
2461
|
+
}
|
|
2462
|
+
else {
|
|
2463
|
+
canEdit = true;
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
const onFlagClick = async (e) => {
|
|
2467
|
+
if (!placement)
|
|
2468
|
+
return;
|
|
2469
|
+
if (e === "completeOnboarding" || e === "reviewOnboarding") {
|
|
2470
|
+
setOnboardingPopup(true);
|
|
2471
|
+
}
|
|
2472
|
+
if (e === "noInsurance") {
|
|
2473
|
+
if (!eliURL) {
|
|
2474
|
+
const storageRef = (0, storage_1.ref)(firebaseConfig_1.storage, `insurance/${placement.providerId}.pdf`);
|
|
2475
|
+
const file = await (0, storage_1.getDownloadURL)(storageRef);
|
|
2476
|
+
setELIURL(file);
|
|
2477
|
+
}
|
|
2478
|
+
setEliPopupOpen(true);
|
|
2479
|
+
}
|
|
2480
|
+
if (e === "noRiskAssessment") {
|
|
2481
|
+
if (!riskAssessmentURL && placement.riskAssessmentType === "file") {
|
|
2482
|
+
console.log("Risk assessment");
|
|
2483
|
+
const storageRef = (0, storage_1.ref)(firebaseConfig_1.storage, `riskAssessments/${placement.placementId || placement.id}.pdf`);
|
|
2484
|
+
const file = await (0, storage_1.getDownloadURL)(storageRef);
|
|
2485
|
+
setRiskAssessmentURL(file);
|
|
2486
|
+
}
|
|
2487
|
+
setExternalDocPopupOpen("riskAssessment");
|
|
2488
|
+
}
|
|
2489
|
+
if (e === "noDbsCheck") {
|
|
2490
|
+
if (!dbsCheckURL && placement.dbsCheckType === "file") {
|
|
2491
|
+
const storageRef = (0, storage_1.ref)(firebaseConfig_1.storage, `dbsChecks/${placement.placementId || placement.id}.pdf`);
|
|
2492
|
+
const file = await (0, storage_1.getDownloadURL)(storageRef);
|
|
2493
|
+
setDbsCheckURL(file);
|
|
2494
|
+
}
|
|
2495
|
+
setExternalDocPopupOpen("dbsCheck");
|
|
2496
|
+
}
|
|
2497
|
+
};
|
|
2498
|
+
const approveELI = async () => {
|
|
2499
|
+
if (!placement)
|
|
2500
|
+
return;
|
|
2501
|
+
await (0, firebase_1.executeCallable)("insurance-approve", { oId: user.oId, providerId: placement.providerId });
|
|
2502
|
+
setEliPopupOpen(false);
|
|
2503
|
+
};
|
|
2504
|
+
const rejectELI = async ({ reason }) => {
|
|
2505
|
+
if (!placement || !institute)
|
|
2506
|
+
return;
|
|
2507
|
+
console.log("Reject", { reason: reason, placement: placement, instituteName: institute.name, staffEmail: user.email });
|
|
2508
|
+
await (0, firebase_1.executeCallable)("insurance-reject", { reason: reason, placementId: placementId, instituteName: institute.name, staffEmail: user.email });
|
|
2509
|
+
setRejectELIPopup(false);
|
|
2510
|
+
setEliPopupOpen(false);
|
|
2511
|
+
};
|
|
2512
|
+
const approveProviderDoc = async (type) => {
|
|
2513
|
+
await (0, firebase_1.executeCallable)(`${type}-approve`, { oId: user.oId, placementId: placementId });
|
|
2514
|
+
setExternalDocPopupOpen(false);
|
|
2515
|
+
};
|
|
2516
|
+
const rejectProviderDoc = async ({ reason }, type) => {
|
|
2517
|
+
if (!placement || !institute)
|
|
2518
|
+
return;
|
|
2519
|
+
await (0, firebase_1.executeCallable)(`${type}-reject`, { reason: reason, placementId: placementId, instituteName: institute.name, staffEmail: user.email });
|
|
2520
|
+
setRejectExternalDocPopup(false);
|
|
2521
|
+
setExternalDocPopupOpen(false);
|
|
2522
|
+
};
|
|
2523
|
+
const manuallyConfigureProvider = async () => {
|
|
2524
|
+
if (!placement)
|
|
2525
|
+
return;
|
|
2526
|
+
if (!placement.providerId) {
|
|
2527
|
+
const res = await (0, firebase_1.executeCallable)("placement-uploadProviderDetails", {
|
|
2528
|
+
pId: placementId,
|
|
2529
|
+
placement: Object.fromEntries(Object.entries(placement).filter(([k]) => k !== "contactId")),
|
|
2530
|
+
stage: wStage,
|
|
2531
|
+
skipSearch: true
|
|
2532
|
+
}).catch((e) => {
|
|
2533
|
+
throw e;
|
|
2534
|
+
});
|
|
2535
|
+
console.log("RETURN", res.data);
|
|
2536
|
+
setPlacement((p) => ({ ...p, ...res.data }));
|
|
2537
|
+
if (uploadProviderDocPopup === "insurance") {
|
|
2538
|
+
setUploadProviderDocPopup(undefined);
|
|
2539
|
+
setUploadInsurance(true);
|
|
2540
|
+
}
|
|
2541
|
+
else if (uploadProviderDocPopup === "riskAssessment") {
|
|
2542
|
+
setUploadProviderDocPopup(undefined);
|
|
2543
|
+
setUploadRA(true);
|
|
2544
|
+
}
|
|
2545
|
+
else if (uploadProviderDocPopup === "DbsCheck") {
|
|
2546
|
+
setUploadProviderDocPopup(undefined);
|
|
2547
|
+
setUploadDBS(true);
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
};
|
|
2551
|
+
const withdrawFromPlacement = async () => {
|
|
2552
|
+
if (user.userType !== "Students")
|
|
2553
|
+
throw new Error("Must be a student to withdraw.");
|
|
2554
|
+
await (0, firebase_1.executeCallable)("placement-withdraw", { placementId: placementId });
|
|
2555
|
+
};
|
|
2556
|
+
return { placement, wStage, student, workflow, editable, withdrawFromPlacementPopup, setWithdrawFromPlacementPopup, withdrawFromPlacement, onFlagClick, setUploadInsurance, setUploadProviderDocPopup, setUploadRA, setUploadDBS, onboardingStatus, setSkipStagePopup, onboardingPopup, setViewExternalLinkPopup, setOnboardingPopup, setRejectELIPopup, eliURL, riskAssessmentURL, dbsCheckURL, setExternalLinkCopied, skipStagePopup, snackbar, setSnackbar, cohort, disableEmail, rejectELIPopup, eliPopupOpen, rejectExternalDocPopup, externalDocPopupOpen, viewExternalLinkPopup, externalLinkCopied, uploadInsurance, uploadRA, uploadDBS, editStage, sendEmail, canEdit, approveELI, setEliPopupOpen, uploadProviderDocPopup, rejectELI, setRejectExternalDocPopup, setExternalDocPopupOpen, approveProviderDoc, rejectProviderDoc, manuallyConfigureProvider, institute };
|
|
2557
|
+
}
|
|
2558
|
+
function useOnboardingPopup({ onboarding, placementId, user, onClose }) {
|
|
2559
|
+
const [fileUploadPopup, setFileUploadPopup] = (0, react_1.useState)(false);
|
|
2560
|
+
const [form, setForm] = (0, react_1.useState)();
|
|
2561
|
+
const [rejectPopup, setRejectPopup] = (0, react_1.useState)(false);
|
|
2562
|
+
const [mOnboarding, setMOnboarding] = (0, react_1.useState)(onboarding);
|
|
2563
|
+
const [completedSections, setCompletedSections] = (0, react_1.useState)();
|
|
2564
|
+
const [uploadedFiles, setUploadedFiles] = (0, react_1.useState)({});
|
|
2565
|
+
const firebaseQuery = new firebaseQuery_1.default();
|
|
2566
|
+
const addFile = (files) => {
|
|
2567
|
+
if (!files.length || fileUploadPopup === false)
|
|
2568
|
+
return;
|
|
2569
|
+
setMOnboarding((a) => (0, util_1.editNestedObject)(["completed", "filesUploaded", fileUploadPopup], a, files));
|
|
2570
|
+
setFileUploadPopup(false);
|
|
2571
|
+
};
|
|
2572
|
+
const viewFile = (file, onOpen) => {
|
|
2573
|
+
setMOnboarding((a) => {
|
|
2574
|
+
var _a, _b, _c;
|
|
2575
|
+
const oldA = { ...a };
|
|
2576
|
+
const viewedFiles = a.completed ? ((_a = a.completed) === null || _a === void 0 ? void 0 : _a.filesViewed) || [] : [];
|
|
2577
|
+
if (viewedFiles === null || viewedFiles === void 0 ? void 0 : viewedFiles.includes(file))
|
|
2578
|
+
return a;
|
|
2579
|
+
((_b = a === null || a === void 0 ? void 0 : a.viewableFiles) === null || _b === void 0 ? void 0 : _b[file].url) && onOpen((_c = a === null || a === void 0 ? void 0 : a.viewableFiles) === null || _c === void 0 ? void 0 : _c[file].url);
|
|
2580
|
+
viewedFiles === null || viewedFiles === void 0 ? void 0 : viewedFiles.push(file);
|
|
2581
|
+
const newA = (0, util_1.editNestedObject)(["completed", "filesViewed"], oldA, viewedFiles);
|
|
2582
|
+
return newA;
|
|
2583
|
+
});
|
|
2584
|
+
};
|
|
2585
|
+
const setFormComplete = (e, formId) => {
|
|
2586
|
+
const mFormId = formId || (form === null || form === void 0 ? void 0 : form.id);
|
|
2587
|
+
if (!mFormId)
|
|
2588
|
+
return;
|
|
2589
|
+
setMOnboarding((a) => (0, util_1.editNestedObject)(["completed", "formsCompleted", mFormId], a, e));
|
|
2590
|
+
setFileUploadPopup(false);
|
|
2591
|
+
};
|
|
2592
|
+
(0, react_1.useEffect)(() => {
|
|
2593
|
+
if (!onboarding)
|
|
2594
|
+
return;
|
|
2595
|
+
const getOnboardingData = async () => {
|
|
2596
|
+
var _a, _b;
|
|
2597
|
+
const onboardingNew = { ...onboarding };
|
|
2598
|
+
const onboardingFiles = onboarding.files ? Object.fromEntries(await Promise.all((_a = onboarding.files) === null || _a === void 0 ? void 0 : _a.map(async (fileId) => {
|
|
2599
|
+
const file = await firebaseQuery.getDocData(["files", fileId]);
|
|
2600
|
+
file.url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `userFiles/${file.fileName}`));
|
|
2601
|
+
return [fileId, file];
|
|
2602
|
+
}))) : [];
|
|
2603
|
+
const onboardingForms = onboarding.forms ? Object.fromEntries(await Promise.all((_b = onboarding.forms) === null || _b === void 0 ? void 0 : _b.map(async (formId) => {
|
|
2604
|
+
return [formId, await firebaseQuery.getDocData(["forms", formId])];
|
|
2605
|
+
}))) : [];
|
|
2606
|
+
onboardingNew.viewableFiles = onboardingFiles;
|
|
2607
|
+
onboardingNew.formDetails = onboardingForms;
|
|
2608
|
+
return onboardingNew;
|
|
2609
|
+
};
|
|
2610
|
+
getOnboardingData().then(setMOnboarding);
|
|
2611
|
+
}, [onboarding]);
|
|
2612
|
+
(0, react_1.useEffect)(() => {
|
|
2613
|
+
console.log("onboarding change", mOnboarding, !(0, util_1.objectsEqual)(mOnboarding, onboarding));
|
|
2614
|
+
if (!(0, util_1.objectsEqual)(mOnboarding, onboarding) && placementId) {
|
|
2615
|
+
firebaseQuery.update(["placements", placementId], { onboarding: mOnboarding });
|
|
2616
|
+
}
|
|
2617
|
+
}, [mOnboarding]);
|
|
2618
|
+
const stagesCompleted = () => {
|
|
2619
|
+
var _a, _b;
|
|
2620
|
+
console.log("CompletedSections", completedSections);
|
|
2621
|
+
for (const fileViewed of (mOnboarding === null || mOnboarding === void 0 ? void 0 : mOnboarding.files) || []) {
|
|
2622
|
+
if (!((_a = completedSections === null || completedSections === void 0 ? void 0 : completedSections.filesViewed) === null || _a === void 0 ? void 0 : _a.includes(fileViewed))) {
|
|
2623
|
+
console.log("Checking file", fileViewed);
|
|
2624
|
+
console.log("File not completed");
|
|
2625
|
+
return false;
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
for (const formCompleted of (mOnboarding === null || mOnboarding === void 0 ? void 0 : mOnboarding.forms) || []) {
|
|
2629
|
+
if (!Object.keys((completedSections === null || completedSections === void 0 ? void 0 : completedSections.formsCompleted) || {}).includes(formCompleted)) {
|
|
2630
|
+
console.log("Form not completed");
|
|
2631
|
+
return false;
|
|
2632
|
+
}
|
|
2633
|
+
}
|
|
2634
|
+
for (var i; i++; i < (((_b = mOnboarding === null || mOnboarding === void 0 ? void 0 : mOnboarding.requiredFiles) === null || _b === void 0 ? void 0 : _b.length) || 1)) {
|
|
2635
|
+
if (!Object.keys((completedSections === null || completedSections === void 0 ? void 0 : completedSections.filesUploaded) || {}).includes((i))) {
|
|
2636
|
+
return false;
|
|
2637
|
+
}
|
|
2638
|
+
}
|
|
2639
|
+
return true;
|
|
2640
|
+
};
|
|
2641
|
+
const rejectOnboarding = async ({ reason }) => {
|
|
2642
|
+
if (user.product !== "providers")
|
|
2643
|
+
return;
|
|
2644
|
+
return await (0, firebase_1.executeCallable)("placement-rejectOnboarding", { reason: reason, placementId: placementId }).then(() => {
|
|
2645
|
+
setRejectPopup(false);
|
|
2646
|
+
onClose();
|
|
2647
|
+
}).catch(() => {
|
|
2648
|
+
throw new Error("Error");
|
|
2649
|
+
});
|
|
2650
|
+
};
|
|
2651
|
+
const acceptOnboarding = async () => {
|
|
2652
|
+
if (user.product !== "providers" || !placementId)
|
|
2653
|
+
return;
|
|
2654
|
+
await firebaseQuery.update(["placements", placementId], { "onboarding.completed.accepted": true });
|
|
2655
|
+
};
|
|
2656
|
+
const submit = async () => {
|
|
2657
|
+
// Check all stages completed.
|
|
2658
|
+
if (!placementId)
|
|
2659
|
+
return;
|
|
2660
|
+
if (!stagesCompleted())
|
|
2661
|
+
throw new Error("Complete all forms before submitting.");
|
|
2662
|
+
await firebaseQuery.update(["placements", placementId], { ["onboarding.completed.submitted"]: (0, util_1.convertDate)(new Date(), "dbstring") });
|
|
2663
|
+
};
|
|
2664
|
+
(0, react_1.useEffect)(() => {
|
|
2665
|
+
const getUploadedFiles = async () => {
|
|
2666
|
+
if (!mOnboarding.completed) {
|
|
2667
|
+
setUploadedFiles({});
|
|
2668
|
+
return;
|
|
2669
|
+
}
|
|
2670
|
+
;
|
|
2671
|
+
const fileIds = Object.values(mOnboarding.completed.filesUploaded || {})
|
|
2672
|
+
.flatMap(fileIds => fileIds);
|
|
2673
|
+
const fileDataPromises = fileIds.map(async (fileId) => {
|
|
2674
|
+
const fileData = await firebaseQuery.getDocData(["files", fileId]);
|
|
2675
|
+
fileData.url = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `userFiles/${fileData.fileName}`));
|
|
2676
|
+
return [fileId, fileData];
|
|
2677
|
+
});
|
|
2678
|
+
const fileDataArray = await Promise.all(fileDataPromises);
|
|
2679
|
+
const fileDataObj = Object.fromEntries(fileDataArray);
|
|
2680
|
+
setUploadedFiles(fileDataObj);
|
|
2681
|
+
};
|
|
2682
|
+
const addCompletedSectionURLs = async () => {
|
|
2683
|
+
const completedSectionsWithURLs = { ...mOnboarding === null || mOnboarding === void 0 ? void 0 : mOnboarding.completed };
|
|
2684
|
+
completedSectionsWithURLs.filesUploaded = Object.fromEntries(await Promise.all(Object.entries(completedSectionsWithURLs.filesUploaded || {}).map(async ([fileId, items]) => {
|
|
2685
|
+
const filesWithObjects = await Promise.all(items.map(async (itemId) => {
|
|
2686
|
+
const file = await firebaseQuery.getDocData(["files", itemId]);
|
|
2687
|
+
const fileUrl = await (0, storage_1.getDownloadURL)((0, storage_1.ref)(firebaseConfig_1.storage, `userFiles/${file.fileName}`));
|
|
2688
|
+
console.log("|FILEURL", fileUrl);
|
|
2689
|
+
return fileUrl;
|
|
2690
|
+
}));
|
|
2691
|
+
return [fileId, filesWithObjects];
|
|
2692
|
+
})));
|
|
2693
|
+
setCompletedSections(completedSectionsWithURLs);
|
|
2694
|
+
};
|
|
2695
|
+
getUploadedFiles();
|
|
2696
|
+
addCompletedSectionURLs();
|
|
2697
|
+
}, [mOnboarding]);
|
|
2698
|
+
return { addFile, viewFile, uploadedFiles, setFormComplete, setRejectPopup, stagesCompleted, setForm, mOnboarding, form, submit, acceptOnboarding, rejectOnboarding, rejectPopup, completedSections, fileUploadPopup, setFileUploadPopup };
|
|
2699
|
+
}
|
|
1581
2700
|
//# sourceMappingURL=hooks.js.map
|