@isoftdata/svelte-user-configuration 2.0.4 → 2.1.0

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,127 +1,127 @@
1
- <script lang="ts">
2
- import type { i18n } from 'i18next'
3
- import type { UserAccount, PasswordValidationRules } from './'
4
-
5
- import { klona } from 'klona'
6
- import { tick, getContext } from 'svelte'
7
- import Input from '@isoftdata/svelte-input'
8
- import Modal from '@isoftdata/svelte-modal'
9
- import PasswordFields from '@isoftdata/svelte-password-fields'
10
- import { translate as defaultTranslate } from '@isoftdata/utility-string'
11
-
12
- let show: boolean = $state(false)
13
- let currentPassword: string = $state('')
14
- let newPassword: string = $state('')
15
- let confirmPassword: string = $state('')
16
- let lastResetDate: Date | null | undefined = $state(undefined)
17
- let currentPasswordInput: HTMLInputElement | undefined = $state(undefined)
18
- let newPasswordInput: HTMLInputElement | undefined = $state(undefined)
19
- let passwordRecoveryEmail: string | null | undefined = $state(undefined)
20
- let passwordIsValid: boolean = $state(false)
21
-
22
- interface Props {
23
- validationRules?: PasswordValidationRules | undefined
24
- changePasswordMode?: boolean
25
- confirmPasswordSet: (ctx: { currentPassword: string; newPassword: string }) => void | Promise<void>
26
- }
27
-
28
- let { validationRules = undefined, changePasswordMode = false, confirmPasswordSet }: Props = $props()
29
- export async function open(userAccount?: UserAccount) {
30
- currentPassword = ''
31
- newPassword = ''
32
- confirmPassword = ''
33
- lastResetDate = klona(userAccount?.lastPasswordResetDate) // Don't mutate the given Date obj
34
- passwordRecoveryEmail = userAccount?.recoveryEmail
35
- show = true
36
- await tick()
37
-
38
- if (changePasswordMode) {
39
- currentPasswordInput?.focus()
40
- } else {
41
- newPasswordInput?.focus()
42
- }
43
- }
44
-
45
- const { t: translate } = getContext<i18n>('i18next') || { t: defaultTranslate }
46
-
47
- // The passwordMismatch prop from the PasswordFields component only updates on:change,
48
- // but we want the component consumer to be able to update their save button disabled state in real time
49
- let passwordMismatch: boolean = $derived(!(newPassword && confirmPassword && newPassword === confirmPassword))
50
- let disablePasswordChange: boolean = $derived(
51
- (changePasswordMode && !currentPassword) ||
52
- passwordMismatch ||
53
- !newPassword ||
54
- !confirmPassword ||
55
- !passwordIsValid,
56
- )
57
- </script>
58
-
59
- <Modal
60
- bind:show
61
- title={changePasswordMode
62
- ? translate('configuration.user.changePassword', 'Change Password')
63
- : translate('configuration.user.setPassword', 'Set Password')}
64
- confirmButtonText={changePasswordMode
65
- ? translate('configuration.user.changePassword', 'Change Password')
66
- : translate('configuration.user.setPassword', 'Set Password')}
67
- confirmButtonIcon="check"
68
- confirmButtonDisabled={disablePasswordChange}
69
- close={() => (show = false)}
70
- confirmButtonType="submit"
71
- confirmButtonFormId="setPasswordForm"
72
- >
73
- <form
74
- id="setPasswordForm"
75
- onsubmit={async e => {
76
- e.preventDefault()
77
- if (!disablePasswordChange) {
78
- await confirmPasswordSet({ currentPassword, newPassword })
79
- show = false
80
- }
81
- }}
82
- >
83
- <Input
84
- label={translate(
85
- 'configuration.user.accountInfo.passwordManagementModal.lastPasswordSetDate',
86
- 'Last Password Set Date',
87
- )}
88
- tabindex={-1}
89
- value={lastResetDate ? lastResetDate.toLocaleString() : ''}
90
- labelParentClass="form-group mb-0"
91
- readonly
92
- />
93
- {#if changePasswordMode}
94
- <Input
95
- bind:input={currentPasswordInput}
96
- label={translate('configuration.user.accountInfo.passwordManagementModal.currentPassword', 'Current Password')}
97
- type="password"
98
- bind:value={currentPassword}
99
- autocomplete="current-password"
100
- required
101
- class={!currentPassword ? 'is-invalid' : ''}
102
- />
103
- <hr />
104
- {/if}
105
- <PasswordFields
106
- bind:password={newPassword}
107
- bind:confirmPassword
108
- bind:passwordInput={newPasswordInput}
109
- bind:passwordIsValid
110
- columnClass="col-12"
111
- {validationRules}
112
- passwordLabel={translate('configuration.user.accountInfo.passwordManagementModal.newPassword', 'New Password')}
113
- confirmPasswordLabel={translate(
114
- 'configuration.user.accountInfo.passwordManagementModal.confirmNewPassword',
115
- 'Confirm New Password',
116
- )}
117
- />
118
- {#if !passwordRecoveryEmail}
119
- <div class="alert alert-danger mt-3 mb-0">
120
- {translate(
121
- 'configuration.user.accountInfo.passwordRecovery.noRecoveryEmail',
122
- 'No recovery email has been set for this user.',
123
- )}
124
- </div>
125
- {/if}
126
- </form>
127
- </Modal>
1
+ <script lang="ts">
2
+ import type { i18n } from 'i18next'
3
+ import type { UserAccount, PasswordValidationRules } from './'
4
+
5
+ import { klona } from 'klona'
6
+ import { tick, getContext } from 'svelte'
7
+ import Input from '@isoftdata/svelte-input'
8
+ import Modal from '@isoftdata/svelte-modal'
9
+ import PasswordFields from '@isoftdata/svelte-password-fields'
10
+ import { translate as defaultTranslate } from '@isoftdata/utility-string'
11
+
12
+ let show: boolean = $state(false)
13
+ let currentPassword: string = $state('')
14
+ let newPassword: string = $state('')
15
+ let confirmPassword: string = $state('')
16
+ let lastResetDate: Date | null | undefined = $state(undefined)
17
+ let currentPasswordInput: HTMLInputElement | undefined = $state(undefined)
18
+ let newPasswordInput: HTMLInputElement | undefined = $state(undefined)
19
+ let passwordRecoveryEmail: string | null | undefined = $state(undefined)
20
+ let passwordIsValid: boolean = $state(false)
21
+
22
+ interface Props {
23
+ validationRules?: PasswordValidationRules | undefined
24
+ changePasswordMode?: boolean
25
+ confirmPasswordSet: (ctx: { currentPassword: string; newPassword: string }) => void | Promise<void>
26
+ }
27
+
28
+ let { validationRules = undefined, changePasswordMode = false, confirmPasswordSet }: Props = $props()
29
+ export async function open(userAccount?: UserAccount) {
30
+ currentPassword = ''
31
+ newPassword = ''
32
+ confirmPassword = ''
33
+ lastResetDate = klona(userAccount?.lastPasswordResetDate) // Don't mutate the given Date obj
34
+ passwordRecoveryEmail = userAccount?.recoveryEmail
35
+ show = true
36
+ await tick()
37
+
38
+ if (changePasswordMode) {
39
+ currentPasswordInput?.focus()
40
+ } else {
41
+ newPasswordInput?.focus()
42
+ }
43
+ }
44
+
45
+ const { t: translate } = getContext<i18n>('i18next') || { t: defaultTranslate }
46
+
47
+ // The passwordMismatch prop from the PasswordFields component only updates on:change,
48
+ // but we want the component consumer to be able to update their save button disabled state in real time
49
+ let passwordMismatch: boolean = $derived(!(newPassword && confirmPassword && newPassword === confirmPassword))
50
+ let disablePasswordChange: boolean = $derived(
51
+ (changePasswordMode && !currentPassword) ||
52
+ passwordMismatch ||
53
+ !newPassword ||
54
+ !confirmPassword ||
55
+ !passwordIsValid,
56
+ )
57
+ </script>
58
+
59
+ <Modal
60
+ bind:show
61
+ title={changePasswordMode
62
+ ? translate('configuration.user.changePassword', 'Change Password')
63
+ : translate('configuration.user.setPassword', 'Set Password')}
64
+ confirmButtonText={changePasswordMode
65
+ ? translate('configuration.user.changePassword', 'Change Password')
66
+ : translate('configuration.user.setPassword', 'Set Password')}
67
+ confirmButtonIcon="check"
68
+ confirmButtonDisabled={disablePasswordChange}
69
+ close={() => (show = false)}
70
+ confirmButtonType="submit"
71
+ confirmButtonFormId="setPasswordForm"
72
+ >
73
+ <form
74
+ id="setPasswordForm"
75
+ onsubmit={async e => {
76
+ e.preventDefault()
77
+ if (!disablePasswordChange) {
78
+ await confirmPasswordSet({ currentPassword, newPassword })
79
+ show = false
80
+ }
81
+ }}
82
+ >
83
+ <Input
84
+ label={translate(
85
+ 'configuration.user.accountInfo.passwordManagementModal.lastPasswordSetDate',
86
+ 'Last Password Set Date',
87
+ )}
88
+ tabindex={-1}
89
+ value={lastResetDate ? lastResetDate.toLocaleString() : ''}
90
+ labelParentClass="form-group mb-0"
91
+ readonly
92
+ />
93
+ {#if changePasswordMode}
94
+ <Input
95
+ bind:input={currentPasswordInput}
96
+ label={translate('configuration.user.accountInfo.passwordManagementModal.currentPassword', 'Current Password')}
97
+ type="password"
98
+ bind:value={currentPassword}
99
+ autocomplete="current-password"
100
+ required
101
+ class={!currentPassword ? 'is-invalid' : ''}
102
+ />
103
+ <hr />
104
+ {/if}
105
+ <PasswordFields
106
+ bind:password={newPassword}
107
+ bind:confirmPassword
108
+ bind:passwordInput={newPasswordInput}
109
+ bind:passwordIsValid
110
+ columnClass="col-12"
111
+ {validationRules}
112
+ passwordLabel={translate('configuration.user.accountInfo.passwordManagementModal.newPassword', 'New Password')}
113
+ confirmPasswordLabel={translate(
114
+ 'configuration.user.accountInfo.passwordManagementModal.confirmNewPassword',
115
+ 'Confirm New Password',
116
+ )}
117
+ />
118
+ {#if !passwordRecoveryEmail}
119
+ <div class="alert alert-danger mt-3 mb-0">
120
+ {translate(
121
+ 'configuration.user.accountInfo.passwordRecovery.noRecoveryEmail',
122
+ 'No recovery email has been set for this user.',
123
+ )}
124
+ </div>
125
+ {/if}
126
+ </form>
127
+ </Modal>