abmp-npm 1.8.38 → 1.8.39

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