abmp-npm 1.8.1 → 1.8.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/backend/cms-data-methods.js +209 -0
- package/backend/consts.js +7 -0
- package/backend/forms-methods.js +1 -1
- package/backend/index.js +1 -0
- package/backend/members-data-methods.js +1 -1
- package/backend/search-filters-methods.js +121 -0
- package/backend/utils.js +11 -0
- package/eslint.config.js +8 -1
- package/package.json +6 -2
- package/pages/Home.js +763 -0
- package/pages/Profile.js +12 -14
- package/pages/index.js +1 -0
- package/public/Utils/homePage.js +763 -0
- package/public/Utils/sharedUtils.js +162 -0
- package/public/consts.js +70 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
const { ADDRESS_STATUS_TYPES, DEBOUNCE_DELAY } = require('../consts.js');
|
|
2
|
+
|
|
3
|
+
const checkAddressIsVisible = (addresses = []) => {
|
|
4
|
+
// ensure we always get an array
|
|
5
|
+
if (!Array.isArray(addresses)) return [];
|
|
6
|
+
|
|
7
|
+
return addresses.filter(
|
|
8
|
+
val => val.addressStatus === undefined || val.addressStatus !== ADDRESS_STATUS_TYPES.DONT_SHOW
|
|
9
|
+
);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
//Formats an array of practice areas, showing as many as fit within 70 characters
|
|
13
|
+
function formatPracticeAreasForDisplay(areaOfPractices = []) {
|
|
14
|
+
// always return a string
|
|
15
|
+
if (!Array.isArray(areaOfPractices) || areaOfPractices.length === 0) {
|
|
16
|
+
return '';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Filter out null/undefined/empty
|
|
20
|
+
const validAreas = areaOfPractices.filter(
|
|
21
|
+
area => area !== null && area !== undefined && area !== ''
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
if (validAreas.length === 0) {
|
|
25
|
+
return '';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (validAreas.length === 1) {
|
|
29
|
+
return validAreas[0].length > 70 ? validAreas[0].substring(0, 67) + '...' : validAreas[0];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// build up to 70-char string
|
|
33
|
+
let current = '';
|
|
34
|
+
const visible = [];
|
|
35
|
+
for (const item of validAreas) {
|
|
36
|
+
const sep = visible.length ? ', ' : '';
|
|
37
|
+
const next = current + sep + item;
|
|
38
|
+
if (next.length > 70) break;
|
|
39
|
+
visible.push(item);
|
|
40
|
+
current = next;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// if nothing fit, at least show the first (truncated)
|
|
44
|
+
if (visible.length === 0) {
|
|
45
|
+
const first = validAreas[0];
|
|
46
|
+
return first.length > 67 ? first.substring(0, 67) + '...' : first;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const remaining = validAreas.length - visible.length;
|
|
50
|
+
return remaining > 0 ? `${visible.join(', ')}, +${remaining} Techniques` : visible.join(', ');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function debouncedFunction({ func, debounceTimeout, timeoutType, args }) {
|
|
54
|
+
return new Promise(resolve => {
|
|
55
|
+
debounceTimeout[timeoutType] = setTimeout(async () => {
|
|
56
|
+
try {
|
|
57
|
+
const response = await func(args);
|
|
58
|
+
resolve({ success: true, response });
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error('Error updating results:', error);
|
|
61
|
+
resolve({ success: false, error });
|
|
62
|
+
}
|
|
63
|
+
}, DEBOUNCE_DELAY[timeoutType]);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const isValidLocation = location => location.latitude && location.longitude;
|
|
68
|
+
|
|
69
|
+
function findMainAddress(addressDisplayOption = [], addresses = []) {
|
|
70
|
+
const options = Array.isArray(addressDisplayOption) ? addressDisplayOption : [];
|
|
71
|
+
const mainOpt = options.find(opt => opt.isMain);
|
|
72
|
+
if (mainOpt) {
|
|
73
|
+
const mainAddr = addresses.find(
|
|
74
|
+
addr => addr.key === mainOpt.key && addr.addressStatus !== ADDRESS_STATUS_TYPES.DONT_SHOW
|
|
75
|
+
);
|
|
76
|
+
if (mainAddr && isValidLocation(mainAddr)) {
|
|
77
|
+
return mainAddr;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// 2) fallback: if there is any visible address, use it
|
|
81
|
+
const visibleAddresses = addresses.filter(
|
|
82
|
+
addr => addr.addressStatus !== ADDRESS_STATUS_TYPES.DONT_SHOW && isValidLocation(addr)
|
|
83
|
+
);
|
|
84
|
+
if (visibleAddresses.length) {
|
|
85
|
+
return visibleAddresses[0];
|
|
86
|
+
}
|
|
87
|
+
return '';
|
|
88
|
+
}
|
|
89
|
+
function formatAddress(item) {
|
|
90
|
+
let addressParts = [];
|
|
91
|
+
const limitedPostalCode = item.postalcode.slice(0, 5); //show only 5 digits to not show full user address
|
|
92
|
+
switch (item.addressStatus) {
|
|
93
|
+
case ADDRESS_STATUS_TYPES.FULL_ADDRESS:
|
|
94
|
+
addressParts = [item.line1, item.city, item.state, limitedPostalCode];
|
|
95
|
+
break;
|
|
96
|
+
case ADDRESS_STATUS_TYPES.STATE_CITY_ZIP:
|
|
97
|
+
addressParts = [item.city, item.state, limitedPostalCode];
|
|
98
|
+
break;
|
|
99
|
+
default:
|
|
100
|
+
return '';
|
|
101
|
+
}
|
|
102
|
+
return addressParts.filter(Boolean).join(', ');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function getMainAddress(addressDisplayOption = [], addresses = []) {
|
|
106
|
+
const mainAddr = findMainAddress(addressDisplayOption, addresses);
|
|
107
|
+
if (mainAddr) {
|
|
108
|
+
return formatAddress(mainAddr);
|
|
109
|
+
}
|
|
110
|
+
return '';
|
|
111
|
+
}
|
|
112
|
+
function shuffleArray(array) {
|
|
113
|
+
const shuffled = [...array];
|
|
114
|
+
for (let i = shuffled.length - 1; i > 0; i--) {
|
|
115
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
116
|
+
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
|
|
117
|
+
}
|
|
118
|
+
return shuffled;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function toRadians(degrees) {
|
|
122
|
+
return degrees * (Math.PI / 180);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function calculateDistance(location1, location2) {
|
|
126
|
+
if (!isValidLocation(location1) || !isValidLocation(location2)) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Earth's radius in miles
|
|
131
|
+
const earthRadius = 3958.8;
|
|
132
|
+
|
|
133
|
+
// Convert latitude and longitude from degrees to radians
|
|
134
|
+
const latRad1 = toRadians(location1.latitude);
|
|
135
|
+
const lonRad1 = toRadians(location1.longitude);
|
|
136
|
+
const latRad2 = toRadians(location2.latitude);
|
|
137
|
+
const lonRad2 = toRadians(location2.longitude);
|
|
138
|
+
|
|
139
|
+
// Differences in coordinates
|
|
140
|
+
const latDiff = latRad2 - latRad1;
|
|
141
|
+
const lonDiff = lonRad2 - lonRad1;
|
|
142
|
+
|
|
143
|
+
// Haversine formula
|
|
144
|
+
const a =
|
|
145
|
+
Math.sin(latDiff / 2) * Math.sin(latDiff / 2) +
|
|
146
|
+
Math.cos(latRad1) * Math.cos(latRad2) * Math.sin(lonDiff / 2) * Math.sin(lonDiff / 2);
|
|
147
|
+
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
148
|
+
const distance = earthRadius * c;
|
|
149
|
+
|
|
150
|
+
return distance;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
module.exports = {
|
|
154
|
+
checkAddressIsVisible,
|
|
155
|
+
formatPracticeAreasForDisplay,
|
|
156
|
+
debouncedFunction,
|
|
157
|
+
findMainAddress,
|
|
158
|
+
getMainAddress,
|
|
159
|
+
shuffleArray,
|
|
160
|
+
calculateDistance,
|
|
161
|
+
toRadians,
|
|
162
|
+
};
|
package/public/consts.js
CHANGED
|
@@ -7,9 +7,79 @@ const COLLECTIONS = {
|
|
|
7
7
|
MEMBERS_DATA: 'MembersDataLatest',
|
|
8
8
|
CONTACT_US_SUBMISSIONS: 'contactUsSubmissions',
|
|
9
9
|
SITE_CONFIGS: 'SiteConfigs',
|
|
10
|
+
COMPILED_STATE_CITY_MAP: 'CompiledStateCityMap',
|
|
11
|
+
STATE: 'State',
|
|
12
|
+
INTERESTS: 'interests',
|
|
13
|
+
STATE_CITY_MAP: 'City',
|
|
10
14
|
};
|
|
11
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Address display status types
|
|
18
|
+
*/
|
|
19
|
+
const ADDRESS_STATUS_TYPES = {
|
|
20
|
+
FULL_ADDRESS: 'full_address',
|
|
21
|
+
STATE_CITY_ZIP: 'state_city_zip',
|
|
22
|
+
DONT_SHOW: 'dont_show',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const DEFAULT_FILTER = {
|
|
26
|
+
skip: 0,
|
|
27
|
+
limit: 12,
|
|
28
|
+
practiceAreas: [],
|
|
29
|
+
practiceAreasSearch: '',
|
|
30
|
+
latitude: 0,
|
|
31
|
+
longitude: 0,
|
|
32
|
+
postalcode: null,
|
|
33
|
+
state: [],
|
|
34
|
+
stateSearch: '',
|
|
35
|
+
citySearch: '',
|
|
36
|
+
city: [],
|
|
37
|
+
searchText: null,
|
|
38
|
+
};
|
|
39
|
+
const DROPDOWN_OPTIONS = {
|
|
40
|
+
state: {
|
|
41
|
+
selectedOptions: [],
|
|
42
|
+
displayText: '',
|
|
43
|
+
},
|
|
44
|
+
city: {
|
|
45
|
+
selectedOptions: [],
|
|
46
|
+
displayText: '',
|
|
47
|
+
},
|
|
48
|
+
practiceAreas: {
|
|
49
|
+
selectedOptions: [],
|
|
50
|
+
displayText: '',
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
const DEBOUNCE_DELAY = {
|
|
54
|
+
searchTimeout: 1000,
|
|
55
|
+
filterTimeout: 300,
|
|
56
|
+
zeroTimeout: 0,
|
|
57
|
+
};
|
|
58
|
+
const MEMBERS_FIELDS = {
|
|
59
|
+
_id: '_id',
|
|
60
|
+
profileImage: 'profileImage',
|
|
61
|
+
fullName: 'fullName',
|
|
62
|
+
addresses: 'addresses',
|
|
63
|
+
aboutService: 'aboutService',
|
|
64
|
+
showBookingUrl: 'showBookingUrl',
|
|
65
|
+
bookingUrl: 'bookingUrl',
|
|
66
|
+
areasOfPractices: 'areasOfPractices',
|
|
67
|
+
url: 'url',
|
|
68
|
+
phones: 'phones',
|
|
69
|
+
toShowPhone: 'toShowPhone',
|
|
70
|
+
showContactForm: 'showContactForm',
|
|
71
|
+
website: 'website',
|
|
72
|
+
showWixUrl: 'showWixUrl',
|
|
73
|
+
memberships: 'memberships',
|
|
74
|
+
showWebsite: 'showWebsite',
|
|
75
|
+
addressDisplayOption: 'addressDisplayOption',
|
|
76
|
+
};
|
|
12
77
|
module.exports = {
|
|
13
78
|
REGEX,
|
|
14
79
|
COLLECTIONS,
|
|
80
|
+
ADDRESS_STATUS_TYPES,
|
|
81
|
+
DEFAULT_FILTER,
|
|
82
|
+
DROPDOWN_OPTIONS,
|
|
83
|
+
DEBOUNCE_DELAY,
|
|
84
|
+
MEMBERS_FIELDS,
|
|
15
85
|
};
|