Skip to content

Commit b377feb

Browse files
committed
MP-39 wrap up change username&password section
1 parent e2412eb commit b377feb

File tree

18 files changed

+276
-47
lines changed

18 files changed

+276
-47
lines changed

src/apps/accounts/src/settings/tabs/AccountSettingsTabs.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Dispatch, FC, SetStateAction, useMemo, useState } from 'react'
22
import { useLocation } from 'react-router-dom'
33

4-
import { UserProfile } from '~/libs/core'
4+
import { useMemberTraits, UserProfile, UserTraits } from '~/libs/core'
55
import { TabsNavbar } from '~/libs/ui'
66

77
import { AccountSettingsTabsConfig, AccountSettingsTabViews, getHashFromTabId, getTabIdFromHash } from './config'
@@ -22,6 +22,8 @@ const AccountSettingsTabs: FC<AccountSettingsTabsProps> = (props: AccountSetting
2222
const [activeTab, setActiveTab]: [string, Dispatch<SetStateAction<string>>]
2323
= useState<string>(activeTabHash)
2424

25+
const memberTraits: UserTraits[] | undefined = useMemberTraits(props.profile.handle)
26+
2527
function handleTabChange(tabId: string): void {
2628
setActiveTab(tabId)
2729
window.location.hash = getHashFromTabId(tabId)
@@ -36,7 +38,7 @@ const AccountSettingsTabs: FC<AccountSettingsTabsProps> = (props: AccountSetting
3638
/>
3739

3840
{activeTab === AccountSettingsTabViews.account && (
39-
<AccountTab profile={props.profile} />
41+
<AccountTab profile={props.profile} memberTraits={memberTraits} />
4042
)}
4143

4244
{activeTab === AccountSettingsTabViews.preferences && (

src/apps/accounts/src/settings/tabs/account/AccountTab.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { FC } from 'react'
22

3-
import { UserProfile } from '~/libs/core'
3+
import { UserProfile, UserTraits } from '~/libs/core'
44

55
import { AccountRole } from './account-role'
66
import { SecuritySection } from './security'
@@ -9,6 +9,7 @@ import styles from './AccountTab.module.scss'
99

1010
interface AccountTabProps {
1111
profile: UserProfile
12+
memberTraits: UserTraits[] | undefined
1213
}
1314

1415
const AccountTab: FC<AccountTabProps> = (props: AccountTabProps) => (
@@ -17,7 +18,7 @@ const AccountTab: FC<AccountTabProps> = (props: AccountTabProps) => (
1718

1819
<AccountRole profile={props.profile} />
1920

20-
<UserAndPassword profile={props.profile} />
21+
<UserAndPassword profile={props.profile} memberTraits={props.memberTraits} />
2122

2223
<SecuritySection profile={props.profile} />
2324
</div>

src/apps/accounts/src/settings/tabs/account/user-and-pass/UserAndPassword.tsx

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
1-
/* eslint-disable no-console */
2-
import { Dispatch, FC, useCallback, useState } from 'react'
1+
import { Dispatch, FC, useCallback, useEffect, useMemo, useState } from 'react'
2+
import { has, trim } from 'lodash'
3+
import { toast } from 'react-toastify'
34

4-
import { Collapsible, Form, FormInputModel, FormToggleSwitch } from '~/libs/ui'
5-
import { UserProfile } from '~/libs/core'
5+
import {
6+
Collapsible,
7+
Form,
8+
FormInputModel,
9+
FormToggleSwitch,
10+
} from '~/libs/ui'
11+
import { updateMemberPasswordAsync, updateMemberTraitsAsync, UserProfile, UserTrait, UserTraits } from '~/libs/core'
612
import { SettingSection } from '~/apps/accounts/src/lib'
713

814
import { UserAndPassFromConfig } from './user-and-pass.form.config'
915
import styles from './UserAndPassword.module.scss'
1016

1117
interface UserAndPasswordProps {
1218
profile: UserProfile
19+
memberTraits: UserTraits[] | undefined
1320
}
1421

1522
const UserAndPassword: FC<UserAndPasswordProps> = (props: UserAndPasswordProps) => {
@@ -18,32 +25,82 @@ const UserAndPassword: FC<UserAndPasswordProps> = (props: UserAndPasswordProps)
1825
handle: props.profile.handle,
1926
})
2027

28+
const personalizationTrait: UserTraits | undefined = useMemo(
29+
() => props.memberTraits?.find((trait: UserTraits) => trait.traitId === 'personalization'),
30+
[props.memberTraits],
31+
)
32+
2133
const [userConsent, setUserConsent]: [boolean, Dispatch<boolean>] = useState(false)
2234

2335
const requestGenerator: (inputs: ReadonlyArray<FormInputModel>) => any
2436
= useCallback((inputs: ReadonlyArray<FormInputModel>) => {
25-
console.log('inputs', inputs)
26-
return {}
27-
}, [])
37+
const currentPassword: any = inputs[2]
38+
const newPassword: any = inputs[3]
39+
40+
return {
41+
currentPassword: currentPassword.value,
42+
newPassword: newPassword.value,
43+
userId: props.profile.userId,
44+
}
45+
}, [props.profile.userId])
2846

29-
async function onSave(val: any): Promise<void> {
30-
console.log('onSave', val)
47+
useEffect(() => {
48+
if (personalizationTrait) {
49+
setUserConsent(
50+
!!personalizationTrait?.traits.data.find(
51+
(trait: UserTrait) => has(trait, 'userConsent') && trait.userConsent === true,
52+
),
53+
)
54+
}
55+
}, [personalizationTrait])
56+
57+
async function onSave(request: any): Promise<void> {
58+
await updateMemberPasswordAsync(request.userId, request.currentPassword, request.newPassword)
3159
}
3260

33-
function handleUserConsentChange(event: any): void {
34-
console.log('handleUserConsentChange', event)
35-
setUserConsent(!userConsent)
61+
function handleUserConsentChange(): void {
62+
updateMemberTraitsAsync(props.profile.handle, [{
63+
categoryName: 'Personalization',
64+
traitId: 'personalization',
65+
traits: {
66+
data: [{
67+
userConsent: !userConsent,
68+
}],
69+
},
70+
}])
71+
.then(() => {
72+
setUserConsent(!userConsent)
73+
toast.success('User consent updated successfully.')
74+
})
75+
.catch(() => {
76+
toast.error('Failed to update user consent.')
77+
})
3678
}
3779

3880
function shouldDisableChangePasswordButton(): boolean {
3981
// pass reset form validation
40-
console.log('formValues', formValues)
82+
const specialChars: any = /[`!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?~]/
83+
const currentPassword: any = formValues[2]
84+
const newPassword: any = formValues[3]
85+
const reTypeNewPassword: any = formValues[4]
86+
87+
if (
88+
trim(currentPassword?.value)
89+
&& trim(newPassword?.value)
90+
&& newPassword.value?.length >= 8
91+
&& (
92+
/\d/.test(newPassword?.value) || specialChars.test(newPassword?.value)
93+
)
94+
&& newPassword?.value !== currentPassword?.value
95+
&& trim(reTypeNewPassword?.value)
96+
&& newPassword?.value === reTypeNewPassword?.value) {
97+
return false
98+
}
4199

42100
return true
43101
}
44102

45103
function setChangePasswordFormValues(val: any): void {
46-
console.log('setChangePasswordFormValues', val)
47104
setFormValues({
48105
...formValues,
49106
...val,
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
@import '@libs/ui/styles/includes';
2+
3+
.container {
4+
display: flex;
5+
flex-direction: column;
6+
align-items: flex-start;
7+
8+
.infoText {
9+
margin-bottom: $sp-3;
10+
font-size: 14px;
11+
font-weight: $font-weight-bold;
12+
}
13+
14+
.tip {
15+
font-size: 14px;
16+
}
17+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { FC } from 'react'
2+
3+
import styles from './PasswordTips.module.scss'
4+
5+
type PasswordTip = { text: string, valid: boolean }
6+
7+
interface PasswordTipsProps {
8+
infoText: string
9+
tips: Array<PasswordTip>
10+
}
11+
12+
const PasswordTips: FC<PasswordTipsProps> = (props: PasswordTipsProps) => (
13+
<div className={styles.container}>
14+
<p className={styles.infoText}>{props.infoText}</p>
15+
{
16+
props.tips.map((tip: PasswordTip) => (
17+
<p className={styles.tip}>{tip.text}</p>
18+
))
19+
}
20+
</div>
21+
)
22+
23+
export default PasswordTips

src/apps/accounts/src/settings/tabs/account/user-and-pass/user-and-pass.form.config.ts renamed to src/apps/accounts/src/settings/tabs/account/user-and-pass/user-and-pass.form.config.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { noop } from 'lodash'
22

33
import { FormDefinition, validatorRequired } from '~/libs/ui'
44

5+
import PasswordTips from './password-tips'
6+
57
export const UserAndPassFromConfig: FormDefinition = {
68
buttons: {
79
primaryGroup: [],
@@ -46,6 +48,19 @@ export const UserAndPassFromConfig: FormDefinition = {
4648
label: 'New Password',
4749
name: 'newPassword',
4850
placeholder: 'Type your new password',
51+
tooltip: {
52+
className: 'passTooltip',
53+
content: <PasswordTips
54+
infoText='Your password must have:'
55+
tips={[
56+
{ text: 'At least 8 characters', valid: true },
57+
{ text: 'At least one letter', valid: true },
58+
{ text: 'At least one number or symbol', valid: true },
59+
{ text: 'Should not be the same as old password', valid: true },
60+
]}
61+
/>,
62+
place: 'bottom',
63+
},
4964
type: 'password',
5065
validators: [
5166
{
@@ -58,6 +73,16 @@ export const UserAndPassFromConfig: FormDefinition = {
5873
label: 'Re-Type New Password',
5974
name: 'reTypeNewPassword',
6075
placeholder: 'Re-Type New password',
76+
tooltip: {
77+
className: 'passTooltip',
78+
content: <PasswordTips
79+
infoText='Your Re-typed password must:'
80+
tips={[
81+
{ text: 'Match the new password entered', valid: true },
82+
]}
83+
/>,
84+
place: 'bottom',
85+
},
6186
type: 'password',
6287
validators: [
6388
{

src/apps/profiles/src/member-profile/tc-activity/ModalTriggerButton/ModalTriggerButton.module.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,9 @@
44
border: 1px solid $black-10;
55
padding: $sp-1 $sp-4 !important;
66
margin-left: $sp-2;
7+
8+
svg {
9+
width: 24px;
10+
height: 24px;
11+
}
712
}

src/libs/core/lib/profile/data-providers/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ export * from './useStatsDistribution'
88
export * from './useMemberEmailPreferences'
99
export * from './useMemberMFAStatus'
1010
export * from './useDiceIdConnection'
11+
export * from './useMemberTraits'
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import useSWR, { SWRResponse } from 'swr'
2+
3+
import { getProfileUrl } from '../profile-functions'
4+
import { UserTraits } from '../user-traits.model'
5+
6+
export function useMemberTraits(handle?: string): UserTraits[] | undefined {
7+
const { data }: SWRResponse = useSWR(handle ? `${getProfileUrl(handle)}/traits` : undefined)
8+
9+
return data
10+
}

src/libs/core/lib/profile/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ export * from './modify-user-role.model'
1212
export * from './user-email-preference.model'
1313
export * from './modify-user-email-preferences.model'
1414
export * from './modify-user-mfa.model'
15+
export * from './user-traits.model'

0 commit comments

Comments
 (0)