Skip to content

Commit

Permalink
Implemented: support to reset the password for the user(hotwax#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
ymaheshwari1 committed Oct 25, 2023
1 parent 2db8459 commit 81ed2e0
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 2 deletions.
15 changes: 15 additions & 0 deletions src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -12,6 +13,14 @@ 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 routes: Array<RouteRecordRaw> = [
{
path: '/',
Expand All @@ -27,6 +36,12 @@ const routes: Array<RouteRecordRaw> = [
name: 'Login',
component: Login,
beforeEnter: loginGuard
},
{
path: '/resetPassword',
name: 'ResetPassword',
component: ResetPassword,
beforeEnter: authGuard
}
];

Expand Down
11 changes: 10 additions & 1 deletion src/services/UserService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,17 @@ const checkLoginOptions = async (): Promise<any> => {
});
}

const resetPassword = async(params: any) : Promise<any> => {
return api({
url: "service/resetPassword",
method: "POST",
data: params
})
}

export const UserService = {
getUserProfile,
checkLoginOptions,
login
login,
resetPassword
}
5 changes: 5 additions & 0 deletions src/store/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const useAuthStore = defineStore('authStore', {
this.redirectUrl = redirectUrl
},
async login(username: string, password: string) {
let requirePasswordChange = false; // denotes if password change is required for the user
try {
const resp = await UserService.login(username, password);
if (hasError(resp)) {
Expand All @@ -54,6 +55,8 @@ export const useAuthStore = defineStore('authStore', {
expiration: resp.data.expirationTime
}

requirePasswordChange = resp.data.requirePasswordChange

this.current = await UserService.getUserProfile(this.token.value);
updateToken(this.token.value)
// Handling case for warnings like password may expire in few days
Expand All @@ -68,6 +71,8 @@ export const useAuthStore = defineStore('authStore', {
console.error("error: ", error);
return Promise.reject(new Error(error))
}

return requirePasswordChange;
},
async samlLogin(token: string, expirationTime: string) {
try {
Expand Down
11 changes: 10 additions & 1 deletion src/views/Login.vue
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,16 @@ export default defineComponent({
}
try {
await this.authStore.login(username.trim(), password)
const requirePasswordChange = await this.authStore.login(username.trim(), password)
// when password needs to be changed, redirecting the user to reset page
if(requirePasswordChange) {
this.username = ''
this.password = ''
this.router.push('/resetPassword');
return
}
if (this.authStore.getRedirectUrl) {
window.location.href = `${this.authStore.getRedirectUrl}?oms=${this.authStore.oms}&token=${this.authStore.token.value}&expirationTime=${this.authStore.token.expiration}`
} else {
Expand Down
161 changes: 161 additions & 0 deletions src/views/ResetPassword.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
<template>
<ion-page>
<ion-content>
<div class="flex">
<form class="login-container" @keyup.enter="resetPassword()" @submit.prevent="resetPassword()">
<Logo />
<section>
<ion-item lines="full">
<ion-label position="fixed">{{ $t("New Password") }}</ion-label>
<ion-input @ionFocus="passwordMatchError = false" name="newPassword" v-model="newPassword" id="newPassword" :type="showNewPassword ? 'text' : 'password'" />
<ion-note slot="error">Invalid email</ion-note>
<ion-button fill="clear" @click="showNewPassword = !showNewPassword">
<ion-icon :icon="showNewPassword ? eyeOutline : eyeOffOutline"/>
</ion-button>
</ion-item>
<ion-item lines="none">
<ion-label position="fixed">{{ $t("Confirm Password") }}</ion-label>
<ion-input @ionFocus="passwordMatchError = false" name="confirmPassword" v-model="confirmPassword" id="confirmPassword" :type="showConfirmPassword ? 'text' : 'password'" error-text="Please enter password" />
<ion-button fill="clear" @click="showConfirmPassword = !showConfirmPassword">
<ion-icon :icon="showConfirmPassword ? eyeOutline : eyeOffOutline"/>
</ion-button>
</ion-item>

<div class="ion-padding">
<ion-button color="primary" expand="block" type="submit">
{{ $t("Reset Password") }}
<ion-icon slot="end" :icon="arrowForwardOutline" />
</ion-button>
</div>

<ion-item lines="none" v-show="passwordMatchError">
<ion-icon color="danger" slot="start" :icon="closeCircleOutline" />
<ion-label>{{ $t('Passwords do not match. Please try again.') }}</ion-label>
</ion-item>
</section>
</form>
</div>
</ion-content>
</ion-page>
</template>


<script lang="ts">
import {
IonButton,
IonContent,
IonIcon,
IonInput,
IonItem,
IonLabel,
IonPage,
IonNote,
loadingController
} 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, closeCircleOutline, eyeOutline, eyeOffOutline, gridOutline } from 'ionicons/icons'
import { translate } from "@/i18n";
import { UserService } from '@/services/UserService'
import { hasError } from "@/adapter";
export default defineComponent({
name: "Login",
components: {
IonButton,
IonContent,
IonIcon,
IonInput,
IonItem,
IonLabel,
IonPage,
IonNote,
Logo
},
data () {
return {
loader: null as any,
newPassword: '',
confirmPassword: '',
passwordMatchError: false,
showConfirmPassword: false,
showNewPassword: false,
isUsernameEmpty: false
};
},
methods: {
async presentLoader(message: string) {
if (!this.loader) {
this.loader = await loadingController
.create({
message: translate(message),
translucent: true,
backdropDismiss: false
});
}
this.loader.present();
},
dismissLoader() {
if (this.loader) {
this.loader.dismiss();
this.loader = null as any;
}
},
async resetPassword() {
if(this.newPassword !== this.confirmPassword) {
this.passwordMatchError = true
return;
}
const params = {
newPassword: this.newPassword,
newPasswordVerify: this.confirmPassword
}
try {
const resp = await UserService.resetPassword(params);
if(!hasError(resp) && resp?.data?.successMessage) {
if (this.authStore.getRedirectUrl) {
window.location.href = `${this.authStore.getRedirectUrl}?oms=${this.authStore.oms}&token=${this.authStore.token.value}&expirationTime=${this.authStore.token.expiration}`
} else {
this.router.push('/')
}
} else {
throw resp.data;
}
} catch(err) {
console.error('Failed to reset password', err)
}
}
},
setup () {
const router = useRouter();
const authStore = useAuthStore();
return {
arrowForwardOutline,
authStore,
closeCircleOutline,
eyeOutline,
eyeOffOutline,
gridOutline,
router
};
}
});
</script>
<style scoped>
.login-container {
width: 375px;
}
.flex {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
</style>

0 comments on commit 81ed2e0

Please sign in to comment.