@sowell/quasar-app-extension-auth 0.3.5 → 0.3.8

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.
@@ -1,67 +1,93 @@
1
1
  <template>
2
2
  <q-layout>
3
3
  <div class="row window-height">
4
- <div class="column col content-center justify-center">
5
- <div style="max-width:500px">
6
- <h4 class="title">{{ $t('auth.title') }}</h4>
7
- <div class="subtitle">{{ $t('auth.subtitle') }}</div>
8
- <q-form @submit="onSubmit">
9
- <div>
10
- <div
11
- class="q-ml-xs q-mb-xs text-subtitle2 text-weight-bold"
12
- >
13
- {{ $t('auth.email') }}
4
+ <div class="col column content-center bgWhite">
5
+ <div class="q-mt-xl">
6
+ <img
7
+ src="../../assets/Sowell-logo.svg"
8
+ style="width: 210px"
9
+ class="logoWhite"
10
+ />
11
+ </div>
12
+ <div class="column col content-center justify-center bgWhite">
13
+ <div style="max-width: 500px">
14
+ <h4 class="title">{{ WELCOME_TITLE }}</h4>
15
+ <div class="subtitle">{{ WELCOME_SUBTITLE }}</div>
16
+ <q-form @submit="onSubmit">
17
+ <div>
18
+ <div class="q-ml-xs q-mb-xs text-subtitle2 text-weight-bold">
19
+ {{ $t("auth.email") }}
20
+ </div>
21
+ <q-input
22
+ v-model.trim="email"
23
+ type="email"
24
+ :rules="validations['email']"
25
+ lazy-rules
26
+ data-cy="email"
27
+ dense
28
+ outlined
29
+ input-class="text-subtitle2 text-weight-medium"
30
+ />
31
+ <div class="q-ml-xs q-mb-xs text-subtitle2 text-weight-bold">
32
+ {{ $t("auth.password") }}
33
+ </div>
34
+ <q-input
35
+ v-model="password"
36
+ :type="showPassword ? 'text' : 'password'"
37
+ :rules="validations['password']"
38
+ data-cy="password"
39
+ lazy-rules
40
+ dense
41
+ outlined
42
+ input-class="text-subtitle2 text-weight-bold"
43
+ >
44
+ <template #append>
45
+ <q-icon
46
+ :name="
47
+ showPassword ? icons.ionEyeSharp : icons.ionEyeOffSharp
48
+ "
49
+ class="cursor-pointer q-mr-sm lightenDark"
50
+ @click="showPassword = !showPassword"
51
+ />
52
+ </template>
53
+ </q-input>
14
54
  </div>
15
- <q-input
16
- v-model.trim="email"
17
- type="email"
18
- :rules="validations['email']"
19
- lazy-rules
20
- dense
21
- standout
22
- input-class="text-subtitle2 text-weight-medium"
23
- />
24
- <div
25
- class="q-ml-xs q-mb-xs text-subtitle2 text-weight-bold"
26
- >
27
- {{ $t('auth.password') }}
55
+ <div class="row justify-between items-center">
56
+ <q-btn
57
+ :label="$t('auth.login')"
58
+ color="primary"
59
+ no-caps
60
+ unelevated
61
+ data-cy="submit-login"
62
+ text-color="white"
63
+ :loading="loading"
64
+ type="submit"
65
+ :disable="isSubmitBtnDisabled()"
66
+ class="submitBtn text-subtitle2 text-weight-bold"
67
+ />
68
+ <div
69
+ class="cursor-pointer text-primary text-subtitle2"
70
+ data-cy="forgot-password"
71
+ @click="forgottenPassword = true"
72
+ >
73
+ {{ $t("auth.forgottenPassword") }}
74
+ </div>
28
75
  </div>
29
- <q-input
30
- v-model="password"
31
- :type="showPassword ? 'text' : 'password'"
32
- :rules="validations['password']"
33
- lazy-rules
34
- dense
35
- standout
36
- input-class="text-subtitle2 text-weight-bold"
37
- >
38
- <template #append>
39
- <q-icon
40
- :name="showPassword ? ionEyeSharp : ionEyeOffSharp"
41
- class="cursor-pointer q-mr-sm"
42
- @click="showPassword = !showPassword"
43
- />
44
- </template>
45
- </q-input>
46
- </div>
47
- <div class="row justify-between items-center">
48
- <q-btn
49
- :label="$t('auth.login')"
50
- color="primary"
51
- no-caps
52
- unelevated
53
- text-color="white"
54
- :loading="loading"
55
- type="submit"
56
- :disable="submitBtnDisabled"
57
- />
58
- <div class="cursor-pointer" @click="forgottenPassword = true">{{ $t('auth.forgottenPassword') }}</div>
59
- </div>
60
- </q-form>
76
+ </q-form>
77
+ </div>
61
78
  </div>
62
79
  </div>
63
- <div class="column col bgBlue justify-center content-center">
64
- <img src="../../assets/SowellWhite.svg" class="logoWhite"/>
80
+ <div
81
+ class="column col justify-center content-center"
82
+ :style="isManager ? 'background: #eef8fd' : ''"
83
+ :class="!isManager ? 'bgBlue' : ''"
84
+ >
85
+ <img
86
+ v-if="isManager"
87
+ src="../../assets/illustration-login.svg"
88
+ style="width: 600px"
89
+ />
90
+ <img v-else src="../../assets/SowellWhite.svg" class="logoWhite" />
65
91
  </div>
66
92
  </div>
67
93
  <div>
@@ -73,14 +99,13 @@
73
99
  transition-hide="fade"
74
100
  persistent
75
101
  >
76
- <send-email @resetPassword="resetPassword" />
102
+ <web-send-email @resetPassword="resetPassword" />
77
103
  </q-dialog>
78
- <q-dialog v-model="isReset" persistent>
79
- <sowell-message
80
- :emailResetPassword="emailResetPassword"
81
- :sendEmailSuccess="sendEmailSuccess"
82
- :loading="loading"
83
- @retypeEmail="retypeEmail"
104
+ <q-dialog v-model="isNotification" persistent>
105
+ <sw-info-dialog
106
+ :title="infoDialog.title"
107
+ :content="infoDialog.content"
108
+ :image="infoDialog.image"
84
109
  />
85
110
  </q-dialog>
86
111
  </div>
@@ -89,203 +114,132 @@
89
114
 
90
115
  <script lang="ts">
91
116
  import isEmail from "validator/es/lib/isEmail";
92
- import { defineComponent, ref, onMounted, computed } from "vue";
93
- import { $api, $prompts, $router, $store } from "../../injects";
94
- import { useQuasar } from "quasar";
117
+ import { defineComponent, ref, computed } from "vue";
118
+ import { useAuthState } from "../../injects";
95
119
  import { useI18n } from "vue-i18n";
96
- import { AxiosError, AxiosResponse } from "axios";
97
- import prompts from "app/quasar.extensions.json";
98
- import SendEmail from "../dialogs/SendEmail.vue";
99
- import SowellMessage from "../dialogs/Message.vue";
100
- import {
101
- ionMailOutline,
102
- ionLockClosedOutline,
103
- ionEyeSharp,
104
- ionEyeOffSharp,
105
- ionAlertCircleOutline,
106
- ionCloseOutline
107
- } from "@quasar/extras/ionicons-v5";
120
+ import SwInfoDialog from "../dialogs/sw-info-dialog.vue";
121
+ import WebSendEmail from "../dialogs/WebSendEmail.vue";
122
+
123
+ import { useAuth } from "composables/auth";
108
124
 
109
125
  interface HeadersInterface {
110
126
  headers: {
111
- "x-requested-roles"?: string
112
- }
127
+ "x-requested-roles"?: string;
128
+ };
113
129
  }
114
130
  export default defineComponent({
115
- name: 'Auth',
116
- components: { SendEmail, SowellMessage },
131
+ name: "Auth",
132
+ components: { WebSendEmail, SwInfoDialog },
117
133
  setup() {
118
- const {
119
- "@sowell/auth": { X_REQUESTED_ROLES },
120
- } = prompts;
121
- const email = ref("");
122
- const password = ref("");
123
- const loading = ref(false);
124
- const showPassword = ref(false);
125
- const forgottenPassword = ref(false);
126
- const isReset = ref(false);
127
- const sendEmailSuccess = ref(false);
128
- const emailResetPassword = ref("");
129
- const { post } = $api();
130
- const {
131
- LOCAL_SUCCESS_REDIRECTION_ROUTE,
132
- AUTH_SERVER_SIGNING_ROUTE,
133
- AUTH_SERVER_RESET_PASSWORD_ROUTE,
134
- APP_SERVER_BASE_URL,
135
- } = $prompts();
136
- const $q = useQuasar();
137
- const { push, replace } = $router();
138
- const { dispatch, getters } = $store();
139
134
  const { t } = useI18n();
135
+ const authState = useAuthState();
140
136
 
141
- onMounted(() => {
142
- if (getters["token/getRaw"]) {
143
- replace(LOCAL_SUCCESS_REDIRECTION_ROUTE);
144
- }
145
- });
137
+ const {
138
+ email,
139
+ password,
140
+ loading,
141
+ showPassword,
142
+ validations,
143
+ forgottenPassword,
144
+ emailResetPassword,
145
+ WELCOME_TITLE,
146
+ WELCOME_SUBTITLE,
147
+ X_REQUESTED_ROLES,
148
+ APP_SERVER_BASE_URL,
149
+ onSubmit,
150
+ retypeEmail,
151
+ isSubmitBtnDisabled,
152
+ icons,
153
+ } = useAuth();
146
154
 
147
- const validations = ref({
148
- email: [
149
- (val: string) => !!val || t("auth.emailPresenceError"),
150
- (val: string) => isEmail(val.trim()) || t("auth.emailValidationError"),
151
- ],
152
- password: [(val: string) => !!val || t("auth.passwordPresenceError")],
155
+ const isNotification = ref(false);
156
+ const infoDialog = ref({
157
+ title: "",
158
+ content: "",
159
+ image: "",
153
160
  });
154
161
 
155
- const resetPassword = (email: string) => {
162
+ const submitBtnDisabled = computed(
163
+ () =>
164
+ !(
165
+ email.value &&
166
+ isEmail(email.value) &&
167
+ password.value &&
168
+ password.value.length > 5
169
+ ),
170
+ );
171
+ const isManager = computed(() => X_REQUESTED_ROLES === "clean_manager");
172
+ const resetPassword = async (email: string) => {
156
173
  const data = {
157
174
  auth: {
158
175
  email,
159
176
  base: APP_SERVER_BASE_URL,
160
177
  },
161
178
  };
162
-
163
-
164
- post(AUTH_SERVER_RESET_PASSWORD_ROUTE, data)
165
- .then(() => {
166
- forgottenPassword.value = false;
167
- isReset.value = true;
168
- sendEmailSuccess.value = true;
169
- })
170
- .catch(() => {
171
- isReset.value = true;
172
- });
173
- };
174
-
175
- const retypeEmail = () => {
176
- forgottenPassword.value = true
177
- }
178
-
179
- const onSubmit = () => {
180
- loading.value = true;
181
- const data = {
182
- auth: {
183
- email: email.value,
184
- password: password.value,
185
- },
186
- };
187
- const options: HeadersInterface = {
188
- headers:{}
189
- };
190
- // @ts-ignore
191
- let requestedRoles = window.Cypress ? window.Cypress.requestedRoles : X_REQUESTED_ROLES;
192
- if (requestedRoles) options.headers["x-requested-roles"] = requestedRoles;
193
-
194
- post(AUTH_SERVER_SIGNING_ROUTE, data, options)
195
- .then((response: AxiosResponse) => {
196
- const token = response.data.jwt;
197
- dispatch("token/updateRaw", token);
198
- push(LOCAL_SUCCESS_REDIRECTION_ROUTE);
199
- })
200
- .catch((error: AxiosError) => {
201
- loading.value = false;
202
- switch (error.response?.status) {
203
- case 403:
204
- $q.notify({
205
- message: t("auth.403"),
206
- color: "negative",
207
- icon: ionAlertCircleOutline,
208
- position: "top",
209
- actions: [
210
- {
211
- color: "white",
212
- icon: ionCloseOutline,
213
- },
214
- ],
215
- });
216
- break;
217
- case 404:
218
- $q.notify({
219
- message: t("auth.404"),
220
- color: "negative",
221
- icon: ionAlertCircleOutline,
222
- position: "top",
223
- actions: [
224
- {
225
- color: "white",
226
- icon: ionCloseOutline,
227
- },
228
- ],
229
- });
230
- break;
231
- default:
232
- $q.notify({
233
- message: t("auth.loginFailed"),
234
- color: "negative",
235
- icon: ionAlertCircleOutline,
236
- position: "top",
237
- actions: [
238
- {
239
- color: "white",
240
- icon: ionCloseOutline,
241
- },
242
- ],
243
- });
244
- }
245
- });
179
+ try {
180
+ await authState.resetPassword(data);
181
+ forgottenPassword.value = false;
182
+ infoDialog.value = {
183
+ title: t("auth.mailVerificationTitle"),
184
+ content: t("auth.mailVerificationSubtitle"),
185
+ image: "emailVerification",
186
+ };
187
+ forgottenPassword.value = false;
188
+ isNotification.value = true;
189
+ } catch {
190
+ infoDialog.value = {
191
+ title: t("auth.userNotFoundTitle"),
192
+ content: t("auth.userNotFoundSubtitle"),
193
+ image: "userNotFound",
194
+ };
195
+ isNotification.value = true;
196
+ }
246
197
  };
247
198
 
248
- const submitBtnDisabled = computed(() => !(
249
- email.value &&
250
- isEmail(email.value) &&
251
- password.value &&
252
- password.value.length > 5
253
- )
254
- )
255
199
  return {
256
200
  email,
201
+ infoDialog,
257
202
  password,
258
203
  loading,
259
204
  showPassword,
260
205
  validations,
261
206
  submitBtnDisabled,
262
- onSubmit,
263
207
  forgottenPassword,
264
208
  emailResetPassword,
209
+ isNotification,
210
+ isManager,
211
+ WELCOME_SUBTITLE,
212
+ WELCOME_TITLE,
213
+ isSubmitBtnDisabled,
265
214
  resetPassword,
266
- isReset,
267
215
  retypeEmail,
268
- sendEmailSuccess,
269
- ionMailOutline,
270
- ionLockClosedOutline,
271
- ionEyeSharp,
272
- ionEyeOffSharp,
273
- }
216
+ onSubmit,
217
+ icons,
218
+ };
274
219
  },
275
- })
220
+ });
276
221
  </script>
277
222
 
278
223
  <style scoped>
224
+ .bgWhite {
225
+ background: #ffffff;
226
+ }
279
227
  .bgBlue {
280
228
  background: var(--q-primary);
281
229
  }
230
+ .lightenDark {
231
+ color: rgba(0, 0, 0, 0.24);
232
+ }
282
233
  .title {
283
234
  margin: 0px 0px 16px 0px;
284
235
  }
285
236
  .subtitle {
286
- margin-bottom: 104px
237
+ margin-bottom: 80px;
287
238
  }
288
239
  .logoWhite {
289
- width: 30%
240
+ width: 30%;
241
+ }
242
+ .submitBtn {
243
+ width: 254px;
290
244
  }
291
245
  </style>
@@ -0,0 +1,128 @@
1
+ <template>
2
+ <q-layout>
3
+ <q-page class="q-pa-md row justify-center">
4
+ <div>
5
+ <div class="q-mt-xl">
6
+ <img
7
+ src="../../assets/Sowell-logo.svg"
8
+ class="q-mb-sm q-mr-md"
9
+ style="width: 190px"
10
+ />
11
+ </div>
12
+ <div
13
+ class="column justify-center full-height"
14
+ style="max-width: 550px; margin-top: -90px"
15
+ >
16
+ <div></div>
17
+ <div
18
+ class="text-subtitle1 q-mt-lg"
19
+ style="font-size: 34px; font-weight: 600; line-height: 34px"
20
+ >
21
+ {{ $t("auth.passwordRecovery") }}
22
+ </div>
23
+ <div
24
+ class="text-subtitle1 q-mt-lg q-mb-lg"
25
+ style="font-size: 16px; font-weight: 400; line-height: 24px"
26
+ >
27
+ {{ $t("auth.recommendPassword") }}
28
+ </div>
29
+ <q-form class="column form" @submit="onSubmit">
30
+ <div>
31
+ <div class="q-mb-sm" style="font-size: 14px; font-weight: 600">
32
+ {{ $t("auth.newPassword") }}
33
+ </div>
34
+ <q-input
35
+ id="password"
36
+ v-model="password"
37
+ data-cy="reset-password"
38
+ :rules="validations['passwordRules']"
39
+ outlined
40
+ :type="showPassword ? 'text' : 'password'"
41
+ bg-color="white"
42
+ dense
43
+ class="full-width q-mb-md"
44
+ >
45
+ <template #append>
46
+ <q-icon
47
+ :name="
48
+ showPassword
49
+ ? icons.ionEyeOffOutline
50
+ : icons.ionEyeOutline
51
+ "
52
+ class="cursor-pointer q-mr-sm"
53
+ @click="showPassword = !showPassword"
54
+ />
55
+ </template>
56
+ </q-input>
57
+ </div>
58
+ <q-space class="mobile" />
59
+ <div>
60
+ <q-btn
61
+ :label="$t('common.register')"
62
+ color="primary"
63
+ :loading="loading"
64
+ type="submit"
65
+ no-caps
66
+ class="submitBtn"
67
+ data-cy="send-new-password"
68
+ :disable="!canSubmit"
69
+ />
70
+ </div>
71
+ </q-form>
72
+ </div>
73
+ </div>
74
+ <q-dialog v-model="passwordUpdated" persistent>
75
+ <sw-info-dialog
76
+ :title="$t('auth.passwordChanged')"
77
+ :content="$t('auth.passwordUpdated')"
78
+ :image="'passwordUpdated'"
79
+ :passwordUpdated="passwordUpdated"
80
+ @goToLoginPage="goToLoginPage"
81
+ />
82
+ </q-dialog>
83
+ </q-page>
84
+ </q-layout>
85
+ </template>
86
+
87
+ <script lang="ts">
88
+ //@ts-ignore
89
+ import { defineComponent } from "vue";
90
+ import SwInfoDialog from "../dialogs/sw-info-dialog.vue";
91
+ import { useResetPassword } from "composables/resetPassword";
92
+
93
+ export default defineComponent({
94
+ name: "ResetPassword",
95
+ components: { SwInfoDialog },
96
+ setup() {
97
+ const {
98
+ password,
99
+ loading,
100
+ passwordUpdated,
101
+ showPassword,
102
+ validations,
103
+ canSubmit,
104
+ onSubmit,
105
+ goToLoginPage,
106
+ icons
107
+ } = useResetPassword();
108
+
109
+ return {
110
+ password,
111
+ validations,
112
+ loading,
113
+ canSubmit,
114
+ passwordUpdated,
115
+ showPassword,
116
+ goToLoginPage,
117
+ onSubmit,
118
+ icons
119
+ };
120
+ },
121
+ });
122
+ </script>
123
+
124
+ <style scoped>
125
+ .submitBtn {
126
+ width: 254px;
127
+ }
128
+ </style>