@thejob/util 1.0.0
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/dist/cjs/common/constants.d.ts +2 -0
- package/dist/cjs/common/constants.d.ts.map +1 -0
- package/dist/cjs/common/constants.js +2 -0
- package/dist/cjs/common/index.d.ts +4 -0
- package/dist/cjs/common/index.d.ts.map +1 -0
- package/dist/cjs/common/index.js +19 -0
- package/dist/cjs/common/types.d.ts +2 -0
- package/dist/cjs/common/types.d.ts.map +1 -0
- package/dist/cjs/common/types.js +17 -0
- package/dist/cjs/common/utils.d.ts +95 -0
- package/dist/cjs/common/utils.d.ts.map +1 -0
- package/dist/cjs/common/utils.js +402 -0
- package/dist/cjs/completeness/completeness.d.ts +2 -0
- package/dist/cjs/completeness/completeness.d.ts.map +1 -0
- package/dist/cjs/completeness/completeness.js +119 -0
- package/dist/cjs/completeness/index.d.ts +2 -0
- package/dist/cjs/completeness/index.d.ts.map +1 -0
- package/dist/cjs/completeness/index.js +17 -0
- package/dist/cjs/date/index.d.ts +2 -0
- package/dist/cjs/date/index.d.ts.map +1 -0
- package/dist/cjs/date/index.js +17 -0
- package/dist/cjs/date/utils.d.ts +14 -0
- package/dist/cjs/date/utils.d.ts.map +1 -0
- package/dist/cjs/date/utils.js +70 -0
- package/dist/cjs/index.d.ts +7 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +22 -0
- package/dist/cjs/job/index.d.ts +2 -0
- package/dist/cjs/job/index.d.ts.map +1 -0
- package/dist/cjs/job/index.js +17 -0
- package/dist/cjs/job/utils.d.ts +2 -0
- package/dist/cjs/job/utils.d.ts.map +1 -0
- package/dist/cjs/job/utils.js +2 -0
- package/dist/cjs/job-application/index.d.ts +2 -0
- package/dist/cjs/job-application/index.d.ts.map +1 -0
- package/dist/cjs/job-application/index.js +17 -0
- package/dist/cjs/job-application/utils.d.ts +3 -0
- package/dist/cjs/job-application/utils.d.ts.map +1 -0
- package/dist/cjs/job-application/utils.js +19 -0
- package/dist/cjs/user/index.d.ts +2 -0
- package/dist/cjs/user/index.d.ts.map +1 -0
- package/dist/cjs/user/index.js +17 -0
- package/dist/cjs/user/utils.d.ts +8 -0
- package/dist/cjs/user/utils.d.ts.map +1 -0
- package/dist/cjs/user/utils.js +18 -0
- package/dist/esm/common/constants.d.ts +2 -0
- package/dist/esm/common/constants.d.ts.map +1 -0
- package/dist/esm/common/constants.js +1 -0
- package/dist/esm/common/index.d.ts +4 -0
- package/dist/esm/common/index.d.ts.map +1 -0
- package/dist/esm/common/index.js +3 -0
- package/dist/esm/common/types.d.ts +2 -0
- package/dist/esm/common/types.d.ts.map +1 -0
- package/dist/esm/common/types.js +16 -0
- package/dist/esm/common/utils.d.ts +95 -0
- package/dist/esm/common/utils.d.ts.map +1 -0
- package/dist/esm/common/utils.js +372 -0
- package/dist/esm/completeness/completeness.d.ts +2 -0
- package/dist/esm/completeness/completeness.d.ts.map +1 -0
- package/dist/esm/completeness/completeness.js +118 -0
- package/dist/esm/completeness/index.d.ts +2 -0
- package/dist/esm/completeness/index.d.ts.map +1 -0
- package/dist/esm/completeness/index.js +1 -0
- package/dist/esm/date/index.d.ts +2 -0
- package/dist/esm/date/index.d.ts.map +1 -0
- package/dist/esm/date/index.js +1 -0
- package/dist/esm/date/utils.d.ts +14 -0
- package/dist/esm/date/utils.d.ts.map +1 -0
- package/dist/esm/date/utils.js +61 -0
- package/dist/esm/index.d.ts +7 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +6 -0
- package/dist/esm/job/index.d.ts +2 -0
- package/dist/esm/job/index.d.ts.map +1 -0
- package/dist/esm/job/index.js +1 -0
- package/dist/esm/job/utils.d.ts +2 -0
- package/dist/esm/job/utils.d.ts.map +1 -0
- package/dist/esm/job/utils.js +1 -0
- package/dist/esm/job-application/index.d.ts +2 -0
- package/dist/esm/job-application/index.d.ts.map +1 -0
- package/dist/esm/job-application/index.js +1 -0
- package/dist/esm/job-application/utils.d.ts +3 -0
- package/dist/esm/job-application/utils.d.ts.map +1 -0
- package/dist/esm/job-application/utils.js +15 -0
- package/dist/esm/user/index.d.ts +2 -0
- package/dist/esm/user/index.d.ts.map +1 -0
- package/dist/esm/user/index.js +1 -0
- package/dist/esm/user/utils.d.ts +8 -0
- package/dist/esm/user/utils.d.ts.map +1 -0
- package/dist/esm/user/utils.js +14 -0
- package/package.json +52 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { ExperienceLevel, ProficiencyLevel, UserCompletenessSchema, } from "@thejob/schema";
|
|
3
|
+
import { customAlphabet } from "nanoid";
|
|
4
|
+
export const removeEmpty = (obj) => {
|
|
5
|
+
// Check if the value is an object and not null
|
|
6
|
+
if (obj !== null && typeof obj === "object") {
|
|
7
|
+
// Iterate over each key in the object
|
|
8
|
+
for (const key in obj) {
|
|
9
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
10
|
+
const value = obj[key];
|
|
11
|
+
// Recursively remove empty properties from nested objects
|
|
12
|
+
if (typeof value === "object" && value !== null) {
|
|
13
|
+
obj[key] = removeEmpty(value);
|
|
14
|
+
}
|
|
15
|
+
// Remove the property if it's null, undefined, or an empty string, array, or object
|
|
16
|
+
if (value === null ||
|
|
17
|
+
value === undefined ||
|
|
18
|
+
value === "" ||
|
|
19
|
+
(typeof value === "object" && Object.keys(value).length === 0)) {
|
|
20
|
+
delete obj[key];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return obj;
|
|
26
|
+
};
|
|
27
|
+
export const deepEqual = (obj1, obj2) => {
|
|
28
|
+
return (JSON.stringify(removeEmpty(obj1)) === JSON.stringify(removeEmpty(obj2)));
|
|
29
|
+
};
|
|
30
|
+
// export const getYupDefaults = <T>(schema: any) => {
|
|
31
|
+
// const defaultValues: any = {};
|
|
32
|
+
// for (const key in schema.fields) {
|
|
33
|
+
// const field = schema.fields[key];
|
|
34
|
+
// if (field?.type === "object") {
|
|
35
|
+
// defaultValues[key] = getYupDefaults(field); // Recursively get defaults for nested objects
|
|
36
|
+
// } else {
|
|
37
|
+
// defaultValues[key] = field.default ? field.getDefault() : undefined; // Use `getDefault` to get default value
|
|
38
|
+
// }
|
|
39
|
+
// }
|
|
40
|
+
// return defaultValues as T;
|
|
41
|
+
// };
|
|
42
|
+
const replaceEmptyObjectsWithNull = (obj) => {
|
|
43
|
+
if (typeof obj !== "object" || obj === null) {
|
|
44
|
+
return obj;
|
|
45
|
+
}
|
|
46
|
+
if (Array.isArray(obj)) {
|
|
47
|
+
return obj.map((item) => replaceEmptyObjectsWithNull(item));
|
|
48
|
+
}
|
|
49
|
+
const newObj = {};
|
|
50
|
+
let isEmpty = true;
|
|
51
|
+
for (const key in obj) {
|
|
52
|
+
if (obj.hasOwnProperty(key)) {
|
|
53
|
+
const value = replaceEmptyObjectsWithNull(obj[key]);
|
|
54
|
+
newObj[key] = value;
|
|
55
|
+
if (typeof value === "object" &&
|
|
56
|
+
value !== null &&
|
|
57
|
+
Object.keys(value).length > 0) {
|
|
58
|
+
isEmpty = false;
|
|
59
|
+
}
|
|
60
|
+
else if (typeof value !== "undefined" &&
|
|
61
|
+
value !== null &&
|
|
62
|
+
value !== "") {
|
|
63
|
+
isEmpty = false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return isEmpty && Object.keys(obj).length > 0 ? null : newObj;
|
|
68
|
+
};
|
|
69
|
+
export const getYupDefaults = (schema) => {
|
|
70
|
+
const defaultValues = schema.getDefault();
|
|
71
|
+
return replaceEmptyObjectsWithNull(defaultValues);
|
|
72
|
+
};
|
|
73
|
+
export const getFormDefaultValues = (inputValue, // TODO: Use react hook form default values type definition,,
|
|
74
|
+
onComplete = () => null) => {
|
|
75
|
+
const isCallable = typeof inputValue === "function";
|
|
76
|
+
return async () => {
|
|
77
|
+
const values = isCallable ? await inputValue() : inputValue;
|
|
78
|
+
onComplete(values);
|
|
79
|
+
return values;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
export const proficiencyLevelToRating = (level) => {
|
|
83
|
+
switch (level) {
|
|
84
|
+
case ProficiencyLevel.BasicAwareness:
|
|
85
|
+
return 1;
|
|
86
|
+
case ProficiencyLevel.Beginner:
|
|
87
|
+
return 2;
|
|
88
|
+
case ProficiencyLevel.Intermediate:
|
|
89
|
+
return 3;
|
|
90
|
+
case ProficiencyLevel.Advanced:
|
|
91
|
+
return 4;
|
|
92
|
+
case ProficiencyLevel.Expert:
|
|
93
|
+
return 5;
|
|
94
|
+
default:
|
|
95
|
+
return 0;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
export const slugify = (str) => {
|
|
99
|
+
str = str?.trim(); // trim leading/trailing white space
|
|
100
|
+
str = str
|
|
101
|
+
?.replace(/([a-z0-9])([A-Z])/g, "$1-$2") // Convert camelCase to camel-Case
|
|
102
|
+
.toLowerCase() // convert string to lowercase
|
|
103
|
+
.replace(/[^a-z0-9 -]/g, "") // remove any non-alphanumeric characters
|
|
104
|
+
.replace(/\s+/g, "-") // replace spaces with hyphens
|
|
105
|
+
.replace(/-+/g, "-"); // remove consecutive hyphens
|
|
106
|
+
return str;
|
|
107
|
+
};
|
|
108
|
+
export const getShortId = (size = 12) => {
|
|
109
|
+
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
110
|
+
const nanoid = customAlphabet(alphabet, 12);
|
|
111
|
+
return nanoid(size);
|
|
112
|
+
};
|
|
113
|
+
export const minifyString = (seed, length = 10) => {
|
|
114
|
+
let alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
115
|
+
function createRandom() {
|
|
116
|
+
let a = 1664525;
|
|
117
|
+
let c = 1013904223;
|
|
118
|
+
let m = Math.pow(2, 32);
|
|
119
|
+
let state = 0;
|
|
120
|
+
for (let i = 0; i < seed.length; i++) {
|
|
121
|
+
state += seed.charCodeAt(i);
|
|
122
|
+
}
|
|
123
|
+
return function () {
|
|
124
|
+
state = (a * state + c) % m;
|
|
125
|
+
return state;
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
let random = createRandom();
|
|
129
|
+
let generatedString = "";
|
|
130
|
+
for (let i = 0; i < length; i++) {
|
|
131
|
+
let randomIndex = random() % alphabet.length;
|
|
132
|
+
generatedString += alphabet[randomIndex];
|
|
133
|
+
}
|
|
134
|
+
return generatedString;
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Extracts the ID from a given string pattern.
|
|
138
|
+
* Assumes the ID is the last segment after the final hyphen.
|
|
139
|
+
*
|
|
140
|
+
* @param input - The string to extract the ID from.
|
|
141
|
+
* @returns The extracted ID or null if not found.
|
|
142
|
+
*/
|
|
143
|
+
export const extractShortID = (slug) => {
|
|
144
|
+
// Match the last hyphen followed by one or more characters
|
|
145
|
+
const match = slug.match(/-(\w+)$/);
|
|
146
|
+
// Return the first capturing group if a match is found
|
|
147
|
+
return match ? match[1] : null;
|
|
148
|
+
};
|
|
149
|
+
export const allResults = async (promises) => {
|
|
150
|
+
const results = await Promise.allSettled(promises);
|
|
151
|
+
return results.map((result) => result.status === "fulfilled" ? result.value : { error: result.reason });
|
|
152
|
+
};
|
|
153
|
+
export const sleep = async (duration) => {
|
|
154
|
+
return new Promise((resolve) => {
|
|
155
|
+
setTimeout(() => {
|
|
156
|
+
resolve({});
|
|
157
|
+
}, duration);
|
|
158
|
+
});
|
|
159
|
+
};
|
|
160
|
+
export const hasOtherValue = (input) => {
|
|
161
|
+
return (input?.value === "others" ||
|
|
162
|
+
(Array.isArray(input?.value) && input?.value.includes("others")));
|
|
163
|
+
};
|
|
164
|
+
export const fromWithOtherValue = (input, displayFn = (value) => value) => {
|
|
165
|
+
if (!input)
|
|
166
|
+
return "Not avaiable";
|
|
167
|
+
if (hasOtherValue(input)) {
|
|
168
|
+
return input.otherValue || "Not Available";
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
return displayFn(input);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
export const isJSON = (value) => {
|
|
175
|
+
try {
|
|
176
|
+
JSON.parse(value);
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
export const displayByName = (option) => {
|
|
184
|
+
return option?.name;
|
|
185
|
+
};
|
|
186
|
+
export const displayLocation = (location, display) => {
|
|
187
|
+
const { city, state, country, address } = location || {};
|
|
188
|
+
let keywords = [];
|
|
189
|
+
if (display === "address") {
|
|
190
|
+
keywords = [address];
|
|
191
|
+
}
|
|
192
|
+
else if (display === "medium") {
|
|
193
|
+
keywords = [city, state, country];
|
|
194
|
+
}
|
|
195
|
+
else if (display === "small") {
|
|
196
|
+
keywords = [city, country];
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
keywords = [country];
|
|
200
|
+
}
|
|
201
|
+
const result = keywords.filter((value) => !!value).join(", ");
|
|
202
|
+
return result || "Not Available";
|
|
203
|
+
};
|
|
204
|
+
/**
|
|
205
|
+
* Generates a random integer between two given values (inclusive).
|
|
206
|
+
*
|
|
207
|
+
* @param {number} min - The minimum value (inclusive).
|
|
208
|
+
* @param {number} max - The maximum value (inclusive).
|
|
209
|
+
* @returns {number} A random integer between min and max.
|
|
210
|
+
*/
|
|
211
|
+
export const getRandomInt = (min, max) => {
|
|
212
|
+
if (min > max) {
|
|
213
|
+
throw new Error("Min value must be less than or equal to max value.");
|
|
214
|
+
}
|
|
215
|
+
const minCeiled = Math.ceil(min);
|
|
216
|
+
const maxFloored = Math.floor(max);
|
|
217
|
+
return Math.floor(Math.random() * (maxFloored - minCeiled + 1)) + minCeiled;
|
|
218
|
+
};
|
|
219
|
+
/**
|
|
220
|
+
* Generates a random floating-point number between two given values (inclusive).
|
|
221
|
+
*
|
|
222
|
+
* @param {number} min - The minimum value (inclusive).
|
|
223
|
+
* @param {number} max - The maximum value (inclusive).
|
|
224
|
+
* @returns {number} A random floating-point number between min and max.
|
|
225
|
+
*/
|
|
226
|
+
export const getRandomFloat = (min, max) => {
|
|
227
|
+
if (min > max) {
|
|
228
|
+
throw new Error("Min value must be less than or equal to max value.");
|
|
229
|
+
}
|
|
230
|
+
return Math.random() * (max - min) + min;
|
|
231
|
+
};
|
|
232
|
+
export const displayNameLabel = (name, type = "full") => {
|
|
233
|
+
if (!name) {
|
|
234
|
+
return "Not available";
|
|
235
|
+
}
|
|
236
|
+
if (typeof name === "string") {
|
|
237
|
+
return name;
|
|
238
|
+
}
|
|
239
|
+
const { first, last } = name;
|
|
240
|
+
if (type === "full") {
|
|
241
|
+
return `${first} ${last}`;
|
|
242
|
+
}
|
|
243
|
+
else if (type === "first") {
|
|
244
|
+
return first;
|
|
245
|
+
}
|
|
246
|
+
else if (type === "last") {
|
|
247
|
+
return last;
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
return "Render Failed";
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
export const displayMobileNumberLabel = (mobileNumber, options) => {
|
|
254
|
+
const { number, country } = mobileNumber;
|
|
255
|
+
const { name, dial_code } = country;
|
|
256
|
+
if (!options?.countryName) {
|
|
257
|
+
return `${dial_code} ${number}`;
|
|
258
|
+
}
|
|
259
|
+
return `${name} (${dial_code}) ${number}`;
|
|
260
|
+
};
|
|
261
|
+
export const toPositiveWholeNumber = (value) => {
|
|
262
|
+
if (typeof value !== "number") {
|
|
263
|
+
return 0;
|
|
264
|
+
}
|
|
265
|
+
const wholePercentage = Math.round(value); // Round to the nearest whole number
|
|
266
|
+
return wholePercentage < 0 ? 0 : wholePercentage; // Ensure the value is positive
|
|
267
|
+
};
|
|
268
|
+
export const formatNumberToKMB = (num) => {
|
|
269
|
+
if (num < 1000) {
|
|
270
|
+
return num.toString();
|
|
271
|
+
}
|
|
272
|
+
else if (num < 1000000) {
|
|
273
|
+
return (num / 1000).toFixed(1) + "K";
|
|
274
|
+
}
|
|
275
|
+
else if (num < 1000000000) {
|
|
276
|
+
return (num / 1000000).toFixed(1) + "M";
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
return (num / 1000000000).toFixed(1) + "B";
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
export const formatCountWithLabel = (count, options) => {
|
|
283
|
+
const { singularLabel, pluralLabel, zeroCountLabel } = options;
|
|
284
|
+
if (count === undefined || count === 0) {
|
|
285
|
+
return zeroCountLabel || `No ${pluralLabel}`;
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
const formattedCount = formatNumberToKMB(count);
|
|
289
|
+
const label = count > 1 ? pluralLabel : singularLabel;
|
|
290
|
+
return `${formattedCount} ${label}`;
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
/**
|
|
294
|
+
* Recursively parses a dirty fields object to detect if the form or a specific field is dirty.
|
|
295
|
+
*
|
|
296
|
+
* @param dirtyFields The object representing the dirty state of form fields.
|
|
297
|
+
* @param fieldName (Optional) The name of a specific field to check for dirtiness.
|
|
298
|
+
* @returns True if the form or the specified field is dirty, false otherwise.
|
|
299
|
+
*/
|
|
300
|
+
export const isFormDirty = (dirtyFields, //PickFrom<FormState<any>, "dirtyFields">,
|
|
301
|
+
fieldName) => {
|
|
302
|
+
if (fieldName) {
|
|
303
|
+
const field = dirtyFields[fieldName];
|
|
304
|
+
if (typeof field === "boolean") {
|
|
305
|
+
return field;
|
|
306
|
+
}
|
|
307
|
+
else if (typeof field === "object" && field !== null) {
|
|
308
|
+
// If the field is an object or array, recursively check its contents
|
|
309
|
+
return isFormDirty(field);
|
|
310
|
+
}
|
|
311
|
+
return false; // FieldName not found or not a boolean/object
|
|
312
|
+
}
|
|
313
|
+
// If no fieldName is provided, check the entire form
|
|
314
|
+
for (const key in dirtyFields) {
|
|
315
|
+
if (Object.prototype.hasOwnProperty.call(dirtyFields, key)) {
|
|
316
|
+
const value = dirtyFields[key];
|
|
317
|
+
if (typeof value === "boolean") {
|
|
318
|
+
if (value === true) {
|
|
319
|
+
return true; // Found a dirty boolean field
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
else if (typeof value === "object" && value !== null) {
|
|
323
|
+
// Recursively check nested objects or arrays
|
|
324
|
+
if (isFormDirty(value)) {
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return false; // No dirty fields found
|
|
331
|
+
};
|
|
332
|
+
/**
|
|
333
|
+
* Extracts the root path of each error within the 'inner' property of the input object.
|
|
334
|
+
*
|
|
335
|
+
* @param data The input object containing error details.
|
|
336
|
+
* @returns An array of strings, where each string is the root path of an error.
|
|
337
|
+
*/
|
|
338
|
+
export const getErrorRootPaths = (data) => {
|
|
339
|
+
const rootPaths = [];
|
|
340
|
+
if (data && Array.isArray(data.inner)) {
|
|
341
|
+
data.inner.forEach((errorDetail) => {
|
|
342
|
+
if (errorDetail.path) {
|
|
343
|
+
// The root path is typically the first part before the dot
|
|
344
|
+
const rootPath = errorDetail.path.split(".")[0];
|
|
345
|
+
if (rootPath && !rootPaths.includes(rootPath)) {
|
|
346
|
+
rootPaths.push(rootPath);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
return rootPaths;
|
|
352
|
+
};
|
|
353
|
+
export const getRequiredUserInformation = (completeness, skip = []) => {
|
|
354
|
+
try {
|
|
355
|
+
UserCompletenessSchema.omit(skip).validateSync(completeness, {
|
|
356
|
+
abortEarly: false,
|
|
357
|
+
});
|
|
358
|
+
return [];
|
|
359
|
+
}
|
|
360
|
+
catch (error) {
|
|
361
|
+
return getErrorRootPaths(error);
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
export const getRequiredInformationByUser = (user, completeness) => {
|
|
365
|
+
if (user.experienceLevel === ExperienceLevel.Student ||
|
|
366
|
+
user.experienceLevel === ExperienceLevel.Entry) {
|
|
367
|
+
return getRequiredUserInformation(completeness, ["workExperiences"]);
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
return getRequiredUserInformation(completeness);
|
|
371
|
+
}
|
|
372
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completeness.d.ts","sourceRoot":"","sources":["../../../src/completeness/completeness.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const extractFields = (schema, prefix = "", includeOptionals = false) => {
|
|
2
|
+
if (!schema?.fields)
|
|
3
|
+
return [];
|
|
4
|
+
const schemaFields = schema.fields;
|
|
5
|
+
let extractedFields = [];
|
|
6
|
+
const processField = (key, fieldSchema, currentPath) => {
|
|
7
|
+
const isRequired = !fieldSchema.spec?.optional;
|
|
8
|
+
const type = fieldSchema.type;
|
|
9
|
+
const innerType = fieldSchema.innerType?.type;
|
|
10
|
+
if (!isRequired && !includeOptionals)
|
|
11
|
+
return;
|
|
12
|
+
if (type === "array") {
|
|
13
|
+
const minItems = fieldSchema.tests?.find((t) => t.OPTIONS?.name === "min")?.OPTIONS
|
|
14
|
+
?.params?.min || 0;
|
|
15
|
+
const itemSchema = fieldSchema.innerType;
|
|
16
|
+
// Handle required array items
|
|
17
|
+
for (let i = 0; i < minItems; i++) {
|
|
18
|
+
const indexPath = `${currentPath}.${i}`;
|
|
19
|
+
const itemFields = extractFields(itemSchema, indexPath, includeOptionals);
|
|
20
|
+
extractedFields.push(...itemFields);
|
|
21
|
+
if (itemFields.length === 0) {
|
|
22
|
+
extractedFields.push({ key: indexPath, required: true });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// Handle optional array items
|
|
26
|
+
if (includeOptionals) {
|
|
27
|
+
const optionalFields = extractFields(itemSchema, currentPath, includeOptionals).map((f) => ({ ...f, key: `${f.key}[]`, required: false }));
|
|
28
|
+
extractedFields.push(...optionalFields);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else if (type === "object" || innerType === "object") {
|
|
32
|
+
const targetSchema = type === "object" ? fieldSchema : fieldSchema.innerType;
|
|
33
|
+
const nestedFields = extractFields(targetSchema, currentPath, includeOptionals);
|
|
34
|
+
extractedFields.push(...nestedFields);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
extractedFields.push({ key: currentPath, required: isRequired });
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
for (const key in schemaFields) {
|
|
41
|
+
const fieldSchema = schemaFields[key];
|
|
42
|
+
if (!fieldSchema)
|
|
43
|
+
continue;
|
|
44
|
+
const currentPath = prefix ? `${prefix}.${key}` : key;
|
|
45
|
+
processField(key, fieldSchema, currentPath);
|
|
46
|
+
}
|
|
47
|
+
return extractedFields;
|
|
48
|
+
};
|
|
49
|
+
export {};
|
|
50
|
+
// const getValueByPath = (data: any, path: string) => {
|
|
51
|
+
// const parts = path.replace("[]", "").split(".");
|
|
52
|
+
// return parts.reduce((acc, part) => {
|
|
53
|
+
// if (acc === undefined || acc === null) return undefined;
|
|
54
|
+
// const match = part.match(/^(\d+)$/);
|
|
55
|
+
// if (match && match[1]) {
|
|
56
|
+
// const index = parseInt(match[1]);
|
|
57
|
+
// return Array.isArray(acc) ? acc[index] : undefined;
|
|
58
|
+
// }
|
|
59
|
+
// return acc[part];
|
|
60
|
+
// }, data);
|
|
61
|
+
// };
|
|
62
|
+
// export const getCompletenessScore = <T>(
|
|
63
|
+
// schema: any,
|
|
64
|
+
// data: T | T[],
|
|
65
|
+
// options: CompletenessOptions = { includeOptionals: false }
|
|
66
|
+
// ): CompletenessScore => {
|
|
67
|
+
// const { includeOptionals = false, emptyArrayScore } = options;
|
|
68
|
+
// if (Array.isArray(data)) {
|
|
69
|
+
// if (data.length === 0) {
|
|
70
|
+
// return {
|
|
71
|
+
// score: emptyArrayScore === "perfect" ? 100 : 0,
|
|
72
|
+
// completedSteps: 0,
|
|
73
|
+
// totalSteps: 0,
|
|
74
|
+
// children: [],
|
|
75
|
+
// };
|
|
76
|
+
// }
|
|
77
|
+
// const children = data.map((item) =>
|
|
78
|
+
// getCompletenessScore(schema, item, options)
|
|
79
|
+
// );
|
|
80
|
+
// const contentScore =
|
|
81
|
+
// children.reduce((sum, child) => sum + child.score, 0) / children.length;
|
|
82
|
+
// return {
|
|
83
|
+
// score: Math.round(contentScore),
|
|
84
|
+
// completedSteps: children.reduce((sum, c) => sum + c.completedSteps, 0),
|
|
85
|
+
// totalSteps: children.reduce((sum, c) => sum + c.totalSteps, 0),
|
|
86
|
+
// children,
|
|
87
|
+
// };
|
|
88
|
+
// }
|
|
89
|
+
// const fields = extractFields(schema, "", includeOptionals);
|
|
90
|
+
// const requiredFields = fields.filter((f) => f.required);
|
|
91
|
+
// const totalSteps = includeOptionals ? fields.length : requiredFields.length;
|
|
92
|
+
// let completedSteps = 0;
|
|
93
|
+
// const meta = {
|
|
94
|
+
// steps: fields.map((f) => f.key),
|
|
95
|
+
// completed: [] as string[],
|
|
96
|
+
// incomplete: [] as string[],
|
|
97
|
+
// };
|
|
98
|
+
// fields.forEach(({ key, required }) => {
|
|
99
|
+
// const value = getValueByPath(data, key);
|
|
100
|
+
// const exists = value !== undefined && value !== null && value !== "";
|
|
101
|
+
// if (exists) {
|
|
102
|
+
// meta.completed.push(key);
|
|
103
|
+
// if (includeOptionals || required) completedSteps++;
|
|
104
|
+
// } else {
|
|
105
|
+
// if (includeOptionals || required) meta.incomplete.push(key);
|
|
106
|
+
// }
|
|
107
|
+
// });
|
|
108
|
+
// const score =
|
|
109
|
+
// totalSteps > 0 ? Math.floor((completedSteps / totalSteps) * 100) : 100;
|
|
110
|
+
// return {
|
|
111
|
+
// score,
|
|
112
|
+
// completedSteps: includeOptionals
|
|
113
|
+
// ? completedSteps
|
|
114
|
+
// : Math.min(completedSteps, requiredFields.length),
|
|
115
|
+
// totalSteps,
|
|
116
|
+
// meta,
|
|
117
|
+
// };
|
|
118
|
+
// };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/completeness/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./completeness";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/date/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./utils";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DateRangeOption } from "@thejob/schema";
|
|
2
|
+
import dayjs, { Dayjs } from "dayjs";
|
|
3
|
+
export declare const toDayJS: ({ date, dateFormat, strict, utc, }?: {
|
|
4
|
+
date?: string | Dayjs;
|
|
5
|
+
dateFormat?: string;
|
|
6
|
+
strict?: boolean;
|
|
7
|
+
utc?: boolean;
|
|
8
|
+
}) => dayjs.Dayjs;
|
|
9
|
+
export declare const dateAgo: (value: number | string | Date) => string;
|
|
10
|
+
export declare const dateRangeOptionToDateRange: (option: DateRangeOption) => {
|
|
11
|
+
startDate: string | undefined;
|
|
12
|
+
endDate: string | undefined;
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/date/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAoB,MAAM,gBAAgB,CAAC;AACnE,OAAO,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAQrC,eAAO,MAAM,OAAO,GAAI,qCAKrB;IACD,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;CACV,gBASL,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,OAAO,MAAM,GAAG,MAAM,GAAG,IAAI,WAEpD,CAAC;AAEF,eAAO,MAAM,0BAA0B,GAAI,QAAQ,eAAe;;;CA4CjE,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { DateRangeOption, SystemDateFormat } from "@thejob/schema";
|
|
2
|
+
import dayjs from "dayjs";
|
|
3
|
+
import localizedFormat from "dayjs/plugin/localizedFormat";
|
|
4
|
+
import relativeTime from "dayjs/plugin/relativeTime";
|
|
5
|
+
import customParseFormat from "dayjs/plugin/customParseFormat";
|
|
6
|
+
dayjs.extend(relativeTime);
|
|
7
|
+
dayjs.extend(localizedFormat);
|
|
8
|
+
dayjs.extend(customParseFormat);
|
|
9
|
+
export const toDayJS = ({ date, dateFormat = SystemDateFormat, strict = false, utc = false, } = {}) => {
|
|
10
|
+
return dayjs(date, {
|
|
11
|
+
utc,
|
|
12
|
+
format: dateFormat,
|
|
13
|
+
}, strict);
|
|
14
|
+
};
|
|
15
|
+
export const dateAgo = (value) => {
|
|
16
|
+
return dayjs(value).fromNow();
|
|
17
|
+
};
|
|
18
|
+
export const dateRangeOptionToDateRange = (option) => {
|
|
19
|
+
const today = toDayJS({ utc: true });
|
|
20
|
+
let dateRange = {
|
|
21
|
+
startDate: undefined,
|
|
22
|
+
endDate: undefined,
|
|
23
|
+
};
|
|
24
|
+
switch (option) {
|
|
25
|
+
case DateRangeOption.LastMonth:
|
|
26
|
+
dateRange = {
|
|
27
|
+
startDate: today.subtract(1, "month"), //.startOf("month"),
|
|
28
|
+
endDate: today,
|
|
29
|
+
};
|
|
30
|
+
break;
|
|
31
|
+
case DateRangeOption.LastWeek:
|
|
32
|
+
dateRange = {
|
|
33
|
+
startDate: today.subtract(1, "week"), //.startOf("week"),
|
|
34
|
+
endDate: today, //.endOf("week"),
|
|
35
|
+
};
|
|
36
|
+
break;
|
|
37
|
+
case DateRangeOption.Last_3_Days:
|
|
38
|
+
dateRange = {
|
|
39
|
+
startDate: today.subtract(3, "days"),
|
|
40
|
+
endDate: today,
|
|
41
|
+
};
|
|
42
|
+
break;
|
|
43
|
+
case DateRangeOption.Last_24_Hours:
|
|
44
|
+
dateRange = {
|
|
45
|
+
startDate: today.subtract(24, "hours"),
|
|
46
|
+
endDate: today,
|
|
47
|
+
};
|
|
48
|
+
break;
|
|
49
|
+
case DateRangeOption.Any:
|
|
50
|
+
default:
|
|
51
|
+
dateRange = {
|
|
52
|
+
startDate: undefined,
|
|
53
|
+
endDate: undefined,
|
|
54
|
+
};
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
startDate: dateRange.startDate?.format(SystemDateFormat),
|
|
59
|
+
endDate: dateRange.endDate?.format(SystemDateFormat),
|
|
60
|
+
};
|
|
61
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,OAAO,CAAC;AACtB,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/job/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./utils";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/job/utils.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/job-application/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./utils";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/job-application/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAErD,eAAO,MAAM,0BAA0B,GAAI,OAAO,mBAAmB,8EAapE,CAAC"}
|