@modernman00/shared-js-lib 1.2.13 → 1.2.23
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/.github/workflows/publish.yml +53 -0
- package/.github/workflows/release.yml +29 -0
- package/.github/workflows/test.yml +32 -0
- package/AcctMgt/changePassword.js +90 -0
- package/AcctMgt/code.js +50 -0
- package/AcctMgt/forgot.js +57 -0
- package/AcctMgt/login.js +73 -0
- package/AcctMgt/loginUtility.js +11 -0
- package/{Login.js → AcctMgt/processAll.js} +30 -17
- package/Cookie.js +6 -0
- package/CountryCode.js +1 -1
- package/{FormProcessing.js → FileUpload.js} +1 -8
- package/FormHelper.js +139 -82
- package/Http.js +182 -88
- package/Loader.js +1 -1
- package/Utility.js +18 -0
- package/__tests__/handlers.test.js +152 -0
- package/axiosWrapper.js +22 -0
- package/babel.config.js +3 -0
- package/config/version.php +3 -0
- package/general.js +62 -0
- package/index.js +8 -1
- package/jest.config.js +6 -0
- package/package.json +26 -2
- package/release.sh +161 -0
- package/ForgotPassword.js +0 -102
package/Utility.js
CHANGED
|
@@ -131,3 +131,21 @@ export const sanitizeInput = (input) => {
|
|
|
131
131
|
.replace(/'/g, ''')
|
|
132
132
|
.trim();
|
|
133
133
|
};
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Binds an event listener to an element with the specified ID.
|
|
138
|
+
*
|
|
139
|
+
* @param {Object} options - An object containing the following properties:
|
|
140
|
+
* - id {string}: The ID of the element to bind the event listener to.
|
|
141
|
+
* - event {string} (optional): The type of event to listen for. Defaults to 'click'.
|
|
142
|
+
* - handler {function}: The function to be called when the event occurs.
|
|
143
|
+
* @throws {Error} Throws an error if the element with the specified ID is not found,
|
|
144
|
+
* or if the handler is not a function.
|
|
145
|
+
*/
|
|
146
|
+
export function bindEvent({ id, event = 'click', handler }) {
|
|
147
|
+
const el = document.getElementById(id);
|
|
148
|
+
if (el && typeof handler === 'function') {
|
|
149
|
+
el.addEventListener(event, handler);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { createCodeSubmitHandler } from '../AcctMgt/code.js';
|
|
2
|
+
import { forgotSubmitHandler } from '../AcctMgt/forgot.js';
|
|
3
|
+
import { createAdminLoginHandler } from '../AcctMgt/login.js';
|
|
4
|
+
import { setupPasswordChange } from '../AcctMgt/changePassword.js';
|
|
5
|
+
import { loginSubmission } from '../AcctMgt/processAll.js';
|
|
6
|
+
import { showPassword } from '../AcctMgt/loginUtility.js';
|
|
7
|
+
|
|
8
|
+
jest.mock('../AcctMgt/processAll.js');
|
|
9
|
+
jest.mock('../AcctMgt/loginUtility.js');
|
|
10
|
+
|
|
11
|
+
// Utility to mock DOM elements
|
|
12
|
+
const mockDOM = (ids) => {
|
|
13
|
+
ids.forEach(id => {
|
|
14
|
+
const el = document.createElement('button');
|
|
15
|
+
el.setAttribute('id', id);
|
|
16
|
+
document.body.appendChild(el);
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
document.body.innerHTML = '';
|
|
22
|
+
jest.clearAllMocks();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('AcctMgt Handlers', () => {
|
|
26
|
+
test('createCodeSubmitHandler submits code form correctly', () => {
|
|
27
|
+
mockDOM(['button']);
|
|
28
|
+
createCodeSubmitHandler({
|
|
29
|
+
formId: 'codeForm',
|
|
30
|
+
inputId: 'code_id',
|
|
31
|
+
buttonId: 'button',
|
|
32
|
+
route: '/api/code',
|
|
33
|
+
redirect: '/success',
|
|
34
|
+
theme: 'bulma',
|
|
35
|
+
maxLength: 40
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
document.getElementById('button').dispatchEvent(new Event('click'));
|
|
39
|
+
|
|
40
|
+
expect(loginSubmission).toHaveBeenCalledWith(
|
|
41
|
+
'codeForm',
|
|
42
|
+
'/api/code',
|
|
43
|
+
'/success',
|
|
44
|
+
'bulma',
|
|
45
|
+
{ maxLength: { id: ['code_id'], max: [40] } }
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('forgotSubmitHandler submits email form correctly', () => {
|
|
50
|
+
mockDOM(['button']);
|
|
51
|
+
const emailInput = document.createElement('input');
|
|
52
|
+
emailInput.setAttribute('id', 'email_id');
|
|
53
|
+
document.body.appendChild(emailInput);
|
|
54
|
+
|
|
55
|
+
forgotSubmitHandler({
|
|
56
|
+
formId: 'forgotPassword',
|
|
57
|
+
inputId: 'email_id',
|
|
58
|
+
buttonId: 'button',
|
|
59
|
+
route: '/api/forgot',
|
|
60
|
+
redirect: '/reset',
|
|
61
|
+
theme: 'bulma',
|
|
62
|
+
maxLength: 50
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
document.getElementById('button').dispatchEvent(new Event('click'));
|
|
66
|
+
|
|
67
|
+
expect(loginSubmission).toHaveBeenCalledWith(
|
|
68
|
+
'forgotPassword',
|
|
69
|
+
'/api/forgot',
|
|
70
|
+
'/reset',
|
|
71
|
+
'bulma',
|
|
72
|
+
{ maxLength: { id: ['email_id'], max: [50] } }
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('createAdminLoginHandler sets attributes and submits login', () => {
|
|
77
|
+
mockDOM(['button', 'showPassword_id']);
|
|
78
|
+
const passwordInput = document.createElement('input');
|
|
79
|
+
passwordInput.setAttribute('id', 'password_id');
|
|
80
|
+
document.body.appendChild(passwordInput);
|
|
81
|
+
|
|
82
|
+
createAdminLoginHandler({
|
|
83
|
+
formId: 'managed',
|
|
84
|
+
emailId: 'email_id',
|
|
85
|
+
passwordId: 'password_id',
|
|
86
|
+
buttonId: 'button',
|
|
87
|
+
showToggleId: 'showPassword_id',
|
|
88
|
+
route: '/api/login',
|
|
89
|
+
redirect: '/admin',
|
|
90
|
+
theme: 'bootstrap',
|
|
91
|
+
maxLength: [30, 50]
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
document.getElementById('button').dispatchEvent(new Event('click'));
|
|
95
|
+
document.getElementById('showPassword_id').dispatchEvent(new Event('click'));
|
|
96
|
+
|
|
97
|
+
expect(loginSubmission).toHaveBeenCalledWith(
|
|
98
|
+
'managed',
|
|
99
|
+
'/api/login',
|
|
100
|
+
'/admin',
|
|
101
|
+
'bootstrap',
|
|
102
|
+
{ maxLength: { id: ['password_id', 'email_id'], max: [30, 50] } }
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
expect(passwordInput.getAttribute('autocomplete')).toBe('current-password');
|
|
106
|
+
expect(showPassword).toHaveBeenCalledWith('password_id');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test('setupPasswordChange submits when passwords match', () => {
|
|
110
|
+
mockDOM(['button', 'showPassword_id']);
|
|
111
|
+
const passwordInput = document.createElement('input');
|
|
112
|
+
passwordInput.setAttribute('id', 'password_id');
|
|
113
|
+
passwordInput.value = 'Secure123!';
|
|
114
|
+
document.body.appendChild(passwordInput);
|
|
115
|
+
|
|
116
|
+
const confirmInput = document.createElement('input');
|
|
117
|
+
confirmInput.setAttribute('id', 'confirm_password_id');
|
|
118
|
+
confirmInput.value = 'Secure123!';
|
|
119
|
+
document.body.appendChild(confirmInput);
|
|
120
|
+
|
|
121
|
+
const errorEl = document.createElement('div');
|
|
122
|
+
errorEl.setAttribute('id', 'confirm_password_error');
|
|
123
|
+
document.body.appendChild(errorEl);
|
|
124
|
+
|
|
125
|
+
const helpEl = document.createElement('div');
|
|
126
|
+
helpEl.setAttribute('id', 'password_help');
|
|
127
|
+
document.body.appendChild(helpEl);
|
|
128
|
+
|
|
129
|
+
setupPasswordChange({
|
|
130
|
+
buttonId: 'button',
|
|
131
|
+
passwordId: 'password_id',
|
|
132
|
+
confirmId: 'confirm_password_id',
|
|
133
|
+
errorId: 'confirm_password_error',
|
|
134
|
+
helpId: 'password_help',
|
|
135
|
+
showToggleId: 'showPassword_id',
|
|
136
|
+
route: '/api/change-password',
|
|
137
|
+
redirect: '/dashboard',
|
|
138
|
+
theme: 'bulma',
|
|
139
|
+
maxLength: 50
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
document.getElementById('button').dispatchEvent(new Event('click'));
|
|
143
|
+
|
|
144
|
+
expect(loginSubmission).toHaveBeenCalledWith(
|
|
145
|
+
'changePassword',
|
|
146
|
+
'/api/change-password',
|
|
147
|
+
'/dashboard',
|
|
148
|
+
'bulma',
|
|
149
|
+
{ maxLength: { id: ['password_id', 'confirm_password_id'], max: [50, 50] } }
|
|
150
|
+
);
|
|
151
|
+
});
|
|
152
|
+
});
|
package/axiosWrapper.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { getCookieValue } from './Cookie.js';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
import axiosRetry from 'axios-retry';
|
|
4
|
+
|
|
5
|
+
axiosRetry(axios, { retries: 3 });
|
|
6
|
+
|
|
7
|
+
const csrfToken = getCookieValue('XSRF-TOKEN');
|
|
8
|
+
|
|
9
|
+
axios.interceptors.request.use(config => {
|
|
10
|
+
if (csrfToken) {
|
|
11
|
+
config.headers['X-Requested-With'] = 'XMLHttpRequest';
|
|
12
|
+
config.headers['Content-Type'] = 'application/json';
|
|
13
|
+
config.headers['Accept'] = 'application/json';
|
|
14
|
+
if (csrfToken) {
|
|
15
|
+
config.headers['X-XSRF-TOKEN'] = csrfToken; // Set CSRF token header
|
|
16
|
+
}
|
|
17
|
+
return config;
|
|
18
|
+
}
|
|
19
|
+
return config;
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export default axios;
|
package/babel.config.js
ADDED
package/general.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
import { id } from './UtilityHtml.js';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* @param { id of the first element} first
|
|
8
|
+
* @param {* id of the second element} second
|
|
9
|
+
* @param {* error id - if error - where to show it} err
|
|
10
|
+
*/
|
|
11
|
+
export const matchInput = (first, second, err) => {
|
|
12
|
+
let error, firstInput, secondInput;
|
|
13
|
+
error = id(err);
|
|
14
|
+
firstInput = id(first);
|
|
15
|
+
secondInput = id(second);
|
|
16
|
+
|
|
17
|
+
secondInput.addEventListener('keyup', () => {
|
|
18
|
+
|
|
19
|
+
if (secondInput.value !== firstInput.value) {
|
|
20
|
+
error.innerHTML = 'Your passwords do not match';
|
|
21
|
+
error.style.color = 'red';
|
|
22
|
+
} else {
|
|
23
|
+
error.innerHTML = 'The password is matched: <i class=\'fa fa-check\' aria-hidden=\'true\'></i>';
|
|
24
|
+
error.style.color = 'green';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Redirects the browser to a new URL after a specified delay.
|
|
36
|
+
*
|
|
37
|
+
* @param {string} url - The URL to redirect to.
|
|
38
|
+
* @param {number} delay - The delay, in milliseconds, before the redirect occurs.
|
|
39
|
+
* @return {void} This function does not return anything.
|
|
40
|
+
*/
|
|
41
|
+
export const redirectAfterDelay = (url, delay) => {
|
|
42
|
+
setTimeout(() => {
|
|
43
|
+
window.location.href = url;
|
|
44
|
+
}, delay);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
export const parseErrorResponse = (error) => {
|
|
49
|
+
let errorMessage = 'An unknown error occurred';
|
|
50
|
+
|
|
51
|
+
if (Array.isArray(error?.response?.data?.message)) {
|
|
52
|
+
errorMessage = `<ul>${error.response.data.message.map(e => `<li>${e}</li>`).join('')}</ul>`;
|
|
53
|
+
} else if (typeof error?.response?.data?.message === 'string') {
|
|
54
|
+
errorMessage = error.response.data.message;
|
|
55
|
+
} else if (typeof error.message === 'string') {
|
|
56
|
+
errorMessage = error.message;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return errorMessage;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
|
package/index.js
CHANGED
|
@@ -10,4 +10,11 @@ export * from './FormHelper.js';
|
|
|
10
10
|
export * from './Loader.js';
|
|
11
11
|
export * from './ShowResponse.js';
|
|
12
12
|
export * from './DateTime.js';
|
|
13
|
-
export * from './CountryCode.js'
|
|
13
|
+
export * from './CountryCode.js'
|
|
14
|
+
export * from './AcctMgt/changePassword.js';
|
|
15
|
+
export * from './AcctMgt/code.js';
|
|
16
|
+
export * from './AcctMgt/forgot.js';
|
|
17
|
+
export * from './AcctMgt/login.js';
|
|
18
|
+
export * from './AcctMgt/loginUtility.js';
|
|
19
|
+
export * from './AcctMgt/processAll.js';
|
|
20
|
+
export * from './general.js';
|
package/jest.config.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modernman00/shared-js-lib",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.23",
|
|
4
4
|
"description": "Reusable JS utilities for numerous js problems",
|
|
5
5
|
"homepage": "https://github.com/modernman00/shared-js-lib#readme",
|
|
6
6
|
"keywords": [
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"author": "olawale olaogun",
|
|
21
21
|
"main": "index.js",
|
|
22
22
|
"scripts": {
|
|
23
|
-
"test": "
|
|
23
|
+
"test": "jest"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"axios": "^1.9.0",
|
|
@@ -28,5 +28,29 @@
|
|
|
28
28
|
},
|
|
29
29
|
"publishConfig": {
|
|
30
30
|
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@babel/core": "^7.28.3",
|
|
34
|
+
"@babel/preset-env": "^7.28.3",
|
|
35
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
36
|
+
"@semantic-release/git": "^10.0.1",
|
|
37
|
+
"@semantic-release/github": "^11.0.4",
|
|
38
|
+
"@semantic-release/npm": "^12.0.2",
|
|
39
|
+
"auto-changelog": "^2.5.0",
|
|
40
|
+
"babel-jest": "^30.0.5",
|
|
41
|
+
"jest": "^30.0.5",
|
|
42
|
+
"jest-environment-jsdom": "^30.0.5",
|
|
43
|
+
"semantic-release": "^24.2.7"
|
|
44
|
+
},
|
|
45
|
+
"release": {
|
|
46
|
+
"branches": [
|
|
47
|
+
"main"
|
|
48
|
+
],
|
|
49
|
+
"plugins": [
|
|
50
|
+
"@semantic-release/npm",
|
|
51
|
+
"@semantic-release/changelog",
|
|
52
|
+
"@semantic-release/git",
|
|
53
|
+
"@semantic-release/github"
|
|
54
|
+
]
|
|
31
55
|
}
|
|
32
56
|
}
|
package/release.sh
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
# --- Config ---
|
|
5
|
+
VERSION_FILE="config/version.php"
|
|
6
|
+
HISTORY_FILE="release-history.md"
|
|
7
|
+
REPO="origin"
|
|
8
|
+
DEFAULT_BRANCH="main"
|
|
9
|
+
|
|
10
|
+
# --- Utilities ---
|
|
11
|
+
function detect_branch() {
|
|
12
|
+
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
|
13
|
+
echo "🔍 Current branch: $CURRENT_BRANCH"
|
|
14
|
+
if [[ "$CURRENT_BRANCH" != "$DEFAULT_BRANCH" && "$CURRENT_BRANCH" != "master" ]]; then
|
|
15
|
+
echo "⚠️ You're on '$CURRENT_BRANCH'. Switch to '$DEFAULT_BRANCH' or 'master' before releasing."
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function ensure_clean_git() {
|
|
21
|
+
if [[ -n $(git status --porcelain) ]]; then
|
|
22
|
+
echo "🛑 Uncommitted changes detected."
|
|
23
|
+
git status
|
|
24
|
+
read -p "❓ Auto-commit all changes before release? (y/n): " choice
|
|
25
|
+
if [[ "$choice" == "y" ]]; then
|
|
26
|
+
git add .
|
|
27
|
+
git commit -m "🧹 Auto-commit before release"
|
|
28
|
+
else
|
|
29
|
+
echo "🚫 Aborting release."
|
|
30
|
+
exit 1
|
|
31
|
+
fi
|
|
32
|
+
fi
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function run_tests() {
|
|
36
|
+
echo "🧪 Running tests with coverage..."
|
|
37
|
+
npm test -- --coverage || {
|
|
38
|
+
echo "❌ Tests failed. Aborting release."
|
|
39
|
+
exit 1
|
|
40
|
+
}
|
|
41
|
+
echo "✅ Tests passed."
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function validate_dependencies() {
|
|
45
|
+
command -v gh >/dev/null || {
|
|
46
|
+
echo "❌ GitHub CLI (gh) not found. Install it to publish releases."
|
|
47
|
+
exit 1
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function extract_version() {
|
|
52
|
+
grep -q "APP_VERSION" "$VERSION_FILE" || {
|
|
53
|
+
echo "❌ APP_VERSION not found in $VERSION_FILE"
|
|
54
|
+
exit 1
|
|
55
|
+
}
|
|
56
|
+
CURRENT=$(grep "APP_VERSION" "$VERSION_FILE" | sed -E "s/.*'([^']+)'.*/\1/")
|
|
57
|
+
IFS='.' read -r MAJOR MINOR PATCH <<< "${CURRENT//v/}"
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function determine_bump_type() {
|
|
61
|
+
LAST_COMMIT=$(git log -1 --pretty=%s)
|
|
62
|
+
MODE="patch"
|
|
63
|
+
[[ "$LAST_COMMIT" == feat:* ]] && MODE="minor"
|
|
64
|
+
[[ "$LAST_COMMIT" == fix:* ]] && MODE="patch"
|
|
65
|
+
[[ "$LAST_COMMIT" == chore:* || "$LAST_COMMIT" == docs:* ]] && MODE="patch"
|
|
66
|
+
[[ "$LAST_COMMIT" == BREAKING:* ]] && MODE="major"
|
|
67
|
+
|
|
68
|
+
case "$MODE" in
|
|
69
|
+
major) MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0 ;;
|
|
70
|
+
minor) MINOR=$((MINOR + 1)); PATCH=0 ;;
|
|
71
|
+
patch) PATCH=$((PATCH + 1)) ;;
|
|
72
|
+
esac
|
|
73
|
+
|
|
74
|
+
SEMVER="${MAJOR}.${MINOR}.${PATCH}"
|
|
75
|
+
NEW="v$SEMVER"
|
|
76
|
+
echo "🔧 Current version: $CURRENT"
|
|
77
|
+
echo "⏫ Detected bump: $MODE → $NEW"
|
|
78
|
+
echo "📦 Last commit: $LAST_COMMIT"
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function update_version_file() {
|
|
82
|
+
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
83
|
+
sed -i '' "s/$CURRENT/$NEW/" "$VERSION_FILE"
|
|
84
|
+
else
|
|
85
|
+
sed -i "s/$CURRENT/$NEW/" "$VERSION_FILE"
|
|
86
|
+
fi
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function commit_and_tag() {
|
|
90
|
+
COMMIT_MSG="🔖 Bump version to $NEW"
|
|
91
|
+
npm version "$SEMVER" --no-git-tag-version
|
|
92
|
+
git add "$VERSION_FILE"
|
|
93
|
+
git commit -m "$COMMIT_MSG"
|
|
94
|
+
|
|
95
|
+
if git rev-parse "$NEW" >/dev/null 2>&1; then
|
|
96
|
+
echo "⚠️ Tag $NEW already exists. Skipping tag creation."
|
|
97
|
+
else
|
|
98
|
+
git tag "$NEW"
|
|
99
|
+
git push "$REPO" "$NEW"
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
echo "🚀 Pushing changes to $REPO/$DEFAULT_BRANCH..."
|
|
103
|
+
git push "$REPO" "$DEFAULT_BRANCH" || {
|
|
104
|
+
echo "❌ Failed to push to $DEFAULT_BRANCH. Check your Git credentials or branch name."
|
|
105
|
+
exit 1
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function generate_changelog() {
|
|
110
|
+
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null)
|
|
111
|
+
[ "$LAST_TAG" = "$NEW" ] && LAST_TAG=$(git rev-list --tags --max-count=2 | tail -n1 | xargs git describe --tags --abbrev=0)
|
|
112
|
+
NOTES="### Changelog for $NEW\n\n"
|
|
113
|
+
NOTES+=$(git log "$LAST_TAG"..HEAD --pretty=format:"- %s _(by %an)_" --no-merges)
|
|
114
|
+
[ -z "$NOTES" ] && NOTES="Initial release."
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function publish_github_release() {
|
|
118
|
+
gh release create "$NEW" \
|
|
119
|
+
--title "Release $NEW" \
|
|
120
|
+
--notes "$NOTES" \
|
|
121
|
+
--verify-tag
|
|
122
|
+
echo "✅ Published $NEW with changelog and updated $VERSION_FILE!"
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function log_release_history() {
|
|
126
|
+
echo -e "\n## $NEW — $(date '+%Y-%m-%d %H:%M')\n$NOTES" >> "$HISTORY_FILE"
|
|
127
|
+
echo "📝 Logged release to $HISTORY_FILE"
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function publish_to_npm() {
|
|
131
|
+
echo "🚀 Publishing $SEMVER to npm..."
|
|
132
|
+
npm publish --access public || {
|
|
133
|
+
echo "❌ npm publish failed. Check your credentials, registry access, or package.json config."
|
|
134
|
+
exit 1
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
echo "🔍 Verifying publish on npm registry..."
|
|
138
|
+
PACKAGE_NAME=$(node -p "require('./package.json').name")
|
|
139
|
+
PUBLISHED_VERSION=$(npm view "$PACKAGE_NAME" version)
|
|
140
|
+
|
|
141
|
+
if [[ "$PUBLISHED_VERSION" == "$SEMVER" ]]; then
|
|
142
|
+
echo "✅ npm publish confirmed: $PUBLISHED_VERSION is live on npmjs.org"
|
|
143
|
+
else
|
|
144
|
+
echo "⚠️ Publish may not have propagated yet. Expected $SEMVER, got $PUBLISHED_VERSION"
|
|
145
|
+
fi
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
# --- Execution ---
|
|
150
|
+
detect_branch
|
|
151
|
+
ensure_clean_git
|
|
152
|
+
run_tests
|
|
153
|
+
validate_dependencies
|
|
154
|
+
extract_version
|
|
155
|
+
determine_bump_type
|
|
156
|
+
update_version_file
|
|
157
|
+
commit_and_tag
|
|
158
|
+
generate_changelog
|
|
159
|
+
publish_github_release
|
|
160
|
+
log_release_history
|
|
161
|
+
publish_to_npm
|
package/ForgotPassword.js
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
import { id } from './UtilityHtml.js'
|
|
3
|
-
import { postFormData } from "./Http.js"
|
|
4
|
-
import { emailVal } from "./Utility.js"
|
|
5
|
-
import { showError } from "./ShowResponse.js";
|
|
6
|
-
|
|
7
|
-
// Environment detection
|
|
8
|
-
const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
9
|
-
|
|
10
|
-
// Log warning for browser-only features
|
|
11
|
-
const warnNodeEnvironment = (feature) => {
|
|
12
|
-
if (!isBrowser) {
|
|
13
|
-
console.warn(`Warning: ${feature} is only available in browser environments. This code may not work as expected in Node.js.`);
|
|
14
|
-
return false;
|
|
15
|
-
}
|
|
16
|
-
return true;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
// Initialize UI - only in browser environment
|
|
20
|
-
if (isBrowser) {
|
|
21
|
-
const loaderElement = id("setLoader");
|
|
22
|
-
if (loaderElement) {
|
|
23
|
-
loaderElement.style.display = "none";
|
|
24
|
-
} else {
|
|
25
|
-
console.warn("Element 'setLoader' not found in the DOM");
|
|
26
|
-
}
|
|
27
|
-
} else {
|
|
28
|
-
console.warn("Running in Node.js environment. DOM manipulation is not available.");
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @description Handles the forgot password submission process.
|
|
33
|
-
* @param {string} formId - The ID of the form to submit.
|
|
34
|
-
* @param {string} url - The URL to make the POST request to.
|
|
35
|
-
* @param {string} redirectUrl - The URL to redirect the user to after the submission is complete.
|
|
36
|
-
* @returns {function} - A function that handles the submission process.
|
|
37
|
-
*/
|
|
38
|
-
export const forgotPasswordSubmission = (formId, url, redirectUrl) => {
|
|
39
|
-
// Check if we're in a browser environment before creating the helper
|
|
40
|
-
if (!warnNodeEnvironment('forgotPasswordSubmission')) {
|
|
41
|
-
// Return a no-op function in Node.js environment
|
|
42
|
-
return (e) => {
|
|
43
|
-
if (e && typeof e.preventDefault === 'function') {
|
|
44
|
-
e.preventDefault();
|
|
45
|
-
}
|
|
46
|
-
console.warn("Forgot password functionality is only available in browser environments");
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const emailInput = id('email_id');
|
|
51
|
-
if (!emailInput) {
|
|
52
|
-
console.warn("Email input element not found");
|
|
53
|
-
return (e) => {
|
|
54
|
-
if (e && typeof e.preventDefault === 'function') {
|
|
55
|
-
e.preventDefault();
|
|
56
|
-
}
|
|
57
|
-
console.error("Email input element not found");
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* @description Handles the submission of the forgot password form.
|
|
63
|
-
* @param {Event} e - The event object passed by the event listener.
|
|
64
|
-
* @returns {void}
|
|
65
|
-
* @throws {Error} - If there is an error with the submission
|
|
66
|
-
*/
|
|
67
|
-
const forgotPasswordSubmissionHelper = (e) => {
|
|
68
|
-
try {
|
|
69
|
-
if (e && typeof e.preventDefault === 'function') {
|
|
70
|
-
e.preventDefault();
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Ensure emailInput still exists in the DOM
|
|
74
|
-
if (!emailInput) {
|
|
75
|
-
throw new Error("Email input element not found");
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const email = emailInput.value.trim();
|
|
79
|
-
if (!emailVal(email)) {
|
|
80
|
-
const loaderElement = id("setLoader");
|
|
81
|
-
if (loaderElement) {
|
|
82
|
-
loaderElement.style.display = "block";
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Only use localStorage in browser environment
|
|
86
|
-
if (typeof localStorage !== 'undefined') {
|
|
87
|
-
localStorage.setItem('redirect', redirectUrl);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
postFormData(url, formId, redirectUrl);
|
|
91
|
-
}
|
|
92
|
-
} catch (error) {
|
|
93
|
-
if (typeof showError === 'function') {
|
|
94
|
-
showError(error);
|
|
95
|
-
} else {
|
|
96
|
-
console.error("Error in forgot password submission:", error);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
return forgotPasswordSubmissionHelper;
|
|
102
|
-
};
|