abmp-npm 2.0.76 → 2.0.78
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/package.json +8 -1
- package/pages/Home.js +27 -55
- package/pages/index.js +0 -1
- package/public/Utils/personalDetailsUtils.js +5 -1
- package/public/Utils/sharedUtils.js +32 -0
- package/public/consts.js +0 -1
- package/.claude/worktrees/fix-save-button-disable/.husky/pre-commit +0 -19
- package/.claude/worktrees/fix-save-button-disable/.prettierignore +0 -7
- package/.claude/worktrees/fix-save-button-disable/.prettierrc.json +0 -16
- package/.claude/worktrees/fix-save-button-disable/README.md +0 -1
- package/.claude/worktrees/fix-save-button-disable/backend/README-member-contact-flows.md +0 -136
- package/.claude/worktrees/fix-save-button-disable/backend/__tests__/daily-pull-execution-check.test.js +0 -124
- package/.claude/worktrees/fix-save-button-disable/backend/__tests__/ensure-unique-urls-in-batch.test.js +0 -129
- package/.claude/worktrees/fix-save-button-disable/backend/__tests__/login-email-sync.test.js +0 -49
- package/.claude/worktrees/fix-save-button-disable/backend/__tests__/transient-retry-and-bulk-lookup.test.js +0 -129
- package/.claude/worktrees/fix-save-button-disable/backend/__tests__/url-uniqueness.test.js +0 -194
- package/.claude/worktrees/fix-save-button-disable/backend/automations-methods.js +0 -13
- package/.claude/worktrees/fix-save-button-disable/backend/cms-data-methods.js +0 -251
- package/.claude/worktrees/fix-save-button-disable/backend/consts.js +0 -58
- package/.claude/worktrees/fix-save-button-disable/backend/contacts-methods.js +0 -67
- package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/bulk-process-methods.js +0 -222
- package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/consts.js +0 -39
- package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/index.js +0 -5
- package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/process-member-methods.js +0 -213
- package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/schedule-methods.js +0 -41
- package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/sync-to-cms-methods.js +0 -161
- package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/utils.js +0 -151
- package/.claude/worktrees/fix-save-button-disable/backend/data-hooks.js +0 -29
- package/.claude/worktrees/fix-save-button-disable/backend/dev-only-methods.js +0 -58
- package/.claude/worktrees/fix-save-button-disable/backend/elevated-modules.js +0 -18
- package/.claude/worktrees/fix-save-button-disable/backend/forms-methods.js +0 -52
- package/.claude/worktrees/fix-save-button-disable/backend/http-functions/httpFunctions.js +0 -86
- package/.claude/worktrees/fix-save-button-disable/backend/http-functions/index.js +0 -3
- package/.claude/worktrees/fix-save-button-disable/backend/http-functions/interests.js +0 -35
- package/.claude/worktrees/fix-save-button-disable/backend/index.js +0 -19
- package/.claude/worktrees/fix-save-button-disable/backend/jobs.js +0 -158
- package/.claude/worktrees/fix-save-button-disable/backend/login/generate-member-session-token.js +0 -27
- package/.claude/worktrees/fix-save-button-disable/backend/login/index.js +0 -8
- package/.claude/worktrees/fix-save-button-disable/backend/login/qa-login-methods.js +0 -54
- package/.claude/worktrees/fix-save-button-disable/backend/login/sso-methods.js +0 -159
- package/.claude/worktrees/fix-save-button-disable/backend/member-contact-orchestration.js +0 -111
- package/.claude/worktrees/fix-save-button-disable/backend/members-area-methods.js +0 -88
- package/.claude/worktrees/fix-save-button-disable/backend/members-data-methods.js +0 -789
- package/.claude/worktrees/fix-save-button-disable/backend/pac-api-methods.js +0 -54
- package/.claude/worktrees/fix-save-button-disable/backend/routers/index.js +0 -3
- package/.claude/worktrees/fix-save-button-disable/backend/routers/methods.js +0 -191
- package/.claude/worktrees/fix-save-button-disable/backend/routers/utils.js +0 -128
- package/.claude/worktrees/fix-save-button-disable/backend/search-filters-methods.js +0 -124
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/address-primary-methods.js +0 -256
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/address-visibility-methods.js +0 -160
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/consts.js +0 -34
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/daily-pull-check-methods.js +0 -78
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/email-normalize-methods.js +0 -134
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/index.js +0 -10
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/migration-methods.js +0 -46
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/tasks-configs.js +0 -251
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/tasks-helpers-methods.js +0 -433
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/tasks-process-methods.js +0 -606
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/url-migration-methods.js +0 -378
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/url-space-fix-methods.js +0 -174
- package/.claude/worktrees/fix-save-button-disable/backend/utils.js +0 -277
- package/.claude/worktrees/fix-save-button-disable/dev-only-scripts/extract-duplicate-url-groups.js +0 -201
- package/.claude/worktrees/fix-save-button-disable/dev-only-scripts/find-duplicate-ids.js +0 -159
- package/.claude/worktrees/fix-save-button-disable/dev-only-scripts/find-duplicate-urls.js +0 -201
- package/.claude/worktrees/fix-save-button-disable/eslint.config.js +0 -120
- package/.claude/worktrees/fix-save-button-disable/index.js +0 -5
- package/.claude/worktrees/fix-save-button-disable/package-lock.json +0 -12160
- package/.claude/worktrees/fix-save-button-disable/package.json +0 -60
- package/.claude/worktrees/fix-save-button-disable/pages/ContactUs.js +0 -129
- package/.claude/worktrees/fix-save-button-disable/pages/Home.js +0 -779
- package/.claude/worktrees/fix-save-button-disable/pages/LearnMore.js +0 -27
- package/.claude/worktrees/fix-save-button-disable/pages/LoadingPage.js +0 -29
- package/.claude/worktrees/fix-save-button-disable/pages/Profile.js +0 -354
- package/.claude/worktrees/fix-save-button-disable/pages/QAPage.js +0 -39
- package/.claude/worktrees/fix-save-button-disable/pages/SaveAlerts.js +0 -13
- package/.claude/worktrees/fix-save-button-disable/pages/SelectBannerImages.js +0 -46
- package/.claude/worktrees/fix-save-button-disable/pages/deleteConfirm.js +0 -19
- package/.claude/worktrees/fix-save-button-disable/pages/index.js +0 -12
- package/.claude/worktrees/fix-save-button-disable/pages/personalDetails.js +0 -2486
- package/.claude/worktrees/fix-save-button-disable/public/Utils/homePage.js +0 -798
- package/.claude/worktrees/fix-save-button-disable/public/Utils/personalDetailsUtils.js +0 -25
- package/.claude/worktrees/fix-save-button-disable/public/Utils/sharedUtils.js +0 -235
- package/.claude/worktrees/fix-save-button-disable/public/consts.js +0 -113
- package/.claude/worktrees/fix-save-button-disable/public/index.js +0 -5
- package/.claude/worktrees/fix-save-button-disable/public/messages.js +0 -16
- package/.claude/worktrees/fix-save-button-disable/public/sso-auth-methods.js +0 -43
- package/.husky/pre-commit +0 -19
- package/.prettierignore +0 -7
- package/.prettierrc.json +0 -16
- package/backend/__tests__/daily-pull-execution-check.test.js +0 -124
- package/backend/__tests__/ensure-unique-urls-in-batch.test.js +0 -129
- package/backend/__tests__/login-email-sync.test.js +0 -49
- package/backend/__tests__/transient-retry-and-bulk-lookup.test.js +0 -129
- package/backend/__tests__/url-uniqueness.test.js +0 -194
- package/dev-only-scripts/extract-duplicate-url-groups.js +0 -201
- package/dev-only-scripts/find-duplicate-ids.js +0 -159
- package/dev-only-scripts/find-duplicate-urls.js +0 -201
- package/eslint.config.js +0 -120
- package/pages/contactForLocation.js +0 -28
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
const axios = require('axios');
|
|
2
|
-
|
|
3
|
-
const { PAC_API_URL, TEST_PAC_API_URL, BACKUP_API_URL } = require('./consts');
|
|
4
|
-
const { getSecret } = require('./utils');
|
|
5
|
-
|
|
6
|
-
const getPacApiBaseUrl = ({ backupDate, isTestEnvironment }) =>
|
|
7
|
-
backupDate ? BACKUP_API_URL : isTestEnvironment ? TEST_PAC_API_URL : PAC_API_URL;
|
|
8
|
-
|
|
9
|
-
const getHeaders = async () => {
|
|
10
|
-
const AUTH_TOKEN = await getSecret('members-data-api-key');
|
|
11
|
-
const headers = {
|
|
12
|
-
Authorization: `Bearer ${AUTH_TOKEN}`,
|
|
13
|
-
};
|
|
14
|
-
return headers;
|
|
15
|
-
};
|
|
16
|
-
/**
|
|
17
|
-
*
|
|
18
|
-
* @param {*} params
|
|
19
|
-
* @param {number} params.page - The page number to fetch
|
|
20
|
-
* @param {string} params.action - The action to fetch
|
|
21
|
-
* @param {string} [params.backupDate] - Optional. The backup date to fetch in format YYYY-MM-DD, use only to fetch from backup endpoint not from PAC endpoint.
|
|
22
|
-
* @returns {Promise<Object>} - The response from the API
|
|
23
|
-
*/
|
|
24
|
-
const fetchPACMembers = async ({ page, action, backupDate, isTestEnvironment }) => {
|
|
25
|
-
const baseUrl = getPacApiBaseUrl({
|
|
26
|
-
backupDate,
|
|
27
|
-
isTestEnvironment,
|
|
28
|
-
});
|
|
29
|
-
const queryParams = { page, actionFilter: action };
|
|
30
|
-
if (backupDate) {
|
|
31
|
-
queryParams.date = backupDate;
|
|
32
|
-
}
|
|
33
|
-
const url = `${baseUrl}/Members?${new URLSearchParams(queryParams).toString()}`;
|
|
34
|
-
console.log(`Fetching PAC members from: ${url}`);
|
|
35
|
-
const headers = await getHeaders();
|
|
36
|
-
const response = await axios.get(url, {
|
|
37
|
-
headers,
|
|
38
|
-
validateStatus: () => true,
|
|
39
|
-
});
|
|
40
|
-
const responseType = response.headers['content-type'] || '';
|
|
41
|
-
if (!responseType.includes('application/json')) {
|
|
42
|
-
const errorMessage = `[fetchPACMembers] got invalid responseType: ${responseType} for page ${page} and actionFilter ${action}`;
|
|
43
|
-
console.error(errorMessage);
|
|
44
|
-
throw new Error(errorMessage);
|
|
45
|
-
}
|
|
46
|
-
if (response.status >= 200 && response.status < 300) {
|
|
47
|
-
return response.data;
|
|
48
|
-
}
|
|
49
|
-
const errorMessage = `[fetchPACMembers] failed with status ${response.status} for page ${page} and actionFilter ${action}`;
|
|
50
|
-
console.error(errorMessage);
|
|
51
|
-
throw new Error(errorMessage);
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
module.exports = { fetchPACMembers, getHeaders }; //TODO: remove getHeaders from exported methods once npm movement finishes
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
const { PAGES_PATHS } = require('../../public/consts');
|
|
2
|
-
const { isWixHostedImage } = require('../../public/Utils/sharedUtils');
|
|
3
|
-
//const { fetchAllItemsInParallel } = require('../cms-data-methods'); unused at host site
|
|
4
|
-
const { CONFIG_KEYS } = require('../consts');
|
|
5
|
-
const { getSiteConfigs } = require('../utils');
|
|
6
|
-
|
|
7
|
-
const { generateSEOTitle, stripHtmlTags, getMemberProfileData } = require('./utils');
|
|
8
|
-
|
|
9
|
-
const createRoutersHandlers = wixRouterMethods => {
|
|
10
|
-
const {
|
|
11
|
-
redirect,
|
|
12
|
-
ok,
|
|
13
|
-
notFound,
|
|
14
|
-
sendStatus,
|
|
15
|
-
WixRouterSitemapEntry: _WixRouterSitemapEntry,
|
|
16
|
-
} = wixRouterMethods; // These dependencies needs to be injected as they do not have an SDK equivalent for now
|
|
17
|
-
|
|
18
|
-
async function profileRouter(request) {
|
|
19
|
-
const slug = request.path[0];
|
|
20
|
-
if (!slug) {
|
|
21
|
-
return redirect(request.baseUrl);
|
|
22
|
-
}
|
|
23
|
-
try {
|
|
24
|
-
const siteConfigs = await getSiteConfigs();
|
|
25
|
-
const siteAssociation = siteConfigs[CONFIG_KEYS.SITE_ASSOCIATION];
|
|
26
|
-
const defaultSEODescription = siteConfigs[CONFIG_KEYS.DEFAULT_PROFILE_SEO_DESCRIPTION];
|
|
27
|
-
const siteLogoUrl = siteConfigs[CONFIG_KEYS.SITE_LOGO_URL];
|
|
28
|
-
const defaultProfileImage = siteConfigs[CONFIG_KEYS.DEFAULT_PROFILE_IMAGE];
|
|
29
|
-
const profileData = await getMemberProfileData(slug, siteAssociation);
|
|
30
|
-
if (profileData && profileData.showWixUrl) {
|
|
31
|
-
const profileImage =
|
|
32
|
-
profileData.profileImage?.trim() && isWixHostedImage(profileData.profileImage)
|
|
33
|
-
? profileData.profileImage
|
|
34
|
-
: defaultProfileImage;
|
|
35
|
-
const ogImage = profileImage || profileData.logoImage || siteLogoUrl;
|
|
36
|
-
const seoTitle = generateSEOTitle({
|
|
37
|
-
fullName: profileData.fullName,
|
|
38
|
-
areasOfPractices: profileData.areasOfPractices,
|
|
39
|
-
siteAssociation,
|
|
40
|
-
});
|
|
41
|
-
// Use stripped HTML from aboutService rich text content
|
|
42
|
-
let description = stripHtmlTags(profileData.aboutService) || defaultSEODescription;
|
|
43
|
-
|
|
44
|
-
// Limit description to 160 characters for optimal SEO
|
|
45
|
-
if (description.length > 160) {
|
|
46
|
-
description = description.substring(0, 157) + '...';
|
|
47
|
-
}
|
|
48
|
-
const profileUrl = `${request.baseUrl}/${PAGES_PATHS.PROFILE}/${profileData.url}`;
|
|
49
|
-
const isPrivateMember = profileData.isPrivateMember;
|
|
50
|
-
const isStudent = profileData.shouldHaveStudentBadge;
|
|
51
|
-
const shouldNoIndex = isPrivateMember || isStudent;
|
|
52
|
-
const seoData = {
|
|
53
|
-
title: seoTitle,
|
|
54
|
-
description: description,
|
|
55
|
-
noIndex: shouldNoIndex,
|
|
56
|
-
metaTags: [
|
|
57
|
-
{
|
|
58
|
-
name: 'description',
|
|
59
|
-
content: description,
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
name: 'keywords',
|
|
63
|
-
content:
|
|
64
|
-
`${profileData.fullName}, ${profileData.areasOfPractices ? profileData.areasOfPractices.slice(0, 3).join(', ') : ''}, ${siteAssociation}, ${profileData.city || ''}, ${profileData.state || ''}`
|
|
65
|
-
.replace(/,\s*,/g, ',')
|
|
66
|
-
.replace(/^,|,$/g, ''),
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
name: 'author',
|
|
70
|
-
content: profileData.fullName,
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
name: 'robots',
|
|
74
|
-
content: shouldNoIndex ? 'noindex, nofollow' : 'index, follow',
|
|
75
|
-
},
|
|
76
|
-
// Open Graph tags
|
|
77
|
-
{
|
|
78
|
-
property: 'og:type',
|
|
79
|
-
content: 'profile',
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
property: 'og:title',
|
|
83
|
-
content: seoTitle,
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
property: 'og:description',
|
|
87
|
-
content: description,
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
property: 'og:image',
|
|
91
|
-
content: ogImage,
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
property: 'og:url',
|
|
95
|
-
content: profileUrl,
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
property: 'og:site_name',
|
|
99
|
-
content: `${siteAssociation} Members`,
|
|
100
|
-
},
|
|
101
|
-
// Twitter Card tags
|
|
102
|
-
{
|
|
103
|
-
name: 'twitter:card',
|
|
104
|
-
content: 'summary_large_image',
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
name: 'twitter:title',
|
|
108
|
-
content: seoTitle,
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
name: 'twitter:description',
|
|
112
|
-
content: description,
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
name: 'twitter:image',
|
|
116
|
-
content: ogImage,
|
|
117
|
-
},
|
|
118
|
-
// Additional SEO tags
|
|
119
|
-
{
|
|
120
|
-
name: 'geo.region',
|
|
121
|
-
content: profileData.state || '',
|
|
122
|
-
},
|
|
123
|
-
{
|
|
124
|
-
name: 'geo.placename',
|
|
125
|
-
content: profileData.city || '',
|
|
126
|
-
},
|
|
127
|
-
].filter(tag => tag.content && tag.content.trim() !== ''), // Remove empty tags
|
|
128
|
-
};
|
|
129
|
-
return ok('profile', { ...profileData, defaultProfileImage }, seoData);
|
|
130
|
-
}
|
|
131
|
-
console.log(
|
|
132
|
-
`[profileRouter] Profile not found returning 404 for: ${JSON.stringify({
|
|
133
|
-
slug,
|
|
134
|
-
profileData,
|
|
135
|
-
showWixUrl: profileData?.showWixUrl,
|
|
136
|
-
})}`
|
|
137
|
-
);
|
|
138
|
-
return notFound();
|
|
139
|
-
} catch (error) {
|
|
140
|
-
console.error(`Error in profileRouter for slug: ${slug} : ${error.message}`);
|
|
141
|
-
return sendStatus('500', 'Internal Server Error');
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
function profileSiteMap(_sitemapRequest) {
|
|
145
|
-
return [];
|
|
146
|
-
// Commented out - currently disabled in host site
|
|
147
|
-
// try {
|
|
148
|
-
// const membersQuery = wixData
|
|
149
|
-
// .query(COLLECTIONS.MEMBERS_DATA)
|
|
150
|
-
// .eq('showWixUrl', true)
|
|
151
|
-
// .isNotEmpty('url')
|
|
152
|
-
// .ne('action', 'drop')
|
|
153
|
-
// .fields('url', 'fullName');
|
|
154
|
-
|
|
155
|
-
// const allMembers = await fetchAllItemsInParallel(membersQuery);
|
|
156
|
-
|
|
157
|
-
// const batchSize = 1000;
|
|
158
|
-
// const sitemapEntries = [];
|
|
159
|
-
// const totalItems = allMembers.items.length;
|
|
160
|
-
|
|
161
|
-
// for (let i = 0; i < totalItems; i += batchSize) {
|
|
162
|
-
// const batch = allMembers.items.slice(i, i + batchSize);
|
|
163
|
-
// const batchEntries = batch.map(member => {
|
|
164
|
-
// const entry = new WixRouterSitemapEntry(member.fullName);
|
|
165
|
-
// entry.pageName = 'profile';
|
|
166
|
-
// entry.url = `${PAGES_PATHS.PROFILE}/${member.url}`;
|
|
167
|
-
// entry.title = member.fullName;
|
|
168
|
-
// entry.changeFrequency = 'monthly';
|
|
169
|
-
// entry.priority = 1.0;
|
|
170
|
-
// return entry;
|
|
171
|
-
// });
|
|
172
|
-
// sitemapEntries.push(...batchEntries);
|
|
173
|
-
// }
|
|
174
|
-
|
|
175
|
-
// return sitemapEntries;
|
|
176
|
-
// } catch (error) {
|
|
177
|
-
// console.error('Error generating profile sitemap:', error);
|
|
178
|
-
// return [];
|
|
179
|
-
// }
|
|
180
|
-
}
|
|
181
|
-
//Add other routers here
|
|
182
|
-
return {
|
|
183
|
-
profileRouter,
|
|
184
|
-
profileSiteMap,
|
|
185
|
-
//Add other routers here
|
|
186
|
-
};
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
module.exports = {
|
|
190
|
-
createRoutersHandlers,
|
|
191
|
-
};
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
const { getMainAddress } = require('../../public/Utils/sharedUtils');
|
|
2
|
-
const { getMemberBySlug } = require('../members-data-methods');
|
|
3
|
-
const {
|
|
4
|
-
getMoreAddressesToDisplay,
|
|
5
|
-
formatDateToMonthYear,
|
|
6
|
-
hasStudentMembership,
|
|
7
|
-
isPAC_STAFF,
|
|
8
|
-
} = require('../utils');
|
|
9
|
-
|
|
10
|
-
function generateSEOTitle({ fullName, areasOfPractices, siteAssociation }) {
|
|
11
|
-
return `${fullName}${
|
|
12
|
-
areasOfPractices && areasOfPractices.length > 0
|
|
13
|
-
? ` | ${areasOfPractices.slice(0, 3).join(', ')}`
|
|
14
|
-
: ''
|
|
15
|
-
} | ${siteAssociation} Member`;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function stripHtmlTags(html) {
|
|
19
|
-
if (!html) return '';
|
|
20
|
-
// Remove HTML tags and decode HTML entities
|
|
21
|
-
return html
|
|
22
|
-
.replace(/<[^>]*>/g, '') // Remove HTML tags
|
|
23
|
-
.replace(/ /g, ' ') // Replace non-breaking spaces
|
|
24
|
-
.replace(/&/g, '&') // Replace encoded ampersands
|
|
25
|
-
.replace(/</g, '<') // Replace encoded less than
|
|
26
|
-
.replace(/>/g, '>') // Replace encoded greater than
|
|
27
|
-
.replace(/"/g, '"') // Replace encoded quotes
|
|
28
|
-
.replace(/'/g, "'") // Replace encoded apostrophes
|
|
29
|
-
.replace(/\s+/g, ' ') // Replace multiple whitespace with single space
|
|
30
|
-
.trim(); // Remove leading/trailing whitespace
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function shouldHaveStudentBadge(member, siteAssociation) {
|
|
34
|
-
return hasStudentMembership({
|
|
35
|
-
member,
|
|
36
|
-
checkAssociation: true,
|
|
37
|
-
siteAssociation,
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function transformMemberToProfileData(member, siteAssociation) {
|
|
42
|
-
if (!member) {
|
|
43
|
-
throw new Error('member is required');
|
|
44
|
-
}
|
|
45
|
-
const addresses = member.addresses || [];
|
|
46
|
-
const mainAddress = getMainAddress(member.addressDisplayOption, addresses);
|
|
47
|
-
const licenceNo = member.licenses
|
|
48
|
-
?.map(val => val.license)
|
|
49
|
-
.filter(Boolean)
|
|
50
|
-
.join(', ');
|
|
51
|
-
const moreAddressesToDisplay = getMoreAddressesToDisplay(
|
|
52
|
-
member.addresses,
|
|
53
|
-
member.addressDisplayOption
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
const memberships = member.memberships || [];
|
|
57
|
-
const siteAssociationMembership = memberships.find(m => m.association === siteAssociation);
|
|
58
|
-
|
|
59
|
-
const areasOfPractices =
|
|
60
|
-
member.areasOfPractices
|
|
61
|
-
?.filter(item => typeof item === 'string' && item.trim().length > 0)
|
|
62
|
-
.map(item => item.trim())
|
|
63
|
-
.sort((a, b) =>
|
|
64
|
-
a.localeCompare(b, undefined, {
|
|
65
|
-
sensitivity: 'base',
|
|
66
|
-
numeric: true,
|
|
67
|
-
})
|
|
68
|
-
) || [];
|
|
69
|
-
|
|
70
|
-
const phones = Array.isArray(member.phones) ? member.phones : [];
|
|
71
|
-
const toShowPhone = member.toShowPhone || '';
|
|
72
|
-
const phone = toShowPhone && phones.includes(toShowPhone) ? toShowPhone : '';
|
|
73
|
-
|
|
74
|
-
return {
|
|
75
|
-
mainAddress,
|
|
76
|
-
testimonials: member.testimonial || [],
|
|
77
|
-
licenceNo,
|
|
78
|
-
moreAddressesToDisplay,
|
|
79
|
-
memberSince:
|
|
80
|
-
(member.showABMP &&
|
|
81
|
-
siteAssociationMembership &&
|
|
82
|
-
formatDateToMonthYear(siteAssociationMembership?.membersince)) ||
|
|
83
|
-
'',
|
|
84
|
-
shouldHaveStudentBadge: shouldHaveStudentBadge(member, siteAssociation),
|
|
85
|
-
logoImage: member.logoImage,
|
|
86
|
-
fullName: member.fullName,
|
|
87
|
-
profileImage: member.profileImage,
|
|
88
|
-
showContactForm: member.showContactForm,
|
|
89
|
-
bookingUrl: member.bookingUrl,
|
|
90
|
-
aboutService: member.aboutService,
|
|
91
|
-
businessName: (member.showBusinessName && member.businessName) || '',
|
|
92
|
-
phone,
|
|
93
|
-
areasOfPractices,
|
|
94
|
-
gallery: member.gallery,
|
|
95
|
-
bannerImages: member.bannerImages,
|
|
96
|
-
showWixUrl: member.showWixUrl,
|
|
97
|
-
_id: member._id,
|
|
98
|
-
url: member.url,
|
|
99
|
-
isPrivateMember: isPAC_STAFF(member),
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const getMemberProfileData = async (slug, siteAssociation) => {
|
|
104
|
-
try {
|
|
105
|
-
const member = await getMemberBySlug({
|
|
106
|
-
slug,
|
|
107
|
-
excludeDropped: true,
|
|
108
|
-
excludeSearchedMember: false,
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
if (!member) {
|
|
112
|
-
console.log(`[getMemberProfileData] Member not found for slug: ${slug}`);
|
|
113
|
-
return null;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return transformMemberToProfileData(member, siteAssociation);
|
|
117
|
-
} catch (error) {
|
|
118
|
-
const errorMessage = `Error in getMemberProfileData for slug: ${slug} : ${error.message}`;
|
|
119
|
-
console.error(errorMessage);
|
|
120
|
-
throw new Error(errorMessage);
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
module.exports = {
|
|
125
|
-
generateSEOTitle,
|
|
126
|
-
stripHtmlTags,
|
|
127
|
-
getMemberProfileData,
|
|
128
|
-
};
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
const { COLLECTIONS } = require('../public/consts');
|
|
2
|
-
|
|
3
|
-
const { buildMembersSearchQuery } = require('./cms-data-methods');
|
|
4
|
-
const { wixData } = require('./elevated-modules');
|
|
5
|
-
const { retrieveAllItems } = require('./utils');
|
|
6
|
-
|
|
7
|
-
const getCompiledFiltersOptions = () =>
|
|
8
|
-
wixData.get(COLLECTIONS.COMPILED_STATE_CITY_MAP, 'SINGLE_ITEM_ID');
|
|
9
|
-
|
|
10
|
-
const getNonCompiledFiltersOptions = async () => {
|
|
11
|
-
const [completeStateList, areasOfPracticesList, stateCityMapList] = await Promise.all([
|
|
12
|
-
getCompleteStateList(),
|
|
13
|
-
getAreasOfPracticeList(),
|
|
14
|
-
getStateCityMap(),
|
|
15
|
-
]);
|
|
16
|
-
return { completeStateList, areasOfPracticesList, stateCityMapList };
|
|
17
|
-
};
|
|
18
|
-
const filterProfiles = async data => {
|
|
19
|
-
const membersSearchQuery = buildMembersSearchQuery({ ...data, includeStudents: false });
|
|
20
|
-
const query = await membersSearchQuery.get();
|
|
21
|
-
return membersSearchQuery.run(query);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
async function getAreasOfPracticeList() {
|
|
25
|
-
const interestsData = await retrieveAllItems(COLLECTIONS.INTERESTS);
|
|
26
|
-
return interestsData.map(({ title }) => ({ label: title, value: title }));
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async function getStateCityMap() {
|
|
30
|
-
const getAllCitiesMap = async () => {
|
|
31
|
-
const totalCount = await wixData.query(COLLECTIONS.STATE_CITY_MAP).count();
|
|
32
|
-
const baseQuery = wixData.query(COLLECTIONS.STATE_CITY_MAP).limit(1000);
|
|
33
|
-
const batchedQueries = Array.from({ length: Math.ceil(totalCount / 1000) }, (_, i) =>
|
|
34
|
-
baseQuery.skip(i * 1000)
|
|
35
|
-
);
|
|
36
|
-
const allCities = await Promise.all(
|
|
37
|
-
batchedQueries.map(query => query.find({ omitTotalCount: true }).then(res => res.items))
|
|
38
|
-
);
|
|
39
|
-
return allCities.flat();
|
|
40
|
-
};
|
|
41
|
-
const allCities = await getAllCitiesMap();
|
|
42
|
-
const stateCityMap = new Map();
|
|
43
|
-
allCities.forEach(cityObj => {
|
|
44
|
-
const state = cityObj.stateText;
|
|
45
|
-
const city = cityObj.title;
|
|
46
|
-
const cityArray = stateCityMap.has(state) ? [...stateCityMap.get(state), city] : [city];
|
|
47
|
-
stateCityMap.set(state, cityArray);
|
|
48
|
-
});
|
|
49
|
-
return Object.fromEntries(stateCityMap);
|
|
50
|
-
}
|
|
51
|
-
//Besan comments on moved code: Below code assumes that Velo can cache value, however this isn't valid so it needs adjustment
|
|
52
|
-
// Cache for state list
|
|
53
|
-
let stateListCache = null;
|
|
54
|
-
let lastCacheTime = 0;
|
|
55
|
-
const CACHE_DURATION = 24 * 60 * 60 * 1000; // 24 hours in milliseconds
|
|
56
|
-
|
|
57
|
-
async function getCompleteStateList() {
|
|
58
|
-
// Check if we have a valid cache
|
|
59
|
-
const now = Date.now();
|
|
60
|
-
if (stateListCache && now - lastCacheTime < CACHE_DURATION) {
|
|
61
|
-
return stateListCache;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// 1. fire both queries at once:
|
|
65
|
-
const [stateRecords, memberStates] = await Promise.all([
|
|
66
|
-
retrieveAllItems(COLLECTIONS.STATE),
|
|
67
|
-
getMembersStateList(), //this method a
|
|
68
|
-
]);
|
|
69
|
-
|
|
70
|
-
const fullNameByCode = new Map(stateRecords.map(st => [st.title, st.name]));
|
|
71
|
-
|
|
72
|
-
const states = memberStates.map(({ value: code }) => ({
|
|
73
|
-
value: code,
|
|
74
|
-
label: fullNameByCode.get(code) || code,
|
|
75
|
-
}));
|
|
76
|
-
|
|
77
|
-
// Update cache
|
|
78
|
-
stateListCache = states;
|
|
79
|
-
lastCacheTime = now;
|
|
80
|
-
|
|
81
|
-
return states;
|
|
82
|
-
}
|
|
83
|
-
//Besan Comments on moved code: THIS WILL IGNORE SOME STATES VALUES while we should return all states AFAIU
|
|
84
|
-
async function getMembersStateList() {
|
|
85
|
-
try {
|
|
86
|
-
// Use a more efficient query to get only the addresses field
|
|
87
|
-
const results = await wixData
|
|
88
|
-
.query(COLLECTIONS.MEMBERS_DATA)
|
|
89
|
-
.fields('addresses')
|
|
90
|
-
.limit(1000)
|
|
91
|
-
.find();
|
|
92
|
-
|
|
93
|
-
// Extract all state codes from addresses
|
|
94
|
-
const allStates = new Set();
|
|
95
|
-
results.items.forEach(member => {
|
|
96
|
-
if (Array.isArray(member.addresses)) {
|
|
97
|
-
member.addresses.forEach(addr => {
|
|
98
|
-
if (addr.state) allStates.add(addr.state);
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
// Convert to array and sort
|
|
104
|
-
const uniqueStates = Array.from(allStates).sort();
|
|
105
|
-
|
|
106
|
-
// Map to label/value format
|
|
107
|
-
return uniqueStates.map(stateCode => ({
|
|
108
|
-
label: stateCode,
|
|
109
|
-
value: stateCode,
|
|
110
|
-
}));
|
|
111
|
-
} catch (error) {
|
|
112
|
-
console.error('Error in getMembersStateList:', error);
|
|
113
|
-
return [];
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
module.exports = {
|
|
118
|
-
getCompiledFiltersOptions,
|
|
119
|
-
getNonCompiledFiltersOptions,
|
|
120
|
-
filterProfiles,
|
|
121
|
-
getCompleteStateList,
|
|
122
|
-
getAreasOfPracticeList,
|
|
123
|
-
getStateCityMap,
|
|
124
|
-
};
|