placementt-core 11.0.533 → 11.0.892

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/lib/constants.d.ts +13 -1
  2. package/lib/constants.js +86 -1
  3. package/lib/constants.js.map +1 -1
  4. package/lib/features/analytics/useAnalytics.d.ts +2 -0
  5. package/lib/features/analytics/useAnalytics.js +22 -19
  6. package/lib/features/analytics/useAnalytics.js.map +1 -1
  7. package/lib/features/global/downtime/useDowntime.d.ts +1 -0
  8. package/lib/features/global/downtime/useDowntime.js +9 -7
  9. package/lib/features/global/downtime/useDowntime.js.map +1 -1
  10. package/lib/features/global/users/useUserFunctions.js +1 -1
  11. package/lib/features/global/users/useUserFunctions.js.map +1 -1
  12. package/lib/features/jobs/jobsSlice.d.ts +10 -2
  13. package/lib/features/jobs/jobsSlice.js +5 -2
  14. package/lib/features/jobs/jobsSlice.js.map +1 -1
  15. package/lib/features/placements/studentPlacements/activePlacement.d.ts +5 -1
  16. package/lib/features/placements/studentPlacements/activePlacement.js +7 -3
  17. package/lib/features/placements/studentPlacements/activePlacement.js.map +1 -1
  18. package/lib/features/placements/studentPlacements/completedStudentPlacementsSlice.d.ts +3 -2
  19. package/lib/features/placements/studentPlacements/completedStudentPlacementsSlice.js +4 -1
  20. package/lib/features/placements/studentPlacements/completedStudentPlacementsSlice.js.map +1 -1
  21. package/lib/features/placements/studentPlacements/upcomingStudentPlacementsSlice.d.ts +2 -2
  22. package/lib/features/placements/studentPlacements/upcomingStudentPlacementsSlice.js +1 -1
  23. package/lib/features/placements/studentPlacements/upcomingStudentPlacementsSlice.js.map +1 -1
  24. package/lib/features/placements/studentPlacements/useStudentPlacements.d.ts +2 -12
  25. package/lib/features/placements/studentPlacements/useStudentPlacements.js +1 -26
  26. package/lib/features/placements/studentPlacements/useStudentPlacements.js.map +1 -1
  27. package/lib/features/updates/useUpdates.d.ts +1 -0
  28. package/lib/features/updates/useUpdates.js +13 -12
  29. package/lib/features/updates/useUpdates.js.map +1 -1
  30. package/lib/firebase/firebase.d.ts +5 -3
  31. package/lib/firebase/firebase.js +23 -12
  32. package/lib/firebase/firebase.js.map +1 -1
  33. package/lib/firebase/firebaseConfig.js.map +1 -1
  34. package/lib/firebase/firebaseQuery.d.ts +6 -2
  35. package/lib/firebase/firebaseQuery.js +11 -3
  36. package/lib/firebase/firebaseQuery.js.map +1 -1
  37. package/lib/firebase/readDatabase.d.ts +2 -4
  38. package/lib/firebase/readDatabase.js +30 -5
  39. package/lib/firebase/readDatabase.js.map +1 -1
  40. package/lib/firebase/writeDatabase.d.ts +6 -2
  41. package/lib/firebase/writeDatabase.js +2 -1
  42. package/lib/firebase/writeDatabase.js.map +1 -1
  43. package/lib/hooks.d.ts +277 -192
  44. package/lib/hooks.js +1437 -704
  45. package/lib/hooks.js.map +1 -1
  46. package/lib/reduxHooks.d.ts +122 -5
  47. package/lib/reduxHooks.js +132 -29
  48. package/lib/reduxHooks.js.map +1 -1
  49. package/lib/tasksAndTips.d.ts +19 -7
  50. package/lib/tasksAndTips.js +637 -164
  51. package/lib/tasksAndTips.js.map +1 -1
  52. package/lib/typeDefinitions.d.ts +321 -110
  53. package/lib/util.d.ts +15 -3
  54. package/lib/util.js +47 -10
  55. package/lib/util.js.map +1 -1
  56. package/package.json +7 -4
  57. package/src/constants.ts +91 -3
  58. package/src/features/analytics/useAnalytics.tsx +25 -17
  59. package/src/features/global/downtime/useDowntime.tsx +11 -7
  60. package/src/features/global/users/useUserFunctions.tsx +1 -1
  61. package/src/features/jobs/jobsSlice.ts +9 -3
  62. package/src/features/placements/studentPlacements/activePlacement.ts +8 -3
  63. package/src/features/placements/studentPlacements/completedStudentPlacementsSlice.ts +5 -2
  64. package/src/features/placements/studentPlacements/upcomingStudentPlacementsSlice.ts +2 -2
  65. package/src/features/placements/studentPlacements/useStudentPlacements.tsx +4 -28
  66. package/src/features/updates/useUpdates.tsx +14 -12
  67. package/src/firebase/firebase.tsx +26 -15
  68. package/src/firebase/firebaseConfig.tsx +1 -1
  69. package/src/firebase/firebaseQuery.tsx +11 -3
  70. package/src/firebase/readDatabase.tsx +34 -6
  71. package/src/firebase/writeDatabase.tsx +3 -1
  72. package/src/hooks.tsx +1804 -935
  73. package/src/reduxHooks.ts +144 -32
  74. package/src/tasksAndTips.ts +689 -166
  75. package/src/typeDefinitions.ts +373 -109
  76. package/src/util.ts +63 -18
package/src/reduxHooks.ts CHANGED
@@ -1,28 +1,30 @@
1
- import { where } from "firebase/firestore"
1
+ import { documentId, orderBy, where } from "firebase/firestore"
2
2
  import { useEffect, useState } from "react"
3
3
  import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux"
4
4
  import { AppDispatch, RootState } from "./config"
5
5
  import { addContact, deleteContact, setContacts, updateContact } from "./features/contacts/contactsSlice"
6
- import { Job, addJob, setJobStatus, setJobs, setMarkRead } from "./features/jobs/jobsSlice"
7
- import { fetchActivePlacement } from "./features/placements/studentPlacements/activePlacement"
6
+ import { Job, addJob, setJobStatus, setJobs, setMarkRead, updateJob } from "./features/jobs/jobsSlice"
7
+ import { editActivePlacement, fetchActivePlacement, setActivePlacement } from "./features/placements/studentPlacements/activePlacement"
8
8
  import { addCompletedStudentPlacements, deleteCompletedStudentPlacement, setCompletedStudentPlacements, updateCompletedStudentPlacement } from "./features/placements/studentPlacements/completedStudentPlacementsSlice"
9
9
  import { addUpcomingStudentPlacements, deleteUpcomingStudentPlacement, setUpcoming, setUpcomingStudentPlacements, updateUpcomingStudentPlacement } from "./features/placements/studentPlacements/upcomingStudentPlacementsSlice"
10
10
  import FirebaseQuery from "./firebase/firebaseQuery"
11
- import { Address, Application, Contact, PlacementListing, ProviderData, StudentPlacementData, UserData } from "./typeDefinitions"
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"
12
14
 
13
15
  export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
14
16
  export const useAppDispatch = () => useDispatch<AppDispatch>();
15
17
 
16
18
 
17
19
  export function useStudent({user} : {user: UserData}) {
18
- if (!user || user.product !== "students") return {};
20
+ if (!user || user.userType !== "Students") return {error: "Unauthorized"};
19
21
 
20
22
  const upcomingPlacements = useAppSelector((state) => state.upcomingStudentPlacements.values)
21
23
  const completedPlacements = useAppSelector((state) => state.completedStudentPlacements.values)
22
24
  const activePlacement = useAppSelector((state) => state.activePlacement.values)
23
25
  const upcoming = useAppSelector((state) => state.upcomingStudentPlacements.upcoming)
24
26
  const contacts = useAppSelector((state) => state.contacts.values)
25
- const [applications, setApplications] = useState<{[key: string]: Application&{listing: PlacementListing, provider: ProviderData, address: Address}}>();
27
+ const [applications, setApplications] = useState<{[key: string]: Application&{listing: PlacementListing|false, provider: ProviderData|false, address: Address}}>();
26
28
  const firebaseQuery = new FirebaseQuery();
27
29
 
28
30
  const dispatch = useAppDispatch();
@@ -41,35 +43,52 @@ export function useStudent({user} : {user: UserData}) {
41
43
  firebaseQuery.collectionSnapshot(async (fApplications: {[key: string]: Application}) => {
42
44
 
43
45
  const applicationsWithProviderAndListing:{[key: string]: Application&{listing: PlacementListing, provider: ProviderData, address: Address}} = Object.fromEntries(await Promise.all(Object.entries(fApplications).map(async ([id, application]) => {
44
- const provider = await firebaseQuery.getDocData(["providers", application.providerId]) as ProviderData;
45
- const listing = await firebaseQuery.getDocData(["placementListings", application.listingId]) as PlacementListing;
46
- const address = listing.addressId && await firebaseQuery.getDocData(["addresses", listing.addressId]) as Address;
47
-
48
- return [id, {...application, listing: listing, provider: provider, address: address}];
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
49
  })));
50
50
 
51
51
  setApplications(applicationsWithProviderAndListing);
52
52
 
53
53
  }, "applications", applicationsConstraints);
54
- }, [dispatch, user.id]);
55
-
54
+ }, [user.id]);
55
+ /*
56
56
  useEffect(() => {
57
57
  if (!user.id) return
58
58
  dispatch(fetchActivePlacement({userId: user.id}))
59
- }, [dispatch, user.id, upcomingPlacements])
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
+ }
60
65
 
61
- useEffect(() => {
62
- console.log("UPDATE UPCOMING");
63
-
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 = () => {
64
77
  if (!upcomingPlacements || !Object.entries(upcomingPlacements).length) {
65
78
  dispatch(setUpcoming(undefined));
66
79
  return;
67
80
  }
68
81
  const upcomingPlacement = Object.entries(upcomingPlacements).find(([, v]) => new Date(v.startDate).getTime() > today.getTime())
69
82
  upcomingPlacement ? dispatch(setUpcoming(upcomingPlacement[1])) : dispatch(setUpcoming(undefined))
83
+ }
70
84
 
71
- }, [dispatch, upcomingPlacements]);
72
-
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
+ }
73
92
 
74
93
  const getItemById = async (path: "contacts"|"placements", id: string) => {
75
94
  return await firebaseQuery.getDocData([path, id])
@@ -80,9 +99,9 @@ export function useStudent({user} : {user: UserData}) {
80
99
  else dispatch(deleteCompletedStudentPlacement({placementId: id}))
81
100
  }
82
101
 
83
- const handleUpdatePlacement = async (id: string, data: StudentPlacementData) => {
84
- if (upcomingPlacements[id]) dispatch(updateUpcomingStudentPlacement({placementId: id, attributes: data}))
85
- else dispatch(updateCompletedStudentPlacement({placementId: id, attributes: data}))
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}))
86
105
  }
87
106
 
88
107
  const handleAddPlacement = async (formData: StudentPlacementData) => {
@@ -90,19 +109,46 @@ export function useStudent({user} : {user: UserData}) {
90
109
  else dispatch(addUpcomingStudentPlacements({formData}))
91
110
  }
92
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
+
93
128
  return {
94
129
  contacts: {
95
- add: async (contactForm: Contact) => dispatch(addContact({contactForm: contactForm, userId: user.id})),
96
- update: async (contactId: string, data: Partial<Contact>) => dispatch(updateContact({contactId: contactId, attributes: data})),
97
- delete: async (contactId: string) => dispatch(deleteContact({contactId: contactId})),
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})),
98
133
  contacts,
134
+ fetchContacts,
99
135
  getById: async (item: string) => await getItemById("contacts", item)
100
136
  },
137
+
101
138
  placements: {
102
139
  add: async (formData: StudentPlacementData) => await handleAddPlacement(formData),
103
- update: async (placementId: string, data: StudentPlacementData) => handleUpdatePlacement(placementId, data),
140
+ update: async (placementId: string, attributes: Partial<StudentPlacementData>) => await handleUpdatePlacement(placementId, attributes),
104
141
  delete: async (id: string) => await handleDeletePlacement(id),
142
+ getUserPlacements,
143
+ getPlacementsStart,
144
+ getPlacementsEnd,
105
145
  activePlacement,
146
+ editActivePlacement: (attributes: Partial<StudentPlacementData>) => dispatch(editActivePlacement(attributes)),
147
+ updateActivePlacement,
148
+ updateUpcomingPlacement,
149
+ fetchUpcomingPlacements,
150
+ fetchCompletedPlacements,
151
+ dispatchActivePlacement,
106
152
  upcoming,
107
153
  upcomingPlacements: upcomingPlacements || {},
108
154
  completedPlacements: completedPlacements || {},
@@ -114,10 +160,28 @@ export function useStudent({user} : {user: UserData}) {
114
160
 
115
161
 
116
162
  export function useInstituteStaff({user}: {user: UserData}) {
163
+ if (!user || user?.product !== "institutes" || user.userType !== "Staff") return {error: "Unauthorized"};
164
+
117
165
  const firebaseQuery = new FirebaseQuery();
118
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
+
119
171
 
120
- if (!user || user?.product !== "institutes" || user.userType !== "Staff") return {};
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])
121
185
 
122
186
  const getJobById = async (id: string) => {
123
187
  try {
@@ -135,27 +199,75 @@ export function useInstituteStaff({user}: {user: UserData}) {
135
199
  addJob: async ({job, jobId} : {job: Partial<Job>, jobId: string}) => dispatch(addJob({job: job, jobId: jobId})),
136
200
  setMarkRead: async (payload) => dispatch(setMarkRead(payload)),
137
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})),
138
203
  getById: getJobById
139
- }
204
+ },
205
+ institute,
206
+ userGroups,
207
+ forms,
208
+ cohorts,
209
+ emailTemplates,
140
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();
141
220
 
142
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
+
143
234
  }
144
235
 
145
236
  export function useInstituteStudent({user}: {user: UserData}) {
146
- const {contacts, placements} = useStudent({user});
237
+ if (!user || user?.product !== "institutes" || user.userType !== "Students") return {error: "Unauthorized"};
147
238
 
148
- if (!user || user?.product !== "institutes" || user.userType !== "Students") return {};
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]);
149
256
 
150
257
  return {
151
258
  contacts,
152
- placements
259
+ placements,
260
+ institute,
261
+ userGroups,
262
+ forms,
263
+ cohorts,
264
+ applications,
153
265
  }
154
266
 
155
267
  }
156
268
 
157
269
  export function useProvider({user}: {user: UserData}) {
158
- if (!user || user?.product !== "providers") return {};
270
+ if (!user || user?.product !== "providers") return {error: "Unauthorized"};
159
271
 
160
272
  const {jobs} = useInstituteStaff({user});
161
273