abmp-npm 1.8.38 → 1.8.40

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.
@@ -1,161 +1,7 @@
1
- const {
2
- DEFAULT_SEO_DESCRIPTION,
3
- ADDRESS_STATUS_TYPES,
4
- ABMP_LOGO_URL,
5
- SITE_ASSOCIATION,
6
- MEMBERSHIPS_TYPES,
7
- formatAddress,
8
- getMainAddress,
9
- generateId,
10
- } = require('../public');
1
+ const { DEFAULT_SEO_DESCRIPTION, ABMP_LOGO_URL } = require('../public');
11
2
 
12
3
  const { getMemberBySlug } = require('./members-data-methods');
13
- const { formatDateToMonthYear } = require('./utils');
14
-
15
- /**
16
- * Generates SEO title for member profile
17
- * @param {string} fullName - Member's full name
18
- * @param {Array<string>} areasOfPractices - Member's areas of practice
19
- * @returns {string} SEO title
20
- */
21
- function generateSEOTitle(fullName, areasOfPractices) {
22
- return `${fullName}${
23
- areasOfPractices && areasOfPractices.length > 0
24
- ? ` | ${areasOfPractices.slice(0, 3).join(', ')}`
25
- : ''
26
- } | ABMP Member`;
27
- }
28
-
29
- /**
30
- * Strips HTML tags and decodes HTML entities from a string
31
- * @param {string} html - HTML string to clean
32
- * @returns {string} Cleaned text
33
- */
34
- function stripHtmlTags(html) {
35
- if (!html) return '';
36
- // Remove HTML tags and decode HTML entities
37
- return html
38
- .replace(/<[^>]*>/g, '') // Remove HTML tags
39
- .replace(/&nbsp;/g, ' ') // Replace non-breaking spaces
40
- .replace(/&amp;/g, '&') // Replace encoded ampersands
41
- .replace(/&lt;/g, '<') // Replace encoded less than
42
- .replace(/&gt;/g, '>') // Replace encoded greater than
43
- .replace(/&quot;/g, '"') // Replace encoded quotes
44
- .replace(/&#39;/g, "'") // Replace encoded apostrophes
45
- .replace(/\s+/g, ' ') // Replace multiple whitespace with single space
46
- .trim(); // Remove leading/trailing whitespace
47
- }
48
-
49
- /**
50
- * Check if member has student membership
51
- * @param {Object} member - Member object
52
- * @param {boolean} checkAssociation - Whether to check for specific association
53
- * @returns {boolean} True if member has student membership
54
- */
55
- function hasStudentMembership(member, checkAssociation) {
56
- const memberships = member?.memberships;
57
- if (!Array.isArray(memberships)) return false;
58
-
59
- return memberships.some(membership => {
60
- const isStudent = membership.membertype === MEMBERSHIPS_TYPES.STUDENT;
61
- const hasCorrectAssociation = !checkAssociation || membership.association === SITE_ASSOCIATION;
62
- return isStudent && hasCorrectAssociation;
63
- });
64
- }
65
-
66
- /**
67
- * Check if member should have student badge
68
- * @param {Object} member - Member object
69
- * @returns {boolean} True if should have badge
70
- */
71
- function shouldHaveStudentBadge(member) {
72
- return hasStudentMembership(member, true);
73
- }
74
-
75
- /**
76
- * Get addresses by status, excluding main address
77
- * @param {Array} addresses - All addresses
78
- * @param {Array} addressDisplayOption - Display options
79
- * @returns {Array} Processed addresses
80
- */
81
- function getAddressesByStatus(addresses = [], addressDisplayOption = []) {
82
- const visible = addresses.filter(addr => addr.addressStatus !== ADDRESS_STATUS_TYPES.DONT_SHOW);
83
- if (visible.length < 2) {
84
- return [];
85
- }
86
- const opts = Array.isArray(addressDisplayOption) ? addressDisplayOption : [];
87
- const mainOpt = opts.find(o => o.isMain);
88
- const mainKey = mainOpt ? mainOpt.key : visible[0].key;
89
- return visible
90
- .filter(addr => addr?.key !== mainKey)
91
- .map(addr => {
92
- const addressString = formatAddress(addr);
93
- return addressString ? { _id: generateId(), address: addressString } : null;
94
- })
95
- .filter(Boolean);
96
- }
97
-
98
- /**
99
- * Get member profile data formatted for display
100
- * @param {Object} member - Member object
101
- * @returns {Object} Formatted profile data
102
- */
103
- function getMemberProfileData(member) {
104
- if (!member) {
105
- throw new Error('member is required');
106
- }
107
-
108
- const addresses = member.addresses || [];
109
- const licenceNo = member.licenses
110
- ?.map(val => val.license)
111
- .filter(Boolean)
112
- .join(', ');
113
- const processedAddresses = getAddressesByStatus(member.addresses, member.addressDisplayOption);
114
-
115
- const memberships = member.memberships || [];
116
- const abmp = memberships.find(m => m.association === SITE_ASSOCIATION);
117
-
118
- const areasOfPractices =
119
- member.areasOfPractices
120
- ?.filter(item => typeof item === 'string' && item.trim().length > 0)
121
- .map(item => item.trim())
122
- .sort((a, b) =>
123
- a.localeCompare(b, undefined, {
124
- sensitivity: 'base',
125
- numeric: true,
126
- })
127
- ) || [];
128
-
129
- const mainAddress = getMainAddress(member.addressDisplayOption, addresses);
130
-
131
- return {
132
- mainAddress: mainAddress,
133
- testimonials: member.testimonial || [],
134
- licenceNo,
135
- processedAddresses,
136
- memberSince: (member.showABMP && abmp && formatDateToMonthYear(abmp?.membersince)) || '',
137
- shouldHaveStudentBadge: shouldHaveStudentBadge(member),
138
- logoImage: member.logoImage,
139
- fullName: member.fullName,
140
- profileImage: member.profileImage,
141
- showContactForm: member.showContactForm,
142
- bookingUrl: member.bookingUrl,
143
- aboutService: member.aboutService,
144
- businessName: (member.showBusinessName && member.businessName) || '',
145
- phone: member.toShowPhone || '',
146
- areasOfPractices,
147
- gallery: member.gallery,
148
- bannerImages: member.bannerImages,
149
- showWixUrl: member.showWixUrl,
150
- _id: member._id,
151
- url: member.url,
152
- city: mainAddress?.city || '',
153
- state: mainAddress?.state || '',
154
- isPrivateMember: member.memberships.some(
155
- membership => membership.membertype === MEMBERSHIPS_TYPES.PAC_STAFF
156
- ),
157
- };
158
- }
4
+ const { generateSEOTitle, stripHtmlTags, getMemberProfileData } = require('./routers-utils');
159
5
 
160
6
  /**
161
7
  * Profile router handler
@@ -333,6 +179,7 @@ function profileSiteMap(_sitemapRequest, _dependencies, _fetchAllItemsInParallel
333
179
  module.exports = {
334
180
  profileRouter,
335
181
  profileSiteMap,
182
+ // Re-export utilities for backward compatibility
336
183
  getMemberProfileData,
337
184
  generateSEOTitle,
338
185
  stripHtmlTags,
@@ -0,0 +1,158 @@
1
+ const { ADDRESS_STATUS_TYPES, SITE_ASSOCIATION, MEMBERSHIPS_TYPES } = require('../public');
2
+ const { formatAddress, generateId, getMainAddress } = require('../public/Utils/sharedUtils');
3
+
4
+ const { formatDateToMonthYear } = require('./utils');
5
+
6
+ /**
7
+ * Generates SEO title for member profile
8
+ * @param {string} fullName - Member's full name
9
+ * @param {Array<string>} areasOfPractices - Member's areas of practice
10
+ * @returns {string} SEO title
11
+ */
12
+ function generateSEOTitle(fullName, areasOfPractices) {
13
+ return `${fullName}${
14
+ areasOfPractices && areasOfPractices.length > 0
15
+ ? ` | ${areasOfPractices.slice(0, 3).join(', ')}`
16
+ : ''
17
+ } | ABMP Member`;
18
+ }
19
+
20
+ /**
21
+ * Strips HTML tags and decodes HTML entities from a string
22
+ * @param {string} html - HTML string to clean
23
+ * @returns {string} Cleaned text
24
+ */
25
+ function stripHtmlTags(html) {
26
+ if (!html) return '';
27
+ // Remove HTML tags and decode HTML entities
28
+ return html
29
+ .replace(/<[^>]*>/g, '') // Remove HTML tags
30
+ .replace(/&nbsp;/g, ' ') // Replace non-breaking spaces
31
+ .replace(/&amp;/g, '&') // Replace encoded ampersands
32
+ .replace(/&lt;/g, '<') // Replace encoded less than
33
+ .replace(/&gt;/g, '>') // Replace encoded greater than
34
+ .replace(/&quot;/g, '"') // Replace encoded quotes
35
+ .replace(/&#39;/g, "'") // Replace encoded apostrophes
36
+ .replace(/\s+/g, ' ') // Replace multiple whitespace with single space
37
+ .trim(); // Remove leading/trailing whitespace
38
+ }
39
+
40
+ /**
41
+ * Check if member has student membership
42
+ * @param {Object} member - Member object
43
+ * @param {boolean} checkAssociation - Whether to check for specific association
44
+ * @returns {boolean} True if member has student membership
45
+ */
46
+ function hasStudentMembership(member, checkAssociation) {
47
+ const memberships = member?.memberships;
48
+ if (!Array.isArray(memberships)) return false;
49
+
50
+ return memberships.some(membership => {
51
+ const isStudent = membership.membertype === MEMBERSHIPS_TYPES.STUDENT;
52
+ const hasCorrectAssociation = !checkAssociation || membership.association === SITE_ASSOCIATION;
53
+ return isStudent && hasCorrectAssociation;
54
+ });
55
+ }
56
+
57
+ /**
58
+ * Check if member should have student badge
59
+ * @param {Object} member - Member object
60
+ * @returns {boolean} True if should have badge
61
+ */
62
+ function shouldHaveStudentBadge(member) {
63
+ return hasStudentMembership(member, true);
64
+ }
65
+
66
+ /**
67
+ * Get addresses by status, excluding main address
68
+ * @param {Array} addresses - All addresses
69
+ * @param {Array} addressDisplayOption - Display options
70
+ * @returns {Array} Processed addresses
71
+ */
72
+ function getAddressesByStatus(addresses = [], addressDisplayOption = []) {
73
+ const visible = addresses.filter(addr => addr.addressStatus !== ADDRESS_STATUS_TYPES.DONT_SHOW);
74
+ if (visible.length < 2) {
75
+ return [];
76
+ }
77
+ const opts = Array.isArray(addressDisplayOption) ? addressDisplayOption : [];
78
+ const mainOpt = opts.find(o => o.isMain);
79
+ const mainKey = mainOpt ? mainOpt.key : visible[0].key;
80
+ return visible
81
+ .filter(addr => addr?.key !== mainKey)
82
+ .map(addr => {
83
+ const addressString = formatAddress(addr);
84
+ return addressString ? { _id: generateId(), address: addressString } : null;
85
+ })
86
+ .filter(Boolean);
87
+ }
88
+
89
+ /**
90
+ * Get member profile data formatted for display
91
+ * @param {Object} member - Member object
92
+ * @returns {Object} Formatted profile data
93
+ */
94
+ function getMemberProfileData(member) {
95
+ if (!member) {
96
+ throw new Error('member is required');
97
+ }
98
+
99
+ const addresses = member.addresses || [];
100
+ const licenceNo = member.licenses
101
+ ?.map(val => val.license)
102
+ .filter(Boolean)
103
+ .join(', ');
104
+ const processedAddresses = getAddressesByStatus(member.addresses, member.addressDisplayOption);
105
+
106
+ const memberships = member.memberships || [];
107
+ const abmp = memberships.find(m => m.association === SITE_ASSOCIATION);
108
+
109
+ const areasOfPractices =
110
+ member.areasOfPractices
111
+ ?.filter(item => typeof item === 'string' && item.trim().length > 0)
112
+ .map(item => item.trim())
113
+ .sort((a, b) =>
114
+ a.localeCompare(b, undefined, {
115
+ sensitivity: 'base',
116
+ numeric: true,
117
+ })
118
+ ) || [];
119
+
120
+ const mainAddress = getMainAddress(member.addressDisplayOption, addresses);
121
+
122
+ return {
123
+ mainAddress: mainAddress,
124
+ testimonials: member.testimonial || [],
125
+ licenceNo,
126
+ processedAddresses,
127
+ memberSince: (member.showABMP && abmp && formatDateToMonthYear(abmp?.membersince)) || '',
128
+ shouldHaveStudentBadge: shouldHaveStudentBadge(member),
129
+ logoImage: member.logoImage,
130
+ fullName: member.fullName,
131
+ profileImage: member.profileImage,
132
+ showContactForm: member.showContactForm,
133
+ bookingUrl: member.bookingUrl,
134
+ aboutService: member.aboutService,
135
+ businessName: (member.showBusinessName && member.businessName) || '',
136
+ phone: member.toShowPhone || '',
137
+ areasOfPractices,
138
+ gallery: member.gallery,
139
+ bannerImages: member.bannerImages,
140
+ showWixUrl: member.showWixUrl,
141
+ _id: member._id,
142
+ url: member.url,
143
+ city: mainAddress?.city || '',
144
+ state: mainAddress?.state || '',
145
+ isPrivateMember: member.memberships.some(
146
+ membership => membership.membertype === MEMBERSHIPS_TYPES.PAC_STAFF
147
+ ),
148
+ };
149
+ }
150
+
151
+ module.exports = {
152
+ generateSEOTitle,
153
+ stripHtmlTags,
154
+ hasStudentMembership,
155
+ shouldHaveStudentBadge,
156
+ getAddressesByStatus,
157
+ getMemberProfileData,
158
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abmp-npm",
3
- "version": "1.8.38",
3
+ "version": "1.8.40",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",
@@ -168,4 +168,5 @@ module.exports = {
168
168
  calculateDistance,
169
169
  toRadians,
170
170
  generateId,
171
+ formatAddress,
171
172
  };