@becollective/utils 2.0.12 → 2.0.14

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 (60) hide show
  1. package/.semaphore/utils.yml +13 -22
  2. package/jestconfig.json +12 -1
  3. package/lib/constants/allowedHtmlTags.d.ts +6 -2
  4. package/lib/constants/allowedHtmlTags.js +9 -5
  5. package/lib/constants/countries.d.ts +2 -2
  6. package/lib/constants/countries.js +3 -1
  7. package/lib/constants/customFields.d.ts +2 -2
  8. package/lib/constants/customFields.js +3 -1
  9. package/lib/constants/distancesUnits.d.ts +2 -2
  10. package/lib/constants/distancesUnits.js +13 -9
  11. package/lib/constants/groups.d.ts +12 -2
  12. package/lib/constants/groups.js +86 -81
  13. package/lib/constants/insuranceStatuses.d.ts +14 -2
  14. package/lib/constants/insuranceStatuses.js +9 -4
  15. package/lib/constants/insuranceTypes.d.ts +34 -2
  16. package/lib/constants/insuranceTypes.js +43 -33
  17. package/lib/constants/languages.d.ts +2 -2
  18. package/lib/constants/languages.js +3 -1
  19. package/lib/constants/qualificationTypes.d.ts +2 -2
  20. package/lib/constants/qualificationTypes.js +3 -2
  21. package/lib/constants/rules.d.ts +12 -2
  22. package/lib/constants/rules.js +7 -5
  23. package/lib/constants/surveys.d.ts +15 -2
  24. package/lib/constants/surveys.js +18 -14
  25. package/lib/date-time.js +1 -1
  26. package/lib/forms.d.ts +3 -0
  27. package/lib/forms.js +3 -0
  28. package/package.json +10 -1
  29. package/src/constants/allowedHtmlTags.ts +10 -5
  30. package/src/constants/countries.ts +3 -1
  31. package/src/constants/customFields.ts +3 -1
  32. package/src/constants/distancesUnits.ts +15 -9
  33. package/src/constants/groups.ts +89 -81
  34. package/src/constants/insuranceStatuses.ts +10 -4
  35. package/src/constants/insuranceTypes.ts +51 -33
  36. package/src/constants/languages.ts +3 -1
  37. package/src/constants/qualificationTypes.ts +2 -1
  38. package/src/constants/rules.ts +5 -3
  39. package/src/constants/surveys.ts +20 -14
  40. package/src/date-time.ts +1 -1
  41. package/src/forms.ts +3 -0
  42. package/tests/forms.test.ts +121 -1
  43. package/lib/rrule/parsing.test.d.ts +0 -1
  44. package/lib/rrule/parsing.test.js +0 -11
  45. package/lib/src/FeatureFlag.d.ts +0 -12
  46. package/lib/src/FeatureFlag.js +0 -51
  47. package/lib/src/date-time.d.ts +0 -28
  48. package/lib/src/date-time.js +0 -79
  49. package/lib/src/forms.d.ts +0 -1
  50. package/lib/src/forms.js +0 -728
  51. package/lib/src/locality.d.ts +0 -5
  52. package/lib/src/locality.js +0 -15
  53. package/lib/src/money.d.ts +0 -7
  54. package/lib/src/money.js +0 -32
  55. package/lib/src/opportunity.d.ts +0 -1
  56. package/lib/src/opportunity.js +0 -11
  57. package/lib/src/opportunityUser.d.ts +0 -8
  58. package/lib/src/opportunityUser.js +0 -29
  59. package/lib/src/password.d.ts +0 -8
  60. package/lib/src/password.js +0 -43
@@ -1,5 +1,5 @@
1
1
  'use strict';
2
- const validator = require('../src/forms');
2
+ const { validator } = require('../lib/forms');
3
3
  const testSchema = require('./forms.test-schema.json');
4
4
  const testUischema = require('./forms.test-uischema.json');
5
5
  const testData = require('./forms.test-data.json');
@@ -136,6 +136,40 @@ describe('validateSchema', () => {
136
136
  ]);
137
137
  });
138
138
 
139
+ test('should accept array schema with custom answer pattern in anyOf', () => {
140
+ const t = {
141
+ data: {
142
+ type: 'object',
143
+ required: [],
144
+ properties: {
145
+ q1: {
146
+ title: 'Pick one',
147
+ type: 'array',
148
+ uniqueItems: true,
149
+ items: {
150
+ type: 'string',
151
+ anyOf: [
152
+ { type: 'string', enum: ['Yes'] },
153
+ { type: 'string', enum: ['No'] },
154
+ { type: 'string', pattern: '^Other: .+' },
155
+ ],
156
+ },
157
+ },
158
+ },
159
+ },
160
+ ui: {
161
+ 'ui:order': ['q1'],
162
+ q1: {
163
+ 'ui:widget': 'WidgetRadio',
164
+ 'ui:title': 'Pick one',
165
+ 'ui:bc-allowCustomAnswer': true,
166
+ },
167
+ },
168
+ };
169
+
170
+ return expect(validateSchema(t.data, t.ui)).resolves.toBe(true);
171
+ });
172
+
139
173
  test('should succeed, returning true when schema and uischema are valid', () => {
140
174
  return expect(validateSchema(schema, uischema)).resolves.toBe(true);
141
175
  });
@@ -303,6 +337,58 @@ describe('validateData', () => {
303
337
 
304
338
  return expect(validateData(schema, data)).resolves.toBe(undefined);
305
339
  });
340
+
341
+ test('should accept custom answer values for choice fields', () => {
342
+ const customChoiceSchema = {
343
+ type: 'object',
344
+ required: [],
345
+ properties: {
346
+ q1: {
347
+ title: 'Pick one',
348
+ type: 'array',
349
+ uniqueItems: true,
350
+ items: {
351
+ type: 'string',
352
+ anyOf: [
353
+ { type: 'string', enum: ['Yes'] },
354
+ { type: 'string', enum: ['No'] },
355
+ { type: 'string', pattern: '^Other: .+' },
356
+ ],
357
+ },
358
+ },
359
+ },
360
+ };
361
+
362
+ return expect(
363
+ validateData(customChoiceSchema, { q1: ['Other: Prefer weekends'] }),
364
+ ).resolves.toBe(undefined);
365
+ });
366
+
367
+ test('should reject incomplete custom answer values for choice fields', () => {
368
+ const customChoiceSchema = {
369
+ type: 'object',
370
+ required: [],
371
+ properties: {
372
+ q1: {
373
+ title: 'Pick one',
374
+ type: 'array',
375
+ uniqueItems: true,
376
+ items: {
377
+ type: 'string',
378
+ anyOf: [
379
+ { type: 'string', enum: ['Yes'] },
380
+ { type: 'string', enum: ['No'] },
381
+ { type: 'string', pattern: '^Other: .+' },
382
+ ],
383
+ },
384
+ },
385
+ },
386
+ };
387
+
388
+ return expect(validateData(customChoiceSchema, { q1: ['Other'] })).rejects.toEqual([
389
+ expect.objectContaining({ name: 'Datatype is not an array of strings' }),
390
+ ]);
391
+ });
306
392
  });
307
393
 
308
394
  describe('stripEmptyArraysFromData', () => {
@@ -569,6 +655,40 @@ describe('dataTypeIsValid', () => {
569
655
  });
570
656
  });
571
657
 
658
+ describe('array with custom answer', () => {
659
+ const choice = {
660
+ schema: {
661
+ type: 'array',
662
+ title: 'Pick one',
663
+ items: {
664
+ type: 'string',
665
+ anyOf: [
666
+ { type: 'string', enum: ['Yes'] },
667
+ { type: 'string', enum: ['No'] },
668
+ { type: 'string', pattern: '^Other: .+' },
669
+ ],
670
+ },
671
+ uniqueItems: true,
672
+ },
673
+ };
674
+
675
+ test('should return true for a completed custom answer', () => {
676
+ expect(isValid.array(['Other: Prefer weekends'], choice.schema)).toBe(true);
677
+ });
678
+
679
+ test('should return true for a predefined option', () => {
680
+ expect(isValid.array(['No'], choice.schema)).toBe(true);
681
+ });
682
+
683
+ test('should return false for incomplete Other without text', () => {
684
+ expect(isValid.array(['Other'], choice.schema)).toBe(false);
685
+ });
686
+
687
+ test('should return false for arbitrary text not matching pattern', () => {
688
+ expect(isValid.array(['Maybe'], choice.schema)).toBe(false);
689
+ });
690
+ });
691
+
572
692
  describe('skills', () => {
573
693
  const skills = {
574
694
  schema: {
@@ -1 +0,0 @@
1
- export {};
@@ -1,11 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const parsing_1 = require("./parsing");
4
- it('removes null or undefined fields', () => {
5
- expect((0, parsing_1.toRruleStr)({
6
- DTSTART: '20120201T023000Z',
7
- DURATION: '1h',
8
- COUNT: null,
9
- UNTIL: undefined,
10
- })).toEqual('DTSTART=20120201T023000Z;DURATION=1h');
11
- });
@@ -1,12 +0,0 @@
1
- export declare class FeatureFlag {
2
- ttl: number;
3
- expiry: number;
4
- constructor(ttl?: any);
5
- isFeatureActive(feature: string, options: {
6
- env: string;
7
- region?: string;
8
- }): Promise<boolean>;
9
- clearCache(): void;
10
- setCacheTtl(ttl: number): void;
11
- }
12
- export default FeatureFlag;
@@ -1,51 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FeatureFlag = void 0;
4
- const cache = {
5
- store: new Map(),
6
- memoize: async (feature, options) => {
7
- const stringified = JSON.stringify({ feature, options });
8
- const response = cache.store.get(stringified);
9
- if (response) {
10
- return JSON.parse(response);
11
- }
12
- const fetchResponse = await fetchFeatureActive(feature, options);
13
- cache.store.set(stringified, JSON.stringify(fetchResponse));
14
- return fetchResponse;
15
- },
16
- };
17
- const fetchFeatureActive = async (feature, options) => {
18
- const getFlagByFeatureUrl = `https://lb-central.becollective.com/api/v2/feature-flags/${feature}`;
19
- let isFeatureActive = false;
20
- const featureFlags = await fetch(getFlagByFeatureUrl, { method: 'get' });
21
- const json = await featureFlags.json();
22
- const environments = json.Environments;
23
- if (environments) {
24
- isFeatureActive = environments.includes(options.env);
25
- }
26
- return isFeatureActive;
27
- };
28
- class FeatureFlag {
29
- constructor(ttl) {
30
- this.ttl = ttl || 1000 * 60 * 5; // default to 5 minutes
31
- this.expiry = Date.now() + ttl;
32
- }
33
- async isFeatureActive(feature, options) {
34
- // Lazy expiration upon function call
35
- const now = Date.now();
36
- if (now >= this.expiry) {
37
- cache.store.clear();
38
- this.expiry = now + this.ttl;
39
- }
40
- return cache.memoize(feature, options);
41
- }
42
- clearCache() {
43
- cache.store.clear();
44
- }
45
- setCacheTtl(ttl) {
46
- this.ttl = ttl;
47
- this.expiry = Date.now() + ttl;
48
- }
49
- }
50
- exports.FeatureFlag = FeatureFlag;
51
- exports.default = FeatureFlag;
@@ -1,28 +0,0 @@
1
- /**
2
- * Get current age based on the given birth date
3
- * @param {string} dateOfBirth
4
- * @param {string} unit the measurement of the the difference
5
- * The supported measurements are:
6
- * years, months, weeks, days, hours, minutes, and seconds.
7
- * @returns {number} age
8
- */
9
- export declare const getAge: (dateOfBirth: any, unit?: string) => number;
10
- /**
11
- * Check if a user requires parent(guardian) consent
12
- * i.e. Is under the age of 16 years, based on GDPR
13
- * https://gdpr-info.eu/art-8-gdpr/
14
- * @param {string} dateOfBirth moment.js compatible date time
15
- * @returns {boolean}
16
- * NOTE:
17
- * We used to not allow child (under 16) to register,
18
- * and birthdate is not a required field for ghost user
19
- * So an existing user could have no birthdate, we assume these users are adults
20
- * TODO:
21
- * Remove above logic after we migrated all legacy
22
- * data to have a consistent birthdate property.
23
- * Then we should throw error if birthdate is not valid
24
- */
25
- export declare const isUnderSixteen: (dateOfBirth: any) => boolean;
26
- export declare const isUnderAge: (dateOfBirth: any, limit: any, maxAcknowledgedAge?: number | null) => boolean;
27
- export declare const datesByThemselves: (a: any, b: any) => number;
28
- export declare const getShiftText: (from: any, to: any, timezone: any) => string;
@@ -1,79 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getShiftText = exports.datesByThemselves = exports.isUnderAge = exports.isUnderSixteen = exports.getAge = void 0;
4
- const luxon_1 = require("luxon");
5
- /**
6
- * Get current age based on the given birth date
7
- * @param {string} dateOfBirth
8
- * @param {string} unit the measurement of the the difference
9
- * The supported measurements are:
10
- * years, months, weeks, days, hours, minutes, and seconds.
11
- * @returns {number} age
12
- */
13
- const getAge = (dateOfBirth, unit = 'years') => {
14
- if (!dateOfBirth) {
15
- throw new Error('Invalid date');
16
- }
17
- const dob = luxon_1.DateTime.fromJSDate(new Date(dateOfBirth));
18
- if (!dob.isValid) {
19
- throw new Error('Invalid date');
20
- }
21
- const age = dob.diffNow(unit);
22
- const ageUnit = -age.as(unit);
23
- // Note: luxon returns scientific notation, ie 6.976154236428209e-9
24
- return Number(ageUnit.toString().split('.').shift());
25
- };
26
- exports.getAge = getAge;
27
- /**
28
- * Check if a user requires parent(guardian) consent
29
- * i.e. Is under the age of 16 years, based on GDPR
30
- * https://gdpr-info.eu/art-8-gdpr/
31
- * @param {string} dateOfBirth moment.js compatible date time
32
- * @returns {boolean}
33
- * NOTE:
34
- * We used to not allow child (under 16) to register,
35
- * and birthdate is not a required field for ghost user
36
- * So an existing user could have no birthdate, we assume these users are adults
37
- * TODO:
38
- * Remove above logic after we migrated all legacy
39
- * data to have a consistent birthdate property.
40
- * Then we should throw error if birthdate is not valid
41
- */
42
- const isUnderSixteen = (dateOfBirth) => {
43
- if (!dateOfBirth || !luxon_1.DateTime.fromJSDate(new Date(dateOfBirth)).isValid) {
44
- return false;
45
- }
46
- const age = (0, exports.getAge)(dateOfBirth);
47
- return isNaN(age) ? false : age < 16;
48
- };
49
- exports.isUnderSixteen = isUnderSixteen;
50
- const isUnderAge = (dateOfBirth, limit, maxAcknowledgedAge = null) => {
51
- if ((!dateOfBirth || !luxon_1.DateTime.fromJSDate(new Date(dateOfBirth)).isValid) && !maxAcknowledgedAge) {
52
- return false;
53
- }
54
- if (dateOfBirth) {
55
- const age = (0, exports.getAge)(dateOfBirth);
56
- return isNaN(age) ? true : age < limit;
57
- }
58
- return maxAcknowledgedAge ? maxAcknowledgedAge < limit : true;
59
- };
60
- exports.isUnderAge = isUnderAge;
61
- const datesByThemselves = (a, b) => {
62
- if (!a.from)
63
- return 1;
64
- return new Date(a.from).getTime() - new Date(b.from).getTime();
65
- };
66
- exports.datesByThemselves = datesByThemselves;
67
- const getShiftText = (from, to, timezone) => {
68
- try {
69
- if (!from || !to || !timezone)
70
- return '';
71
- const startToTimezone = luxon_1.DateTime.fromJSDate(from).setZone(timezone);
72
- const endToTimezone = luxon_1.DateTime.fromJSDate(to).setZone(timezone);
73
- return `${startToTimezone.toFormat('cccc, DD, h:mma')}-${endToTimezone.toFormat('h:mma')}`;
74
- }
75
- catch (e) {
76
- return '';
77
- }
78
- };
79
- exports.getShiftText = getShiftText;
@@ -1 +0,0 @@
1
- export {};