abmp-npm 1.0.0 → 1.7.2

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/README.md ADDED
@@ -0,0 +1 @@
1
+ # abmp-npm
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Default display settings for member profiles
3
+ */
4
+ const DEFAULT_MEMBER_DISPLAY_SETTINGS = {
5
+ showLicenseNo: true,
6
+ showName: true,
7
+ showBookingUrl: false,
8
+ showWebsite: false,
9
+ showWixUrl: true,
10
+ };
11
+
12
+ /**
13
+ * Address display status types
14
+ */
15
+ const ADDRESS_STATUS_TYPES = {
16
+ FULL_ADDRESS: 'full_address',
17
+ STATE_CITY_ZIP: 'state_city_zip',
18
+ DONT_SHOW: 'dont_show',
19
+ };
20
+
21
+ /**
22
+ * Address visibility configuration options
23
+ */
24
+ const ADDRESS_VISIBILITY_OPTIONS = {
25
+ ALL: 'all',
26
+ NONE: 'none',
27
+ };
28
+
29
+ const COLLECTIONS = {
30
+ MEMBERS_DATA: 'MembersDataLatest',
31
+ };
32
+
33
+
34
+
35
+ const MEMBER_ACTIONS = {
36
+ UPDATE: 'update',
37
+ NEW: 'new',
38
+ DROP: 'drop',
39
+ NONE: 'none'
40
+ };
41
+
42
+ const PRECISION = 3;
43
+
44
+ module.exports = {
45
+ DEFAULT_MEMBER_DISPLAY_SETTINGS,
46
+ ADDRESS_STATUS_TYPES,
47
+ ADDRESS_VISIBILITY_OPTIONS,
48
+ PRECISION,
49
+ COLLECTIONS,
50
+ MEMBER_ACTIONS,
51
+ };
52
+
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ ...require('./consts'),
3
+ ...require('./utils'),
4
+ ...require('./updateMemberData'),
5
+ };
6
+
@@ -0,0 +1,210 @@
1
+ import { generateGeoHash } from './utils.js';
2
+ import {
3
+ ADDRESS_STATUS_TYPES,
4
+ DEFAULT_MEMBER_DISPLAY_SETTINGS,
5
+ MEMBER_ACTIONS,
6
+ } from './consts.js';
7
+ import {
8
+ determineAddressDisplayStatus,
9
+ isValidArray,
10
+ processInterests,
11
+ createFullName,
12
+ } from './utils.js';
13
+ import { findMemberById } from './utils.js';
14
+
15
+ /**
16
+ * Validates core member data requirements
17
+ * @param {Object} inputMemberData - Raw member data from API to validate
18
+ * @returns {boolean} - True if all required fields are valid, false otherwise
19
+ */
20
+ const validateCoreMemberData = (inputMemberData) => {
21
+ // Check memberid
22
+ if (!inputMemberData?.memberid) {
23
+ console.warn('validateCoreMemberData: Missing required field - memberid is mandatory');
24
+ return false;
25
+ }
26
+
27
+ // Check email
28
+ if (!inputMemberData?.email ||
29
+ typeof inputMemberData.email !== 'string' ||
30
+ !inputMemberData.email.trim()) {
31
+ console.warn('validateCoreMemberData: Missing required field - email (valid string) is mandatory');
32
+ return false;
33
+ }
34
+
35
+ // Check memberships
36
+ if (!inputMemberData?.memberships || !Array.isArray(inputMemberData.memberships) || inputMemberData.memberships.length === 0) {
37
+ console.warn('validateCoreMemberData: Missing required field - memberships (non-empty array) is mandatory');
38
+ return false;
39
+ }
40
+
41
+ return true;
42
+ };
43
+
44
+ /**
45
+ * Creates base member data structure with core properties
46
+ * @param {Object} inputMemberData - Raw member data from API
47
+ * @param {Object} existingDbMember - Existing member data from database
48
+ * @param {number} currentPageNumber - Current page number being processed
49
+ * @returns {Object|null} - Structured base member data or null if required fields are missing
50
+ */
51
+ const createCoreMemberData = (
52
+ inputMemberData,
53
+ existingDbMember,
54
+ currentPageNumber
55
+ ) => {
56
+ // Validate required fields
57
+ if (!validateCoreMemberData(inputMemberData)) {
58
+ return null;
59
+ }
60
+
61
+ const sanitizedFirstName = inputMemberData.firstname?.trim() || '';
62
+ const sanitizedLastName = inputMemberData.lastname?.trim() || '';
63
+ const bookingUrl = inputMemberData.migrationData?.schedule_code?.startsWith('http') ? inputMemberData.migrationData?.schedule_code : '';
64
+ return {
65
+ ...existingDbMember,
66
+ memberId: inputMemberData.memberid,
67
+ firstName: sanitizedFirstName,
68
+ lastName: sanitizedLastName,
69
+ fullName: createFullName(sanitizedFirstName, sanitizedLastName),
70
+ email: inputMemberData.email.trim(),
71
+ phones: inputMemberData.phones || [],
72
+ toShowPhone: inputMemberData.migrationData?.show_phone || '',
73
+ action: inputMemberData.action,
74
+ licenses: inputMemberData.licenses || [],
75
+ memberships: inputMemberData.memberships,
76
+ pageNumber: currentPageNumber,
77
+ optOut: inputMemberData.migrationData?.opted_out || false,
78
+ showABMP: inputMemberData.migrationData?.show_member_since || false,
79
+ locHash: generateGeoHash(inputMemberData.addresses || []),
80
+ ...DEFAULT_MEMBER_DISPLAY_SETTINGS,
81
+ isVisible: inputMemberData.action !== MEMBER_ACTIONS.DROP,
82
+ url: inputMemberData.url,
83
+ bookingUrl,
84
+ APIBookingUrl: inputMemberData.migrationData?.schedule_code,//keeping it as a ref if in future they want original
85
+ };
86
+ };
87
+
88
+ /**
89
+ * Enriches member data with optional migration properties
90
+ * @param {Object} memberDataToUpdate - Member data object to enhance
91
+ * @param {Object} migrationData - Migration data containing optional properties
92
+ */
93
+ const enrichWithMigrationData = (memberDataToUpdate, migrationData) => {
94
+ if (!migrationData) return;
95
+
96
+ memberDataToUpdate.logoImage = migrationData.logo_url;
97
+ memberDataToUpdate.aboutYouHtml = migrationData.detailtext;
98
+ memberDataToUpdate.addressInfo = migrationData.addressinfo;
99
+
100
+
101
+ if (migrationData.website) {
102
+ memberDataToUpdate.website = migrationData.website;
103
+ memberDataToUpdate.showWebsite = true;
104
+ }
105
+
106
+ if (migrationData.interests) {
107
+ memberDataToUpdate.areasOfPractices = processInterests(
108
+ migrationData.interests
109
+ );
110
+ }
111
+ };
112
+
113
+ /**
114
+ * Processes multiple addresses with their display statuses
115
+ * @param {Array} addressesList - Array of address objects
116
+ * @param {Object} displayConfiguration - Address display configuration
117
+ * @returns {Array} - Processed addresses with status information
118
+ */
119
+ const processAddressesWithStatus = (
120
+ addressesList,
121
+ displayConfiguration = {}
122
+ ) => {
123
+ if (!isValidArray(addressesList)) {
124
+ return [];
125
+ }
126
+
127
+ return addressesList.map((address) => {
128
+ const displayStatus = displayConfiguration[address.key]
129
+ ? determineAddressDisplayStatus(displayConfiguration[address.key])
130
+ : ADDRESS_STATUS_TYPES.STATE_CITY_ZIP;
131
+
132
+ return {
133
+ ...address,
134
+ addressStatus: displayStatus,
135
+ };
136
+ });
137
+ };
138
+
139
+ /**
140
+ * Processes and adds address data with proper status
141
+ * @param {Object} memberDataToUpdate - Member data object to enhance
142
+ * @param {Array} addressesList - Array of address objects
143
+ * @param {Object} addressDisplayInfo - Address visibility configuration
144
+ */
145
+ const enrichWithAddressData = (
146
+ memberDataToUpdate,
147
+ addressesList,
148
+ addressDisplayInfo
149
+ ) => {
150
+ if (isValidArray(addressesList)) {
151
+ memberDataToUpdate.addresses = processAddressesWithStatus(
152
+ addressesList,
153
+ addressDisplayInfo
154
+ );
155
+ }
156
+ };
157
+
158
+ /**
159
+ * Generates complete updated member data by combining existing and migration data
160
+ * @param {Object} inputMemberData - Raw member data from API
161
+ * @param {number} currentPageNumber - Current page number being processed
162
+ * @returns {Promise<Object|null>} - Complete updated member data or null if validation fails
163
+ */
164
+ const generateUpdatedMemberData = async (
165
+ inputMemberData,
166
+ currentPageNumber,
167
+ isVelo = false
168
+ ) => {
169
+ if (!validateCoreMemberData(inputMemberData)) {
170
+ throw new Error('Invalid member data: memberid, email (valid string), and memberships (array) are required');
171
+ }
172
+
173
+ try {
174
+
175
+ const existingDbMember = isVelo? await findMemberById(inputMemberData.memberid) : {};
176
+ const updatedMemberData = createCoreMemberData(
177
+ inputMemberData,
178
+ existingDbMember,
179
+ currentPageNumber
180
+ );
181
+
182
+ // If createCoreMemberData returns null due to validation failure, return null
183
+ if (!updatedMemberData) {
184
+ return null;
185
+ }
186
+
187
+ enrichWithMigrationData(updatedMemberData, inputMemberData.migrationData);
188
+
189
+ enrichWithAddressData(
190
+ updatedMemberData,
191
+ inputMemberData.addresses,
192
+ inputMemberData.migrationData?.addressinfo
193
+ );
194
+
195
+ return updatedMemberData;
196
+ } catch (error) {
197
+ throw error;
198
+ }
199
+ }
200
+
201
+ module.exports = {
202
+ validateCoreMemberData,
203
+ createCoreMemberData,
204
+ enrichWithMigrationData,
205
+ processAddressesWithStatus,
206
+ enrichWithAddressData,
207
+ generateUpdatedMemberData,
208
+ };
209
+
210
+
@@ -0,0 +1,134 @@
1
+ const {
2
+ ADDRESS_STATUS_TYPES,
3
+ ADDRESS_VISIBILITY_OPTIONS,
4
+ COLLECTIONS,
5
+ } = require('./consts.js');
6
+
7
+ /**
8
+ * Safely adds optional properties from source to target object
9
+ * @param {Object} targetObject - Object to add properties to
10
+ * @param {Object} sourceObject - Object to get properties from
11
+ * @param {string} sourcePropertyKey - Key to get from source
12
+ * @param {string} targetPropertyKey - Key to set on target (defaults to sourcePropertyKey)
13
+ */
14
+ const addOptionalProperty = (
15
+ targetObject,
16
+ sourceObject,
17
+ sourcePropertyKey,
18
+ targetPropertyKey = sourcePropertyKey
19
+ ) => {
20
+ if (sourceObject && sourceObject[sourcePropertyKey]) {
21
+ targetObject[targetPropertyKey] = sourceObject[sourcePropertyKey];
22
+ }
23
+ };
24
+
25
+ /**
26
+ * Safely trims a string value with fallback
27
+ * @param {string} value - The string to trim
28
+ * @param {string} fallback - Fallback value if input is invalid
29
+ * @returns {string} - The trimmed string or fallback
30
+ */
31
+ const safeTrim = (value, fallback = '') => {
32
+ return value ? value.toString().trim() : fallback;
33
+ };
34
+
35
+ /**
36
+ * Determines address display status based on visibility settings
37
+ * @param {string} visibilityValue - The address visibility value from migration data
38
+ * @returns {string} - The corresponding address status
39
+ */
40
+ const determineAddressDisplayStatus = (visibilityValue) => {
41
+ if (!visibilityValue) {
42
+ return ADDRESS_STATUS_TYPES.STATE_CITY_ZIP;
43
+ }
44
+
45
+ const normalizedValue = visibilityValue.trim().toLowerCase();
46
+
47
+ switch (normalizedValue) {
48
+ case ADDRESS_VISIBILITY_OPTIONS.ALL:
49
+ return ADDRESS_STATUS_TYPES.FULL_ADDRESS;
50
+ case ADDRESS_VISIBILITY_OPTIONS.NONE:
51
+ return ADDRESS_STATUS_TYPES.DONT_SHOW;
52
+ default:
53
+ return ADDRESS_STATUS_TYPES.STATE_CITY_ZIP;
54
+ }
55
+ };
56
+
57
+ /**
58
+ * Validates if input is a non-empty array
59
+ * @param {*} input - Input to validate
60
+ * @returns {boolean} - True if input is a non-empty array
61
+ */
62
+ const isValidArray = (input) => {
63
+ return Array.isArray(input) && input.length > 0;
64
+ };
65
+
66
+ /**
67
+ * Processes interests string into clean array
68
+ * @param {string} interestsString - Comma-separated interests string
69
+ * @returns {Array} - Array of trimmed, non-empty interests
70
+ */
71
+ const processInterests = (interestsString) => {
72
+ if (!interestsString) return [];
73
+
74
+ return interestsString
75
+ .split(',')
76
+ .map((interest) => interest.trim())
77
+ .filter((interest) => interest.length > 0);
78
+ };
79
+
80
+ /**
81
+ * Creates a full name from first and last name components
82
+ * @param {string} firstName - First name
83
+ * @param {string} lastName - Last name
84
+ * @returns {string} - Combined full name
85
+ */
86
+ const createFullName = (firstName, lastName) => {
87
+ const trimmedFirst = firstName?.trim() || '';
88
+ const trimmedLast = lastName?.trim() || '';
89
+ return `${trimmedFirst} ${trimmedLast}`.trim();
90
+ };
91
+
92
+ function generateGeoHash(addresses) {
93
+ const geohash = addresses
94
+ ?.filter((address) =>
95
+ isNaN(address?.latitude) && isNaN(address?.longitude) ? false : address
96
+ )
97
+ ?.map((address) =>
98
+ ngeohash.encode(address.latitude, address.longitude, PRECISION)
99
+ );
100
+ return geohash && geohash.length > 0 ? geohash : [];
101
+ }
102
+
103
+ /**
104
+ * Retrieves member data by member ID
105
+ * @param {string} memberId - The member ID to search for
106
+ * @returns {Promise<Object|null>} - Member data or null if not found
107
+ */
108
+ const findMemberById = async (memberId) => {
109
+ if (!memberId) {
110
+ throw new Error('Member ID is required');
111
+ }
112
+
113
+ try {
114
+ const queryResult = await wixData.query(COLLECTIONS.MEMBERS_DATA)
115
+ .eq("memberId", memberId)
116
+ .find({ suppressAuth: true });
117
+
118
+ return queryResult.items.length > 0 ? queryResult.items[0] : null;
119
+ } catch (error) {
120
+ throw new Error(`Failed to retrieve member data: ${error.message}`);
121
+ }
122
+ }
123
+
124
+ module.exports = {
125
+ addOptionalProperty,
126
+ safeTrim,
127
+ determineAddressDisplayStatus,
128
+ isValidArray,
129
+ processInterests,
130
+ createFullName,
131
+ generateGeoHash,
132
+ findMemberById,
133
+ };
134
+
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
- function helloNpm() {
2
- return "hello NPM"
3
- }
4
-
5
- module.exports = helloNpm
1
+ module.exports = {
2
+ ...require('./public'),
3
+ ...require('./pages'),
4
+ ...require('./backend'),
5
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abmp-npm",
3
- "version": "1.0.0",
3
+ "version": "1.7.2",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"