From e1cc156c58cd075c21b4ef1bdb5b34757f34cd01 Mon Sep 17 00:00:00 2001 From: Nirvan Bobde Date: Wed, 6 Aug 2025 17:59:45 +0530 Subject: [PATCH 01/10] Implemented : Password Change Prompt After Expiration (#63) --- src/components/ForgotPasswordModal.vue | 132 ++++++++++++++++++++ src/locales/en.json | 4 +- src/router/index.ts | 27 ++++- src/services/UserService.ts | 20 ++- src/store/auth.ts | 5 +- src/views/Login.vue | 50 +++++++- src/views/ResetPassword.vue | 162 +++++++++++++++++++++++++ 7 files changed, 390 insertions(+), 10 deletions(-) create mode 100644 src/components/ForgotPasswordModal.vue create mode 100644 src/views/ResetPassword.vue diff --git a/src/components/ForgotPasswordModal.vue b/src/components/ForgotPasswordModal.vue new file mode 100644 index 0000000..265ae27 --- /dev/null +++ b/src/components/ForgotPasswordModal.vue @@ -0,0 +1,132 @@ + + + \ No newline at end of file diff --git a/src/locales/en.json b/src/locales/en.json index 851679e..0dd586e 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -8,6 +8,7 @@ "Not configured": "Not configured", "OMS": "OMS", "Password": "Password", + "Reset Password":"Reset Password", "Please fill in the OMS": "Please fill in the OMS", "Please fill in the user details": "Please fill in the user details", "Processing": "Processing", @@ -15,5 +16,6 @@ "Sorry, your username or password is incorrect. Please try again.": "Sorry, your username or password is incorrect. Please try again.", "This application is not enabled for your account": "This application is not enabled for your account", "Username": "Username", - "View profile": "View profile" + "View profile": "View profile", + "Your username must have an email already associated with it in HotWax to receive a reset password email. If you do not have an email linked to your account already, please contact your administrator to manually reset your password.":"Your username must have an email already associated with it in HotWax to receive a reset password email. If you do not have an email linked to your account already, please contact your administrator to manually reset your password." } \ No newline at end of file diff --git a/src/router/index.ts b/src/router/index.ts index 2a5fe6c..0d59fc0 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -3,6 +3,7 @@ import { RouteRecordRaw } from 'vue-router'; import Home from '@/views/Home.vue'; import Login from '@/views/Login.vue'; import { useAuthStore } from "@/store/auth"; +import ResetPassword from '@/views/ResetPassword.vue'; const loginGuard = (to: any, from: any, next: any) => { const authStore = useAuthStore() @@ -12,6 +13,23 @@ const loginGuard = (to: any, from: any, next: any) => { next(); }; +const authGuard = async (to: any, from: any, next: any) => { + const authStore = useAuthStore() + if (!authStore.isAuthenticated) { + next('/login') + } + next() +}; + +const resetGuard = async (to: any, from: any, next: any) => { + const authStore = useAuthStore() + if (authStore.requirePasswordChange) { + next('/resetPassword') + return; + } + next() +}; + const routes: Array = [ { path: '/', @@ -21,13 +39,20 @@ const routes: Array = [ path: '/home', name: 'Home', component: Home, + beforeEnter: resetGuard }, { path: '/login', name: 'Login', component: Login, beforeEnter: loginGuard - } + }, + { + path: '/resetPassword', + name: 'ResetPassword', + component: ResetPassword, + beforeEnter: authGuard + }, ]; const router = createRouter({ diff --git a/src/services/UserService.ts b/src/services/UserService.ts index 837cf9d..6c173d9 100644 --- a/src/services/UserService.ts +++ b/src/services/UserService.ts @@ -130,9 +130,27 @@ const getUserPermissions = async (payload: any, token: any): Promise => { } } +const resetPassword = async(params: any) : Promise => { + return api({ + url: "service/resetPassword", + method: "POST", + data: params + }) +} + +const forgotPassword = async(params: any) : Promise => { + return api({ + url: "service/sendResetPasswordMailToParty", + method: "post", + data: params + }) +} + export const UserService = { getUserProfile, checkLoginOptions, login, - getUserPermissions + getUserPermissions, + resetPassword, + forgotPassword } \ No newline at end of file diff --git a/src/store/auth.ts b/src/store/auth.ts index 58a34fe..9406996 100644 --- a/src/store/auth.ts +++ b/src/store/auth.ts @@ -21,6 +21,7 @@ export const useAuthStore = defineStore('authStore', { expiration: undefined }, redirectUrl: '', + requirePasswordChange: false, // denotes if password change is required for the user maargOms: '', permissions: [] as any }), @@ -54,7 +55,7 @@ export const useAuthStore = defineStore('authStore', { try { const resp = await UserService.login(username, password); if (hasError(resp)) { - showToast(translate('Sorry, your username or password is incorrect. Please try again.')); + // showToast(translate('Sorry, your username or password is incorrect. Please try again.')); console.error("error", resp.data._ERROR_MESSAGE_); return Promise.reject(new Error(resp.data._ERROR_MESSAGE_)); } @@ -64,6 +65,8 @@ export const useAuthStore = defineStore('authStore', { expiration: resp.data.expirationTime } + this.requirePasswordChange = resp.data.requirePasswordChange + this.current = await UserService.getUserProfile(this.token.value); updateToken(this.token.value) diff --git a/src/views/Login.vue b/src/views/Login.vue index f34cd45..b1393d0 100644 --- a/src/views/Login.vue +++ b/src/views/Login.vue @@ -41,6 +41,17 @@ + + +
+ + {{ $t('The username or password you entered is incorrect. Please try again.') }} + + + {{ $t('forgot password') }} + +
+
@@ -67,18 +78,20 @@ import { IonItem, IonPage, IonSpinner, - loadingController + loadingController, + modalController } from "@ionic/vue"; import { defineComponent } from "vue"; import { useRouter } from "vue-router"; import { useAuthStore } from "@/store/auth"; import Logo from '@/components/Logo.vue'; -import { arrowForwardOutline, gridOutline } from 'ionicons/icons' +import { arrowForwardOutline, gridOutline,warningOutline } from 'ionicons/icons' import { UserService } from "@/services/UserService"; import { translate } from "@/i18n"; import { appInfo, isMaargLogin, isOmsWithMaarg, showToast } from "@/util"; import { hasError } from "@hotwax/oms-api"; import { Actions, hasPermission } from "@/authorization"; +import ForgotPasswordModal from "@/components/ForgotPasswordModal.vue"; export default defineComponent({ name: "Login", @@ -109,12 +122,16 @@ export default defineComponent({ loader: null as any, loginOption: {} as any, isCheckingOms: false, - isLoggingIn: false + isLoggingIn: false, + errorMessage: '', }; }, ionViewWillEnter() { this.initialise() }, + ionViewWillLeave() { + this.errorMessage = '' + }, methods: { async initialise() { this.hideBackground = true @@ -256,6 +273,13 @@ export default defineComponent({ this.isLoggingIn = true; try { await this.authStore.login(username.trim(), password) + // when password needs to be changed, redirecting the user to reset page + if(this.authStore.requirePasswordChange) { + this.username = '' + this.password = '' + this.router.push('/resetPassword'); + return + } if (this.authStore.getRedirectUrl) { this.generateRedirectionLink() } else { @@ -264,7 +288,8 @@ export default defineComponent({ this.password = '' this.router.push('/') } - } catch (error) { + } catch (error:any) { + this.errorMessage = error console.error(error) } this.isLoggingIn = false; @@ -283,6 +308,9 @@ export default defineComponent({ console.error(error) } }, + forgotPassword() { + this.router.push('/forgotPassword') + }, async basicLogin() { try { const { oms, token, expirationTime } = this.$route.query as any @@ -339,6 +367,12 @@ export default defineComponent({ omsUrl = omsUrl ? omsUrl : this.authStore.oms.startsWith('http') ? this.authStore.oms.includes('/api') ? this.authStore.oms : `${this.authStore.oms}/api/` : this.authStore.oms window.location.replace(`${url}?oms=${omsUrl}&token=${this.authStore.token.value}&expirationTime=${this.authStore.token.expiration}${omsRedirectionUrl ? '&omsRedirectionUrl=' + omsRedirectionUrl : ''}`) + }, + async openForgotPasswordModal(){ + const rejectOrderModal = await modalController.create({ + component:ForgotPasswordModal, + }) + return rejectOrderModal.present() } }, setup () { @@ -348,7 +382,8 @@ export default defineComponent({ arrowForwardOutline, authStore, gridOutline, - router + router, + warningOutline }; } }); @@ -364,5 +399,8 @@ export default defineComponent({ align-items: center; height: 100%; } - +.ion-item-banner { + --background:#ED576B1A; + --border-radius: 8px; +} diff --git a/src/views/ResetPassword.vue b/src/views/ResetPassword.vue new file mode 100644 index 0000000..28b92b7 --- /dev/null +++ b/src/views/ResetPassword.vue @@ -0,0 +1,162 @@ + + + + + \ No newline at end of file From 1a1c7bb2ecc9ac7539d0018d672c21a96b76096a Mon Sep 17 00:00:00 2001 From: Nirvan Bobde Date: Thu, 7 Aug 2025 10:13:31 +0530 Subject: [PATCH 02/10] Fixed : removed unused code and consoles (#63) --- src/views/ResetPassword.vue | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/views/ResetPassword.vue b/src/views/ResetPassword.vue index 28b92b7..c59d05f 100644 --- a/src/views/ResetPassword.vue +++ b/src/views/ResetPassword.vue @@ -22,8 +22,6 @@ -

{{ newPassword }} : {{ confirmPassword }}

-
{{ $t("Reset Password") }} From 7cde4097f2b18df19850d692426f15a6447464fd Mon Sep 17 00:00:00 2001 From: Nirvan Bobde Date: Thu, 7 Aug 2025 11:06:51 +0530 Subject: [PATCH 03/10] Fixed : added static text to locales file (#63) --- src/components/ForgotPasswordModal.vue | 2 +- src/locales/en.json | 8 ++++++++ src/views/ResetPassword.vue | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/components/ForgotPasswordModal.vue b/src/components/ForgotPasswordModal.vue index 265ae27..e48f942 100644 --- a/src/components/ForgotPasswordModal.vue +++ b/src/components/ForgotPasswordModal.vue @@ -103,7 +103,7 @@ export default defineComponent({ if (!hasError(resp)) { this.successMessage = this.$t( - 'Your request for reset password has been processed. Please check your email, for further instructions.', + 'Your request for reset password has been processed. Please check your email, for further instructions.' ); this.errorMessage = ''; this.router.push('/resetPassword') diff --git a/src/locales/en.json b/src/locales/en.json index 0dd586e..f8e926f 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1,9 +1,14 @@ { + "Confirm Password": "Confirm Password", "Failed to fetch user-profile, please try again": "Failed to fetch user-profile, please try again", + "Failed to reset password, please try again and follow the instructions for creating a new password.": "Failed to reset password, please try again and follow the instructions for creating a new password.", + "Failed to send password reset link, please try again or contact administrator.": "Failed to send password reset link, please try again or contact administrator.", + "Finish resetting your password": "Finish resetting your password", "Launch Pad": "Launch Pad", "Login": "Login", "Logout": "Logout", "Logging out...": "Logging out...", + "New Password": "New Password", "Next": "Next", "Not configured": "Not configured", "OMS": "OMS", @@ -16,6 +21,9 @@ "Sorry, your username or password is incorrect. Please try again.": "Sorry, your username or password is incorrect. Please try again.", "This application is not enabled for your account": "This application is not enabled for your account", "Username": "Username", + "Username cannot be empty.": "Username cannot be empty.", "View profile": "View profile", + "Your password has been successfully reset.": "Your password has been successfully reset.", + "Your request for reset password has been processed. Please check your email, for further instructions.":"Your request for reset password has been processed. Please check your email, for further instructions.", "Your username must have an email already associated with it in HotWax to receive a reset password email. If you do not have an email linked to your account already, please contact your administrator to manually reset your password.":"Your username must have an email already associated with it in HotWax to receive a reset password email. If you do not have an email linked to your account already, please contact your administrator to manually reset your password." } \ No newline at end of file diff --git a/src/views/ResetPassword.vue b/src/views/ResetPassword.vue index c59d05f..4e34e92 100644 --- a/src/views/ResetPassword.vue +++ b/src/views/ResetPassword.vue @@ -125,7 +125,7 @@ export default defineComponent({ throw resp.data; } } catch(err: any) { - this.errorMessage = 'Failed to reset password, please try again and follow the instructions for creating a new password.' + this.errorMessage = this.$t('Failed to reset password, please try again and follow the instructions for creating a new password.') console.error('Failed to reset password', err) } }, From 028d3809654bba274001ff428d8561a7db8e141e Mon Sep 17 00:00:00 2001 From: Nirvan Bobde Date: Thu, 7 Aug 2025 15:49:42 +0530 Subject: [PATCH 04/10] Fixed : styles for the login page forgot password message box (#63) --- src/views/Login.vue | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/views/Login.vue b/src/views/Login.vue index b1393d0..2339037 100644 --- a/src/views/Login.vue +++ b/src/views/Login.vue @@ -47,9 +47,9 @@ {{ $t('The username or password you entered is incorrect. Please try again.') }} - - {{ $t('forgot password') }} - + + {{ $t('forgot password') }} +
@@ -403,4 +403,8 @@ export default defineComponent({ --background:#ED576B1A; --border-radius: 8px; } +.forgot-password-label{ + text-decoration: underline; + cursor: pointer; +} From a6fc8190dd951b2ed9e597ae2d570d0584a6c032 Mon Sep 17 00:00:00 2001 From: Nirvan Bobde Date: Wed, 20 Aug 2025 10:45:10 +0530 Subject: [PATCH 05/10] Fixed : improved indentations issues (#63) --- src/components/ForgotPasswordModal.vue | 16 ++++++++-------- src/store/auth.ts | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/ForgotPasswordModal.vue b/src/components/ForgotPasswordModal.vue index e48f942..a9a7985 100644 --- a/src/components/ForgotPasswordModal.vue +++ b/src/components/ForgotPasswordModal.vue @@ -1,13 +1,13 @@ @@ -85,10 +81,8 @@ export default defineComponent({ loader: null as any, newPassword: '', confirmPassword: '', - passwordMatchError: false, showConfirmPassword: false, showNewPassword: false, - isUsernameEmpty: false, errorMessage: '', passwordResetSuccess: false }; @@ -100,13 +94,15 @@ export default defineComponent({ this.confirmPassword = '' this.showConfirmPassword = false this.showNewPassword = false - this.passwordMatchError = false - this.isUsernameEmpty = false this.passwordResetSuccess = false }, methods: { async resetPassword() { - if(this.newPassword !== this.confirmPassword) { + if (!this.newPassword.trim() || !this.confirmPassword.trim()) { + this.errorMessage = 'Fill all the required fields and try again.' + return; + } + if(this.newPassword.trim() !== this.confirmPassword.trim()) { this.errorMessage = 'Passwords do not match. Please try again' return; } From 50a190f8f130d81115daf43919262a07c4e72438 Mon Sep 17 00:00:00 2001 From: Nirvan-Bobde30 Date: Wed, 24 Sep 2025 12:13:32 +0530 Subject: [PATCH 08/10] Fixed : Forgot password flow ,changed api endpoint for reset password email and some minor fixes (#63) --- src/components/ForgotPasswordModal.vue | 8 ++++---- src/services/UserService.ts | 2 +- src/views/Login.vue | 7 ++++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/components/ForgotPasswordModal.vue b/src/components/ForgotPasswordModal.vue index 5783bd6..0bb7f01 100644 --- a/src/components/ForgotPasswordModal.vue +++ b/src/components/ForgotPasswordModal.vue @@ -54,6 +54,7 @@ import { closeOutline, informationOutline, sendOutline } from 'ionicons/icons'; import { UserService } from '@/services/UserService'; import { hasError } from '@hotwax/oms-api'; import { useRouter } from 'vue-router'; +import { showToast } from '@/util'; export default defineComponent({ name:'ForgotPasswordModal', @@ -101,11 +102,10 @@ export default defineComponent({ const resp = await UserService.forgotPassword(params); if (!hasError(resp)) { - this.successMessage = this.$t( - 'Your request for reset password has been processed. Please check your email, for further instructions.' - ); + this.successMessage = this.$t(resp.data._EVENT_MESSAGE_); this.errorMessage = ''; - this.router.push('/resetPassword') + showToast(this.successMessage) + this.closeModal() } else { throw resp.data._ERROR_MESSAGE_; } diff --git a/src/services/UserService.ts b/src/services/UserService.ts index 6c173d9..f16eef1 100644 --- a/src/services/UserService.ts +++ b/src/services/UserService.ts @@ -140,7 +140,7 @@ const resetPassword = async(params: any) : Promise => { const forgotPassword = async(params: any) : Promise => { return api({ - url: "service/sendResetPasswordMailToParty", + url: "sendResetPasswordEmail", method: "post", data: params }) diff --git a/src/views/Login.vue b/src/views/Login.vue index 7cf8a78..c409ca1 100644 --- a/src/views/Login.vue +++ b/src/views/Login.vue @@ -309,9 +309,6 @@ export default defineComponent({ console.error(error) } }, - forgotPassword() { - this.router.push('/forgotPassword') - }, async basicLogin() { try { const { oms, token, expirationTime } = this.$route.query as any @@ -373,6 +370,10 @@ export default defineComponent({ const forgotPasswordModal = await modalController.create({ component:ForgotPasswordModal, }) + forgotPasswordModal.onDidDismiss() + this.errorMessage = '' + this.username = '' + this.password = '' return forgotPasswordModal.present() } }, From b6bfe3683c25969268781d571a5121c7bd3a9077 Mon Sep 17 00:00:00 2001 From: Nirvan-Bobde30 Date: Tue, 14 Oct 2025 18:45:00 +0530 Subject: [PATCH 09/10] Fixed : indentation issue and updated UI according figma (#63) --- src/components/ForgotPasswordModal.vue | 8 ++++---- src/views/Login.vue | 11 ++++------- src/views/ResetPassword.vue | 2 +- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/components/ForgotPasswordModal.vue b/src/components/ForgotPasswordModal.vue index 0bb7f01..c29b3aa 100644 --- a/src/components/ForgotPasswordModal.vue +++ b/src/components/ForgotPasswordModal.vue @@ -6,10 +6,10 @@ - {{$t("Reset Password")}} + {{$t("Reset password")}} - + @@ -21,8 +21,8 @@ - - {{ $t("Your username must have an email already associated with it in HotWax to receive a reset password email. If you do not have an email linked to your account already, please contact your administrator to manually reset your password.") }} + + {{ $t("Your username must have an email already associated with it in HotWax to receive a reset password email. If you do not have an email linked to your account already, please contact your administrator to manually reset your password.") }} diff --git a/src/views/Login.vue b/src/views/Login.vue index c409ca1..51654f6 100644 --- a/src/views/Login.vue +++ b/src/views/Login.vue @@ -46,10 +46,8 @@
{{ $t('The username or password you entered is incorrect. Please try again.') }} - - - {{ $t('forgot password') }} - + + {{ $t('forgot password') }}
@@ -405,8 +403,7 @@ export default defineComponent({ --background:#ED576B1A; --border-radius: 8px; } -.forgot-password-label{ - text-decoration: underline; - cursor: pointer; +.forgot-password-color { + color: #EB445A; } diff --git a/src/views/ResetPassword.vue b/src/views/ResetPassword.vue index abf66ab..d15d625 100644 --- a/src/views/ResetPassword.vue +++ b/src/views/ResetPassword.vue @@ -33,7 +33,7 @@