abmp-npm 1.0.0 → 1.1.1
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/.husky/pre-commit +22 -0
- package/.prettierignore +7 -0
- package/.prettierrc.json +16 -0
- package/README.md +1 -0
- package/backend/automations-methods.js +13 -0
- package/backend/consts.js +18 -0
- package/backend/forms-methods.web.js +54 -0
- package/backend/members-area-methods.js +36 -0
- package/backend/members-data-methods.js +61 -0
- package/backend/utils.js +39 -0
- package/eslint.config.js +113 -0
- package/index.js +5 -5
- package/package.json +29 -3
- package/pages/ContactUs.js +131 -0
- package/pages/index.js +3 -0
- package/public/consts.js +15 -0
- package/public/index.js +4 -0
- package/public/messages.js +16 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
. "$(dirname -- "$0")/_/husky.sh"
|
|
3
|
+
|
|
4
|
+
echo "Running ESLint check..."
|
|
5
|
+
npm run lint
|
|
6
|
+
|
|
7
|
+
if [ $? -ne 0 ]; then
|
|
8
|
+
echo "❌ ESLint check failed. Please fix the linting errors before committing."
|
|
9
|
+
exit 1
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
echo "Running Prettier check..."
|
|
13
|
+
npm run format:check
|
|
14
|
+
|
|
15
|
+
if [ $? -ne 0 ]; then
|
|
16
|
+
echo "❌ Prettier check failed. Please format your code before committing."
|
|
17
|
+
echo "Run 'npm run format' to automatically format your files."
|
|
18
|
+
exit 1
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
echo "✅ All checks passed!"
|
|
22
|
+
|
package/.prettierignore
ADDED
package/.prettierrc.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"singleQuote": true,
|
|
3
|
+
"trailingComma": "es5",
|
|
4
|
+
"printWidth": 100,
|
|
5
|
+
"tabWidth": 2,
|
|
6
|
+
"semi": true,
|
|
7
|
+
"bracketSpacing": true,
|
|
8
|
+
"bracketSameLine": false,
|
|
9
|
+
"arrowParens": "avoid",
|
|
10
|
+
"endOfLine": "lf",
|
|
11
|
+
"quoteProps": "as-needed",
|
|
12
|
+
"jsxSingleQuote": false,
|
|
13
|
+
"requirePragma": false,
|
|
14
|
+
"insertPragma": false,
|
|
15
|
+
"proseWrap": "preserve"
|
|
16
|
+
}
|
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# abmp-npm
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const { customTrigger } = require('@wix/automations');
|
|
2
|
+
const { auth } = require('@wix/essentials');
|
|
3
|
+
const triggerMethod = auth.elevate(customTrigger.runTrigger);
|
|
4
|
+
|
|
5
|
+
const triggerAutomation = async (triggerId, payload) =>
|
|
6
|
+
await triggerMethod({
|
|
7
|
+
triggerId,
|
|
8
|
+
payload,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
triggerAutomation,
|
|
13
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const ELEVATED_QUERY_OPTIONS = {
|
|
2
|
+
suppressAuth: true,
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Valid configuration keys for getSiteConfigs function
|
|
7
|
+
* @readonly
|
|
8
|
+
* @enum {string}
|
|
9
|
+
*/
|
|
10
|
+
const CONFIG_KEYS = {
|
|
11
|
+
AUTOMATION_EMAIL_TRIGGER_ID: 'AUTOMATION_EMAIL_TRIGGER_ID',
|
|
12
|
+
SITE_ASSOCIATION: 'SITE_ASSOCIATION',
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
module.exports = {
|
|
16
|
+
ELEVATED_QUERY_OPTIONS,
|
|
17
|
+
CONFIG_KEYS,
|
|
18
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const { items: wixData } = require('@wix/data');
|
|
2
|
+
const { webMethod, Permissions } = require('@wix/web-methods');
|
|
3
|
+
|
|
4
|
+
const { COLLECTIONS } = require('../public');
|
|
5
|
+
|
|
6
|
+
const { triggerAutomation } = require('./automations-methods');
|
|
7
|
+
const { CONFIG_KEYS, ELEVATED_QUERY_OPTIONS } = require('./consts');
|
|
8
|
+
const { findMemberByWixDataId, createContactAndMemberIfNew } = require('./members-data-methods');
|
|
9
|
+
const { getSiteConfigs } = require('./utils');
|
|
10
|
+
|
|
11
|
+
const contactSubmission = webMethod(Permissions.Anyone, async (data, memberDataId) => {
|
|
12
|
+
const { firstName, lastName, email, phone, message } = data;
|
|
13
|
+
const [memberData, automationEmailTriggerId] = await Promise.all([
|
|
14
|
+
findMemberByWixDataId(memberDataId),
|
|
15
|
+
getSiteConfigs(CONFIG_KEYS.AUTOMATION_EMAIL_TRIGGER_ID),
|
|
16
|
+
]);
|
|
17
|
+
if (!memberData.showContactForm) {
|
|
18
|
+
console.log('Member contact form is not enabled for user, skipping contact submission!');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
let memberContactId = memberData.contactId;
|
|
22
|
+
if (!memberContactId) {
|
|
23
|
+
/**
|
|
24
|
+
* Create a member contact here since some members may have never logged in
|
|
25
|
+
* and therefore don’t have a contact ID. However, these members can still
|
|
26
|
+
* appear in the directory, and site visitors can reach out to them if they’ve
|
|
27
|
+
* enabled their contact form. To handle this, we ensure a contact is created for
|
|
28
|
+
* them during this flow if it doesn’t already exist.
|
|
29
|
+
*/
|
|
30
|
+
console.info('Member contact id not found for user, creating new contact!');
|
|
31
|
+
const member = await createContactAndMemberIfNew(memberData);
|
|
32
|
+
memberContactId = member.contactId;
|
|
33
|
+
}
|
|
34
|
+
console.log('memberContactId', memberContactId);
|
|
35
|
+
const emailTriggered = await triggerAutomation(automationEmailTriggerId, {
|
|
36
|
+
contactId: memberContactId,
|
|
37
|
+
name: `${firstName} ${lastName}`,
|
|
38
|
+
email: email,
|
|
39
|
+
phone: phone,
|
|
40
|
+
message: message,
|
|
41
|
+
});
|
|
42
|
+
data = {
|
|
43
|
+
...data,
|
|
44
|
+
phone: Number(data.phone),
|
|
45
|
+
memberContactId: memberContactId,
|
|
46
|
+
memberEmail: memberData.contactFormEmail,
|
|
47
|
+
};
|
|
48
|
+
await wixData.insert(COLLECTIONS.CONTACT_US_SUBMISSIONS, data, ELEVATED_QUERY_OPTIONS);
|
|
49
|
+
return emailTriggered;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
module.exports = {
|
|
53
|
+
contactSubmission,
|
|
54
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const { auth } = require('@wix/essentials');
|
|
2
|
+
const { members } = require('@wix/members');
|
|
3
|
+
const elevatedCreateMember = auth.elevate(members.createMember);
|
|
4
|
+
|
|
5
|
+
function prepareContactData(partner) {
|
|
6
|
+
const phones = Array.isArray(partner.phones) ? partner.phones : []; //some users don't have phones
|
|
7
|
+
const options = {
|
|
8
|
+
member: {
|
|
9
|
+
contact: {
|
|
10
|
+
...partner,
|
|
11
|
+
phones,
|
|
12
|
+
emails: [partner.contactFormEmail || partner.email],
|
|
13
|
+
},
|
|
14
|
+
loginEmail: partner.email,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
return options;
|
|
18
|
+
}
|
|
19
|
+
async function createMemberFunction(member) {
|
|
20
|
+
const newMember = await elevatedCreateMember(member);
|
|
21
|
+
return newMember._id;
|
|
22
|
+
}
|
|
23
|
+
const createSiteMember = async memberDetails => {
|
|
24
|
+
try {
|
|
25
|
+
const options = prepareContactData(memberDetails);
|
|
26
|
+
const contactId = await createMemberFunction(options);
|
|
27
|
+
return contactId;
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error(`Error in createSiteMember ${error.message}`);
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
module.exports = {
|
|
35
|
+
createSiteMember,
|
|
36
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const { items: wixData } = require('@wix/data');
|
|
2
|
+
|
|
3
|
+
const { COLLECTIONS } = require('../public');
|
|
4
|
+
|
|
5
|
+
const { ELEVATED_QUERY_OPTIONS } = require('./consts');
|
|
6
|
+
const { createSiteMember } = require('./members-area-methods');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Retrieves member data by member ID
|
|
10
|
+
* @param {string} memberId - The member ID to search for
|
|
11
|
+
* @returns {Promise<Object|null>} - Member data or null if not found
|
|
12
|
+
*/
|
|
13
|
+
async function findMemberByWixDataId(memberId) {
|
|
14
|
+
if (!memberId) {
|
|
15
|
+
throw new Error('Member ID is required');
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
const member = await wixData.get(COLLECTIONS.MEMBERS_DATA, memberId, ELEVATED_QUERY_OPTIONS);
|
|
19
|
+
return member;
|
|
20
|
+
} catch (error) {
|
|
21
|
+
throw new Error(`Failed to retrieve member data: ${error.message}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function createContactAndMemberIfNew(memberData) {
|
|
26
|
+
if (!memberData) {
|
|
27
|
+
throw new Error('Member data is required');
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const toCreateMemberData = {
|
|
31
|
+
firstName: memberData.firstName,
|
|
32
|
+
lastName: memberData.lastName,
|
|
33
|
+
email: memberData.email,
|
|
34
|
+
phones: memberData.phones,
|
|
35
|
+
contactFormEmail: memberData.contactFormEmail || memberData.email,
|
|
36
|
+
};
|
|
37
|
+
const contactId = await createSiteMember(toCreateMemberData);
|
|
38
|
+
let memberDataWithContactId = {
|
|
39
|
+
...memberData,
|
|
40
|
+
contactId,
|
|
41
|
+
};
|
|
42
|
+
const updatedResult = await wixData.update(
|
|
43
|
+
COLLECTIONS.MEMBERS_DATA,
|
|
44
|
+
memberDataWithContactId,
|
|
45
|
+
ELEVATED_QUERY_OPTIONS
|
|
46
|
+
);
|
|
47
|
+
memberDataWithContactId = {
|
|
48
|
+
...memberDataWithContactId,
|
|
49
|
+
...updatedResult,
|
|
50
|
+
};
|
|
51
|
+
return memberDataWithContactId;
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error('Error creating contact and member if new:', error);
|
|
54
|
+
throw new Error(`Failed to create contact and member if new: ${error.message}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
module.exports = {
|
|
59
|
+
findMemberByWixDataId,
|
|
60
|
+
createContactAndMemberIfNew,
|
|
61
|
+
};
|
package/backend/utils.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const { items: wixData } = require('@wix/data');
|
|
2
|
+
|
|
3
|
+
const { COLLECTIONS } = require('../public/consts');
|
|
4
|
+
|
|
5
|
+
const { ELEVATED_QUERY_OPTIONS, CONFIG_KEYS } = require('./consts');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Retrieves site configuration values from the database
|
|
9
|
+
* @param {string} [configKey] - The configuration key to retrieve. Must be one of:
|
|
10
|
+
* - 'AUTOMATION_EMAIL_TRIGGER_ID' - Email template ID for triggered emails
|
|
11
|
+
* - 'SITE_ASSOCIATION' - Site association configuration
|
|
12
|
+
* @returns {Promise<any>} The configuration value for the specified key, or all configs if no key provided
|
|
13
|
+
* @example
|
|
14
|
+
* // Get specific config
|
|
15
|
+
* const emailTemplateId = await getSiteConfigs('AUTOMATION_EMAIL_TRIGGER_ID');
|
|
16
|
+
*
|
|
17
|
+
* // Get all configs
|
|
18
|
+
* const allConfigs = await getSiteConfigs();
|
|
19
|
+
*/
|
|
20
|
+
const getSiteConfigs = async configKey => {
|
|
21
|
+
if (configKey && !Object.values(CONFIG_KEYS).includes(configKey)) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`Invalid configKey: ${configKey}. Must be one of: ${Object.values(CONFIG_KEYS).join(', ')}`
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
const siteConfigs = await wixData.get(
|
|
27
|
+
COLLECTIONS.SITE_CONFIGS,
|
|
28
|
+
'SINGLE_ITEM_ID',
|
|
29
|
+
ELEVATED_QUERY_OPTIONS
|
|
30
|
+
);
|
|
31
|
+
if (configKey) {
|
|
32
|
+
return siteConfigs[configKey];
|
|
33
|
+
}
|
|
34
|
+
return siteConfigs;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
module.exports = {
|
|
38
|
+
getSiteConfigs,
|
|
39
|
+
};
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
const js = require('@eslint/js');
|
|
2
|
+
const prettierConfig = require('eslint-config-prettier');
|
|
3
|
+
const importPlugin = require('eslint-plugin-import');
|
|
4
|
+
const prettier = require('eslint-plugin-prettier');
|
|
5
|
+
const promisePlugin = require('eslint-plugin-promise');
|
|
6
|
+
const globals = require('globals');
|
|
7
|
+
|
|
8
|
+
module.exports = [
|
|
9
|
+
// Recommended base configurations
|
|
10
|
+
js.configs.recommended,
|
|
11
|
+
prettierConfig,
|
|
12
|
+
|
|
13
|
+
// Main configuration
|
|
14
|
+
{
|
|
15
|
+
files: ['**/*.js'],
|
|
16
|
+
languageOptions: {
|
|
17
|
+
ecmaVersion: 2021,
|
|
18
|
+
sourceType: 'commonjs',
|
|
19
|
+
globals: {
|
|
20
|
+
...globals.node,
|
|
21
|
+
...globals.es2021,
|
|
22
|
+
...globals.jest,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
plugins: {
|
|
26
|
+
prettier,
|
|
27
|
+
import: importPlugin,
|
|
28
|
+
promise: promisePlugin,
|
|
29
|
+
},
|
|
30
|
+
rules: {
|
|
31
|
+
// Error prevention
|
|
32
|
+
'no-var': 'error',
|
|
33
|
+
'no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
|
|
34
|
+
'no-console': ['warn', { allow: ['warn', 'error', 'log', 'info'] }],
|
|
35
|
+
'no-debugger': 'warn',
|
|
36
|
+
'no-duplicate-imports': 'error',
|
|
37
|
+
'no-unused-expressions': ['error', { allowShortCircuit: true, allowTernary: true }],
|
|
38
|
+
'no-use-before-define': ['error', { functions: false }],
|
|
39
|
+
|
|
40
|
+
// Best practices
|
|
41
|
+
'prefer-const': 'error',
|
|
42
|
+
'no-const-assign': 'error',
|
|
43
|
+
'prefer-arrow-callback': 'error',
|
|
44
|
+
'arrow-body-style': ['error', 'as-needed'],
|
|
45
|
+
'no-return-await': 'off',
|
|
46
|
+
'require-await': 'warn',
|
|
47
|
+
|
|
48
|
+
// Import rules
|
|
49
|
+
'import/order': [
|
|
50
|
+
'error',
|
|
51
|
+
{
|
|
52
|
+
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
|
|
53
|
+
'newlines-between': 'always',
|
|
54
|
+
alphabetize: { order: 'asc', caseInsensitive: true },
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
'import/no-unresolved': 'error',
|
|
58
|
+
'import/no-duplicates': 'error',
|
|
59
|
+
'import/no-commonjs': 'off',
|
|
60
|
+
'import/no-dynamic-require': 'off',
|
|
61
|
+
|
|
62
|
+
// Promise rules
|
|
63
|
+
'promise/always-return': 'off',
|
|
64
|
+
'promise/no-return-wrap': 'error',
|
|
65
|
+
'promise/param-names': 'error',
|
|
66
|
+
'promise/catch-or-return': 'error',
|
|
67
|
+
'promise/no-native': 'off',
|
|
68
|
+
'promise/no-callback-in-promise': 'warn',
|
|
69
|
+
'promise/no-promise-in-callback': 'warn',
|
|
70
|
+
'promise/no-nesting': 'warn',
|
|
71
|
+
|
|
72
|
+
// Prettier rules
|
|
73
|
+
'prettier/prettier': [
|
|
74
|
+
'error',
|
|
75
|
+
{
|
|
76
|
+
singleQuote: true,
|
|
77
|
+
trailingComma: 'es5',
|
|
78
|
+
printWidth: 100,
|
|
79
|
+
tabWidth: 2,
|
|
80
|
+
semi: true,
|
|
81
|
+
bracketSpacing: true,
|
|
82
|
+
arrowParens: 'avoid',
|
|
83
|
+
endOfLine: 'lf',
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
settings: {
|
|
88
|
+
'import/resolver': {
|
|
89
|
+
node: {
|
|
90
|
+
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
// Test files override
|
|
97
|
+
{
|
|
98
|
+
files: ['**/*.test.js', '**/*.spec.js'],
|
|
99
|
+
languageOptions: {
|
|
100
|
+
globals: {
|
|
101
|
+
...globals.jest,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
rules: {
|
|
105
|
+
'no-console': 'off',
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
// Ignore patterns
|
|
110
|
+
{
|
|
111
|
+
ignores: ['node_modules/**', 'dist/**', 'build/**', 'coverage/**', '*.min.js'],
|
|
112
|
+
},
|
|
113
|
+
];
|
package/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
module.exports = {
|
|
2
|
+
...require('./pages'),
|
|
3
|
+
...require('./backend'),
|
|
4
|
+
...require('./public'),
|
|
5
|
+
};
|
package/package.json
CHANGED
|
@@ -1,11 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "abmp-npm",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
6
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
7
|
+
"lint": "eslint .",
|
|
8
|
+
"lint:fix": "eslint . --fix",
|
|
9
|
+
"format": "prettier --write \"**/*.{js,json,md}\"",
|
|
10
|
+
"format:check": "prettier --check \"**/*.{js,json,md}\"",
|
|
11
|
+
"prepare": "husky"
|
|
7
12
|
},
|
|
8
13
|
"author": "",
|
|
9
14
|
"license": "ISC",
|
|
10
|
-
"description": ""
|
|
15
|
+
"description": "",
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@eslint/js": "^9.12.0",
|
|
18
|
+
"eslint": "^9.12.0",
|
|
19
|
+
"eslint-config-prettier": "^9.1.0",
|
|
20
|
+
"eslint-plugin-import": "^2.30.0",
|
|
21
|
+
"eslint-plugin-prettier": "^5.2.1",
|
|
22
|
+
"eslint-plugin-promise": "^7.1.0",
|
|
23
|
+
"globals": "^15.10.0",
|
|
24
|
+
"husky": "^9.1.6",
|
|
25
|
+
"prettier": "^3.3.3"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@wix/automations": "^1.0.261",
|
|
29
|
+
"@wix/crm": "^1.0.1061",
|
|
30
|
+
"@wix/data": "^1.0.303",
|
|
31
|
+
"@wix/essentials": "^0.1.28",
|
|
32
|
+
"@wix/members": "^1.0.330",
|
|
33
|
+
"@wix/site-window": "^1.44.0",
|
|
34
|
+
"@wix/web-methods": "^1.0.11",
|
|
35
|
+
"phone": "^3.1.67"
|
|
36
|
+
}
|
|
11
37
|
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
const { lightbox } = require('@wix/site-window');
|
|
2
|
+
const { phone } = require('phone');
|
|
3
|
+
|
|
4
|
+
const { contactSubmission } = require('../backend/forms-methods.web.js');
|
|
5
|
+
const { VALIDATION_MESSAGES, REGEX } = require('../public');
|
|
6
|
+
|
|
7
|
+
async function contactUsOnReady(_$w) {
|
|
8
|
+
_$w('#submitButton').disable();
|
|
9
|
+
const receivedData = await lightbox.getContext();
|
|
10
|
+
const formFieldsSelectors = ['#firstName', '#lastName', '#email', '#phone', '#message'];
|
|
11
|
+
const inputOnCustomValidation = ({ value, reject, message, pattern }) => {
|
|
12
|
+
const isValid = typeof value === 'string' && pattern.test(value.trim());
|
|
13
|
+
if (!isValid) reject(message);
|
|
14
|
+
};
|
|
15
|
+
async function validateAllFields() {
|
|
16
|
+
let allValid = true;
|
|
17
|
+
for (const selector of formFieldsSelectors) {
|
|
18
|
+
const isValid = await _$w(selector).valid;
|
|
19
|
+
_$w(selector).updateValidityIndication();
|
|
20
|
+
if (!isValid) {
|
|
21
|
+
allValid = false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return allValid;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function resetForm() {
|
|
28
|
+
formFieldsSelectors.forEach(selector => {
|
|
29
|
+
const field = _$w(selector);
|
|
30
|
+
if (field && field.reset) {
|
|
31
|
+
field.reset();
|
|
32
|
+
} else {
|
|
33
|
+
field.value = '';
|
|
34
|
+
}
|
|
35
|
+
if (field && field.resetValidityIndication) {
|
|
36
|
+
field.resetValidityIndication();
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function setAlertMessage(message) {
|
|
42
|
+
const $message = _$w('#successMessage');
|
|
43
|
+
$message.text = message;
|
|
44
|
+
$message.expand();
|
|
45
|
+
|
|
46
|
+
setTimeout(() => {
|
|
47
|
+
$message.collapse();
|
|
48
|
+
}, 8000);
|
|
49
|
+
}
|
|
50
|
+
// First Name
|
|
51
|
+
_$w('#firstName').onCustomValidation((value, reject) => {
|
|
52
|
+
inputOnCustomValidation({
|
|
53
|
+
value,
|
|
54
|
+
reject,
|
|
55
|
+
message: VALIDATION_MESSAGES.CONTACT_US.FIRST_NAME,
|
|
56
|
+
pattern: REGEX.NAME,
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
// Last Name
|
|
60
|
+
_$w('#lastName').onCustomValidation((value, reject) => {
|
|
61
|
+
inputOnCustomValidation({
|
|
62
|
+
value,
|
|
63
|
+
reject,
|
|
64
|
+
message: VALIDATION_MESSAGES.CONTACT_US.LAST_NAME,
|
|
65
|
+
pattern: REGEX.NAME,
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
// Message
|
|
69
|
+
_$w('#message').onCustomValidation((value, reject) => {
|
|
70
|
+
inputOnCustomValidation({
|
|
71
|
+
value,
|
|
72
|
+
reject,
|
|
73
|
+
message: VALIDATION_MESSAGES.CONTACT_US.MESSAGE,
|
|
74
|
+
pattern: REGEX.MESSAGE,
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Email validation uses native input validation
|
|
79
|
+
// No custom validation needed as email input has built-in validation
|
|
80
|
+
|
|
81
|
+
// Phone (US format)
|
|
82
|
+
_$w('#phone').onCustomValidation((value, reject) => {
|
|
83
|
+
const { isValid } = phone(value, { country: 'US' });
|
|
84
|
+
if (!isValid) {
|
|
85
|
+
reject(VALIDATION_MESSAGES.CONTACT_US.PHONE);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
_$w('#captchaInput').onVerified(async () => {
|
|
89
|
+
const allValid = await validateAllFields();
|
|
90
|
+
if (allValid) {
|
|
91
|
+
_$w('#submitButton').enable();
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
_$w('#submitButton').disable();
|
|
95
|
+
setAlertMessage(VALIDATION_MESSAGES.CONTACT_US.CAPTCHA);
|
|
96
|
+
_$w('#captchaInput').reset();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
_$w('#captchaInput').onTimeout(() => {
|
|
100
|
+
_$w('#submitButton').disable();
|
|
101
|
+
});
|
|
102
|
+
_$w('#submitButton').onClick(async () => {
|
|
103
|
+
const allValid = await validateAllFields();
|
|
104
|
+
if (!allValid) {
|
|
105
|
+
setAlertMessage(VALIDATION_MESSAGES.CONTACT_US.INVALID_FIELDS);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const formData = {
|
|
111
|
+
firstName: _$w('#firstName').value,
|
|
112
|
+
lastName: _$w('#lastName').value,
|
|
113
|
+
email: _$w('#email').value,
|
|
114
|
+
phone: _$w('#phone').value,
|
|
115
|
+
message: _$w('#message').value,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
await contactSubmission(formData, receivedData._id);
|
|
119
|
+
await resetForm();
|
|
120
|
+
|
|
121
|
+
setAlertMessage(VALIDATION_MESSAGES.CONTACT_US.SUBMISSION_SUCCESS);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.error('Submission failed:', error);
|
|
124
|
+
setAlertMessage(VALIDATION_MESSAGES.CONTACT_US.SUBMISSION_FAILED);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
module.exports = {
|
|
130
|
+
contactUsOnReady,
|
|
131
|
+
};
|
package/pages/index.js
ADDED
package/public/consts.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const REGEX = {
|
|
2
|
+
NAME: /^[a-zA-Z\s'-]{2,}$/,
|
|
3
|
+
MESSAGE: /^[A-Za-z0-9\s.,!?'"-]{2,}$/,
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
const COLLECTIONS = {
|
|
7
|
+
MEMBERS_DATA: 'MembersDataLatest',
|
|
8
|
+
CONTACT_US_SUBMISSIONS: 'contactUsSubmissions',
|
|
9
|
+
SITE_CONFIGS: 'SiteConfigs',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
REGEX,
|
|
14
|
+
COLLECTIONS,
|
|
15
|
+
};
|
package/public/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const VALIDATION_MESSAGES = {
|
|
2
|
+
CONTACT_US: {
|
|
3
|
+
FIRST_NAME: 'Please enter a valid first name.',
|
|
4
|
+
LAST_NAME: 'Please enter a valid last name.',
|
|
5
|
+
MESSAGE: 'Please enter a valid message.',
|
|
6
|
+
PHONE: 'Please enter a valid US phone number.',
|
|
7
|
+
CAPTCHA: 'Please fix the highlighted fields before captcha verification.',
|
|
8
|
+
INVALID_FIELDS: 'Please fix the highlighted fields before submitting.',
|
|
9
|
+
SUBMISSION_FAILED: 'An error occurred. Please try again.',
|
|
10
|
+
SUBMISSION_SUCCESS: 'Contact submitted successfully',
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
module.exports = {
|
|
15
|
+
VALIDATION_MESSAGES,
|
|
16
|
+
};
|