@sowell/quasar-app-extension-auth 1.8.2 → 1.8.4
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 +1 -1
- package/src/assets/Sowell-plus-logo.svg +31 -0
- package/src/components/pages/AdminAuth.vue +41 -2
- package/src/components/pages/Auth.vue +41 -2
- package/src/components/pages/FirstLogin.vue +94 -39
- package/src/components/pages/WebAuth.vue +41 -2
- package/src/components/pages/WebFirstLogin.vue +930 -0
- package/src/components/pages/WebSetPassword.vue +580 -0
- package/src/composables/useMagicLink.ts +15 -2
- package/src/injects/prompts.ts +1 -0
- package/src/prompts.js +8 -0
- package/src/routes/index.ts +15 -2
|
@@ -0,0 +1,930 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="login-container">
|
|
3
|
+
<div class="login-card">
|
|
4
|
+
<div class="logo-container">
|
|
5
|
+
<img
|
|
6
|
+
src="../../assets/Sowell-plus-logo.svg"
|
|
7
|
+
alt="SoWell+"
|
|
8
|
+
class="logo" />
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
<div class="login-content">
|
|
12
|
+
<!-- Step: forbidden (403) - takes precedence over `step`, the backend can
|
|
13
|
+
reject on either magiclink call (with or without channel). -->
|
|
14
|
+
<template v-if="restricted">
|
|
15
|
+
<div class="forbidden-content" data-testid="magic-link-forbidden">
|
|
16
|
+
<div class="warning-icon-outer">
|
|
17
|
+
<svg
|
|
18
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
19
|
+
width="82"
|
|
20
|
+
height="82"
|
|
21
|
+
viewBox="0 0 82 82"
|
|
22
|
+
fill="none">
|
|
23
|
+
<path
|
|
24
|
+
d="M20.467 13.2638C20.467 13.2638 32.783 22.7041 51.5063 5.05236C68.1346 -10.6241 81.7117 14.1097 81.8067 25.9544C81.9298 41.298 65.1784 53.5748 73.3078 63.6526C81.4372 73.7304 57.1861 90.3722 44.116 75.9698C27.8572 58.0538 23.4525 72.6106 14.185 72.6106C7.53374 72.6106 -6.12216 55.9168 3.09953 43.4971C10.8594 33.0461 6.6273 29.5776 4.57785 25.9544C1.62159 20.7288 8.64242 6.54534 20.467 13.2638Z"
|
|
25
|
+
fill="#FFEFCF" />
|
|
26
|
+
<path
|
|
27
|
+
d="M63.1242 56.9728L44.1383 21.3586C42.7926 18.8336 39.2078 18.8336 37.861 21.3586L18.8762 56.9728C18.584 57.5209 18.4375 58.1363 18.4511 58.7587C18.4646 59.3811 18.6376 59.9894 18.9533 60.5241C19.269 61.0588 19.7165 61.5017 20.2522 61.8095C20.788 62.1174 21.3935 62.2797 22.0099 62.2806H59.9849C60.6017 62.2807 61.208 62.1191 61.7445 61.8116C62.281 61.5042 62.7293 61.0614 63.0457 60.5265C63.362 59.9916 63.5355 59.383 63.5493 58.7601C63.5631 58.1372 63.4166 57.5214 63.1242 56.9728V56.9728ZM41.0002 56.7669C40.5595 56.7669 40.1288 56.6349 39.7624 56.3876C39.396 56.1403 39.1104 55.7888 38.9418 55.3776C38.7732 54.9664 38.729 54.5139 38.815 54.0773C38.901 53.6408 39.1132 53.2397 39.4248 52.925C39.7364 52.6103 40.1333 52.3959 40.5655 52.3091C40.9977 52.2223 41.4457 52.2668 41.8528 52.4372C42.2599 52.6075 42.6079 52.896 42.8527 53.266C43.0975 53.6361 43.2282 54.0712 43.2282 54.5164C43.2282 54.8119 43.1706 55.1045 43.0586 55.3776C42.9466 55.6506 42.7825 55.8987 42.5756 56.1077C42.3687 56.3167 42.1231 56.4824 41.8528 56.5955C41.5825 56.7086 41.2928 56.7669 41.0002 56.7669ZM43.4198 34.1325L42.7804 47.8605C42.7804 48.338 42.5926 48.7959 42.2583 49.1336C41.924 49.4712 41.4707 49.6609 40.998 49.6609C40.5252 49.6609 40.0719 49.4712 39.7376 49.1336C39.4034 48.7959 39.2156 48.338 39.2156 47.8605L38.5761 34.1381C38.5618 33.8102 38.6129 33.4827 38.7265 33.1752C38.8401 32.8677 39.0138 32.5864 39.2373 32.3481C39.4608 32.1099 39.7295 31.9195 40.0274 31.7884C40.3253 31.6573 40.6463 31.5881 40.9712 31.5849H40.9946C41.3218 31.5847 41.6456 31.6515 41.9465 31.7812C42.2474 31.9109 42.5191 32.1009 42.7453 32.3396C42.9716 32.5783 43.1476 32.8608 43.2627 33.1701C43.3779 33.4794 43.4298 33.8091 43.4153 34.1392L43.4198 34.1325Z"
|
|
28
|
+
fill="#FFBD3D" />
|
|
29
|
+
</svg>
|
|
30
|
+
</div>
|
|
31
|
+
<h1 class="forbidden-title" data-testid="forbidden-title">
|
|
32
|
+
{{ $t("auth.restrictedTitle") }}
|
|
33
|
+
</h1>
|
|
34
|
+
<p class="forbidden-message" data-testid="forbidden-message">
|
|
35
|
+
{{ forbiddenMessageParts.before
|
|
36
|
+
}}<strong>{{ forbiddenMessageParts.bold }}</strong
|
|
37
|
+
>{{ forbiddenMessageParts.after }}
|
|
38
|
+
</p>
|
|
39
|
+
|
|
40
|
+
<div class="forbidden-sso-section">
|
|
41
|
+
<p class="forbidden-sso-label">{{ $t("auth.connectWith") }}</p>
|
|
42
|
+
<q-btn
|
|
43
|
+
data-testid="forbidden-sso-btn"
|
|
44
|
+
data-cy="submit-sso-login"
|
|
45
|
+
unelevated
|
|
46
|
+
no-caps
|
|
47
|
+
dense
|
|
48
|
+
:loading="msalLoading"
|
|
49
|
+
:disable="msalLoading"
|
|
50
|
+
class="forbidden-sso-button"
|
|
51
|
+
@click="msalAuth">
|
|
52
|
+
<img
|
|
53
|
+
src="../../assets/logo-microsoft.svg"
|
|
54
|
+
class="forbidden-sso-icon" />
|
|
55
|
+
{{ $t("auth.microsoft") }}
|
|
56
|
+
</q-btn>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<a
|
|
61
|
+
href="#"
|
|
62
|
+
class="back-link back-link--center back-link--lg"
|
|
63
|
+
data-testid="back-to-login-link"
|
|
64
|
+
@click.prevent="goBackToLogin">
|
|
65
|
+
<q-icon :name="icons.ionArrowBackOutline" size="24px" />
|
|
66
|
+
{{ $t("auth.backToLoginFull") }}
|
|
67
|
+
</a>
|
|
68
|
+
</template>
|
|
69
|
+
|
|
70
|
+
<!-- Step: email -->
|
|
71
|
+
<template v-else-if="step === 'email'">
|
|
72
|
+
<div class="step-header" data-testid="first-login-email-step">
|
|
73
|
+
<h1 class="step-title" data-testid="first-login-title">
|
|
74
|
+
{{ stepTitle }}
|
|
75
|
+
</h1>
|
|
76
|
+
<p class="step-subtitle" data-testid="first-login-description">
|
|
77
|
+
{{ stepDescription }}
|
|
78
|
+
</p>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<q-form
|
|
82
|
+
class="login-form"
|
|
83
|
+
data-testid="first-login-email-form"
|
|
84
|
+
@submit.prevent="requestChannels">
|
|
85
|
+
<div class="form-group">
|
|
86
|
+
<q-input
|
|
87
|
+
v-model.trim="email"
|
|
88
|
+
type="email"
|
|
89
|
+
:placeholder="$t('auth.emailPlaceholder')"
|
|
90
|
+
:error="!!emailError"
|
|
91
|
+
:error-message="emailError"
|
|
92
|
+
data-testid="first-login-email-input"
|
|
93
|
+
data-cy="first-login-email"
|
|
94
|
+
outlined
|
|
95
|
+
no-shadow
|
|
96
|
+
class="form-input" />
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<q-btn
|
|
100
|
+
:label="$t('auth.continueButton')"
|
|
101
|
+
no-caps
|
|
102
|
+
unelevated
|
|
103
|
+
type="submit"
|
|
104
|
+
:loading="isLoading"
|
|
105
|
+
:disable="!isEmailValid || isLoading"
|
|
106
|
+
data-testid="first-login-continue-btn"
|
|
107
|
+
data-cy="first-login-continue"
|
|
108
|
+
class="primary-button" />
|
|
109
|
+
</q-form>
|
|
110
|
+
|
|
111
|
+
<div
|
|
112
|
+
v-if="apiErrorMessage"
|
|
113
|
+
class="api-error"
|
|
114
|
+
data-testid="first-login-api-error">
|
|
115
|
+
{{ apiErrorMessage }}
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
<div class="or-divider">
|
|
119
|
+
<div class="or-divider-line"></div>
|
|
120
|
+
<span class="or-divider-text">{{ $t("common.or") }}</span>
|
|
121
|
+
<div class="or-divider-line"></div>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<a
|
|
125
|
+
href="#"
|
|
126
|
+
class="back-link back-link--center back-link--lg"
|
|
127
|
+
data-testid="back-to-login-link"
|
|
128
|
+
@click.prevent="goBackToLogin">
|
|
129
|
+
<q-icon :name="icons.ionArrowBackOutline" size="24px" />
|
|
130
|
+
{{ $t("auth.backToLoginFull") }}
|
|
131
|
+
</a>
|
|
132
|
+
</template>
|
|
133
|
+
|
|
134
|
+
<!-- Step: channel -->
|
|
135
|
+
<template v-else-if="step === 'channel'">
|
|
136
|
+
<div class="step-header" data-testid="first-login-channel-step">
|
|
137
|
+
<h1 class="step-title" data-testid="channel-title">
|
|
138
|
+
{{ $t("auth.channelTitle") }}
|
|
139
|
+
</h1>
|
|
140
|
+
<p class="step-subtitle" data-testid="channel-subtitle">
|
|
141
|
+
{{ $t("auth.channelSubtitle") }}
|
|
142
|
+
</p>
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
<div class="channel-list" data-testid="channel-list">
|
|
146
|
+
<div
|
|
147
|
+
v-for="option in channelOptions"
|
|
148
|
+
:key="option.value"
|
|
149
|
+
class="channel-option"
|
|
150
|
+
:class="{
|
|
151
|
+
'channel-option--selected': selectedChannel === option.value
|
|
152
|
+
}"
|
|
153
|
+
:data-testid="`channel-option-${option.value}`"
|
|
154
|
+
@click="selectChannel(option.value)">
|
|
155
|
+
<div class="channel-icon-box">
|
|
156
|
+
<svg
|
|
157
|
+
v-if="option.value === 'email'"
|
|
158
|
+
width="20"
|
|
159
|
+
height="16"
|
|
160
|
+
viewBox="0 0 20 16"
|
|
161
|
+
fill="none">
|
|
162
|
+
<path
|
|
163
|
+
d="M2 16C1.45 16 0.979167 15.8042 0.5875 15.4125C0.195833 15.0208 0 14.55 0 14V2C0 1.45 0.195833 0.979167 0.5875 0.5875C0.979167 0.195833 1.45 0 2 0H18C18.55 0 19.0208 0.195833 19.4125 0.5875C19.8042 0.979167 20 1.45 20 2V14C20 14.55 19.8042 15.0208 19.4125 15.4125C19.0208 15.8042 18.55 16 18 16H2V16M10 9L2 4V14V14V14H18V14V14V4L10 9V9M10 7L18 2H2L10 7V7M2 4V2V2V4V14V14V14V14V14V14V4V4"
|
|
164
|
+
fill="#40C4FF" />
|
|
165
|
+
</svg>
|
|
166
|
+
<svg
|
|
167
|
+
v-else
|
|
168
|
+
width="20"
|
|
169
|
+
height="20"
|
|
170
|
+
viewBox="0 0 20 20"
|
|
171
|
+
fill="none">
|
|
172
|
+
<path
|
|
173
|
+
d="M6 9C6.28333 9 6.52083 8.90417 6.7125 8.7125C6.90417 8.52083 7 8.28333 7 8C7 7.71667 6.90417 7.47917 6.7125 7.2875C6.52083 7.09583 6.28333 7 6 7C5.71667 7 5.47917 7.09583 5.2875 7.2875C5.09583 7.47917 5 7.71667 5 8C5 8.28333 5.09583 8.52083 5.2875 8.7125C5.47917 8.90417 5.71667 9 6 9V9M10 9C10.2833 9 10.5208 8.90417 10.7125 8.7125C10.9042 8.52083 11 8.28333 11 8C11 7.71667 10.9042 7.47917 10.7125 7.2875C10.5208 7.09583 10.2833 7 10 7C9.71667 7 9.47917 7.09583 9.2875 7.2875C9.09583 7.47917 9 7.71667 9 8C9 8.28333 9.09583 8.52083 9.2875 8.7125C9.47917 8.90417 9.71667 9 10 9V9M14 9C14.2833 9 14.5208 8.90417 14.7125 8.7125C14.9042 8.52083 15 8.28333 15 8C15 7.71667 14.9042 7.47917 14.7125 7.2875C14.5208 7.09583 14.2833 7 14 7C13.7167 7 13.4792 7.09583 13.2875 7.2875C13.0958 7.47917 13 7.71667 13 8C13 8.28333 13.0958 8.52083 13.2875 8.7125C13.4792 8.90417 13.7167 9 14 9V9M0 20V2C0 1.45 0.195833 0.979167 0.5875 0.5875C0.979167 0.195833 1.45 0 2 0H18C18.55 0 19.0208 0.195833 19.4125 0.5875C19.8042 0.979167 20 1.45 20 2V14C20 14.55 19.8042 15.0208 19.4125 15.4125C19.0208 15.8042 18.55 16 18 16H4L0 20V20M3.15 14H18V14V14V2V2V2H2V2V2V15.125L3.15 14V14M2 14V14V2V2V2V2V2V2V14V14V14V14V14"
|
|
174
|
+
fill="#00668A" />
|
|
175
|
+
</svg>
|
|
176
|
+
</div>
|
|
177
|
+
<div class="channel-texts">
|
|
178
|
+
<div class="channel-label" data-testid="channel-option-label">
|
|
179
|
+
{{ option.label }}
|
|
180
|
+
</div>
|
|
181
|
+
<div
|
|
182
|
+
class="channel-description"
|
|
183
|
+
data-testid="channel-option-description">
|
|
184
|
+
{{ option.description }}
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
187
|
+
<div
|
|
188
|
+
class="channel-radio"
|
|
189
|
+
:class="{
|
|
190
|
+
'channel-radio--selected': selectedChannel === option.value
|
|
191
|
+
}">
|
|
192
|
+
<div
|
|
193
|
+
v-if="selectedChannel === option.value"
|
|
194
|
+
class="channel-radio-dot" />
|
|
195
|
+
</div>
|
|
196
|
+
</div>
|
|
197
|
+
</div>
|
|
198
|
+
|
|
199
|
+
<q-btn
|
|
200
|
+
:label="$t('auth.sendMagicLink')"
|
|
201
|
+
no-caps
|
|
202
|
+
unelevated
|
|
203
|
+
:loading="isLoading"
|
|
204
|
+
:disable="isLoading"
|
|
205
|
+
data-testid="send-magic-link-btn"
|
|
206
|
+
data-cy="send-magic-link"
|
|
207
|
+
class="primary-button"
|
|
208
|
+
@click="sendMagicLink(selectedChannel)" />
|
|
209
|
+
|
|
210
|
+
<div
|
|
211
|
+
v-if="apiErrorMessage"
|
|
212
|
+
class="api-error"
|
|
213
|
+
data-testid="first-login-api-error">
|
|
214
|
+
{{ apiErrorMessage }}
|
|
215
|
+
</div>
|
|
216
|
+
|
|
217
|
+
<a
|
|
218
|
+
href="#"
|
|
219
|
+
class="back-link back-link--center back-link--lg"
|
|
220
|
+
data-testid="back-to-login-link"
|
|
221
|
+
@click.prevent="goBackToLogin">
|
|
222
|
+
<q-icon :name="icons.ionArrowBackOutline" size="24px" />
|
|
223
|
+
{{ $t("auth.backToLoginFull") }}
|
|
224
|
+
</a>
|
|
225
|
+
</template>
|
|
226
|
+
|
|
227
|
+
<!-- Step: sent -->
|
|
228
|
+
<template v-else>
|
|
229
|
+
<div class="sent-content" data-testid="magic-link-sent">
|
|
230
|
+
<div class="success-icon-outer">
|
|
231
|
+
<q-icon
|
|
232
|
+
:name="icons.ionCheckmarkCircle"
|
|
233
|
+
size="40px"
|
|
234
|
+
style="color: #06d6a0" />
|
|
235
|
+
</div>
|
|
236
|
+
<h1 class="sent-title" data-testid="sent-title">
|
|
237
|
+
{{ $t("auth.magicLinkSentTitle") }}
|
|
238
|
+
</h1>
|
|
239
|
+
<p class="sent-description" data-testid="sent-description">
|
|
240
|
+
{{ $t("auth.magicLinkSentDescription") }}
|
|
241
|
+
</p>
|
|
242
|
+
|
|
243
|
+
<div
|
|
244
|
+
class="info-banner"
|
|
245
|
+
:data-testid="
|
|
246
|
+
isSmsChannel ? 'check-sms-banner' : 'check-inbox-banner'
|
|
247
|
+
">
|
|
248
|
+
<q-icon
|
|
249
|
+
v-if="isSmsChannel"
|
|
250
|
+
:name="icons.ionChatbubbleEllipsesOutline"
|
|
251
|
+
size="13px"
|
|
252
|
+
color="primary" />
|
|
253
|
+
<svg v-else width="13" height="11" viewBox="0 0 13 11" fill="none">
|
|
254
|
+
<path
|
|
255
|
+
d="M8.1375 10.5L5.65833 8.02083L6.475 7.20417L8.1375 8.86667L11.4333 5.57083L12.25 6.3875L8.1375 10.5ZM5.83333 4.08333L10.5 1.16667H1.16667L5.83333 4.08333ZM5.83333 5.25L1.16667 2.33333V8.16667H4.17083L5.3375 9.33333H1.16667C0.845833 9.33333 0.571181 9.2191 0.342708 8.99063C0.114236 8.76215 0 8.4875 0 8.16667V1.16667C0 0.845833 0.114236 0.571181 0.342708 0.342708C0.571181 0.114236 0.845833 0 1.16667 0H10.5C10.8208 0 11.0955 0.114236 11.324 0.342708C11.5524 0.571181 11.6667 0.845833 11.6667 1.16667V3.70417L10.5 4.87083V2.33333L5.83333 5.25Z"
|
|
256
|
+
fill="#00668A" />
|
|
257
|
+
</svg>
|
|
258
|
+
<span data-testid="magic-link-check-message">{{
|
|
259
|
+
checkChannelMessage
|
|
260
|
+
}}</span>
|
|
261
|
+
</div>
|
|
262
|
+
|
|
263
|
+
<q-btn
|
|
264
|
+
no-caps
|
|
265
|
+
unelevated
|
|
266
|
+
class="resend-button"
|
|
267
|
+
:disable="resendCountdown > 0 || isLoading"
|
|
268
|
+
data-testid="resend-magic-link-btn"
|
|
269
|
+
data-cy="resend-magic-link"
|
|
270
|
+
@click="resend">
|
|
271
|
+
<svg width="14" height="14" viewBox="0 0 14 14" fill="none">
|
|
272
|
+
<path
|
|
273
|
+
d="M6.75 13.5C5.025 13.5 3.52187 12.9281 2.24062 11.7844C0.959375 10.6406 0.225 9.2125 0.0375 7.5H1.575C1.75 8.8 2.32812 9.875 3.30938 10.725C4.29063 11.575 5.4375 12 6.75 12C8.2125 12 9.45312 11.4906 10.4719 10.4719C11.4906 9.45312 12 8.2125 12 6.75C12 5.2875 11.4906 4.04688 10.4719 3.02813C9.45312 2.00938 8.2125 1.5 6.75 1.5C5.8875 1.5 5.08125 1.7 4.33125 2.1C3.58125 2.5 2.95 3.05 2.4375 3.75H4.5V5.25H0V0.75H1.5V2.5125C2.1375 1.7125 2.91562 1.09375 3.83437 0.65625C4.75312 0.21875 5.725 0 6.75 0C7.6875 0 8.56562 0.178125 9.38437 0.534375C10.2031 0.890625 10.9156 1.37188 11.5219 1.97812C12.1281 2.58437 12.6094 3.29688 12.9656 4.11562C13.3219 4.93437 13.5 5.8125 13.5 6.75C13.5 7.6875 13.3219 8.56562 12.9656 9.38437C12.6094 10.2031 12.1281 10.9156 11.5219 11.5219C10.9156 12.1281 10.2031 12.6094 9.38437 12.9656C8.56562 13.3219 7.6875 13.5 6.75 13.5ZM8.85 9.9L6 7.05V3H7.5V6.45L9.9 8.85L8.85 9.9Z"
|
|
274
|
+
fill="white" />
|
|
275
|
+
</svg>
|
|
276
|
+
<span>{{ resendLabel }}</span>
|
|
277
|
+
</q-btn>
|
|
278
|
+
|
|
279
|
+
<div class="warning-banner" data-testid="magic-link-warning">
|
|
280
|
+
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
|
|
281
|
+
<path
|
|
282
|
+
d="M9 15H11V9H9V15V15M10 7C10.2833 7 10.5208 6.90417 10.7125 6.7125C10.9042 6.52083 11 6.28333 11 6C11 5.71667 10.9042 5.47917 10.7125 5.2875C10.5208 5.09583 10.2833 5 10 5C9.71667 5 9.47917 5.09583 9.2875 5.2875C9.09583 5.47917 9 5.71667 9 6C9 6.28333 9.09583 6.52083 9.2875 6.7125C9.47917 6.90417 9.71667 7 10 7V7M10 20C8.61667 20 7.31667 19.7375 6.1 19.2125C4.88333 18.6875 3.825 17.975 2.925 17.075C2.025 16.175 1.3125 15.1167 0.7875 13.9C0.2625 12.6833 0 11.3833 0 10C0 8.61667 0.2625 7.31667 0.7875 6.1C1.3125 4.88333 2.025 3.825 2.925 2.925C3.825 2.025 4.88333 1.3125 6.1 0.7875C7.31667 0.2625 8.61667 0 10 0C11.3833 0 12.6833 0.2625 13.9 0.7875C15.1167 1.3125 16.175 2.025 17.075 2.925C17.975 3.825 18.6875 4.88333 19.2125 6.1C19.7375 7.31667 20 8.61667 20 10C20 11.3833 19.7375 12.6833 19.2125 13.9C18.6875 15.1167 17.975 16.175 17.075 17.075C16.175 17.975 15.1167 18.6875 13.9 19.2125C12.6833 19.7375 11.3833 20 10 20V20M10 18C12.2333 18 14.125 17.225 15.675 15.675C17.225 14.125 18 12.2333 18 10C18 7.76667 17.225 5.875 15.675 4.325C14.125 2.775 12.2333 2 10 2C7.76667 2 5.875 2.775 4.325 4.325C2.775 5.875 2 7.76667 2 10C2 12.2333 2.775 14.125 4.325 15.675C5.875 17.225 7.76667 18 10 18V18M10 10V10V10V10V10V10V10V10V10V10"
|
|
283
|
+
fill="#FFCE6E" />
|
|
284
|
+
</svg>
|
|
285
|
+
<span data-testid="magic-link-warning-label">{{
|
|
286
|
+
magicLinkWarningMessage
|
|
287
|
+
}}</span>
|
|
288
|
+
</div>
|
|
289
|
+
|
|
290
|
+
<div
|
|
291
|
+
v-if="apiErrorMessage"
|
|
292
|
+
class="api-error"
|
|
293
|
+
data-testid="first-login-api-error">
|
|
294
|
+
{{ apiErrorMessage }}
|
|
295
|
+
</div>
|
|
296
|
+
</div>
|
|
297
|
+
|
|
298
|
+
<a
|
|
299
|
+
href="#"
|
|
300
|
+
class="back-link back-link--center"
|
|
301
|
+
data-testid="back-to-login-link"
|
|
302
|
+
@click.prevent="goBackToLogin">
|
|
303
|
+
<q-icon :name="icons.ionArrowBackOutline" size="20px" />
|
|
304
|
+
{{ $t("auth.backToLoginFull") }}
|
|
305
|
+
</a>
|
|
306
|
+
</template>
|
|
307
|
+
</div>
|
|
308
|
+
</div>
|
|
309
|
+
</div>
|
|
310
|
+
</template>
|
|
311
|
+
|
|
312
|
+
<script lang="ts">
|
|
313
|
+
import { defineComponent, computed } from "vue"
|
|
314
|
+
import { useI18n } from "vue-i18n"
|
|
315
|
+
import isEmail from "validator/es/lib/isEmail"
|
|
316
|
+
import {
|
|
317
|
+
ionArrowBackOutline,
|
|
318
|
+
ionCheckmarkCircle,
|
|
319
|
+
ionChatbubbleEllipsesOutline
|
|
320
|
+
} from "@quasar/extras/ionicons-v5"
|
|
321
|
+
|
|
322
|
+
import { useMagicLink } from "composables/useMagicLink"
|
|
323
|
+
import { useAuth } from "composables/auth"
|
|
324
|
+
|
|
325
|
+
type Channel = "email" | "sms"
|
|
326
|
+
|
|
327
|
+
interface ChannelOption {
|
|
328
|
+
value: Channel
|
|
329
|
+
label: string
|
|
330
|
+
description: string
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
interface ForbiddenMessageParts {
|
|
334
|
+
before: string
|
|
335
|
+
bold: string
|
|
336
|
+
after: string
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// The 403 copy names Microsoft explicitly; the word is bolded wherever it lands
|
|
340
|
+
// in the sentence, so the message stays a single i18n string (or the API detail).
|
|
341
|
+
const FORBIDDEN_MESSAGE_BOLD_KEYWORD = "Microsoft"
|
|
342
|
+
|
|
343
|
+
export default defineComponent({
|
|
344
|
+
name: "WebFirstLogin",
|
|
345
|
+
setup() {
|
|
346
|
+
const { t, te } = useI18n()
|
|
347
|
+
|
|
348
|
+
const {
|
|
349
|
+
email,
|
|
350
|
+
emailError,
|
|
351
|
+
apiErrorMessage,
|
|
352
|
+
channels,
|
|
353
|
+
channelTargets,
|
|
354
|
+
selectedChannel,
|
|
355
|
+
step,
|
|
356
|
+
isLoading,
|
|
357
|
+
resendCountdown,
|
|
358
|
+
restricted,
|
|
359
|
+
isActivateContext,
|
|
360
|
+
maskedEmail,
|
|
361
|
+
requestChannels,
|
|
362
|
+
sendMagicLink,
|
|
363
|
+
resend,
|
|
364
|
+
selectChannel,
|
|
365
|
+
goBackToLogin
|
|
366
|
+
} = useMagicLink()
|
|
367
|
+
|
|
368
|
+
const { msalLoading, msalAuth } = useAuth()
|
|
369
|
+
|
|
370
|
+
const icons = {
|
|
371
|
+
ionArrowBackOutline,
|
|
372
|
+
ionCheckmarkCircle,
|
|
373
|
+
ionChatbubbleEllipsesOutline
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const translateOrFallback = (key: string, fallbackKey: string): string =>
|
|
377
|
+
te(key) ? t(key) : t(fallbackKey)
|
|
378
|
+
|
|
379
|
+
const stepTitle = computed(() =>
|
|
380
|
+
isActivateContext
|
|
381
|
+
? t("auth.firstConnectionTitle")
|
|
382
|
+
: t("auth.forgotPasswordTitle")
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
const stepDescription = computed(() =>
|
|
386
|
+
isActivateContext
|
|
387
|
+
? t("auth.firstConnectionDescription")
|
|
388
|
+
: t("auth.forgotPasswordDescription")
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
// The composable only fills emailError on submit; the Continue button needs
|
|
392
|
+
// to know about validity while typing, hence this local check.
|
|
393
|
+
const isEmailValid = computed(() => isEmail(email.value.trim()))
|
|
394
|
+
|
|
395
|
+
const channelDescription = (channel: Channel): string => {
|
|
396
|
+
const target = channelTargets.value[channel]
|
|
397
|
+
if (target) return target
|
|
398
|
+
|
|
399
|
+
return channel === "email"
|
|
400
|
+
? maskedEmail.value
|
|
401
|
+
: t("auth.channelSmsDescription")
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const channelOptions = computed<ChannelOption[]>(() =>
|
|
405
|
+
channels.value.map((channel) => ({
|
|
406
|
+
value: channel,
|
|
407
|
+
label:
|
|
408
|
+
channel === "email"
|
|
409
|
+
? t("auth.channelEmailLabel")
|
|
410
|
+
: t("auth.channelSmsLabel"),
|
|
411
|
+
description: channelDescription(channel)
|
|
412
|
+
}))
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
const isSmsChannel = computed(() => selectedChannel.value === "sms")
|
|
416
|
+
|
|
417
|
+
const checkChannelMessage = computed(() =>
|
|
418
|
+
isSmsChannel.value
|
|
419
|
+
? translateOrFallback(
|
|
420
|
+
"auth.magicLinkCheckSmsMessage",
|
|
421
|
+
"auth.magicLinkCheckInboxMessage"
|
|
422
|
+
)
|
|
423
|
+
: t("auth.magicLinkCheckInboxMessage")
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
const magicLinkWarningMessage = computed(() =>
|
|
427
|
+
isSmsChannel.value
|
|
428
|
+
? translateOrFallback(
|
|
429
|
+
"auth.magicLinkWarningSms",
|
|
430
|
+
"auth.magicLinkWarning"
|
|
431
|
+
)
|
|
432
|
+
: t("auth.magicLinkWarning")
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
const resendLabel = computed(() =>
|
|
436
|
+
resendCountdown.value > 0
|
|
437
|
+
? t("auth.resendMagicLinkCountdown", { seconds: resendCountdown.value })
|
|
438
|
+
: t("auth.resendMagicLink")
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
const forbiddenMessageParts = computed<ForbiddenMessageParts>(() => {
|
|
442
|
+
const message = t("auth.restrictedDescription")
|
|
443
|
+
const keywordIndex = message.indexOf(FORBIDDEN_MESSAGE_BOLD_KEYWORD)
|
|
444
|
+
if (keywordIndex === -1) {
|
|
445
|
+
return { before: message, bold: "", after: "" }
|
|
446
|
+
}
|
|
447
|
+
return {
|
|
448
|
+
before: message.slice(0, keywordIndex),
|
|
449
|
+
bold: FORBIDDEN_MESSAGE_BOLD_KEYWORD,
|
|
450
|
+
after: message.slice(
|
|
451
|
+
keywordIndex + FORBIDDEN_MESSAGE_BOLD_KEYWORD.length
|
|
452
|
+
)
|
|
453
|
+
}
|
|
454
|
+
})
|
|
455
|
+
|
|
456
|
+
return {
|
|
457
|
+
email,
|
|
458
|
+
emailError,
|
|
459
|
+
apiErrorMessage,
|
|
460
|
+
selectedChannel,
|
|
461
|
+
step,
|
|
462
|
+
isLoading,
|
|
463
|
+
resendCountdown,
|
|
464
|
+
restricted,
|
|
465
|
+
msalLoading,
|
|
466
|
+
msalAuth,
|
|
467
|
+
icons,
|
|
468
|
+
stepTitle,
|
|
469
|
+
stepDescription,
|
|
470
|
+
isEmailValid,
|
|
471
|
+
channelOptions,
|
|
472
|
+
isSmsChannel,
|
|
473
|
+
checkChannelMessage,
|
|
474
|
+
magicLinkWarningMessage,
|
|
475
|
+
resendLabel,
|
|
476
|
+
forbiddenMessageParts,
|
|
477
|
+
requestChannels,
|
|
478
|
+
sendMagicLink,
|
|
479
|
+
resend,
|
|
480
|
+
selectChannel,
|
|
481
|
+
goBackToLogin
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
})
|
|
485
|
+
</script>
|
|
486
|
+
|
|
487
|
+
<style scoped>
|
|
488
|
+
.login-container {
|
|
489
|
+
min-height: 100vh;
|
|
490
|
+
display: flex;
|
|
491
|
+
align-items: center;
|
|
492
|
+
justify-content: center;
|
|
493
|
+
padding: 20px;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.login-card {
|
|
497
|
+
background: #ffffff;
|
|
498
|
+
border-radius: 20px;
|
|
499
|
+
padding: 49px 108px;
|
|
500
|
+
width: 100%;
|
|
501
|
+
max-width: 668px;
|
|
502
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
|
503
|
+
display: flex;
|
|
504
|
+
flex-direction: column;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
.login-content {
|
|
508
|
+
flex: 1;
|
|
509
|
+
display: flex;
|
|
510
|
+
flex-direction: column;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
.logo-container {
|
|
514
|
+
display: flex;
|
|
515
|
+
justify-content: center;
|
|
516
|
+
margin-bottom: 49px;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
.logo {
|
|
520
|
+
height: 53px;
|
|
521
|
+
width: auto;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
.step-header {
|
|
525
|
+
margin-bottom: 29px;
|
|
526
|
+
text-align: left;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
.step-title {
|
|
530
|
+
font-size: 24px;
|
|
531
|
+
font-weight: 600;
|
|
532
|
+
line-height: 1.18em;
|
|
533
|
+
letter-spacing: -0.5px;
|
|
534
|
+
color: #152f3b;
|
|
535
|
+
margin: 0 0 18px 0;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
.step-subtitle {
|
|
539
|
+
font-size: 16px;
|
|
540
|
+
font-weight: 400;
|
|
541
|
+
line-height: 1.5em;
|
|
542
|
+
color: #152f3b;
|
|
543
|
+
margin: 0;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
.login-form {
|
|
547
|
+
display: flex;
|
|
548
|
+
flex-direction: column;
|
|
549
|
+
gap: 16px;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
.form-group {
|
|
553
|
+
display: flex;
|
|
554
|
+
flex-direction: column;
|
|
555
|
+
gap: 9px;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
.form-input {
|
|
559
|
+
width: 100%;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
.form-input :deep(.q-field__control) {
|
|
563
|
+
height: 65px;
|
|
564
|
+
border-radius: 15px !important;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
.form-input :deep(.q-field__native) {
|
|
568
|
+
font-size: 16px;
|
|
569
|
+
font-weight: 500;
|
|
570
|
+
line-height: 1.5em;
|
|
571
|
+
letter-spacing: -0.5px;
|
|
572
|
+
color: #103140;
|
|
573
|
+
padding: 0 16px;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
.form-input :deep(.q-field__bottom) {
|
|
577
|
+
font-size: 14px;
|
|
578
|
+
font-weight: 400;
|
|
579
|
+
line-height: 1.5em;
|
|
580
|
+
color: #ef476f;
|
|
581
|
+
padding-top: 9px;
|
|
582
|
+
padding-left: 0;
|
|
583
|
+
min-height: 24px;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.primary-button {
|
|
587
|
+
width: 100%;
|
|
588
|
+
height: 65px;
|
|
589
|
+
background: #40c4ff;
|
|
590
|
+
color: #ffffff;
|
|
591
|
+
font-size: 18px;
|
|
592
|
+
font-weight: 600;
|
|
593
|
+
line-height: 1.33em;
|
|
594
|
+
letter-spacing: -0.5px;
|
|
595
|
+
border-radius: 15px;
|
|
596
|
+
text-transform: none;
|
|
597
|
+
margin-top: 8px;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
.primary-button:hover {
|
|
601
|
+
background: #35b0e6;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
.api-error {
|
|
605
|
+
margin-top: 16px;
|
|
606
|
+
font-size: 14px;
|
|
607
|
+
line-height: 1.5em;
|
|
608
|
+
color: #ef476f;
|
|
609
|
+
text-align: center;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
.channel-list {
|
|
613
|
+
display: flex;
|
|
614
|
+
flex-direction: column;
|
|
615
|
+
gap: 14px;
|
|
616
|
+
margin-bottom: 22px;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
.channel-option {
|
|
620
|
+
display: flex;
|
|
621
|
+
align-items: center;
|
|
622
|
+
gap: 14px;
|
|
623
|
+
border: 1px solid #bdc8d1;
|
|
624
|
+
border-radius: 15px;
|
|
625
|
+
padding: 16px;
|
|
626
|
+
cursor: pointer;
|
|
627
|
+
transition: all 0.15s ease;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
.channel-option--selected {
|
|
631
|
+
border-color: #40c4ff;
|
|
632
|
+
background: #f3fcff;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
.channel-icon-box {
|
|
636
|
+
flex-shrink: 0;
|
|
637
|
+
width: 48px;
|
|
638
|
+
height: 48px;
|
|
639
|
+
border-radius: 8px;
|
|
640
|
+
background: #cff0ff;
|
|
641
|
+
display: flex;
|
|
642
|
+
align-items: center;
|
|
643
|
+
justify-content: center;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
.channel-texts {
|
|
647
|
+
flex: 1;
|
|
648
|
+
min-width: 0;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
.channel-label {
|
|
652
|
+
font-size: 16px;
|
|
653
|
+
font-weight: 600;
|
|
654
|
+
color: #103140;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
.channel-description {
|
|
658
|
+
font-size: 14px;
|
|
659
|
+
font-weight: 400;
|
|
660
|
+
color: #607680;
|
|
661
|
+
margin-top: 2px;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
.channel-radio {
|
|
665
|
+
flex-shrink: 0;
|
|
666
|
+
width: 20px;
|
|
667
|
+
height: 20px;
|
|
668
|
+
border-radius: 9999px;
|
|
669
|
+
border: 1.5px solid #bdc8d1;
|
|
670
|
+
display: flex;
|
|
671
|
+
align-items: center;
|
|
672
|
+
justify-content: center;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
.channel-radio--selected {
|
|
676
|
+
border-color: #40c4ff;
|
|
677
|
+
background: #40c4ff;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
.channel-radio-dot {
|
|
681
|
+
width: 10px;
|
|
682
|
+
height: 10px;
|
|
683
|
+
border-radius: 9999px;
|
|
684
|
+
background: #ffffff;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
.back-link {
|
|
688
|
+
color: #001d3d;
|
|
689
|
+
text-decoration: none;
|
|
690
|
+
font-size: 15px;
|
|
691
|
+
line-height: 1.5em;
|
|
692
|
+
cursor: pointer;
|
|
693
|
+
transition: color 0.2s;
|
|
694
|
+
display: flex;
|
|
695
|
+
align-items: center;
|
|
696
|
+
gap: 8px;
|
|
697
|
+
margin-top: 15px;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
.back-link:hover {
|
|
701
|
+
color: #35b0e6;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
.back-link--center {
|
|
705
|
+
justify-content: center;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
.back-link--lg {
|
|
709
|
+
font-size: 16px;
|
|
710
|
+
font-weight: 600;
|
|
711
|
+
margin-top: 40px;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
.or-divider {
|
|
715
|
+
display: flex;
|
|
716
|
+
align-items: center;
|
|
717
|
+
width: 100%;
|
|
718
|
+
margin-top: 29px;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
.or-divider-line {
|
|
722
|
+
flex: 1;
|
|
723
|
+
height: 1px;
|
|
724
|
+
background: #bdc8d1;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
.or-divider-text {
|
|
728
|
+
padding: 0 16px;
|
|
729
|
+
font-size: 12px;
|
|
730
|
+
font-weight: 500;
|
|
731
|
+
color: #6e7980;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
.sent-content {
|
|
735
|
+
display: flex;
|
|
736
|
+
flex-direction: column;
|
|
737
|
+
align-items: center;
|
|
738
|
+
gap: 16px;
|
|
739
|
+
text-align: center;
|
|
740
|
+
flex: 1;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
.success-icon-outer {
|
|
744
|
+
width: 96px;
|
|
745
|
+
height: 96px;
|
|
746
|
+
border-radius: 9999px;
|
|
747
|
+
background: rgba(6, 214, 160, 0.2);
|
|
748
|
+
display: flex;
|
|
749
|
+
align-items: center;
|
|
750
|
+
justify-content: center;
|
|
751
|
+
margin-bottom: 8px;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
.sent-title {
|
|
755
|
+
font-size: 24px;
|
|
756
|
+
font-weight: 600;
|
|
757
|
+
line-height: 1.18em;
|
|
758
|
+
letter-spacing: -0.5px;
|
|
759
|
+
color: #152f3b;
|
|
760
|
+
margin: 0;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
.sent-description {
|
|
764
|
+
font-size: 16px;
|
|
765
|
+
font-weight: 400;
|
|
766
|
+
line-height: 1.5em;
|
|
767
|
+
color: #152f3b;
|
|
768
|
+
margin: 0;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
.info-banner {
|
|
772
|
+
width: 100%;
|
|
773
|
+
height: 56px;
|
|
774
|
+
display: flex;
|
|
775
|
+
align-items: center;
|
|
776
|
+
justify-content: center;
|
|
777
|
+
gap: 3px;
|
|
778
|
+
background: #f2f4f6;
|
|
779
|
+
border: 1px solid rgba(189, 200, 209, 0.3);
|
|
780
|
+
border-radius: 15px;
|
|
781
|
+
padding: 0 41px;
|
|
782
|
+
font-size: 14px;
|
|
783
|
+
font-weight: 600;
|
|
784
|
+
color: #3e484f;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
.resend-button {
|
|
788
|
+
width: 100%;
|
|
789
|
+
height: 56px;
|
|
790
|
+
background: #40c4ff;
|
|
791
|
+
color: #ffffff;
|
|
792
|
+
font-size: 16px;
|
|
793
|
+
font-weight: 600;
|
|
794
|
+
border-radius: 15px;
|
|
795
|
+
text-transform: none;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/* q-btn wraps the default slot in .q-btn__content: a gap set on the button
|
|
799
|
+
itself would never reach the icon/label pair inside it. */
|
|
800
|
+
.resend-button :deep(.q-btn__content) {
|
|
801
|
+
display: flex;
|
|
802
|
+
align-items: center;
|
|
803
|
+
justify-content: center;
|
|
804
|
+
gap: 10px;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
.resend-button:hover {
|
|
808
|
+
background: #35b0e6;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
.warning-banner {
|
|
812
|
+
width: 100%;
|
|
813
|
+
display: flex;
|
|
814
|
+
align-items: flex-start;
|
|
815
|
+
gap: 10px;
|
|
816
|
+
background: rgba(255, 189, 61, 0.15);
|
|
817
|
+
border-left: 4px solid #ffce6e;
|
|
818
|
+
border-top-right-radius: 8px;
|
|
819
|
+
border-bottom-right-radius: 8px;
|
|
820
|
+
padding: 14px 16px;
|
|
821
|
+
font-size: 13px;
|
|
822
|
+
font-weight: 400;
|
|
823
|
+
line-height: 1.4em;
|
|
824
|
+
color: #607680;
|
|
825
|
+
text-align: left;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
.warning-banner svg {
|
|
829
|
+
flex-shrink: 0;
|
|
830
|
+
margin-top: 1px;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
.forbidden-content {
|
|
834
|
+
display: flex;
|
|
835
|
+
flex-direction: column;
|
|
836
|
+
align-items: center;
|
|
837
|
+
gap: 16px;
|
|
838
|
+
text-align: center;
|
|
839
|
+
flex: 1;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
.warning-icon-outer {
|
|
843
|
+
width: 82px;
|
|
844
|
+
height: 82px;
|
|
845
|
+
display: flex;
|
|
846
|
+
align-items: center;
|
|
847
|
+
justify-content: center;
|
|
848
|
+
margin-bottom: 8px;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
.forbidden-title {
|
|
852
|
+
font-size: 27px;
|
|
853
|
+
font-weight: 600;
|
|
854
|
+
line-height: 1.18em;
|
|
855
|
+
letter-spacing: -0.5px;
|
|
856
|
+
color: #152f3b;
|
|
857
|
+
margin: 0;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
.forbidden-message {
|
|
861
|
+
font-size: 16px;
|
|
862
|
+
font-weight: 400;
|
|
863
|
+
line-height: 1.5em;
|
|
864
|
+
color: #152f3b;
|
|
865
|
+
margin: 0;
|
|
866
|
+
text-align: center;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
.forbidden-sso-section {
|
|
870
|
+
width: 100%;
|
|
871
|
+
margin-top: 8px;
|
|
872
|
+
text-align: left;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
.forbidden-sso-label {
|
|
876
|
+
font-size: 15px;
|
|
877
|
+
font-weight: 600;
|
|
878
|
+
line-height: 1.5em;
|
|
879
|
+
color: #001d3d;
|
|
880
|
+
margin: 0 0 12px 0;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
.forbidden-sso-button {
|
|
884
|
+
display: flex;
|
|
885
|
+
width: 260px;
|
|
886
|
+
max-width: 100%;
|
|
887
|
+
height: 36px;
|
|
888
|
+
margin: 0 auto;
|
|
889
|
+
border-radius: 8.85px;
|
|
890
|
+
background: #ebeeef;
|
|
891
|
+
font-size: 15px;
|
|
892
|
+
font-weight: 600;
|
|
893
|
+
color: #112240;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
.forbidden-sso-button:hover {
|
|
897
|
+
background: #e0e5e7;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
.forbidden-sso-icon {
|
|
901
|
+
width: 18px;
|
|
902
|
+
height: 18px;
|
|
903
|
+
margin-right: 8px;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
@media screen and (max-width: 768px) {
|
|
907
|
+
.login-card {
|
|
908
|
+
padding: 32px 24px;
|
|
909
|
+
max-width: 100%;
|
|
910
|
+
min-height: auto;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
.logo {
|
|
914
|
+
width: 200px;
|
|
915
|
+
height: auto;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
.step-title {
|
|
919
|
+
font-size: 20px;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
.form-input :deep(.q-field__control) {
|
|
923
|
+
height: 56px;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
.primary-button {
|
|
927
|
+
height: 56px;
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
</style>
|