@live-change/user-frontend 0.3.23 → 0.3.24

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.
@@ -0,0 +1,13 @@
1
+ /* eslint-disable */
2
+ /* prettier-ignore */
3
+ // @ts-nocheck
4
+ // Generated by unplugin-vue-components
5
+ // Read more: https://github.com/vuejs/core/pull/3399
6
+ export {}
7
+
8
+ declare module 'vue' {
9
+ export interface GlobalComponents {
10
+ RouterLink: typeof import('vue-router')['RouterLink']
11
+ RouterView: typeof import('vue-router')['RouterView']
12
+ }
13
+ }
@@ -2,14 +2,16 @@
2
2
  <div class="surface-overlay py-3 px-6 shadow-2 flex align-items-center justify-content-between
3
3
  relative md:sticky top-0 z-5"
4
4
  style="min-height: 80px" key="navbar">
5
- <img src="/images/logo.svg" alt="Image" height="40" class="mr-0 lg:mr-6">
5
+
6
+ <router-link to="/">
7
+ <img src="/images/logo.svg" alt="Image" height="40" class="mr-0 lg:mr-6">
8
+ </router-link>
6
9
  <div class="hidden lg:flex">
7
10
  <!-- place for desktop menu -->
8
11
  </div>
9
12
  <div class="flex flex-grow-1"></div>
10
13
  <UserIcon />
11
14
 
12
-
13
15
  <div class="static w-auto w-full surface-overlay left-0 top-100 z-1 shadow-none hidden">
14
16
  <ul class="list-none p-0 m-0 flex align-items-center select-none flex-row border-top-none">
15
17
  <li>
@@ -27,11 +29,11 @@
27
29
  </ul>
28
30
  </div>
29
31
 
30
-
31
32
  <a v-ripple class="cursor-pointer block lg:hidden text-700 p-ripple ml-2 hover:surface-100 p-2"
32
33
  v-styleclass="{ selector: '@next', enterClass: 'hidden', leaveToClass: 'hidden', hideOnOutsideClick: true }">
33
34
  <i class="pi pi-bars text-4xl"></i>
34
35
  </a>
36
+
35
37
  <div class="align-items-center flex-grow-1 justify-content-between hidden absolute lg:static w-full surface-overlay left-0 top-100 z-1 shadow-2 lg:shadow-none">
36
38
  <ul class="list-none p-0 m-0 flex lg:align-items-center select-none flex-column lg:flex-row">
37
39
  <li>
@@ -109,6 +111,7 @@
109
111
  </li>
110
112
  </ul>
111
113
  </div>
114
+
112
115
  </div>
113
116
  </template>
114
117
 
@@ -16,7 +16,8 @@
16
16
 
17
17
  <div class="p-field mb-3" v-if="passwordExists">
18
18
  <label for="currentPassword" class="block text-900 font-medium mb-2">Current password</label>
19
- <Password id="currentPassword" class="w-full" inputClass="w-full" toggleMask
19
+ <Password id="currentPassword" class="w-full" inputClass="w-full"
20
+ v-model:masked="masked"
20
21
  :class="{ 'p-invalid': data.currentPasswordHashError }"
21
22
  v-model="data.currentPasswordHash" />
22
23
  <small id="currentPassword-help" class="p-error">{{ data.currentPasswordHashError }}</small>
@@ -24,7 +25,8 @@
24
25
 
25
26
  <div class="p-field mb-3">
26
27
  <label for="newPassword" class="block text-900 font-medium mb-2">New password</label>
27
- <Password id="newPassword" class="w-full" inputClass="w-full" toggleMask
28
+ <Password id="newPassword" class="w-full" inputClass="w-full"
29
+ v-model:masked="masked"
28
30
  :class="{ 'p-invalid': data.passwordHashError }"
29
31
  v-model="data.passwordHash">
30
32
  <template #footer>
@@ -44,8 +46,9 @@
44
46
  <div class="p-field mb-3">
45
47
  <label for="reenterPassword" class="block text-900 font-medium mb-2">Re-enter password</label>
46
48
  <Password id="reenterPassword" class="w-full" inputClass="w-full"
49
+ v-model:masked="masked"
47
50
  v-model="secondPassword"
48
- :feedback="false" toggleMask />
51
+ :feedback="false" />
49
52
  </div>
50
53
 
51
54
  </template>
@@ -62,42 +65,44 @@
62
65
 
63
66
  <script setup>
64
67
 
65
- import InputText from "primevue/inputtext"
66
- import Checkbox from "primevue/checkbox"
67
- import Button from "primevue/button"
68
- import Divider from "primevue/divider"
69
- import Password from "primevue/password"
70
- import SettingsTabs from "../SettingsTabs.vue"
68
+ import InputText from "primevue/inputtext"
69
+ import Checkbox from "primevue/checkbox"
70
+ import Button from "primevue/button"
71
+ import Divider from "primevue/divider"
72
+ import Password from "primevue/password"
73
+ import SettingsTabs from "../SettingsTabs.vue"
71
74
 
72
- import { live, path } from '@live-change/vue3-ssr'
73
- import { computed, ref, onMounted } from 'vue'
75
+ import { live, path } from '@live-change/vue3-ssr'
76
+ import { computed, ref, onMounted } from 'vue'
74
77
 
75
- import { useRouter } from 'vue-router'
76
- const router = useRouter()
78
+ import { useRouter } from 'vue-router'
79
+ const router = useRouter()
77
80
 
78
- const isMounted = ref(false)
79
- onMounted(() => isMounted.value = true)
81
+ const isMounted = ref(false)
82
+ onMounted(() => isMounted.value = true)
80
83
 
81
- const secondPassword = ref('')
82
- const form = ref()
84
+ const secondPassword = ref('')
85
+ const form = ref()
83
86
 
84
- onMounted(() => {
85
- form.value.addValidator('passwordHash', () => {
86
- const value = form.value.getFieldValue('passwordHash')
87
- console.log("PASSWORDS MATCH?", secondPassword.value, value)
88
- if(value != secondPassword.value) return "passwordsNotMatch"
87
+ const masked = ref(true)
88
+
89
+ onMounted(() => {
90
+ form.value.addValidator('passwordHash', () => {
91
+ const value = form.value.getFieldValue('passwordHash')
92
+ console.log("PASSWORDS MATCH?", secondPassword.value, value)
93
+ if(value != secondPassword.value) return "passwordsNotMatch"
94
+ })
89
95
  })
90
- })
91
96
 
92
97
 
93
- const passwordExists = await live(path().passwordAuthentication.myUserPasswordAuthenticationExists())
98
+ const passwordExists = await live(path().passwordAuthentication.myUserPasswordAuthenticationExists())
94
99
 
95
- function handleDone({ parameters, result }) {
96
- console.log("FORM DONE", parameters, result)
97
- router.push({
98
- name: 'user:changePasswordFinished',
99
- })
100
- }
100
+ function handleDone({ parameters, result }) {
101
+ console.log("FORM DONE", parameters, result)
102
+ router.push({
103
+ name: 'user:changePasswordFinished',
104
+ })
105
+ }
101
106
 
102
107
  </script>
103
108
 
@@ -0,0 +1,498 @@
1
+ <template>
2
+ <div :class="containerClass">
3
+ <PInputText
4
+ ref="input"
5
+ :id="inputId"
6
+ :type="inputType"
7
+ :class="inputFieldClass"
8
+ :style="inputStyle"
9
+ :value="modelValue"
10
+ :aria-labelledby="ariaLabelledby"
11
+ :aria-label="ariaLabel"
12
+ :aria-controls="(panelProps && panelProps.id) || panelId || panelUniqueId"
13
+ :aria-expanded="overlayVisible"
14
+ :aria-haspopup="true"
15
+ :placeholder="placeholder"
16
+ :required="required"
17
+ @input="onInput"
18
+ @focus="onFocus"
19
+ @blur="onBlur"
20
+ @keyup="onKeyUp"
21
+ @invalid="onInvalid"
22
+ v-bind="inputProps"
23
+ />
24
+ <i v-if="toggleMask" :class="toggleIconClass" @click="onMaskToggle" />
25
+ <span class="p-hidden-accessible" aria-live="polite">
26
+ {{ infoText }}
27
+ </span>
28
+ <Portal :appendTo="appendTo">
29
+ <transition name="p-connected-overlay" @enter="onOverlayEnter" @leave="onOverlayLeave" @after-leave="onOverlayAfterLeave">
30
+ <div v-if="overlayVisible" :ref="overlayRef" :id="panelId || panelUniqueId" :class="panelStyleClass" :style="panelStyle" @click="onOverlayClick" v-bind="panelProps">
31
+ <slot name="header"></slot>
32
+ <slot name="content">
33
+ <div class="p-password-meter">
34
+ <div :class="strengthClass" :style="{ width: meter ? meter.width : '' }"></div>
35
+ </div>
36
+ <div class="p-password-info">{{ infoText }}</div>
37
+ </slot>
38
+ <slot name="footer"></slot>
39
+ </div>
40
+ </transition>
41
+ </Portal>
42
+ </div>
43
+ </template>
44
+
45
+ <script>
46
+ import InputText from 'primevue/inputtext';
47
+ import OverlayEventBus from 'primevue/overlayeventbus';
48
+ import Portal from 'primevue/portal';
49
+ import { ConnectedOverlayScrollHandler, DomHandler, UniqueComponentId, ZIndexUtils } from 'primevue/utils';
50
+
51
+ function absolutePosition(element, target) {
52
+ if (element) {
53
+ const elementDimensions = element.offsetParent ? { width: element.offsetWidth, height: element.offsetHeight } : this.getHiddenElementDimensions(element);
54
+ const elementOuterHeight = elementDimensions.height;
55
+ const elementOuterWidth = elementDimensions.width;
56
+ const targetOuterHeight = target.offsetHeight;
57
+ const targetOuterWidth = target.offsetWidth;
58
+ const targetOffset = target.getBoundingClientRect();
59
+ const windowScrollTop = DomHandler.getWindowScrollTop();
60
+ const windowScrollLeft = DomHandler.getWindowScrollLeft();
61
+ const viewport = DomHandler.getViewport();
62
+ let top, left;
63
+
64
+ //if (targetOffset.top + targetOuterHeight + elementOuterHeight > viewport.height) {
65
+ top = targetOffset.top + windowScrollTop - elementOuterHeight;
66
+ element.style.transformOrigin = 'bottom';
67
+
68
+ if (top < 0) {
69
+ top = windowScrollTop;
70
+ }
71
+ /* } else {
72
+ top = targetOuterHeight + targetOffset.top + windowScrollTop;
73
+ element.style.transformOrigin = 'top';
74
+ }*/
75
+
76
+ if (targetOffset.left + elementOuterWidth > viewport.width) left = Math.max(0, targetOffset.left + windowScrollLeft + targetOuterWidth - elementOuterWidth);
77
+ else left = targetOffset.left + windowScrollLeft;
78
+
79
+ element.style.top = top + 'px';
80
+ element.style.left = left + 'px';
81
+ }
82
+ }
83
+
84
+ export default {
85
+ name: 'Password',
86
+ emits: ['update:modelValue', 'change', 'focus', 'blur', 'invalid', 'update:masked'],
87
+ props: {
88
+ modelValue: String,
89
+ promptLabel: {
90
+ type: String,
91
+ default: null
92
+ },
93
+ mediumRegex: {
94
+ type: String,
95
+ default: '^(((?=.*[a-z])(?=.*[A-Z]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[A-Z])(?=.*[0-9])))(?=.{6,})' // eslint-disable-line
96
+ },
97
+ strongRegex: {
98
+ type: String,
99
+ default: '^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{8,})' // eslint-disable-line
100
+ },
101
+ weakLabel: {
102
+ type: String,
103
+ default: null
104
+ },
105
+ mediumLabel: {
106
+ type: String,
107
+ default: null
108
+ },
109
+ strongLabel: {
110
+ type: String,
111
+ default: null
112
+ },
113
+ feedback: {
114
+ type: Boolean,
115
+ default: true
116
+ },
117
+ appendTo: {
118
+ type: String,
119
+ default: 'body'
120
+ },
121
+ toggleMask: {
122
+ type: Boolean,
123
+ default: false
124
+ },
125
+ hideIcon: {
126
+ type: String,
127
+ default: 'pi pi-eye-slash'
128
+ },
129
+ showIcon: {
130
+ type: String,
131
+ default: 'pi pi-eye'
132
+ },
133
+ disabled: {
134
+ type: Boolean,
135
+ default: false
136
+ },
137
+ placeholder: {
138
+ type: String,
139
+ default: null
140
+ },
141
+ required: {
142
+ type: Boolean,
143
+ default: false
144
+ },
145
+ inputId: {
146
+ type: String,
147
+ default: null
148
+ },
149
+ inputClass: {
150
+ type: [String, Object],
151
+ default: null
152
+ },
153
+ inputStyle: {
154
+ type: Object,
155
+ default: null
156
+ },
157
+ inputProps: {
158
+ type: null,
159
+ default: null
160
+ },
161
+ panelId: {
162
+ type: String,
163
+ default: null
164
+ },
165
+ panelClass: {
166
+ type: [String, Object],
167
+ default: null
168
+ },
169
+ panelStyle: {
170
+ type: Object,
171
+ default: null
172
+ },
173
+ panelProps: {
174
+ type: null,
175
+ default: null
176
+ },
177
+ 'aria-labelledby': {
178
+ type: String,
179
+ default: null
180
+ },
181
+ 'aria-label': {
182
+ type: String,
183
+ default: null
184
+ },
185
+ masked: {
186
+ type: Boolean,
187
+ default: true
188
+ }
189
+ },
190
+ data() {
191
+ return {
192
+ overlayVisible: false,
193
+ meter: null,
194
+ infoText: null,
195
+ focused: false,
196
+ unmasked: !this.masked
197
+ };
198
+ },
199
+ mediumCheckRegExp: null,
200
+ strongCheckRegExp: null,
201
+ resizeListener: null,
202
+ scrollHandler: null,
203
+ overlay: null,
204
+ mounted() {
205
+ this.infoText = this.promptText;
206
+ this.mediumCheckRegExp = new RegExp(this.mediumRegex);
207
+ this.strongCheckRegExp = new RegExp(this.strongRegex);
208
+ },
209
+ beforeUnmount() {
210
+ this.unbindResizeListener();
211
+
212
+ if (this.scrollHandler) {
213
+ this.scrollHandler.destroy();
214
+ this.scrollHandler = null;
215
+ }
216
+
217
+ if (this.overlay) {
218
+ ZIndexUtils.clear(this.overlay);
219
+ this.overlay = null;
220
+ }
221
+ },
222
+ methods: {
223
+ onOverlayEnter(el) {
224
+ ZIndexUtils.set('overlay', el, this.$primevue.config.zIndex.overlay);
225
+ this.alignOverlay();
226
+ this.bindScrollListener();
227
+ this.bindResizeListener();
228
+ },
229
+ onOverlayLeave() {
230
+ this.unbindScrollListener();
231
+ this.unbindResizeListener();
232
+ this.overlay = null;
233
+ },
234
+ onOverlayAfterLeave(el) {
235
+ ZIndexUtils.clear(el);
236
+ },
237
+ alignOverlay() {
238
+ if (this.appendTo === 'self') {
239
+ DomHandler.relativePosition(this.overlay, this.$refs.input.$el);
240
+ } else {
241
+ this.overlay.style.minWidth = DomHandler.getOuterWidth(this.$refs.input.$el) + 'px';
242
+ absolutePosition(this.overlay, this.$refs.input.$el);
243
+ }
244
+ },
245
+ testStrength(str) {
246
+ let level = 0;
247
+
248
+ if (this.strongCheckRegExp.test(str)) level = 3;
249
+ else if (this.mediumCheckRegExp.test(str)) level = 2;
250
+ else if (str.length) level = 1;
251
+
252
+ return level;
253
+ },
254
+ onInput(event) {
255
+ this.$emit('update:modelValue', event.target.value);
256
+ },
257
+ onFocus(event) {
258
+ this.focused = true;
259
+
260
+ if (this.feedback) {
261
+ this.setPasswordMeter(this.modelValue);
262
+ this.overlayVisible = true;
263
+ }
264
+
265
+ this.$emit('focus', event);
266
+ },
267
+ onBlur(event) {
268
+ this.focused = false;
269
+
270
+ if (this.feedback) {
271
+ this.overlayVisible = false;
272
+ }
273
+
274
+ this.$emit('blur', event);
275
+ },
276
+ onKeyUp(event) {
277
+ if (this.feedback) {
278
+ const value = event.target.value;
279
+ const { meter, label } = this.checkPasswordStrength(value);
280
+
281
+ this.meter = meter;
282
+ this.infoText = label;
283
+
284
+ if (event.code === 'Escape') {
285
+ this.overlayVisible && (this.overlayVisible = false);
286
+
287
+ return;
288
+ }
289
+
290
+ if (!this.overlayVisible) {
291
+ this.overlayVisible = true;
292
+ }
293
+ }
294
+ },
295
+ setPasswordMeter() {
296
+ if (!this.modelValue) return;
297
+
298
+ const { meter, label } = this.checkPasswordStrength(this.modelValue);
299
+
300
+ this.meter = meter;
301
+ this.infoText = label;
302
+
303
+ if (!this.overlayVisible) {
304
+ this.overlayVisible = true;
305
+ }
306
+ },
307
+ checkPasswordStrength(value) {
308
+ let label = null;
309
+ let meter = null;
310
+
311
+ switch (this.testStrength(value)) {
312
+ case 1:
313
+ label = this.weakText;
314
+ meter = {
315
+ strength: 'weak',
316
+ width: '33.33%'
317
+ };
318
+ break;
319
+
320
+ case 2:
321
+ label = this.mediumText;
322
+ meter = {
323
+ strength: 'medium',
324
+ width: '66.66%'
325
+ };
326
+ break;
327
+
328
+ case 3:
329
+ label = this.strongText;
330
+ meter = {
331
+ strength: 'strong',
332
+ width: '100%'
333
+ };
334
+ break;
335
+
336
+ default:
337
+ label = this.promptText;
338
+ meter = null;
339
+ break;
340
+ }
341
+
342
+ return { label, meter };
343
+ },
344
+ onInvalid(event) {
345
+ this.$emit('invalid', event);
346
+ },
347
+ bindScrollListener() {
348
+ if (!this.scrollHandler) {
349
+ this.scrollHandler = new ConnectedOverlayScrollHandler(this.$refs.input.$el, () => {
350
+ if (this.overlayVisible) {
351
+ this.overlayVisible = false;
352
+ }
353
+ });
354
+ }
355
+
356
+ this.scrollHandler.bindScrollListener();
357
+ },
358
+ unbindScrollListener() {
359
+ if (this.scrollHandler) {
360
+ this.scrollHandler.unbindScrollListener();
361
+ }
362
+ },
363
+ bindResizeListener() {
364
+ if (!this.resizeListener) {
365
+ this.resizeListener = () => {
366
+ if (this.overlayVisible && !DomHandler.isTouchDevice()) {
367
+ this.overlayVisible = false;
368
+ }
369
+ };
370
+
371
+ window.addEventListener('resize', this.resizeListener);
372
+ }
373
+ },
374
+ unbindResizeListener() {
375
+ if (this.resizeListener) {
376
+ window.removeEventListener('resize', this.resizeListener);
377
+ this.resizeListener = null;
378
+ }
379
+ },
380
+ overlayRef(el) {
381
+ this.overlay = el;
382
+ },
383
+ onMaskToggle() {
384
+ this.unmasked = !this.unmasked;
385
+ this.$emit('update:masked', !this.unmasked);
386
+ },
387
+ onOverlayClick(event) {
388
+ OverlayEventBus.emit('overlay-click', {
389
+ originalEvent: event,
390
+ target: this.$el
391
+ });
392
+ }
393
+ },
394
+ computed: {
395
+ containerClass() {
396
+ return [
397
+ 'p-password p-component p-inputwrapper',
398
+ {
399
+ 'p-inputwrapper-filled': this.filled,
400
+ 'p-inputwrapper-focus': this.focused,
401
+ 'p-input-icon-right': this.toggleMask
402
+ }
403
+ ];
404
+ },
405
+ inputFieldClass() {
406
+ return [
407
+ 'p-password-input',
408
+ this.inputClass,
409
+ {
410
+ 'p-disabled': this.disabled
411
+ }
412
+ ];
413
+ },
414
+ panelStyleClass() {
415
+ return [
416
+ 'p-password-panel p-component',
417
+ this.panelClass,
418
+ {
419
+ 'p-input-filled': this.$primevue.config.inputStyle === 'filled',
420
+ 'p-ripple-disabled': this.$primevue.config.ripple === false
421
+ }
422
+ ];
423
+ },
424
+ toggleIconClass() {
425
+ return this.unmasked ? this.hideIcon : this.showIcon;
426
+ },
427
+ strengthClass() {
428
+ return `p-password-strength ${this.meter ? this.meter.strength : ''}`;
429
+ },
430
+ inputType() {
431
+ return this.unmasked ? 'text' : 'password';
432
+ },
433
+ filled() {
434
+ return this.modelValue != null && this.modelValue.toString().length > 0;
435
+ },
436
+ weakText() {
437
+ return this.weakLabel || this.$primevue.config.locale.weak;
438
+ },
439
+ mediumText() {
440
+ return this.mediumLabel || this.$primevue.config.locale.medium;
441
+ },
442
+ strongText() {
443
+ return this.strongLabel || this.$primevue.config.locale.strong;
444
+ },
445
+ promptText() {
446
+ return this.promptLabel || this.$primevue.config.locale.passwordPrompt;
447
+ },
448
+ panelUniqueId() {
449
+ return UniqueComponentId() + '_panel';
450
+ }
451
+ },
452
+ watch: {
453
+ masked(value) {
454
+ this.unmasked = !value;
455
+ },
456
+ },
457
+ components: {
458
+ PInputText: InputText,
459
+ Portal: Portal
460
+ }
461
+ };
462
+ </script>
463
+
464
+ <style>
465
+ .p-password {
466
+ position: relative;
467
+ display: inline-flex;
468
+ }
469
+
470
+ .p-password-panel {
471
+ position: absolute;
472
+ top: 0;
473
+ left: 0;
474
+ }
475
+
476
+ .p-password .p-password-panel {
477
+ min-width: 100%;
478
+ }
479
+
480
+ .p-password-meter {
481
+ height: 10px;
482
+ }
483
+
484
+ .p-password-strength {
485
+ height: 100%;
486
+ width: 0;
487
+ transition: width 1s ease-in-out;
488
+ }
489
+
490
+ .p-fluid .p-password {
491
+ display: flex;
492
+ }
493
+
494
+ .p-password-input::-ms-reveal,
495
+ .p-password-input::-ms-clear {
496
+ display: none;
497
+ }
498
+ </style>
@@ -11,6 +11,8 @@
11
11
  Redirect in {{ pluralize('second', Math.ceil((redirectTime - currentTime) / 1000), true) }}...
12
12
  </p>
13
13
  </div>
14
+ <div v-else>
15
+ Return to <router-link to="/">index page</router-link>.
14
16
  </div>
15
17
  </div>
16
18
  </template>
@@ -1,14 +1,123 @@
1
1
  <template>
2
2
  <div class="w-full lg:w-6 md:w-9" v-shared-element:form="{ duration: '300ms', includeChildren: true }">
3
3
  <div class="surface-card border-round shadow-2 p-4">
4
- <div class="text-900 font-medium mb-3 text-xl mb-4">Signed Up</div>
5
- <p class="mt-0 p-0 line-height-3">Congratulations! You have successfully created your account.</p>
4
+ <div class="text-center mb-5">
5
+ <div class="text-900 text-3xl font-medium mb-3">
6
+ Signed Up
7
+ </div>
8
+ </div>
9
+ <p class="mt-0 p-0 line-height-3">
10
+ Congratulations! You have successfully created your account.
11
+ <span v-if="!needPassword">
12
+ You can now set password to secure your account.
13
+ </span>
14
+ <p v-else>
15
+
16
+ Setup your <router-link to="{ name: 'user:identificatio' }">profile</router-link>
17
+ or return to the <router-link to="/">index page</router-link>.
18
+ </p>
19
+ </p>
6
20
  </div>
21
+
22
+ <div class="surface-card p-4 shadow-2 border-round mt-2" v-if="needPassword">
23
+ <div class="text-center mb-5">
24
+ <div class="text-900 text-3xl font-medium mb-3">
25
+ {{ passwordExists ? 'Change password' : 'Set password' }}
26
+ </div>
27
+ </div>
28
+
29
+ <command-form service="passwordAuthentication"
30
+ :action="passwordExists ? 'changePassword' : 'setPassword'"
31
+ v-slot="{ data }" ref="form" @done="handleDone">
32
+
33
+ <template v-if="isMounted">
34
+
35
+ <div class="p-field mb-3">
36
+ <label for="newPassword" class="block text-900 font-medium mb-2">New password</label>
37
+ <Password id="newPassword" class="w-full" inputClass="w-full"
38
+ toggleMask v-model:masked="masked"
39
+ :class="{ 'p-invalid': data.passwordHashError }"
40
+ v-model="data.passwordHash">
41
+ <template #footer>
42
+ <Divider />
43
+ <p class="p-mt-2">Suggestions</p>
44
+ <ul class="p-pl-2 p-ml-2 p-mt-0" style="line-height: 1.5">
45
+ <li>At least one lowercase</li>
46
+ <li>At least one uppercase</li>
47
+ <li>At least one numeric</li>
48
+ <li>Minimum 8 characters</li>
49
+ </ul>
50
+ </template>
51
+ </Password>
52
+ <small id="newPassword-help" class="p-error">{{ data.passwordHashError }}</small>
53
+ </div>
54
+
55
+ <div class="p-field mb-3">
56
+ <label for="reenterPassword" class="block text-900 font-medium mb-2">Re-enter password</label>
57
+ <Password id="reenterPassword" class="w-full" inputClass="w-full"
58
+ toggleMask v-model:masked="masked"
59
+ v-model="secondPassword"
60
+ :feedback="false" />
61
+ </div>
62
+
63
+ </template>
64
+
65
+ <Button :label="passwordExists ? 'Change password' : 'Set password'"
66
+ type="submit"
67
+ icon="pi pi-key" class="w-full"></Button>
68
+
69
+ </command-form>
70
+ </div>
71
+
72
+
7
73
  </div>
8
74
  </template>
9
75
 
10
76
  <script setup>
11
77
 
78
+ import InputText from "primevue/inputtext"
79
+ import Checkbox from "primevue/checkbox"
80
+ import Button from "primevue/button"
81
+ import Divider from "primevue/divider"
82
+ import Password from "../password/Password.vue"
83
+ import SettingsTabs from "../SettingsTabs.vue"
84
+
85
+ import { live, path } from '@live-change/vue3-ssr'
86
+ import { computed, ref, onMounted } from 'vue'
87
+
88
+ import { useRouter } from 'vue-router'
89
+ const router = useRouter()
90
+
91
+ const isMounted = ref(false)
92
+ onMounted(() => isMounted.value = true)
93
+
94
+ const secondPassword = ref('')
95
+ const form = ref()
96
+
97
+ const masked = ref(true)
98
+
99
+ onMounted(() => {
100
+ form.value.addValidator('passwordHash', () => {
101
+ const value = form.value.getFieldValue('passwordHash')
102
+ console.log("PASSWORDS MATCH?", secondPassword.value, value)
103
+ if(value != secondPassword.value) return "passwordsNotMatch"
104
+ })
105
+ })
106
+
107
+ const [passwordExists, emails] = await Promise.all([
108
+ live(path().passwordAuthentication.myUserPasswordAuthenticationExists()),
109
+ live(path().email.myUserEmails())
110
+ ])
111
+
112
+ const needPassword = computed(() => (!passwordExists.value && emails.value?.length > 0))
113
+
114
+ function handleDone({ parameters, result }) {
115
+ console.log("FORM DONE", parameters, result)
116
+ router.push({
117
+ name: 'user:changePasswordFinished',
118
+ })
119
+ }
120
+
12
121
  </script>
13
122
 
14
123
  <style>
@@ -6,12 +6,12 @@ export function routes(config = {}) {
6
6
  route({ name: 'user:signIn', path: prefix + 'sign-in',
7
7
  component: () => import("./SignIn.vue") }),
8
8
  route({ name: 'user:signInFinished', path: prefix + 'sign-in-finished',
9
- component: () => import("./SignInFinished.vue") }),
9
+ component: () => import("./SignInFinished.vue"), meta: { signedIn: true } }),
10
10
 
11
11
  route({ name: 'user:signUp', path: prefix + 'sign-up',
12
12
  component: () => import("./SignUp.vue") }),
13
13
  route({ name: 'user:signUpFinished', path: prefix + 'sign-up-finished',
14
- component: () => import("./SignUpFinished.vue") }),
14
+ component: () => import("./SignUpFinished.vue"), meta: { signedIn: true } }),
15
15
 
16
16
  route({ name: 'user:signOut', path: prefix + 'sign-out',
17
17
  component: () => import("./SignOut.vue") }),
package/index.js CHANGED
@@ -10,4 +10,7 @@ export { NotificationsIcon, SimpleNotification, notificationTypes }
10
10
  import UserIcon from "./front/src/nav/UserIcon.vue"
11
11
  export { UserIcon }
12
12
 
13
- export * from "./front/src/router.js"
13
+ import Password from "./front/src/password/Password.vue"
14
+ export { Password }
15
+
16
+ export * from "./front/src/router.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/user-frontend",
3
- "version": "0.3.23",
3
+ "version": "0.3.24",
4
4
  "scripts": {
5
5
  "memDev": "lcli memDev --enableSessions --initScript ./init.js --dbAccess",
6
6
  "localDevInit": "rm tmp.db; lcli localDev --enableSessions --initScript ./init.js",
@@ -20,27 +20,27 @@
20
20
  "debug": "node --inspect-brk server"
21
21
  },
22
22
  "dependencies": {
23
- "@live-change/cli": "0.7.38",
23
+ "@live-change/cli": "0.7.39",
24
24
  "@live-change/dao": "0.5.22",
25
25
  "@live-change/dao-vue3": "0.5.22",
26
26
  "@live-change/dao-websocket": "0.5.22",
27
- "@live-change/email-service": "0.3.40",
28
- "@live-change/framework": "0.7.38",
29
- "@live-change/identicon-service": "0.3.40",
30
- "@live-change/image-frontend": "^0.3.23",
31
- "@live-change/message-authentication-service": "0.3.40",
32
- "@live-change/notification-service": "0.3.40",
33
- "@live-change/password-authentication-service": "0.3.40",
27
+ "@live-change/email-service": "0.3.41",
28
+ "@live-change/framework": "0.7.39",
29
+ "@live-change/identicon-service": "0.3.41",
30
+ "@live-change/image-frontend": "^0.3.24",
31
+ "@live-change/message-authentication-service": "0.3.41",
32
+ "@live-change/notification-service": "0.3.41",
33
+ "@live-change/password-authentication-service": "0.3.41",
34
34
  "@live-change/pattern": "0.2.1",
35
- "@live-change/secret-code-service": "0.3.40",
36
- "@live-change/secret-link-service": "0.3.40",
37
- "@live-change/security-frontend": "^0.3.23",
38
- "@live-change/security-service": "0.3.40",
39
- "@live-change/session-service": "0.3.40",
40
- "@live-change/timer-service": "0.3.40",
41
- "@live-change/upload-service": "0.3.40",
42
- "@live-change/user-identification-service": "0.3.40",
43
- "@live-change/user-service": "0.3.40",
35
+ "@live-change/secret-code-service": "0.3.41",
36
+ "@live-change/secret-link-service": "0.3.41",
37
+ "@live-change/security-frontend": "^0.3.24",
38
+ "@live-change/security-service": "0.3.41",
39
+ "@live-change/session-service": "0.3.41",
40
+ "@live-change/timer-service": "0.3.41",
41
+ "@live-change/upload-service": "0.3.41",
42
+ "@live-change/user-identification-service": "0.3.41",
43
+ "@live-change/user-service": "0.3.41",
44
44
  "@live-change/vue3-components": "0.2.34",
45
45
  "@live-change/vue3-ssr": "0.2.34",
46
46
  "@vueuse/core": "^10.4.1",
@@ -66,7 +66,7 @@
66
66
  "wtfnode": "^0.9.1"
67
67
  },
68
68
  "devDependencies": {
69
- "@live-change/codeceptjs-helper": "0.7.38",
69
+ "@live-change/codeceptjs-helper": "0.7.39",
70
70
  "@wdio/selenium-standalone-service": "^8.15.0",
71
71
  "codeceptjs": "^3.5.4",
72
72
  "generate-password": "1.7.0",
@@ -78,5 +78,5 @@
78
78
  "author": "",
79
79
  "license": "BSD-3-Clause",
80
80
  "description": "",
81
- "gitHead": "98a7f97a7844c9f04cfe564e7c7d63a3cc8dce67"
81
+ "gitHead": "1dd8f7ad59e7e40c25cfde3fed2854bf295d069c"
82
82
  }