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/src/firebase/util.tsx
CHANGED
|
@@ -1,308 +1,352 @@
|
|
|
1
|
-
import {Timestamp} from "firebase/firestore";
|
|
2
|
-
import {Address, UserData} from "../typeDefinitions";
|
|
3
|
-
import * as geoHash from "ngeohash";
|
|
4
|
-
|
|
5
|
-
export const getProviderId = async () => {/*
|
|
6
|
-
let user = await getDoc(doc(db, 'users', auth.currentUser.uid))
|
|
7
|
-
return user.data().bi*/
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export const getRandomNumber = (min = 0, max:number) => {
|
|
11
|
-
return Math.random() * (max - min) + min;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export const getUniqueId = (object:object): number => {
|
|
15
|
-
const id = Math.round(getRandomNumber(0, 1000000));
|
|
16
|
-
|
|
17
|
-
if (!object) {
|
|
18
|
-
return id;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (Array.isArray(object)) {
|
|
22
|
-
return object.some((el) => el.id === id) ? getUniqueId(object) : id;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return (Object.keys(object) as any[]).some((el) => el === id) ? getUniqueId(object) : id;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export const capitalise = (s="") => {
|
|
29
|
-
const nS = s.toString().replace("_", " ");
|
|
30
|
-
return nS.charAt(0).toUpperCase() + nS.slice(1);
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export const capitaliseWords = (s="") => {
|
|
34
|
-
return s.replace(/(^|\s)\S/g, (l) => l.toUpperCase());
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export const snakeCase = (s="") => {
|
|
38
|
-
const nS = s.toString().replace(" ", "_");
|
|
39
|
-
return nS.toLowerCase();
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export const validateEmail = (email: string) => {
|
|
43
|
-
console.log(email);
|
|
44
|
-
return email.match(
|
|
45
|
-
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
|
46
|
-
);
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
export const getAccess = (user:UserData, ...perms:
|
|
50
|
-
// If the user has the permission given, grant access
|
|
51
|
-
const finalPerms: {[key: string]: any} = {};
|
|
52
|
-
perms.forEach((perm) => {
|
|
53
|
-
finalPerms[perm] = (user.userGroup === "admin" || (user.groupData as object)[perm] || false);
|
|
54
|
-
});
|
|
55
|
-
// Otherwise, deny access
|
|
56
|
-
return Object.keys(finalPerms).length > 1 ? finalPerms : Object.values(finalPerms)[0];
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
export const dateToString = (date:Date) => {
|
|
60
|
-
const y = date.getFullYear();
|
|
61
|
-
const m = ("0"+(date.getMonth() + 1)).slice(-2);
|
|
62
|
-
const d = ("0"+(date.getDate())).slice(-2);
|
|
63
|
-
return [y, m, d].join("-");
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
export const getPlacementDateArray = (start:string, end:string) => {
|
|
67
|
-
const dates = [start];
|
|
68
|
-
let currentDate = start;
|
|
69
|
-
|
|
70
|
-
while (currentDate !== end) {
|
|
71
|
-
const dateObj = new Date(currentDate);
|
|
72
|
-
dateObj.setDate(dateObj.getDate()+1);
|
|
73
|
-
const dateObjString = dateToString(dateObj);
|
|
74
|
-
dates.push(dateObjString);
|
|
75
|
-
currentDate = dateObjString;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return dates;
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
export const reformatDate = (date: Date|string) => {
|
|
82
|
-
if (!date) {
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
return date.toString().split("-").reverse().join(".");
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
export const convertDate = (date?: string|Date, output: "dbstring"|"date"|"visual" = "date") => {
|
|
89
|
-
// dbstring = yyyy-MM-dd
|
|
90
|
-
// visual = dd MMM yyyy
|
|
91
|
-
// date = Date
|
|
92
|
-
if (!date) return;
|
|
93
|
-
|
|
94
|
-
let year:number;
|
|
95
|
-
let month:number;
|
|
96
|
-
let day:number;
|
|
97
|
-
|
|
98
|
-
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
99
|
-
|
|
100
|
-
if (typeof date === "string") {
|
|
101
|
-
const dateType = date.includes(" ") ? "visual" : "dbstring";
|
|
102
|
-
const dateArray = date.split(dateType === "visual" ? " " : "-");
|
|
103
|
-
|
|
104
|
-
year = parseInt(dateArray[dateType === "visual" ? 2 : 0]);
|
|
105
|
-
month = dateType === "visual" ? months.indexOf(dateArray[1]) : parseInt(dateArray[1]) - 1;
|
|
106
|
-
day = parseInt(dateArray[dateType === "visual" ? 0 : 2]);
|
|
107
|
-
} else {
|
|
108
|
-
year = date.getFullYear();
|
|
109
|
-
month = date.getMonth();
|
|
110
|
-
day = date.getDate();
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
switch (output) {
|
|
114
|
-
case "date":
|
|
115
|
-
return new Date(year, month, day);
|
|
116
|
-
case "dbstring":
|
|
117
|
-
return [year, month+1 < 10 ? `0${month+1}` : month+1, day < 10 ? `0${day}` : day].join("-");
|
|
118
|
-
case "visual":
|
|
119
|
-
return [day, months[month], year].join(" ");
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
export const getDateDiff = (start: Date, end:Date): number => {
|
|
124
|
-
return (Math.round((new Date(dateToString(end)).getTime() - new Date(dateToString(start)).getTime()) / (1000 * 60 * 60 * 24)));
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
export const reformatDateTime = (timestamp: string|Timestamp) => {
|
|
128
|
-
if (typeof timestamp === "string") {
|
|
129
|
-
return `${timestamp.split("T")[1].substring(0, 8)} ${(timestamp.split("T")[0]).split("-").reverse().join(".")}`;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
const created = new Date(timestamp.seconds * 1000).toISOString();
|
|
134
|
-
return `${created.split("T")[1].substring(0, 8)} ${(created.split("T")[0]).split("-").reverse().join(".")}`;
|
|
135
|
-
} catch (e) {
|
|
136
|
-
return null;
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
export function stringToDate(date: string) {
|
|
141
|
-
const formatItems= date.split("/").map((i) => parseInt(i));
|
|
142
|
-
console.log("date array", formatItems);
|
|
143
|
-
return new Date(formatItems[2], formatItems[1]-1, formatItems[0]);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export const editNestedObject = (loc:(string|number)[], data:any[]|{[key: string|number]: unknown}, value:any, objectId=false) => {
|
|
147
|
-
if (!data || !(Array.isArray(data) || typeof data === "object")) {
|
|
148
|
-
console.error("Error editing nested JSON. Invalid type");
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
type IndexType = typeof data extends any[] ? number : number|string
|
|
153
|
-
|
|
154
|
-
const prevData: typeof data = Array.isArray(data) ? [...data] : {...data};
|
|
155
|
-
const locationIndex:IndexType = objectId && Array.isArray(data) ? (prevData as any[]).findIndex((x) => x.id === loc[0]) : loc[0];
|
|
156
|
-
|
|
157
|
-
if (loc.length > 1) {
|
|
158
|
-
prevData[locationIndex as any] = editNestedObject(loc.slice(1), data[locationIndex as any], value, objectId);
|
|
159
|
-
} else {
|
|
160
|
-
if (value === undefined) {
|
|
161
|
-
Array.isArray(prevData) ? prevData.splice(locationIndex as number, 1) : delete prevData[locationIndex];
|
|
162
|
-
} else {
|
|
163
|
-
prevData[locationIndex as any] = value;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return prevData;
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
export const getItemInNestedObject = (path:string[], object) => {
|
|
171
|
-
if (path.length === 0) return;
|
|
172
|
-
|
|
173
|
-
const item = object[path.shift() as string];
|
|
174
|
-
if (path.length > 0) {
|
|
175
|
-
return getItemInNestedObject(path, item);
|
|
176
|
-
}
|
|
177
|
-
return item;
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
export const camelCaseToNormal = (string="") => {
|
|
181
|
-
return string.replace(/([A-Z])/g, " $1").toLowerCase().trim().replace(/^./, function(str) {
|
|
182
|
-
return str.toUpperCase();
|
|
183
|
-
});
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
export const camelCase = (string="") => {
|
|
187
|
-
return string.toLowerCase().replace(/[^a-zA-Z0-9]+(.)/g, (m, chr) => chr.toUpperCase());
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
export const isJson = (item:any) => {
|
|
191
|
-
item = typeof item !== "string" ?
|
|
192
|
-
JSON.stringify(item) :
|
|
193
|
-
item;
|
|
194
|
-
|
|
195
|
-
try {
|
|
196
|
-
item = JSON.parse(item);
|
|
197
|
-
} catch (e) {
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
return (typeof item === "object" && item !== null);
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
export const sortByReverseStringLength = (array: string[]) => {
|
|
205
|
-
return array.sort(function(a, b) {
|
|
206
|
-
return b.length - a.length;
|
|
207
|
-
});
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
export const pathToArr = (path: any[]|any) => Array.isArray(path) ? path : [path];
|
|
211
|
-
|
|
212
|
-
export const arraysEqual = (a:any[], b:any[]) => {
|
|
213
|
-
if (a === b) return true;
|
|
214
|
-
if (a == null || b == null) return false;
|
|
215
|
-
if (a.length !== b.length) return false;
|
|
216
|
-
|
|
217
|
-
return a.every((val, idx) => val === b[idx]);
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
export const objectsEqual = (x:object, y:object):boolean => {
|
|
222
|
-
const ok = Object.keys; const tx = typeof x; const ty = typeof y;
|
|
223
|
-
return x && y && tx === "object" && tx === ty ? (
|
|
224
|
-
ok(x).length === ok(y).length &&
|
|
225
|
-
ok(x).every((key) => objectsEqual(x[key as keyof typeof x], y[key as keyof typeof x]))
|
|
226
|
-
) : (x === y);
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
export const arrayUniqueValues = (array:unknown[]) => {
|
|
230
|
-
return array.filter((value, index, self) => self.indexOf(value) === index);
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
export const flattenObject = (obj) => {
|
|
235
|
-
const flattened = {};
|
|
236
|
-
|
|
237
|
-
Object.keys(obj).forEach((key) => {
|
|
238
|
-
const value = obj[key];
|
|
239
|
-
|
|
240
|
-
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
241
|
-
Object.assign(flattened, flattenObject(value));
|
|
242
|
-
} else {
|
|
243
|
-
flattened[key] = value;
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
return flattened;
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
export const getGeoHash = async (data:Address) => {
|
|
252
|
-
const address = data["address-line1"] + " " + data["address-line2"] +
|
|
253
|
-
" " + data.locality + " " + data.postal_code + " " + data.country;
|
|
254
|
-
address.replace(" ", "+");
|
|
255
|
-
const apiQuery = "https://maps.googleapis.com/maps/api/geocode/json?address=" +
|
|
256
|
-
address + "&key=AIzaSyBOSSi4iHxOoAS9tLAJUAC_46HlZ6-D5Ss";
|
|
257
|
-
|
|
258
|
-
const location = await fetch(apiQuery)
|
|
259
|
-
.then(async (res) =>
|
|
260
|
-
await res.json() as {results: {geometry: {location: unknown}}[]})
|
|
261
|
-
.then((res: {results: {geometry: {location: unknown}}[]}) => {
|
|
262
|
-
return res;
|
|
263
|
-
}, (error: Error) => {
|
|
264
|
-
return error;
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
if (location instanceof Error || !location.results.length) {
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
const result = location.results[0].geometry.location as {lat:number, lng:number};
|
|
272
|
-
|
|
273
|
-
return geoHash.encode(result.lat, result.lng, 12);
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
export const decodeGeoHash = (g: string) => {
|
|
277
|
-
console.log("g", g);
|
|
278
|
-
if (!g) return;
|
|
279
|
-
return geoHash.decode(g);
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
export const randomPassword = () => {
|
|
283
|
-
let text = "";
|
|
284
|
-
const c = "ABCDEFGHIJKLMNNOPQRSTUVWXYZ" +
|
|
285
|
-
"abcdefghijklmnopqrstuvwxyz0123456789";
|
|
286
|
-
|
|
287
|
-
for (let i = 0; i < 12; i++) {
|
|
288
|
-
text += c.charAt(Math.floor(Math.random() * c.length));
|
|
289
|
-
}
|
|
290
|
-
return text;
|
|
291
|
-
};
|
|
292
|
-
|
|
293
|
-
export const arrayEquals = (a:unknown, b:unknown) => {
|
|
294
|
-
return Array.isArray(a) &&
|
|
295
|
-
Array.isArray(b) &&
|
|
296
|
-
a.length === b.length &&
|
|
297
|
-
a.every((val, index) => val === b[index]);
|
|
298
|
-
};
|
|
299
|
-
|
|
300
|
-
export const average = (arr: number[]) => arr.reduce( ( p, c ) => p + c, 0 ) / arr.length;
|
|
301
|
-
|
|
302
|
-
export const readingTime = (text: string) => {
|
|
303
|
-
if (!text) return;
|
|
304
|
-
const wpm = 225;
|
|
305
|
-
const words = text.trim().split(/\s+/).length;
|
|
306
|
-
const time = Math.ceil(words / wpm);
|
|
307
|
-
return `${time} minute${(time > 1) ? "s" : ""}`;
|
|
308
|
-
};
|
|
1
|
+
import {Timestamp} from "firebase/firestore";
|
|
2
|
+
import {Address, ProviderUserPermissions, StaffUserPermissions, UserData} from "../typeDefinitions";
|
|
3
|
+
import * as geoHash from "ngeohash";
|
|
4
|
+
|
|
5
|
+
export const getProviderId = async () => {/*
|
|
6
|
+
let user = await getDoc(doc(db, 'users', auth.currentUser.uid))
|
|
7
|
+
return user.data().bi*/
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const getRandomNumber = (min = 0, max:number) => {
|
|
11
|
+
return Math.random() * (max - min) + min;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const getUniqueId = (object:object): number => {
|
|
15
|
+
const id = Math.round(getRandomNumber(0, 1000000));
|
|
16
|
+
|
|
17
|
+
if (!object) {
|
|
18
|
+
return id;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (Array.isArray(object)) {
|
|
22
|
+
return object.some((el) => el.id === id) ? getUniqueId(object) : id;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return (Object.keys(object) as any[]).some((el) => el === id) ? getUniqueId(object) : id;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const capitalise = (s="") => {
|
|
29
|
+
const nS = s.toString().replace("_", " ");
|
|
30
|
+
return nS.charAt(0).toUpperCase() + nS.slice(1);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const capitaliseWords = (s="") => {
|
|
34
|
+
return s.replace(/(^|\s)\S/g, (l) => l.toUpperCase());
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const snakeCase = (s="") => {
|
|
38
|
+
const nS = s.toString().replace(" ", "_");
|
|
39
|
+
return nS.toLowerCase();
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const validateEmail = (email: string) => {
|
|
43
|
+
console.log(email);
|
|
44
|
+
return email.match(
|
|
45
|
+
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const getAccess = (user:UserData, ...perms: (keyof StaffUserPermissions | keyof ProviderUserPermissions)[]) => {
|
|
50
|
+
// If the user has the permission given, grant access
|
|
51
|
+
const finalPerms: {[key: string]: any} = {};
|
|
52
|
+
perms.forEach((perm) => {
|
|
53
|
+
finalPerms[perm] = (user.userGroup === "admin" || (user.groupData as object)?.[perm] || false);
|
|
54
|
+
});
|
|
55
|
+
// Otherwise, deny access
|
|
56
|
+
return Object.keys(finalPerms).length > 1 ? finalPerms : Object.values(finalPerms)[0];
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const dateToString = (date:Date) => {
|
|
60
|
+
const y = date.getFullYear();
|
|
61
|
+
const m = ("0"+(date.getMonth() + 1)).slice(-2);
|
|
62
|
+
const d = ("0"+(date.getDate())).slice(-2);
|
|
63
|
+
return [y, m, d].join("-");
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const getPlacementDateArray = (start:string, end:string) => {
|
|
67
|
+
const dates = [start];
|
|
68
|
+
let currentDate = start;
|
|
69
|
+
|
|
70
|
+
while (currentDate !== end) {
|
|
71
|
+
const dateObj = new Date(currentDate);
|
|
72
|
+
dateObj.setDate(dateObj.getDate()+1);
|
|
73
|
+
const dateObjString = dateToString(dateObj);
|
|
74
|
+
dates.push(dateObjString);
|
|
75
|
+
currentDate = dateObjString;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return dates;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const reformatDate = (date: Date|string) => {
|
|
82
|
+
if (!date) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
return date.toString().split("-").reverse().join(".");
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const convertDate = (date?: string|Date, output: "dbstring"|"date"|"visual" = "date") => {
|
|
89
|
+
// dbstring = yyyy-MM-dd
|
|
90
|
+
// visual = dd MMM yyyy
|
|
91
|
+
// date = Date
|
|
92
|
+
if (!date) return;
|
|
93
|
+
|
|
94
|
+
let year:number;
|
|
95
|
+
let month:number;
|
|
96
|
+
let day:number;
|
|
97
|
+
|
|
98
|
+
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
99
|
+
|
|
100
|
+
if (typeof date === "string") {
|
|
101
|
+
const dateType = date.includes(" ") ? "visual" : "dbstring";
|
|
102
|
+
const dateArray = date.split(dateType === "visual" ? " " : "-");
|
|
103
|
+
|
|
104
|
+
year = parseInt(dateArray[dateType === "visual" ? 2 : 0]);
|
|
105
|
+
month = dateType === "visual" ? months.indexOf(dateArray[1]) : parseInt(dateArray[1]) - 1;
|
|
106
|
+
day = parseInt(dateArray[dateType === "visual" ? 0 : 2]);
|
|
107
|
+
} else {
|
|
108
|
+
year = date.getFullYear();
|
|
109
|
+
month = date.getMonth();
|
|
110
|
+
day = date.getDate();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
switch (output) {
|
|
114
|
+
case "date":
|
|
115
|
+
return new Date(year, month, day);
|
|
116
|
+
case "dbstring":
|
|
117
|
+
return [year, month+1 < 10 ? `0${month+1}` : month+1, day < 10 ? `0${day}` : day].join("-");
|
|
118
|
+
case "visual":
|
|
119
|
+
return [day, months[month], year].join(" ");
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export const getDateDiff = (start: Date, end:Date): number => {
|
|
124
|
+
return (Math.round((new Date(dateToString(end)).getTime() - new Date(dateToString(start)).getTime()) / (1000 * 60 * 60 * 24)));
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export const reformatDateTime = (timestamp: string|Timestamp) => {
|
|
128
|
+
if (typeof timestamp === "string") {
|
|
129
|
+
return `${timestamp.split("T")[1].substring(0, 8)} ${(timestamp.split("T")[0]).split("-").reverse().join(".")}`;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
const created = new Date(timestamp.seconds * 1000).toISOString();
|
|
134
|
+
return `${created.split("T")[1].substring(0, 8)} ${(created.split("T")[0]).split("-").reverse().join(".")}`;
|
|
135
|
+
} catch (e) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
export function stringToDate(date: string) {
|
|
141
|
+
const formatItems= date.split("/").map((i) => parseInt(i));
|
|
142
|
+
console.log("date array", formatItems);
|
|
143
|
+
return new Date(formatItems[2], formatItems[1]-1, formatItems[0]);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export const editNestedObject = (loc:(string|number)[], data:any[]|{[key: string|number]: unknown}, value:any, objectId=false) => {
|
|
147
|
+
if (!data || !(Array.isArray(data) || typeof data === "object")) {
|
|
148
|
+
console.error("Error editing nested JSON. Invalid type");
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
type IndexType = typeof data extends any[] ? number : number|string
|
|
153
|
+
|
|
154
|
+
const prevData: typeof data = Array.isArray(data) ? [...data] : {...data};
|
|
155
|
+
const locationIndex:IndexType = objectId && Array.isArray(data) ? (prevData as any[]).findIndex((x) => x.id === loc[0]) : loc[0];
|
|
156
|
+
|
|
157
|
+
if (loc.length > 1) {
|
|
158
|
+
prevData[locationIndex as any] = editNestedObject(loc.slice(1), data[locationIndex as any] || {}, value, objectId);
|
|
159
|
+
} else {
|
|
160
|
+
if (value === undefined) {
|
|
161
|
+
Array.isArray(prevData) ? prevData.splice(locationIndex as number, 1) : delete prevData[locationIndex];
|
|
162
|
+
} else {
|
|
163
|
+
prevData[locationIndex as any] = value;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return prevData;
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
export const getItemInNestedObject = (path:string[], object) => {
|
|
171
|
+
if (path.length === 0) return;
|
|
172
|
+
|
|
173
|
+
const item = object[path.shift() as string];
|
|
174
|
+
if (path.length > 0) {
|
|
175
|
+
return getItemInNestedObject(path, item);
|
|
176
|
+
}
|
|
177
|
+
return item;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
export const camelCaseToNormal = (string="") => {
|
|
181
|
+
return string.replace(/([A-Z])/g, " $1").toLowerCase().trim().replace(/^./, function(str) {
|
|
182
|
+
return str.toUpperCase();
|
|
183
|
+
});
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export const camelCase = (string="") => {
|
|
187
|
+
return string.toLowerCase().replace(/[^a-zA-Z0-9]+(.)/g, (m, chr) => chr.toUpperCase());
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
export const isJson = (item:any) => {
|
|
191
|
+
item = typeof item !== "string" ?
|
|
192
|
+
JSON.stringify(item) :
|
|
193
|
+
item;
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
item = JSON.parse(item);
|
|
197
|
+
} catch (e) {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return (typeof item === "object" && item !== null);
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
export const sortByReverseStringLength = (array: string[]) => {
|
|
205
|
+
return array.sort(function(a, b) {
|
|
206
|
+
return b.length - a.length;
|
|
207
|
+
});
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
export const pathToArr = (path: any[]|any) => Array.isArray(path) ? path : [path];
|
|
211
|
+
|
|
212
|
+
export const arraysEqual = (a:any[], b:any[]) => {
|
|
213
|
+
if (a === b) return true;
|
|
214
|
+
if (a == null || b == null) return false;
|
|
215
|
+
if (a.length !== b.length) return false;
|
|
216
|
+
|
|
217
|
+
return a.every((val, idx) => val === b[idx]);
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
export const objectsEqual = (x:object, y:object):boolean => {
|
|
222
|
+
const ok = Object.keys; const tx = typeof x; const ty = typeof y;
|
|
223
|
+
return x && y && tx === "object" && tx === ty ? (
|
|
224
|
+
ok(x).length === ok(y).length &&
|
|
225
|
+
ok(x).every((key) => objectsEqual(x[key as keyof typeof x], y[key as keyof typeof x]))
|
|
226
|
+
) : (x === y);
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
export const arrayUniqueValues = (array:unknown[]) => {
|
|
230
|
+
return array.filter((value, index, self) => self.indexOf(value) === index);
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
export const flattenObject = (obj) => {
|
|
235
|
+
const flattened = {};
|
|
236
|
+
|
|
237
|
+
Object.keys(obj).forEach((key) => {
|
|
238
|
+
const value = obj[key];
|
|
239
|
+
|
|
240
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
241
|
+
Object.assign(flattened, flattenObject(value));
|
|
242
|
+
} else {
|
|
243
|
+
flattened[key] = value;
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
return flattened;
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
export const getGeoHash = async (data:Address) => {
|
|
252
|
+
const address = data["address-line1"] + " " + data["address-line2"] +
|
|
253
|
+
" " + data.locality + " " + data.postal_code + " " + data.country;
|
|
254
|
+
address.replace(" ", "+");
|
|
255
|
+
const apiQuery = "https://maps.googleapis.com/maps/api/geocode/json?address=" +
|
|
256
|
+
address + "&key=AIzaSyBOSSi4iHxOoAS9tLAJUAC_46HlZ6-D5Ss";
|
|
257
|
+
|
|
258
|
+
const location = await fetch(apiQuery)
|
|
259
|
+
.then(async (res) =>
|
|
260
|
+
await res.json() as {results: {geometry: {location: unknown}}[]})
|
|
261
|
+
.then((res: {results: {geometry: {location: unknown}}[]}) => {
|
|
262
|
+
return res;
|
|
263
|
+
}, (error: Error) => {
|
|
264
|
+
return error;
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
if (location instanceof Error || !location.results.length) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const result = location.results[0].geometry.location as {lat:number, lng:number};
|
|
272
|
+
|
|
273
|
+
return geoHash.encode(result.lat, result.lng, 12);
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
export const decodeGeoHash = (g: string) => {
|
|
277
|
+
console.log("g", g);
|
|
278
|
+
if (!g) return;
|
|
279
|
+
return geoHash.decode(g);
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
export const randomPassword = () => {
|
|
283
|
+
let text = "";
|
|
284
|
+
const c = "ABCDEFGHIJKLMNNOPQRSTUVWXYZ" +
|
|
285
|
+
"abcdefghijklmnopqrstuvwxyz0123456789";
|
|
286
|
+
|
|
287
|
+
for (let i = 0; i < 12; i++) {
|
|
288
|
+
text += c.charAt(Math.floor(Math.random() * c.length));
|
|
289
|
+
}
|
|
290
|
+
return text;
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
export const arrayEquals = (a:unknown, b:unknown) => {
|
|
294
|
+
return Array.isArray(a) &&
|
|
295
|
+
Array.isArray(b) &&
|
|
296
|
+
a.length === b.length &&
|
|
297
|
+
a.every((val, index) => val === b[index]);
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
export const average = (arr: number[]) => arr.reduce( ( p, c ) => p + c, 0 ) / arr.length;
|
|
301
|
+
|
|
302
|
+
export const readingTime = (text: string) => {
|
|
303
|
+
if (!text) return;
|
|
304
|
+
const wpm = 225;
|
|
305
|
+
const words = text.trim().split(/\s+/).length;
|
|
306
|
+
const time = Math.ceil(words / wpm);
|
|
307
|
+
return `${time} minute${(time > 1) ? "s" : ""}`;
|
|
308
|
+
};
|
|
309
|
+
/*
|
|
310
|
+
export const imageToPdf = async (image: File):Promise<string> => {
|
|
311
|
+
const doc = PDFDocument;
|
|
312
|
+
|
|
313
|
+
const imgStream = await image.arrayBuffer();
|
|
314
|
+
|
|
315
|
+
doc.image(imgStream, {
|
|
316
|
+
fit: [500, 400],
|
|
317
|
+
align: 'center',
|
|
318
|
+
valign: 'center'
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
doc.end(); // will trigger the stream to end
|
|
322
|
+
|
|
323
|
+
return await pdfToBase64(doc);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function pdfToBase64(doc): Promise<string> {
|
|
327
|
+
return new Promise<string>((resolve, reject) => {
|
|
328
|
+
// Create a buffer
|
|
329
|
+
const buffers: Buffer[] = [];
|
|
330
|
+
doc.on('data', (chunk: Buffer) => {
|
|
331
|
+
buffers.push(chunk);
|
|
332
|
+
});
|
|
333
|
+
doc.on('end', () => {
|
|
334
|
+
// Concatenate all the buffers to form a single buffer
|
|
335
|
+
const pdfBuffer = Buffer.concat(buffers);
|
|
336
|
+
|
|
337
|
+
// Convert the buffer to a base64 string
|
|
338
|
+
const base64String = pdfBuffer.toString('base64');
|
|
339
|
+
|
|
340
|
+
resolve(base64String);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
// Handle errors
|
|
344
|
+
doc.on('error', (error: Error) => {
|
|
345
|
+
reject(error);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// End the document
|
|
349
|
+
doc.end();
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
*/
|