placementt-core 1.20.232 → 1.300.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/.eslintrc.js +40 -40
  2. package/.gitattributes +2 -2
  3. package/deploy-all.js +75 -0
  4. package/lib/config.d.ts +0 -13
  5. package/lib/config.js +1 -3
  6. package/lib/config.js.map +1 -1
  7. package/lib/constants.d.ts +1 -0
  8. package/lib/constants.js +48 -1
  9. package/lib/constants.js.map +1 -1
  10. package/lib/features/config.d.ts +133 -133
  11. package/lib/features/config.js +35 -35
  12. package/lib/features/contacts/contacts.d.ts +75 -75
  13. package/lib/features/contacts/contacts.js +105 -105
  14. package/lib/features/downtime/useDowntime.d.ts +11 -11
  15. package/lib/features/downtime/useDowntime.js +22 -22
  16. package/lib/features/placements/studentPlacements/activePlacement.js +1 -1
  17. package/lib/features/placements/studentPlacements/activePlacement.js.map +1 -1
  18. package/lib/features/placements/studentPlacements/studentPlacementsSlice.d.ts +63 -63
  19. package/lib/features/placements/studentPlacements/studentPlacementsSlice.js +81 -81
  20. package/lib/features/providerPlacements/providerPlacementsSlice.d.ts +19 -19
  21. package/lib/features/providerPlacements/providerPlacementsSlice.js +24 -24
  22. package/lib/features/studentPlacements/studentPlacementsSlice.d.ts +62 -62
  23. package/lib/features/studentPlacements/studentPlacementsSlice.js +87 -87
  24. package/lib/features/studentPlacements/useStudentPlacements.d.ts +6 -6
  25. package/lib/features/studentPlacements/useStudentPlacements.js +18 -18
  26. package/lib/features/userSlice.d.ts +26 -26
  27. package/lib/features/userSlice.js +23 -23
  28. package/lib/features/users/useUserFunctions.d.ts +25 -25
  29. package/lib/features/users/useUserFunctions.js +124 -124
  30. package/lib/features/users/userSlice.d.ts +46 -46
  31. package/lib/features/users/userSlice.js +48 -48
  32. package/lib/firebase/firebase.d.ts +1 -1
  33. package/lib/firebase/firebase.js +8 -3
  34. package/lib/firebase/firebase.js.map +1 -1
  35. package/lib/firebase/firebaseConfig.js +1 -0
  36. package/lib/firebase/firebaseConfig.js.map +1 -1
  37. package/lib/firebase/readDatabase.js +7 -7
  38. package/lib/firebase/readDatabase.js.map +1 -1
  39. package/lib/hooks.d.ts +85 -192
  40. package/lib/hooks.js +731 -671
  41. package/lib/hooks.js.map +1 -1
  42. package/lib/images/GatsbyBenchmarks.d.ts +1 -2
  43. package/lib/index.d.ts +0 -1
  44. package/lib/index.js +0 -1
  45. package/lib/index.js.map +1 -1
  46. package/lib/reduxHooks.d.ts +9 -41
  47. package/lib/reduxHooks.js +1 -49
  48. package/lib/reduxHooks.js.map +1 -1
  49. package/lib/tasksAndTips.js +368 -418
  50. package/lib/tasksAndTips.js.map +1 -1
  51. package/lib/typeDefinitions.d.ts +162 -83
  52. package/lib/util.d.ts +25 -1
  53. package/lib/util.js +329 -2
  54. package/lib/util.js.map +1 -1
  55. package/package.json +56 -56
  56. package/src/DatabaseDefinitions.ts +18 -18
  57. package/src/apiCalls.ts +128 -128
  58. package/src/config.ts +50 -53
  59. package/src/constants.ts +846 -796
  60. package/src/databaseTypes.ts +42 -42
  61. package/src/features/analytics/useAnalytics.tsx +63 -63
  62. package/src/features/contacts/contactsSlice.ts +147 -147
  63. package/src/features/contacts/useContacts.tsx +73 -73
  64. package/src/features/dropdown/useDropdown.tsx +52 -52
  65. package/src/features/global/downtime/useDowntime.tsx +23 -23
  66. package/src/features/global/users/useUserFunctions.tsx +132 -132
  67. package/src/features/jobs/jobsSlice.ts +71 -71
  68. package/src/features/placements/studentPlacements/activePlacement.ts +68 -68
  69. package/src/features/placements/studentPlacements/completedStudentPlacementsSlice.ts +97 -97
  70. package/src/features/placements/studentPlacements/upcomingStudentPlacementsSlice.ts +108 -108
  71. package/src/features/placements/studentPlacements/useStudentPlacements.tsx +9 -9
  72. package/src/features/placements/types.ts +10 -10
  73. package/src/features/referrals/useReferrals.tsx +56 -56
  74. package/src/features/updates/useUpdates.tsx +38 -38
  75. package/src/firebase/firebase.tsx +158 -153
  76. package/src/firebase/firebaseConfig.tsx +47 -45
  77. package/src/firebase/firebaseQuery.tsx +151 -151
  78. package/src/firebase/persistence.ts +84 -84
  79. package/src/firebase/readDatabase.tsx +236 -236
  80. package/src/firebase/util.tsx +352 -352
  81. package/src/firebase/writeDatabase.tsx +77 -77
  82. package/src/hooks.tsx +4476 -4463
  83. package/src/images/GatsbyBenchmarks.tsx +711 -711
  84. package/src/images/LogFuturePlacement.jsx +64 -64
  85. package/src/images/LogPreviousPlacement.jsx +228 -228
  86. package/src/images/gatsby_benchmarks.svg +466 -466
  87. package/src/images/log_future_placement.svg +114 -114
  88. package/src/images/log_previous_placement.svg +199 -199
  89. package/src/index.ts +34 -35
  90. package/src/readDatabase.tsx +3 -3
  91. package/src/reduxHooks.ts +295 -352
  92. package/src/tasksAndTips.ts +1267 -1267
  93. package/src/tutorialTips.ts +58 -58
  94. package/src/typeDefinitions.ts +1260 -1129
  95. package/src/util.ts +523 -177
  96. package/tsconfig.dev.json +5 -5
  97. package/tsconfig.json +21 -21
  98. package/lib/features/logs/logsSlice.d.ts +0 -93
  99. package/lib/features/logs/logsSlice.js +0 -146
  100. package/lib/features/logs/logsSlice.js.map +0 -1
  101. package/src/features/logs/logsSlice.ts +0 -208
package/src/reduxHooks.ts CHANGED
@@ -1,353 +1,296 @@
1
- import { DocumentData, documentId, orderBy, where } from "firebase/firestore"
2
- import { useEffect, useState } from "react"
3
- import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux"
4
- import { AppDispatch, RootState } from "./config"
5
- import { addContact, deleteContact, setContacts, updateContact } from "./features/contacts/contactsSlice"
6
- import { Job, addJob, setJobStatus, setJobs, setMarkRead, updateJob } from "./features/jobs/jobsSlice"
7
- import { addLogFile, deleteLogFile, editLog, fetchLogs } from "./features/logs/logsSlice"
8
- import { editActivePlacement, fetchActivePlacement, setActivePlacement } from "./features/placements/studentPlacements/activePlacement"
9
- import { addCompletedStudentPlacements, deleteCompletedStudentPlacement, setCompletedStudentPlacements, updateCompletedStudentPlacement } from "./features/placements/studentPlacements/completedStudentPlacementsSlice"
10
- import { addUpcomingStudentPlacements, deleteUpcomingStudentPlacement, setUpcoming, setUpcomingStudentPlacements, updateUpcomingStudentPlacement } from "./features/placements/studentPlacements/upcomingStudentPlacementsSlice"
11
- import FirebaseQuery from "./firebase/firebaseQuery"
12
- import { getOrganisation, getPlacementsWhere } from "./firebase/readDatabase"
13
- import { convertDate } from "./firebase/util"
14
- import { Address, Application, CohortData, Contact, EmailTemplate, InstituteData, PlacementListing, ProviderData, SavedPlacement, StudentPlacementData, UserData, UserGroupData } from "./typeDefinitions"
15
-
16
- export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
17
- export const useAppDispatch = () => useDispatch<AppDispatch>();
18
-
19
-
20
- export function useStudent({user} : {user: UserData}) {
21
- if (!user || user.userType !== "Students") return {error: "Unauthorized"};
22
-
23
- const upcomingPlacements = useAppSelector((state) => state.upcomingStudentPlacements.values)
24
- const completedPlacements = useAppSelector((state) => state.completedStudentPlacements.values)
25
- const activePlacement = useAppSelector((state) => state.activePlacement.values)
26
- const upcoming = useAppSelector((state) => state.upcomingStudentPlacements.upcoming)
27
- const contacts = useAppSelector((state) => state.contacts.values)
28
- const [applications, setApplications] = useState<{[key: string]: Application&{listing: PlacementListing|false, provider: ProviderData|false, address: Address}}>();
29
- const firebaseQuery = new FirebaseQuery();
30
-
31
- const dispatch = useAppDispatch();
32
-
33
- const today = new Date();
34
-
35
- const applicationsConstraints = [where("uid", "==", user.id)]
36
- const upcomingPlacementsConstraints = [where("uid", "==", user.id), where("inProgress", "==", true)]
37
- const completedPlacementsConstraints = [where("uid", "==", user.id), where("completed", "==", true)]
38
- const contactsConstraints = [where("uid", "==", user.id)]
39
-
40
- useEffect(() => {
41
- firebaseQuery.collectionSnapshot(setUpcomingStudentPlacements, "placements", upcomingPlacementsConstraints, dispatch);
42
- firebaseQuery.collectionSnapshot(setCompletedStudentPlacements, "placements", completedPlacementsConstraints, dispatch);
43
- firebaseQuery.collectionSnapshot(setContacts, "contacts", contactsConstraints, dispatch);
44
- firebaseQuery.collectionSnapshot(async (fApplications: {[key: string]: Application}) => {
45
-
46
- const applicationsWithProviderAndListing:{[key: string]: Application&{listing: PlacementListing, provider: ProviderData, address: Address}} = Object.fromEntries(await Promise.all(Object.entries(fApplications).map(async ([id, application]) => {
47
- const provider = await firebaseQuery.getDocData(["providers", application.providerId]).catch(() => false) as ProviderData|false;
48
- const listing = await firebaseQuery.getDocData(["placementListings", application.listingId]).catch(() => false) as PlacementListing|false;
49
- const address = listing && listing?.addressId && await firebaseQuery.getDocData(["addresses", listing.addressId]) as Address;
50
-
51
- return [id, {...application, listing: listing, provider: provider, address: address}];
52
- })));
53
-
54
- setApplications(applicationsWithProviderAndListing);
55
-
56
- }, "applications", applicationsConstraints);
57
- }, [user.id]);
58
- /*
59
- useEffect(() => {
60
- if (!user.id) return
61
- dispatch(fetchActivePlacement({userId: user.id}))
62
- }, [dispatch, user.id, upcomingPlacements]);
63
- */
64
- const fetchUpcomingPlacements = () => {
65
- const constraints = [where("uid", "==", user.id), where("inProgress", "==", true), orderBy("startDate")]
66
- firebaseQuery.collectionSnapshot(setUpcomingStudentPlacements, "placements", constraints, dispatch);
67
- }
68
-
69
- const fetchCompletedPlacements = () => {
70
- const constraints = [where("uid", "==", user.id), where("completed", "==", true), orderBy("startDate")]
71
- firebaseQuery.collectionSnapshot(setCompletedStudentPlacements, "placements", constraints, dispatch);
72
- }
73
-
74
- const fetchContacts = () => {
75
- const constraints = [where("uid", "==", user.id)]
76
- firebaseQuery.collectionSnapshot(setContacts, "contacts", constraints, dispatch);
77
- }
78
-
79
- const updateUpcomingPlacement = () => {
80
- if (!upcomingPlacements || !Object.entries(upcomingPlacements).length) {
81
- dispatch(setUpcoming(undefined));
82
- return;
83
- }
84
- const upcomingPlacement = Object.entries(upcomingPlacements).find(([, v]) => new Date(v.startDate).getTime() > today.getTime())
85
- upcomingPlacement ? dispatch(setUpcoming(upcomingPlacement[1])) : dispatch(setUpcoming(undefined))
86
- }
87
-
88
- const updateActivePlacement = () => {
89
- const key = Object.keys(upcomingPlacements).find((key) => {
90
- const placement = upcomingPlacements[key]
91
- return placement.active
92
- })
93
- key ? dispatch(setActivePlacement(upcomingPlacements[key])) : dispatch(setActivePlacement(null))
94
- }
95
-
96
- const getItemById = async (path: "contacts"|"placements", id: string) => {
97
- return await firebaseQuery.getDocData([path, id])
98
- }
99
-
100
- const handleDeletePlacement = async (id: string) => {
101
- if (upcomingPlacements[id]) dispatch(deleteUpcomingStudentPlacement({placementId: id}))
102
- else dispatch(deleteCompletedStudentPlacement({placementId: id}))
103
- }
104
-
105
- const handleUpdatePlacement = async (id: string, attributes: Partial<StudentPlacementData>) => {
106
- if (upcomingPlacements[id]) dispatch(updateUpcomingStudentPlacement({placementId: id, attributes}))
107
- else dispatch(updateCompletedStudentPlacement({placementId: id, attributes}))
108
- }
109
-
110
- const handleAddPlacement = async (formData: StudentPlacementData) => {
111
- if (formData.completed) dispatch(addCompletedStudentPlacements({formData}))
112
- else dispatch(addUpcomingStudentPlacements({formData}))
113
- }
114
-
115
- const getUserPlacements = async () => {
116
- return await getPlacementsWhere({w: where("uid", "==", user?.id)})
117
- }
118
-
119
- const getPlacementsStart = async (start: Date, end: Date) => {
120
- return await firebaseQuery.getDocsWhere("placements", [where("uid", "==", user?.id), where("startDate", ">=", convertDate(start, "dbstring")), where("startDate", "<=", convertDate(end, "dbstring"))]) as {[key:string]: StudentPlacementData};
121
- }
122
-
123
- const getPlacementsEnd = async (end: Date) => {
124
- return await firebaseQuery.getDocsWhere("placements", [where("uid", "==", user?.id), where("endDate", ">=", convertDate(end, "dbstring")), where("endDate", "<=", convertDate(end, "dbstring"))]) as {[key:string]: StudentPlacementData};
125
- }
126
-
127
- const dispatchActivePlacement = () => {
128
- dispatch(fetchActivePlacement({userId: user.id}))
129
- }
130
-
131
- return {
132
- contacts: {
133
- add: async (contactForm: Contact) => await dispatch(addContact({contactForm: contactForm, userId: user.id})),
134
- update: async (contactId: string, data: Partial<Contact>) => await dispatch(updateContact({contactId: contactId, attributes: data})),
135
- delete: async (contactId: string) => await dispatch(deleteContact({contactId: contactId})),
136
- contacts,
137
- fetchContacts,
138
- getById: async (item: string) => await getItemById("contacts", item)
139
- },
140
-
141
- placements: {
142
- add: async (formData: StudentPlacementData) => await handleAddPlacement(formData),
143
- update: async (placementId: string, attributes: Partial<StudentPlacementData>) => await handleUpdatePlacement(placementId, attributes),
144
- delete: async (id: string) => await handleDeletePlacement(id),
145
- getUserPlacements,
146
- getPlacementsStart,
147
- getPlacementsEnd,
148
- activePlacement,
149
- editActivePlacement: (attributes: Partial<StudentPlacementData>) => dispatch(editActivePlacement(attributes)),
150
- updateActivePlacement,
151
- updateUpcomingPlacement,
152
- fetchUpcomingPlacements,
153
- fetchCompletedPlacements,
154
- dispatchActivePlacement,
155
- upcoming,
156
- upcomingPlacements: upcomingPlacements || {},
157
- completedPlacements: completedPlacements || {},
158
- getById: async (item: string) => await getItemById("placements", item)
159
- },
160
- applications: applications,
161
- } ;
162
- };
163
-
164
-
165
- export function useInstituteStaff({user}: {user: UserData}) {
166
- if (!user || user?.product !== "institutes" || user.userType !== "Staff") return {error: "Unauthorized"};
167
-
168
- const firebaseQuery = new FirebaseQuery();
169
- const dispatch = useAppDispatch();
170
- const {userGroups, forms, institute} = useInstitute({user})
171
- const [cohorts, setCohorts] = useState<{[key:string]: CohortData}>();
172
- const [emailTemplates, setEmailTemplates] = useState<{[key:string]: EmailTemplate}>();
173
-
174
-
175
- useEffect(() => {
176
- const cohortConstraints = [where("oId", "==", user.oId)];
177
- if (user.userGroup !== "admin") {
178
- if (user.viewAddresses !== "all") {
179
- cohortConstraints.push(where("addressId", "in", user.visibleAddresses));
180
- }
181
- if (user.viewCohorts !== "all") {
182
- cohortConstraints.push(where(documentId(), "in", user.visibleCohorts));
183
- }
184
- }
185
- firebaseQuery.collectionSnapshot(setCohorts, "cohorts", cohortConstraints);
186
- firebaseQuery.collectionSnapshot(setEmailTemplates, "emailTemplates", [where("product", "==", user.product), where("oId", "==", user.oId)]);
187
- }, [user.oId, user.userGroup, user.viewAddresses, user.viewCohorts, user.visibleAddresses, user.visibleCohorts, user.product])
188
-
189
- const getJobById = async (id: string) => {
190
- try {
191
- const job = await firebaseQuery.getDocData(["jobs", id])
192
- return job
193
-
194
- } catch (error) {
195
- throw error
196
- }
197
- }
198
-
199
- return {
200
- jobs: {
201
- setJobs: async (jobs: {[jobId: string]: Job}) => dispatch(setJobs(jobs)),
202
- addJob: async ({job, jobId} : {job: Partial<Job>, jobId: string}) => dispatch(addJob({job: job, jobId: jobId})),
203
- setMarkRead: async (payload) => dispatch(setMarkRead(payload)),
204
- setJobStatus: async ({jobId, status}: {jobId: string, status: string}) => dispatch(setJobStatus({jobId: jobId, status: status})),
205
- updateJob: async ({jobId, data}: {jobId: string, data: string}) => dispatch(updateJob({jobId: jobId, data: data})),
206
- getById: getJobById
207
- },
208
- institute,
209
- userGroups,
210
- forms,
211
- cohorts,
212
- emailTemplates,
213
- }
214
- }
215
-
216
- export function useInstitute({user}: {user: UserData}) {
217
- if (!user || user?.product !== "institutes") return {error: "Unauthorized"};
218
-
219
- const [userGroups, setUserGroups] = useState<{[key:string]: UserGroupData}>();
220
- const [forms, setForms] = useState<{[key:string]: unknown}>();
221
- const [institute, setInstitute] = useState<InstituteData>();
222
- const firebaseQuery = new FirebaseQuery();
223
-
224
-
225
- useEffect(() => {
226
- getOrganisation(user, (data) => setInstitute(data as InstituteData));
227
- firebaseQuery.collectionSnapshot(setUserGroups, "userGroups", [where("oId", "==", user.oId), where("product", "==", user.product)]);
228
- firebaseQuery.collectionSnapshot(setForms, "forms", [where("oId", "==", user.oId), where("product", "==", user.product)]);
229
- }, [user.product, user.oId])
230
-
231
- return {
232
- userGroups,
233
- forms,
234
- institute,
235
- }
236
-
237
- }
238
-
239
- export function useInstituteStudent({user}: {user: UserData}) {
240
- if (!user || user?.product !== "institutes" || user.userType !== "Students") return {error: "Unauthorized"};
241
-
242
- const {contacts, placements, applications} = useStudent({user});
243
- const [cohorts, setCohorts] = useState<{[key:string]: CohortData}>();
244
- const firebaseQuery = new FirebaseQuery();
245
- const {userGroups, forms, institute} = useInstitute({user})
246
- const logs = useAppSelector((state) => state.logs)
247
- const dispatch = useAppDispatch()
248
-
249
- useEffect(() => {
250
- const isAdmin = user.userGroup === "admin";
251
- const canViewCohorts = user.viewCohorts !== "none";
252
- const canViewAddresses = user.viewAddresses !== "none";
253
-
254
- if (isAdmin || (canViewCohorts && canViewAddresses)) {
255
- const cohortConstraints = [where("oId", "==", user.oId)];
256
- firebaseQuery.collectionSnapshot(setCohorts, "cohorts", cohortConstraints);
257
- } else {
258
- setCohorts({});
259
- }
260
- }, [user.oId, user.id, user.userGroup, user.viewCohorts, user.viewAddresses, user.product]);
261
-
262
- const getPlacementListings = async () => {
263
- const savedPlacements = await firebaseQuery.getDocsWhere(["savedPlacements"], [where("savedById", "==", user.oId), where("savedByProduct", "==", "institutes"), where("listed", "==", true)]) as {[key:string]: SavedPlacement};
264
- console.log("SP", Object.keys(savedPlacements));
265
- const listings = Object.fromEntries((await Promise.all(Object.values(savedPlacements).map(async (value) => {
266
- const listing = await firebaseQuery.getDocData(["placementListings", value.placementId]) as PlacementListing;
267
- if (value.concurrentPlacements !== undefined) {
268
- const concurrentPlacements = await firebaseQuery.getCount(["placements"], [where("placementId", "==", value.placementId), where("oId", "==", user.oId), where("inProgress", "==", true)]);
269
- console.log("placementId", value.placementId, "Concurrent placements", concurrentPlacements);
270
- console.log("max placements", value.concurrentPlacements, "limit reached", value.concurrentPlacements && (concurrentPlacements >= value.concurrentPlacements));
271
- if (concurrentPlacements >= value.concurrentPlacements) return false;
272
- }
273
- if (!listing?.addressId || !listing.providerId) return false;
274
-
275
- const address:DocumentData|false = await firebaseQuery.getDocData(["addresses", listing.addressId]).catch(() => false);
276
- const provider:DocumentData|false = await firebaseQuery.getDocData(["providers", listing.providerId]).catch(() => false);
277
- if (!address || !provider) return false;
278
-
279
- const placementStatus = value.status === "Accepted" ? "Accepted" : "Not accepted";
280
-
281
- return [value.placementId, {...listing, ...address, ...provider, status: placementStatus, savedPlacement: value}];
282
- }))).filter((i) => i) as [string, PlacementListing][]);
283
-
284
- return listings
285
- }
286
-
287
- const fetchLogData = (placementId: string, selectedDate: string) => {
288
- dispatch(fetchLogs({ placementId, selectedDate }));
289
- };
290
-
291
- const saveLogData = (value: any[] | { [key: string]: unknown }, selectedDate: string, userType: string, placementId: string) => {
292
- dispatch(editLog({ value, selectedDate, userType, placementId }));
293
- };
294
-
295
- const addLogFileData = (files: { file: FileList }, userType: string, selectedDate: string, placementId: string) => {
296
- dispatch(addLogFile({ files, userType, selectedDate, placementId }));
297
- };
298
-
299
- const deleteLogFileData = (openFile: { name: string, url: string }, userType: string, selectedDate: string, placementId: string) => {
300
- dispatch(deleteLogFile({ openFile, userType, selectedDate, placementId }));
301
- };
302
-
303
-
304
- return {
305
- contacts,
306
- placements,
307
- institute,
308
- userGroups,
309
- forms,
310
- cohorts,
311
- applications,
312
- getPlacementListings,
313
- logs: {
314
- status: logs.status,
315
- values: logs,
316
- fetchLogs: fetchLogData,
317
- saveLog: saveLogData,
318
- addLogFile: addLogFileData,
319
- deleteLogFile: deleteLogFileData
320
- }
321
-
322
- }
323
-
324
- }
325
-
326
- export function useProvider({user}: {user: UserData}) {
327
- if (!user || user?.product !== "providers") return {error: "Unauthorized"};
328
-
329
- const {jobs} = useInstituteStaff({user});
330
-
331
- return {
332
- jobs
333
- }
334
-
335
- }
336
-
337
-
338
-
339
- // function MyContactComponent() {
340
- // const {contacts} = useStudent({});
341
-
342
- // contacts.add({data})
343
-
344
- // return null
345
- // }
346
-
347
- // function MyPlacementComponent() {
348
- // const {placements} = useStudent();
349
-
350
- // placements.add({data})
351
-
352
- // return null
1
+ import { documentId, orderBy, where } from "firebase/firestore"
2
+ import { useEffect, useState } from "react"
3
+ import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux"
4
+ import { AppDispatch, RootState } from "./config"
5
+ import { addContact, deleteContact, setContacts, updateContact } from "./features/contacts/contactsSlice"
6
+ import { Job, addJob, setJobStatus, setJobs, setMarkRead, updateJob } from "./features/jobs/jobsSlice"
7
+ import { editActivePlacement, fetchActivePlacement, setActivePlacement } from "./features/placements/studentPlacements/activePlacement"
8
+ import { addCompletedStudentPlacements, deleteCompletedStudentPlacement, setCompletedStudentPlacements, updateCompletedStudentPlacement } from "./features/placements/studentPlacements/completedStudentPlacementsSlice"
9
+ import { addUpcomingStudentPlacements, deleteUpcomingStudentPlacement, setUpcoming, setUpcomingStudentPlacements, updateUpcomingStudentPlacement } from "./features/placements/studentPlacements/upcomingStudentPlacementsSlice"
10
+ import FirebaseQuery from "./firebase/firebaseQuery"
11
+ import { Address, Application, CohortData, Contact, EmailTemplate, InstituteData, PlacementListing, ProviderData, StudentPlacementData, UserData, UserGroupData } from "./typeDefinitions"
12
+ import {getOrganisation, getPlacementsWhere} from "./firebase/readDatabase"
13
+ import {convertDate} from "./firebase/util"
14
+
15
+ export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
16
+ export const useAppDispatch = () => useDispatch<AppDispatch>();
17
+
18
+
19
+ export function useStudent({user} : {user: UserData}) {
20
+ if (!user || user.userType !== "Students") return {error: "Unauthorized"};
21
+
22
+ const upcomingPlacements = useAppSelector((state) => state.upcomingStudentPlacements.values)
23
+ const completedPlacements = useAppSelector((state) => state.completedStudentPlacements.values)
24
+ const activePlacement = useAppSelector((state) => state.activePlacement.values)
25
+ const upcoming = useAppSelector((state) => state.upcomingStudentPlacements.upcoming)
26
+ const contacts = useAppSelector((state) => state.contacts.values)
27
+ const [applications, setApplications] = useState<{[key: string]: Application&{listing: PlacementListing|false, provider: ProviderData|false, address: Address}}>();
28
+ const firebaseQuery = new FirebaseQuery();
29
+
30
+ const dispatch = useAppDispatch();
31
+
32
+ const today = new Date();
33
+
34
+ const applicationsConstraints = [where("uid", "==", user.id)]
35
+ const upcomingPlacementsConstraints = [where("uid", "==", user.id), where("inProgress", "==", true)]
36
+ const completedPlacementsConstraints = [where("uid", "==", user.id), where("completed", "==", true)]
37
+ const contactsConstraints = [where("uid", "==", user.id)]
38
+
39
+ useEffect(() => {
40
+ firebaseQuery.collectionSnapshot(setUpcomingStudentPlacements, "placements", upcomingPlacementsConstraints, dispatch);
41
+ firebaseQuery.collectionSnapshot(setCompletedStudentPlacements, "placements", completedPlacementsConstraints, dispatch);
42
+ firebaseQuery.collectionSnapshot(setContacts, "contacts", contactsConstraints, dispatch);
43
+ firebaseQuery.collectionSnapshot(async (fApplications: {[key: string]: Application}) => {
44
+
45
+ const applicationsWithProviderAndListing:{[key: string]: Application&{listing: PlacementListing, provider: ProviderData, address: Address}} = Object.fromEntries(await Promise.all(Object.entries(fApplications).map(async ([id, application]) => {
46
+ const provider = await firebaseQuery.getDocData(["providers", application.providerId]).catch(() => false) as ProviderData|false;
47
+ const listing = await firebaseQuery.getDocData(["placementListings", application.listingId]).catch(() => false) as PlacementListing|false;
48
+ return [id, {...application, listing: listing, provider: provider}];
49
+ })));
50
+
51
+ setApplications(applicationsWithProviderAndListing);
52
+
53
+ }, "applications", applicationsConstraints);
54
+ }, [user.id]);
55
+ /*
56
+ useEffect(() => {
57
+ if (!user.id) return
58
+ dispatch(fetchActivePlacement({userId: user.id}))
59
+ }, [dispatch, user.id, upcomingPlacements]);
60
+ */
61
+ const fetchUpcomingPlacements = () => {
62
+ const constraints = [where("uid", "==", user.id), where("inProgress", "==", true), orderBy("startDate")]
63
+ firebaseQuery.collectionSnapshot(setUpcomingStudentPlacements, "placements", constraints, dispatch);
64
+ }
65
+
66
+ const fetchCompletedPlacements = () => {
67
+ const constraints = [where("uid", "==", user.id), where("completed", "==", true), orderBy("startDate")]
68
+ firebaseQuery.collectionSnapshot(setCompletedStudentPlacements, "placements", constraints, dispatch);
69
+ }
70
+
71
+ const fetchContacts = () => {
72
+ const constraints = [where("uid", "==", user.id)]
73
+ firebaseQuery.collectionSnapshot(setContacts, "contacts", constraints, dispatch);
74
+ }
75
+
76
+ const updateUpcomingPlacement = () => {
77
+ if (!upcomingPlacements || !Object.entries(upcomingPlacements).length) {
78
+ dispatch(setUpcoming(undefined));
79
+ return;
80
+ }
81
+ const upcomingPlacement = Object.entries(upcomingPlacements).find(([, v]) => new Date(v.startDate).getTime() > today.getTime())
82
+ upcomingPlacement ? dispatch(setUpcoming(upcomingPlacement[1])) : dispatch(setUpcoming(undefined))
83
+ }
84
+
85
+ const updateActivePlacement = () => {
86
+ const key = Object.keys(upcomingPlacements).find((key) => {
87
+ const placement = upcomingPlacements[key]
88
+ return placement.active
89
+ })
90
+ key ? dispatch(setActivePlacement(upcomingPlacements[key])) : dispatch(setActivePlacement(null))
91
+ }
92
+
93
+ const getItemById = async (path: "contacts"|"placements", id: string) => {
94
+ return await firebaseQuery.getDocData([path, id])
95
+ }
96
+
97
+ const handleDeletePlacement = async (id: string) => {
98
+ if (upcomingPlacements[id]) dispatch(deleteUpcomingStudentPlacement({placementId: id}))
99
+ else dispatch(deleteCompletedStudentPlacement({placementId: id}))
100
+ }
101
+
102
+ const handleUpdatePlacement = async (id: string, attributes: Partial<StudentPlacementData>) => {
103
+ if (upcomingPlacements[id]) dispatch(updateUpcomingStudentPlacement({placementId: id, attributes}))
104
+ else dispatch(updateCompletedStudentPlacement({placementId: id, attributes}))
105
+ }
106
+
107
+ const handleAddPlacement = async (formData: StudentPlacementData) => {
108
+ if (formData.completed) dispatch(addCompletedStudentPlacements({formData}))
109
+ else dispatch(addUpcomingStudentPlacements({formData}))
110
+ }
111
+
112
+ const getUserPlacements = async () => {
113
+ return await getPlacementsWhere({w: where("uid", "==", user?.id)})
114
+ }
115
+
116
+ const getPlacementsStart = async (start: Date, end: Date) => {
117
+ return await firebaseQuery.getDocsWhere("placements", [where("uid", "==", user?.id), where("startDate", ">=", convertDate(start, "dbstring")), where("startDate", "<=", convertDate(end, "dbstring"))]) as {[key:string]: StudentPlacementData};
118
+ }
119
+
120
+ const getPlacementsEnd = async (end: Date) => {
121
+ return await firebaseQuery.getDocsWhere("placements", [where("uid", "==", user?.id), where("endDate", ">=", convertDate(end, "dbstring")), where("endDate", "<=", convertDate(end, "dbstring"))]) as {[key:string]: StudentPlacementData};
122
+ }
123
+
124
+ const dispatchActivePlacement = () => {
125
+ dispatch(fetchActivePlacement({userId: user.id}))
126
+ }
127
+
128
+ return {
129
+ contacts: {
130
+ add: async (contactForm: Contact) => await dispatch(addContact({contactForm: contactForm, userId: user.id})),
131
+ update: async (contactId: string, data: Partial<Contact>) => await dispatch(updateContact({contactId: contactId, attributes: data})),
132
+ delete: async (contactId: string) => await dispatch(deleteContact({contactId: contactId})),
133
+ contacts,
134
+ fetchContacts,
135
+ getById: async (item: string) => await getItemById("contacts", item)
136
+ },
137
+
138
+ placements: {
139
+ add: async (formData: StudentPlacementData) => await handleAddPlacement(formData),
140
+ update: async (placementId: string, attributes: Partial<StudentPlacementData>) => await handleUpdatePlacement(placementId, attributes),
141
+ delete: async (id: string) => await handleDeletePlacement(id),
142
+ getUserPlacements,
143
+ getPlacementsStart,
144
+ getPlacementsEnd,
145
+ activePlacement,
146
+ editActivePlacement: (attributes: Partial<StudentPlacementData>) => dispatch(editActivePlacement(attributes)),
147
+ updateActivePlacement,
148
+ updateUpcomingPlacement,
149
+ fetchUpcomingPlacements,
150
+ fetchCompletedPlacements,
151
+ dispatchActivePlacement,
152
+ upcoming,
153
+ upcomingPlacements: upcomingPlacements || {},
154
+ completedPlacements: completedPlacements || {},
155
+ getById: async (item: string) => await getItemById("placements", item)
156
+ },
157
+ applications: applications,
158
+ } ;
159
+ };
160
+
161
+
162
+ export function useInstituteStaff({user}: {user: UserData}) {
163
+ if (!user || user?.product !== "institutes" || user.userType !== "Staff") return {error: "Unauthorized"};
164
+
165
+ const firebaseQuery = new FirebaseQuery();
166
+ const dispatch = useAppDispatch();
167
+ const {userGroups, forms, institute} = useInstitute({user})
168
+ const [cohorts, setCohorts] = useState<{[key:string]: CohortData}>();
169
+ const [emailTemplates, setEmailTemplates] = useState<{[key:string]: EmailTemplate}>();
170
+
171
+
172
+ useEffect(() => {
173
+ const cohortConstraints = [where("oId", "==", user.oId)];
174
+ if (user.userGroup !== "admin") {
175
+ if (user.viewAddresses !== "all") {
176
+ cohortConstraints.push(where("addressId", "in", user.visibleAddresses));
177
+ }
178
+ if (user.viewCohorts !== "all") {
179
+ cohortConstraints.push(where(documentId(), "in", user.visibleCohorts));
180
+ }
181
+ }
182
+ firebaseQuery.collectionSnapshot(setCohorts, "cohorts", cohortConstraints);
183
+ firebaseQuery.collectionSnapshot(setEmailTemplates, "emailTemplates", [where("product", "==", user.product), where("oId", "==", user.oId)]);
184
+ }, [user.oId, user.userGroup, user.viewAddresses, user.viewCohorts, user.visibleAddresses, user.visibleCohorts, user.product])
185
+
186
+ const getJobById = async (id: string) => {
187
+ try {
188
+ const job = await firebaseQuery.getDocData(["jobs", id])
189
+ return job
190
+
191
+ } catch (error) {
192
+ throw error
193
+ }
194
+ }
195
+
196
+ return {
197
+ jobs: {
198
+ setJobs: async (jobs: {[jobId: string]: Job}) => dispatch(setJobs(jobs)),
199
+ addJob: async ({job, jobId} : {job: Partial<Job>, jobId: string}) => dispatch(addJob({job: job, jobId: jobId})),
200
+ setMarkRead: async (payload) => dispatch(setMarkRead(payload)),
201
+ setJobStatus: async ({jobId, status}: {jobId: string, status: string}) => dispatch(setJobStatus({jobId: jobId, status: status})),
202
+ updateJob: async ({jobId, data}: {jobId: string, data: string}) => dispatch(updateJob({jobId: jobId, data: data})),
203
+ getById: getJobById
204
+ },
205
+ institute,
206
+ userGroups,
207
+ forms,
208
+ cohorts,
209
+ emailTemplates,
210
+ }
211
+ }
212
+
213
+ export function useInstitute({user}: {user: UserData}) {
214
+ if (!user || user?.product !== "institutes") return {error: "Unauthorized"};
215
+
216
+ const [userGroups, setUserGroups] = useState<{[key:string]: UserGroupData}>();
217
+ const [forms, setForms] = useState<{[key:string]: unknown}>();
218
+ const [institute, setInstitute] = useState<InstituteData>();
219
+ const firebaseQuery = new FirebaseQuery();
220
+
221
+
222
+ useEffect(() => {
223
+ getOrganisation(user, (data) => setInstitute(data as InstituteData));
224
+ firebaseQuery.collectionSnapshot(setUserGroups, "userGroups", [where("oId", "==", user.oId), where("product", "==", user.product)]);
225
+ firebaseQuery.collectionSnapshot(setForms, "forms", [where("oId", "==", user.oId), where("product", "==", user.product)]);
226
+ }, [user.product, user.oId])
227
+
228
+ return {
229
+ userGroups,
230
+ forms,
231
+ institute,
232
+ }
233
+
234
+ }
235
+
236
+ export function useInstituteStudent({user}: {user: UserData}) {
237
+ if (!user || user?.product !== "institutes" || user.userType !== "Students") return {error: "Unauthorized"};
238
+
239
+ const {contacts, placements, applications} = useStudent({user});
240
+ const [cohorts, setCohorts] = useState<{[key:string]: CohortData}>();
241
+ const firebaseQuery = new FirebaseQuery();
242
+ const {userGroups, forms, institute} = useInstitute({user})
243
+
244
+ useEffect(() => {
245
+ const isAdmin = user.userGroup === "admin";
246
+ const canViewCohorts = user.viewCohorts !== "none";
247
+ const canViewAddresses = user.viewAddresses !== "none";
248
+
249
+ if (isAdmin || (canViewCohorts && canViewAddresses)) {
250
+ const cohortConstraints = [where("oId", "==", user.oId)];
251
+ firebaseQuery.collectionSnapshot(setCohorts, "cohorts", cohortConstraints);
252
+ } else {
253
+ setCohorts({});
254
+ }
255
+ }, [user.oId, user.id, user.userGroup, user.viewCohorts, user.viewAddresses, user.product]);
256
+
257
+ return {
258
+ contacts,
259
+ placements,
260
+ institute,
261
+ userGroups,
262
+ forms,
263
+ cohorts,
264
+ applications,
265
+ }
266
+
267
+ }
268
+
269
+ export function useProvider({user}: {user: UserData}) {
270
+ if (!user || user?.product !== "providers") return {error: "Unauthorized"};
271
+
272
+ const {jobs} = useInstituteStaff({user});
273
+
274
+ return {
275
+ jobs
276
+ }
277
+
278
+ }
279
+
280
+
281
+
282
+ // function MyContactComponent() {
283
+ // const {contacts} = useStudent({});
284
+
285
+ // contacts.add({data})
286
+
287
+ // return null
288
+ // }
289
+
290
+ // function MyPlacementComponent() {
291
+ // const {placements} = useStudent();
292
+
293
+ // placements.add({data})
294
+
295
+ // return null
353
296
  // }