@sowell/quasar-app-extension-auth 1.10.1 → 1.11.1

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/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@sowell/quasar-app-extension-auth",
3
- "version": "1.10.1",
3
+ "version": "1.11.1",
4
4
  "description": "A Quasar app extension to manage Authentication",
5
5
  "main": "src/index.js",
6
6
  "repository": "https://github.com/sowell-ai/quasar.extension.auth",
7
7
  "scripts": {
8
- "lint": "cd dev && eslint --ext .js,.ts,.vue ./",
8
+ "lint": "eslint --ext .js,.ts,.vue ./",
9
9
  "dev": "cd dev && quasar dev",
10
10
  "dep": "cd dev && yarn",
11
11
  "test:link": "cd dev && yarn test:link",
12
12
  "test:browser": "cd dev && yarn test:browser",
13
- "test": "cd dev && yarn test"
13
+ "test": "vitest run"
14
14
  },
15
15
  "keywords": [],
16
16
  "author": "SoWell SAS",
@@ -34,7 +34,10 @@
34
34
  "eslint-plugin-vue": "^7.0.0",
35
35
  "jwt-decode": "^3.1.2",
36
36
  "quasar": "^2.8.4",
37
- "typescript": "^4.4.2"
37
+ "typescript": "^4.4.2",
38
+ "vitest": "^4.1.11",
39
+ "vue": "^3.2.0",
40
+ "vue-i18n": "^9"
38
41
  },
39
42
  "directories": {
40
43
  "test": "test"
@@ -11,7 +11,7 @@
11
11
  alt="Background logo"
12
12
  />
13
13
  </div>
14
- <div class="row justify-between items-center full-width q-px-lg q-pt-lg top-bar">
14
+ <div class="row justify-between items-center full-width q-px-lg top-bar">
15
15
  <div
16
16
  class="row items-center back-link"
17
17
  data-testid="restricted-back-btn"
@@ -62,7 +62,7 @@
62
62
 
63
63
  <div
64
64
  v-else
65
- class="row justify-center full-height q-pl-sm q-pr-sm"
65
+ class="row justify-center full-height q-pl-sm q-pr-sm send-email-form"
66
66
  style="background: #f4f5f6"
67
67
  data-testid="ask-password-change-form"
68
68
  >
@@ -107,6 +107,9 @@
107
107
  <q-input
108
108
  data-testid="email-input"
109
109
  v-model="email"
110
+ type="email"
111
+ autocapitalize="off"
112
+ autocorrect="off"
110
113
  dense
111
114
  borderless
112
115
  bg-color="white"
@@ -247,9 +250,18 @@ export default defineComponent({
247
250
  max-height: 100vh;
248
251
  }
249
252
 
253
+ /* Ce composant s'affiche dans un q-dialog. Sur iOS, Quasar (q-ios-padding)
254
+ décale déjà .q-dialog__inner sous la barre d'état : on ne lit donc PAS
255
+ env(), sinon le décalage serait doublé. --safe-area-inset-top n'est
256
+ injectée que par Capacitor SystemBars sur Android (edge-to-edge, 15+). */
250
257
  .top-bar {
251
258
  z-index: 1;
252
259
  max-width: 430px;
260
+ padding-top: calc(24px + var(--safe-area-inset-top, 0px));
261
+ }
262
+
263
+ .send-email-form {
264
+ padding-top: var(--safe-area-inset-top, 0px);
253
265
  }
254
266
 
255
267
  .back-link {
@@ -8,7 +8,7 @@
8
8
  class="background-logo"
9
9
  alt="Background logo" />
10
10
  </div>
11
- <div class="row justify-between items-center full-width q-px-lg q-pt-lg top-bar">
11
+ <div class="row justify-between items-center full-width q-px-lg top-bar">
12
12
  <div
13
13
  class="row items-center back-link"
14
14
  data-testid="back-btn"
@@ -424,6 +424,11 @@ export default defineComponent({
424
424
  .top-bar {
425
425
  z-index: 1;
426
426
  max-width: 430px;
427
+ /* 24px = ancien q-pt-lg. Sur iOS (viewport-fit=cover), la page n'a pas de
428
+ q-header : le padding iOS de Quasar ne s'applique pas, on ajoute donc la
429
+ safe-area ici. --safe-area-inset-top est injectée par SystemBars sur
430
+ Android ; env() vaut 0 sur le web. */
431
+ padding-top: calc(24px + var(--safe-area-inset-top, env(safe-area-inset-top, 0px)));
427
432
  }
428
433
 
429
434
  .back-link {
@@ -8,7 +8,7 @@
8
8
  class="background-logo"
9
9
  alt="Background logo" />
10
10
  </div>
11
- <div class="row justify-between items-center full-width q-px-lg q-pt-lg top-bar">
11
+ <div class="row justify-between items-center full-width q-px-lg top-bar">
12
12
  <div
13
13
  class="row items-center back-link"
14
14
  data-testid="back-btn"
@@ -317,6 +317,11 @@ export default defineComponent({
317
317
  .top-bar {
318
318
  z-index: 1;
319
319
  max-width: 430px;
320
+ /* 24px = ancien q-pt-lg. Sur iOS (viewport-fit=cover), la page n'a pas de
321
+ q-header : le padding iOS de Quasar ne s'applique pas, on ajoute donc la
322
+ safe-area ici. --safe-area-inset-top est injectée par SystemBars sur
323
+ Android ; env() vaut 0 sur le web. */
324
+ padding-top: calc(24px + var(--safe-area-inset-top, env(safe-area-inset-top, 0px)));
320
325
  }
321
326
 
322
327
  .back-link {
@@ -124,6 +124,9 @@ export function useMagicLink() {
124
124
  }
125
125
 
126
126
  const requestChannels = async () => {
127
+ // Quasar's `loading` does not disable the button: Enter would resubmit and send
128
+ // a second e-mail, invalidating the first link (the API replaces the token).
129
+ if (isLoading.value) return
127
130
  apiErrorMessage.value = ""
128
131
  if (!validateEmail()) return
129
132
  isLoading.value = true
@@ -138,14 +141,21 @@ export function useMagicLink() {
138
141
  channels.value = offered.length ? offered : ["email"]
139
142
  channelTargets.value = targets
140
143
  selectedChannel.value = "email"
144
+ // Nothing to choose when only e-mail is offered (user without phone, or an
145
+ // app restricted to e-mail): send the link straight away.
146
+ if (channels.value.length === 1 && channels.value[0] === "email") {
147
+ await sendMagicLink("email")
148
+ return
149
+ }
141
150
  step.value = "channel"
142
151
  } catch (error) {
143
152
  const axiosError = error as AxiosError
144
153
  if (axiosError.response?.status === 403) {
145
- // Backend check: ENV["COMPANY_RESET_PASSWORD_FORBIDDEN"] vs user.company_id,
146
- // rescued as Rescueable::Forbidden with i18n key errors.magiclink.forbidden.
147
- // No pre-flight signal exists (no Company.config field, nothing on /me) - the
148
- // front can only ever find out by attempting the call, hence no button hiding.
154
+ // Backend check: the user's company (or its master/slaves) has
155
+ // `no_password_reset` set, rescued as Rescueable::Forbidden with i18n key
156
+ // errors.magiclink.forbidden. No pre-flight signal exists on the front, so
157
+ // it only finds out by attempting the call, hence no button hiding. The
158
+ // same 403 can come from the automatic send in requestChannels.
149
159
  restricted.value = true
150
160
  restrictedMessage.value = readApiError(error) || ""
151
161
  } else if (axiosError.response?.status === 404) {