Skip to content

Commit 2278a27

Browse files
feat(auth): password reset ✨
1 parent 725f499 commit 2278a27

File tree

6 files changed

+277
-36
lines changed

6 files changed

+277
-36
lines changed

src/modules/auth/router/auth.router.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
*/
44
import signin from '@/modules/auth/views/auth.signin.view.vue';
55
import signup from '@/modules/auth/views/auth.signup.view.vue';
6+
import forgot from '@/modules/auth/views/auth.forgot.view.vue';
7+
import reset from '@/modules/auth/views/auth.reset.view.vue';
68

79
/**
810
* Router configuration
@@ -25,4 +27,20 @@ export default [
2527
display: false, // hide any time
2628
},
2729
},
30+
{
31+
path: '/forgot',
32+
name: 'Forgot',
33+
component: forgot,
34+
meta: {
35+
display: false, // hide any time
36+
},
37+
},
38+
{
39+
path: '/reset',
40+
name: 'Reset',
41+
component: reset,
42+
meta: {
43+
display: false, // hide any time
44+
},
45+
},
2846
];

src/modules/auth/stores/auth.store.js

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const api = `${config.api.protocol}://${config.api.host}:${config.api.port}/${co
1212
const getters = {
1313
isLoggedIn: (state) => !!state.cookieExpire,
1414
authStatus: (state) => state.status,
15+
mail: (state) => state.mail,
1516
};
1617

1718
/**
@@ -31,7 +32,7 @@ const actions = {
3132
dispatch('refreshNav');
3233
} catch (err) {
3334
localStorage.removeItem('token');
34-
commit('auth_error');
35+
commit('auth_error', err);
3536
}
3637
},
3738
signup: async ({ commit, dispatch }, params) => {
@@ -47,47 +48,79 @@ const actions = {
4748
dispatch('refreshNav');
4849
} catch (err) {
4950
localStorage.removeItem('token');
50-
commit('auth_error');
51+
commit('auth_error', err);
5152
}
5253
},
53-
signout({ commit }) {
54-
return new Promise((resolve) => {
54+
signout: ({ commit }) =>
55+
new Promise((resolve) => {
5556
commit('auth_logout');
5657
localStorage.removeItem(`${config.cookie.prefix}UserRoles`);
5758
localStorage.removeItem(`${config.cookie.prefix}CookieExpire`);
5859
resolve();
59-
});
60+
}),
61+
forgot: async ({ commit }, params) => {
62+
try {
63+
const res = await Vue.prototype.axios({
64+
url: `${api}/${config.api.endPoints.auth}/forgot`,
65+
data: params,
66+
method: 'POST',
67+
});
68+
commit('forgot_success', res.data);
69+
} catch (err) {
70+
commit('auth_error', err);
71+
}
72+
},
73+
reset: async ({ commit, dispatch }, params) => {
74+
try {
75+
const res = await Vue.prototype.axios({
76+
url: `${api}/${config.api.endPoints.auth}/reset`,
77+
data: params,
78+
method: 'POST',
79+
});
80+
localStorage.setItem(`${config.cookie.prefix}UserRoles`, res.data.user.roles);
81+
localStorage.setItem(`${config.cookie.prefix}CookieExpire`, res.data.tokenExpiresIn);
82+
commit('auth_success', res.data);
83+
dispatch('refreshNav');
84+
} catch (err) {
85+
localStorage.removeItem('token');
86+
commit('auth_error', err);
87+
}
6088
},
6189
};
6290

6391
/**
6492
* Mutation: change state in a Vuex store is by committing a mutation
6593
*/
6694
const mutations = {
67-
auth_request(state) {
68-
state.status = 'loading';
69-
},
7095
auth_success(state, data) {
71-
state.status = 'success';
7296
state.cookieExpire = data.tokenExpiresIn;
7397
state.user = data.user;
7498
},
75-
auth_error(state) {
76-
state.status = 'error';
99+
auth_error(state, err) {
100+
console.log(err);
77101
},
78102
auth_logout(state) {
79-
state.status = '';
80103
state.cookieExpire = 0;
81104
},
105+
forgot_success(state, data) {
106+
state.mail.status = data.data.status;
107+
state.mail.message = data.message;
108+
},
109+
reset_success(state, data) {
110+
console.log(data);
111+
},
82112
};
83113

84114
/**
85115
* State
86116
*/
87117
const state = {
88-
status: '',
89118
cookieExpire: localStorage.getItem(`${config.cookie.prefix}CookieExpire`) || 0,
90119
user: {},
120+
mail: {
121+
status: false,
122+
message: '',
123+
},
91124
};
92125

93126
/**
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<template>
2+
<v-container fluid>
3+
<v-row align="start" justify="center">
4+
<v-card
5+
class="mx-6 my-3"
6+
outlined
7+
tile
8+
width="100%"
9+
:style="{ background: config.vuetify.theme.themes[theme].surface }"
10+
:flat="config.vuetify.theme.flat"
11+
>
12+
<v-col cols="12">
13+
<v-subheader><h4>Forgot</h4></v-subheader>
14+
<v-divider></v-divider>
15+
</v-col>
16+
<v-container>
17+
<v-form ref="form" v-model="valid">
18+
<v-row>
19+
<v-col cols="12">
20+
<v-text-field
21+
v-model="email"
22+
:rules="[rules.required, rules.mail]"
23+
label="E-mail"
24+
prepend-icon="fa fa-envelope"
25+
required
26+
></v-text-field>
27+
</v-col>
28+
<v-col cols="12">
29+
<v-btn
30+
:disabled="!valid || mail.status"
31+
color="success"
32+
class="mr-4"
33+
@click="validate"
34+
>Validate</v-btn
35+
>
36+
<v-btn color="error" class="mr-4" @click="reset">Reset Form</v-btn>
37+
</v-col>
38+
</v-row>
39+
</v-form>
40+
<br />
41+
<p v-if="config.vuetify.theme.signup">
42+
<b>
43+
<router-link to="/signin">Back</router-link>
44+
</b>
45+
to sign in !
46+
</p>
47+
<v-alert v-if="mail.message" type="success">
48+
{{ mail.message }}
49+
</v-alert>
50+
</v-container>
51+
</v-card>
52+
</v-row>
53+
</v-container>
54+
</template>
55+
56+
<script>
57+
/**
58+
* Module dependencies.
59+
*/
60+
import { mapGetters } from 'vuex';
61+
/**
62+
* Export default
63+
*/
64+
export default {
65+
data() {
66+
return {
67+
valid: false,
68+
email: '',
69+
rules: {
70+
required: (v) => !!v || 'Required',
71+
mail: (v) => /\S+@\S+\.\S+/.test(v) || 'E-mail must be valid',
72+
},
73+
};
74+
},
75+
computed: {
76+
...mapGetters(['theme', 'mail']),
77+
},
78+
methods: {
79+
validate() {
80+
if (this.$refs.form.validate()) {
81+
const { email } = this;
82+
this.$store.dispatch('forgot', { email }).catch((err) => console.log(err));
83+
}
84+
},
85+
reset() {
86+
this.$refs.form.reset();
87+
},
88+
},
89+
};
90+
</script>
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<template>
2+
<v-container fluid>
3+
<v-row align="start" justify="center">
4+
<v-card
5+
class="mx-6 my-3"
6+
outlined
7+
tile
8+
width="100%"
9+
:style="{ background: config.vuetify.theme.themes[theme].surface }"
10+
:flat="config.vuetify.theme.flat"
11+
>
12+
<v-col cols="12">
13+
<v-subheader><h4>Reset</h4></v-subheader>
14+
<v-divider></v-divider>
15+
</v-col>
16+
<v-container>
17+
<v-form ref="form" v-model="valid">
18+
<v-row>
19+
<v-col cols="12">
20+
<v-text-field
21+
:type="'password'"
22+
:rules="[rules.password]"
23+
v-model="password"
24+
label="New password"
25+
prepend-icon="fa fa-key"
26+
required
27+
></v-text-field>
28+
</v-col>
29+
<v-col cols="12">
30+
<v-btn :disabled="!valid" color="success" class="mr-4" @click="validate"
31+
>Validate</v-btn
32+
>
33+
<v-btn color="error" class="mr-4" @click="reset">Reset Form</v-btn>
34+
</v-col>
35+
</v-row>
36+
</v-form>
37+
<br />
38+
<p v-if="config.vuetify.theme.signup">
39+
<b>
40+
<router-link to="/signin">Back</router-link>
41+
</b>
42+
to sign in !
43+
</p>
44+
</v-container>
45+
</v-card>
46+
</v-row>
47+
</v-container>
48+
</template>
49+
50+
<script>
51+
/**
52+
* Module dependencies.
53+
*/
54+
import { mapGetters } from 'vuex';
55+
/**
56+
* Export default
57+
*/
58+
export default {
59+
data() {
60+
return {
61+
valid: false,
62+
password: '',
63+
rules: {
64+
required: (v) => !!v || 'Required',
65+
mail: (v) => /\S+@\S+\.\S+/.test(v) || 'E-mail must be valid',
66+
},
67+
};
68+
},
69+
computed: {
70+
...mapGetters(['theme', 'mail']),
71+
},
72+
methods: {
73+
validate() {
74+
if (this.$refs.form.validate()) {
75+
const { password } = this;
76+
this.$store
77+
.dispatch('reset', { newPassword: password, token: this.$route.query.token })
78+
.then(() => this.$router.push(this.config.sign.route))
79+
.catch((err) => console.log(err));
80+
}
81+
},
82+
reset() {
83+
this.$refs.form.reset();
84+
},
85+
},
86+
};
87+
</script>

src/modules/auth/views/auth.signin.view.vue

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,40 +9,48 @@
99
:style="{ background: config.vuetify.theme.themes[theme].surface }"
1010
:flat="config.vuetify.theme.flat"
1111
>
12-
<v-container class="pa-10">
12+
<v-col cols="12">
13+
<v-subheader><h4>Sign In</h4></v-subheader>
14+
<v-divider></v-divider>
15+
</v-col>
16+
<v-container>
1317
<v-form ref="form" v-model="valid">
1418
<v-row>
1519
<v-col cols="12">
1620
<v-text-field
1721
v-model="email"
1822
:rules="[rules.required, rules.mail]"
1923
label="E-mail"
24+
prepend-icon="fa fa-envelope"
2025
required
2126
></v-text-field>
22-
</v-col>
23-
<v-col cols="12">
2427
<v-text-field
2528
:type="'password'"
2629
:rules="[rules.password]"
2730
v-model="password"
2831
label="Password"
32+
prepend-icon="fa fa-key"
2933
required
3034
></v-text-field>
3135
</v-col>
32-
</v-row>
33-
<v-row>
34-
<v-btn :disabled="!valid" color="success" class="mr-4" @click="validate"
35-
>Validate</v-btn
36-
>
37-
<v-btn color="error" class="mr-4" @click="reset">Reset Form</v-btn>
36+
<v-col cols="12">
37+
<v-btn :disabled="!valid" color="success" class="mr-4" @click="validate"
38+
>Validate</v-btn
39+
>
40+
<v-btn color="error" class="mr-4" @click="reset">Reset Form</v-btn>
41+
</v-col>
3842
</v-row>
3943
</v-form>
4044
<br />
4145
<p v-if="config.vuetify.theme.signup">
4246
<b>
4347
<router-link to="/signup">Sign Up</router-link>
4448
</b>
45-
if you have no account yet :) !
49+
if you don't have an account yet :) ! or maybe
50+
<b>
51+
<router-link to="/forgot">reset</router-link>
52+
</b>
53+
your password ?
4654
</p>
4755
</v-container>
4856
</v-card>

0 commit comments

Comments
 (0)