PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.4.8
Booking for Appointments and Events Calendar – Amelia v2.4.8
2.4.9 2.4.8 2.4.7 2.4.6 2.4.5 2.4.4 2.4.3 2.4.2 2.4.1 2.4 trunk 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 1.2.17 1.2.18 1.2.19 1.2.2 1.2.20 1.2.21 1.2.22 1.2.23 1.2.24 1.2.25 1.2.26 1.2.27 1.2.28 1.2.29 1.2.3 1.2.30 1.2.31 1.2.32 1.2.33 1.2.34 1.2.35 1.2.36 1.2.37 1.2.38 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.1.3 2.2 2.2.1 2.3
ameliabooking / v3 / src / views / public / Cabinet / common / Authentication / parts / SetPass.vue
ameliabooking / v3 / src / views / public / Cabinet / common / Authentication / parts Last commit date
SendAccessLink.vue 1 month ago SendAccessLinkSuccess.vue 1 month ago SetPass.vue 1 month ago SetPassSuccess.vue 1 month ago SignIn.vue 1 week ago Skeleton.vue 1 month ago
SetPass.vue
412 lines
1 <template>
2 <div
3 v-if="!loading"
4 ref="setPassContainerRef"
5 class="am-asi"
6 :style="cssVars"
7 role="region"
8 aria-labelledby="am-sp-title"
9 aria-describedby="am-sp-description"
10 >
11 <div class="am-asi__top">
12 <div id="am-sp-title" class="am-asi__header">
13 {{ amLabels.new_password_set }}
14 </div>
15 <div id="am-sp-description" class="am-asi__text">
16 {{ amLabels.new_password_set_description }}
17 </div>
18 </div>
19
20 <el-form
21 ref="authFormRef"
22 :model="infoFormData"
23 :rules="infoFormRules"
24 label-position="top"
25 class="am-asi__form"
26 :class="responsiveClass"
27 @submit.prevent="submitForm"
28 >
29 <template v-for="(item, index) in signInFormConstruction" :key="index">
30 <component
31 :is="item.template"
32 ref="customerCollectorRef"
33 v-model="infoFormData[index]"
34 v-bind="item.props"
35 @enter="submitForm"
36 ></component>
37 </template>
38 </el-form>
39
40 <AmButton
41 class="am-asi__btn"
42 :type="amCustomize.setPass.options.newPassBtn.buttonType"
43 @click="submitForm"
44 >
45 {{ amLabels.new_password_set_action }}
46 </AmButton>
47 </div>
48 <Skeleton v-else :count="4" :center-first="true" :main-class="'am-asi'"></Skeleton>
49 </template>
50
51 <script setup>
52 // * import from Vue
53 import { ref, reactive, computed, inject, watch, nextTick } from 'vue'
54
55 // * Import from Vuex
56 import { useStore } from 'vuex'
57
58 // * Import from Libraries
59 import httpClient from '../../../../../../plugins/axios'
60
61 // * Components
62 import { formFieldsTemplates } from '../../../../../../assets/js/common/formFieldsTemplates'
63 import AmButton from '../../../../../_components/button/AmButton.vue'
64 import Skeleton from './Skeleton'
65
66 // * Composables
67 import { useResponsiveClass } from '../../../../../../assets/js/common/responsive.js'
68 import { useColorTransparency } from '../../../../../../assets/js/common/colorManipulation.js'
69
70 // * Vars
71 let store = useStore()
72
73 // * Root Settings
74 const amSettings = inject('settings')
75
76 // * Customized form data
77 let amCustomize = inject('amCustomize')
78
79 // * labels
80 const labels = inject('labels')
81
82 // * local language short code
83 const localLanguage = inject('localLanguage')
84
85 // * if local lang is in settings lang
86 let langDetection = computed(() => amSettings.general.usedLanguages.includes(localLanguage.value))
87
88 // * Computed labels
89 let amLabels = computed(() => {
90 let computedLabels = reactive({ ...labels })
91
92 let customizedLabels = amCustomize.value.setPass.translations
93 if (customizedLabels) {
94 Object.keys(customizedLabels).forEach((labelKey) => {
95 if (customizedLabels[labelKey][localLanguage.value] && langDetection.value) {
96 computedLabels[labelKey] = customizedLabels[labelKey][localLanguage.value]
97 } else if (customizedLabels[labelKey].default) {
98 computedLabels[labelKey] = customizedLabels[labelKey].default
99 }
100 })
101 }
102 return computedLabels
103 })
104
105 /********
106 * Form *
107 ********/
108 // * Form reference
109 let authFormRef = ref(null)
110
111 // * Form data
112 let infoFormData = ref({
113 newPassword: computed({
114 get: () => store.getters['auth/getNewPassword'],
115 set: (val) => {
116 store.commit('auth/setNewPassword', val ? val : '')
117 },
118 }),
119 confirmPassword: computed({
120 get: () => store.getters['auth/getConfirmPassword'],
121 set: (val) => {
122 store.commit('auth/setConfirmPassword', val ? val : '')
123 },
124 }),
125 })
126
127 // * Form validation rules
128 let infoFormRules = ref({
129 newPassword: [
130 {
131 required: true,
132 message: amLabels.value.new_password_required,
133 trigger: 'submit',
134 },
135 {
136 min: 4,
137 message: amLabels.value.new_password_length,
138 trigger: 'submit',
139 },
140 ],
141 confirmPassword: [
142 {
143 required: true,
144 message: amLabels.value.new_password_required,
145 trigger: 'submit',
146 },
147 {
148 min: 4,
149 message: amLabels.value.new_password_length,
150 trigger: 'submit',
151 },
152 {
153 validator: () =>
154 store.getters['auth/getNewPassword'] === store.getters['auth/getConfirmPassword'],
155 message: amLabels.value.passwords_not_match,
156 trigger: 'submit',
157 },
158 ],
159 })
160
161 // * Form construction
162 let signInFormConstruction = ref({
163 newPassword: {
164 template: formFieldsTemplates.text,
165 props: {
166 itemName: 'newPassword',
167 itemType: 'password',
168 showPassword: true,
169 label: amLabels.value.new_password_colon,
170 placeholder: '',
171 minLength: 3,
172 class: 'am-asi__item',
173 },
174 },
175 confirmPassword: {
176 template: formFieldsTemplates.text,
177 props: {
178 itemName: 'confirmPassword',
179 itemType: 'password',
180 showPassword: true,
181 label: amLabels.value.new_password_colon_retype,
182 placeholder: '',
183 minLength: 3,
184 class: 'am-asi__item',
185 },
186 },
187 })
188
189 // * Cabinet type
190 let cabinetType = inject('cabinetType')
191
192 // * Loading
193 let loading = computed(() => {
194 return store.getters['getLoading']
195 })
196
197 // * Accessibility refs
198 let setPassContainerRef = ref(null)
199 let hasInitialFocus = ref(false)
200
201 function focusFirstInput() {
202 if (!setPassContainerRef.value) {
203 return
204 }
205 const firstInput = setPassContainerRef.value.querySelector(
206 '.am-asi__form input, .am-asi__form textarea, .am-asi__form select',
207 )
208 if (firstInput) {
209 firstInput.focus()
210 }
211 }
212
213 // * Move focus to first field once loading completes
214 watch(
215 loading,
216 (isLoading) => {
217 if (!isLoading && !hasInitialFocus.value) {
218 hasInitialFocus.value = true
219 nextTick(() => {
220 focusFirstInput()
221 })
222 }
223 },
224 { immediate: true },
225 )
226
227 // * Submit Form
228 function submitForm() {
229 authFormRef.value.validate((valid) => {
230 if (
231 valid &&
232 store.getters['auth/getNewPassword'] === store.getters['auth/getConfirmPassword']
233 ) {
234 let user = store.getters['auth/getProfile']
235
236 store.commit('setLoading', true)
237
238 httpClient
239 .post(
240 '/users/' + cabinetType.value + 's/' + user.id,
241 { password: store.getters['auth/getNewPassword'] },
242 { params: { source: 'cabinet-' + cabinetType.value } },
243 )
244 .then(() => {
245 store.commit('auth/setAuthenticated', true)
246 })
247 .catch(() => {})
248 .finally(() => {
249 store.commit('setLoading', false)
250 })
251 } else {
252 return false
253 }
254 })
255 }
256
257 /*************
258 * Customize *
259 *************/
260
261 // * Responsive - Container Width
262 let cWidth = inject('containerWidth')
263
264 let responsiveClass = computed(() => useResponsiveClass(cWidth.value))
265
266 // * Fonts
267 let amFonts = inject('amFonts')
268
269 // * Colors block
270 let amColors = inject('amColors')
271
272 let cssVars = computed(() => {
273 return {
274 '--am-c-primary': amColors.value.colorPrimary,
275 '--am-c-success': amColors.value.colorSuccess,
276 '--am-c-error': amColors.value.colorError,
277 '--am-c-warning': amColors.value.colorWarning,
278 '--am-c-main-bgr': amColors.value.colorMainBgr,
279 '--am-c-main-heading-text': amColors.value.colorMainHeadingText,
280 '--am-c-main-text': amColors.value.colorMainText,
281 '--am-c-main-text-op70': useColorTransparency(amColors.value.colorMainText, 0.7),
282 '--am-c-main-text-op60': useColorTransparency(amColors.value.colorMainText, 0.6),
283 '--am-c-main-text-op40': useColorTransparency(amColors.value.colorMainText, 0.4),
284 '--am-c-main-text-op25': useColorTransparency(amColors.value.colorMainText, 0.25),
285 '--am-c-inp-bgr': amColors.value.colorInpBgr,
286 '--am-c-inp-border': amColors.value.colorInpBorder,
287 '--am-c-inp-text': amColors.value.colorInpText,
288 '--am-c-inp-placeholder': amColors.value.colorInpPlaceHolder,
289 '--am-c-btn-prim': amColors.value.colorBtnPrim,
290 '--am-c-btn-prim-text': amColors.value.colorBtnPrimText,
291 '--am-c-skeleton-op20': useColorTransparency(amColors.value.colorMainText, 0.2),
292 '--am-c-skeleton-op60': useColorTransparency(amColors.value.colorMainText, 0.6),
293 '--am-font-family': amFonts.value.fontFamily,
294
295 '--am-c-scroll-op30': useColorTransparency(amColors.value.colorPrimary, 0.3),
296 '--am-c-scroll-op10': useColorTransparency(amColors.value.colorPrimary, 0.1),
297 }
298 })
299 </script>
300
301 <script>
302 export default {
303 name: 'AuthNewPass',
304 }
305 </script>
306
307 <style lang="scss">
308 // am - amelia
309 // asi - authentication sign in
310 @mixin auth {
311 .am-asi {
312 max-width: 400px;
313 width: 100%;
314 background-color: var(--am-c-main-bgr);
315 box-shadow:
316 0 0 9px -4px var(--am-c-main-text-op40),
317 0px 17px 35px -12px var(--am-c-main-text-op25);
318 border-radius: 12px;
319 padding: 32px 24px 24px;
320 margin: 0 auto;
321 font-family: var(--am-font-family);
322
323 * {
324 font-family: var(--am-font-family);
325 box-sizing: border-box;
326 }
327
328 &__top {
329 display: flex;
330 flex-direction: column;
331 align-items: center;
332 margin: 0 0 32px;
333 }
334
335 &__header {
336 font-size: 24px;
337 font-weight: 500;
338 line-height: 1.33333;
339 color: var(--am-c-main-heading-text);
340 margin: 0 0 4px;
341 }
342
343 &__text {
344 font-size: 15px;
345 font-weight: 400;
346 line-height: 1.6;
347 text-align: center;
348 color: var(--am-c-main-text-op70);
349 }
350
351 &__form {
352 .am-ff {
353 &__item {
354 &-label {
355 font-size: 15px;
356 font-weight: 500;
357 color: var(--am-c-main-text);
358 }
359 }
360 }
361
362 .el-form {
363 &-item {
364 margin-bottom: 30px;
365
366 &__label {
367 margin: 0 0 4px;
368 }
369 }
370 }
371 }
372
373 &__btn {
374 width: 100%;
375 margin: 16px 0;
376 }
377
378 &__footer {
379 display: flex;
380 align-items: center;
381 justify-content: center;
382
383 &-text {
384 font-size: 15px;
385 font-weight: 400;
386 line-height: 1.6;
387 margin: 0 4px 0 0;
388 color: var(--am-c-main-text-op60);
389 }
390
391 &-link {
392 font-size: 15px;
393 font-weight: 400;
394 line-height: 1.6;
395 color: var(--am-c-primary);
396 cursor: pointer;
397 }
398 }
399 }
400 }
401
402 // Public
403 .amelia-v2-booking #amelia-container {
404 @include auth;
405 }
406
407 // Admin
408 #amelia-app-backend-new {
409 @include auth;
410 }
411 </style>
412