Skip to content

Commit eea4d92

Browse files
committed
feat: add getMappedUserProfileValue utility for improved user profile attribute mapping
1 parent 3e1d3c9 commit eea4d92

File tree

3 files changed

+59
-41
lines changed

3 files changed

+59
-41
lines changed

packages/react/src/components/presentation/UserDropdown/BaseUserDropdown.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import clsx from 'clsx';
2222
import {useTheme} from '../../../theme/useTheme';
2323
import {Avatar} from '../../primitives/Avatar/Avatar';
2424
import {Popover} from '../../primitives/Popover/Popover';
25+
import getMappedUserProfileValue from '../../../utils/getMappedUserProfileValue';
2526

2627
const useStyles = () => {
2728
const {theme} = useTheme();
@@ -148,11 +149,11 @@ export interface BaseUserDropdownProps {
148149
* Allows customizing which user profile fields should be used for each attribute.
149150
*/
150151
attributeMapping?: {
151-
picture?: string;
152-
firstName?: string;
153-
lastName?: string;
154-
username?: string;
155-
[key: string]: string | undefined;
152+
picture?: string | string[];
153+
firstName?: string | string[];
154+
lastName?: string | string[];
155+
username?: string | string[];
156+
[key: string]: string | string[] | undefined;
156157
};
157158
}
158159

@@ -176,7 +177,7 @@ export const BaseUserDropdown: FC<BaseUserDropdownProps> = ({
176177
const [isOpen, setIsOpen] = useState(false);
177178

178179
const defaultAttributeMappings = {
179-
picture: 'profile',
180+
picture: ['profile', 'profileUrl'],
180181
firstName: 'givenName',
181182
lastName: 'familyName',
182183
};
@@ -218,7 +219,7 @@ export const BaseUserDropdown: FC<BaseUserDropdownProps> = ({
218219
onClick={() => setIsOpen(!isOpen)}
219220
>
220221
<Avatar
221-
imageUrl={getMappedValue('picture')}
222+
imageUrl={getMappedUserProfileValue('picture', mergedMappings, user)}
222223
name={getDisplayName()}
223224
size={avatarSize}
224225
alt={`${getDisplayName()}'s avatar`}
@@ -232,7 +233,7 @@ export const BaseUserDropdown: FC<BaseUserDropdownProps> = ({
232233
{showDropdownHeader && (
233234
<div className={withVendorCSSClassPrefix('user-dropdown-header')} style={styles.dropdownHeader}>
234235
<Avatar
235-
imageUrl={getMappedValue('picture')}
236+
imageUrl={getMappedUserProfileValue('picture', mergedMappings, user)}
236237
name={getDisplayName()}
237238
size={avatarSize * 1.25}
238239
alt={`${getDisplayName()}'s avatar`}

packages/react/src/components/presentation/UserProfile/BaseUserProfile.tsx

Lines changed: 5 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {Avatar} from '../../primitives/Avatar/Avatar';
2525
import {useTheme} from '../../../theme/useTheme';
2626
import {withVendorCSSClassPrefix} from '@asgardeo/browser';
2727
import clsx from 'clsx';
28+
import getMappedUserProfileValue from '../../../utils/getMappedUserProfileValue';
2829

2930
interface Schema {
3031
caseExact?: boolean;
@@ -212,44 +213,15 @@ export const BaseUserProfile: FC<BaseUserProfileProps> = ({
212213

213214
const mergedMappings = {...defaultAttributeMappings, ...attributeMapping};
214215

215-
const getMappedValue = (key: string) => {
216-
const mappedKey = mergedMappings[key];
217-
218-
if (Array.isArray(user)) {
219-
// If user is an array, find the first matching schema attribute
220-
if (Array.isArray(mappedKey)) {
221-
// Try each possible field name in order
222-
for (const field of mappedKey) {
223-
const found = user.find(u => u.name === field);
224-
if (found?.value !== undefined) {
225-
return found.value;
226-
}
227-
}
228-
} else {
229-
// Look for single mapped key
230-
const found = user.find(u => u.name === mappedKey);
231-
if (found?.value !== undefined) {
232-
return found.value;
233-
}
234-
}
235-
// Fallback to original key if no mapped fields exist
236-
const found = user.find(u => u.name === key);
237-
return found?.value;
238-
}
239-
240-
// For single user object, return the mapped key or original key
241-
return mappedKey ? user[mappedKey] : user[key];
242-
};
243-
244216
const getDisplayName = () => {
245-
const firstName = getMappedValue('firstName');
246-
const lastName = getMappedValue('lastName');
217+
const firstName = getMappedUserProfileValue('firstName', mergedMappings, user);
218+
const lastName = getMappedUserProfileValue('lastName', mergedMappings, user);
247219

248220
if (firstName && lastName) {
249221
return `${firstName} ${lastName}`;
250222
}
251223

252-
return getMappedValue('username') || '';
224+
return getMappedUserProfileValue('username', mergedMappings, user) || '';
253225
};
254226

255227
if (!user) {
@@ -356,7 +328,7 @@ export const BaseUserProfile: FC<BaseUserProfileProps> = ({
356328
<div style={containerStyle} className={clsx(withVendorCSSClassPrefix('user-profile'), className)}>
357329
<div style={styles.header}>
358330
<Avatar
359-
imageUrl={getMappedValue('picture')}
331+
imageUrl={getMappedUserProfileValue('picture', mergedMappings, user)}
360332
name={getDisplayName()}
361333
size={80}
362334
alt={`${getDisplayName()}'s avatar`}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
3+
*
4+
* WSO2 LLC. licenses this file to you under the Apache License,
5+
* Version 2.0 (the "License"); you may not use this file except
6+
* in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing,
12+
* software distributed under the License is distributed on an
13+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
* KIND, either express or implied. See the License for the
15+
* specific language governing permissions and limitations
16+
* under the License.
17+
*/
18+
19+
const getMappedUserProfileValue = (key: string, mappings, user) => {
20+
const mappedKey = mappings[key];
21+
22+
if (Array.isArray(user)) {
23+
if (Array.isArray(mappedKey)) {
24+
for (const field of mappedKey) {
25+
const found = user.find(u => u.name === field);
26+
if (found?.value !== undefined) {
27+
return found.value;
28+
}
29+
}
30+
} else {
31+
const found = user.find(u => u.name === mappedKey);
32+
if (found?.value !== undefined) {
33+
return found.value;
34+
}
35+
}
36+
37+
const found = user.find(u => u.name === key);
38+
39+
return found?.value;
40+
}
41+
42+
return mappedKey ? user[mappedKey] : user[key];
43+
};
44+
45+
export default getMappedUserProfileValue;

0 commit comments

Comments
 (0)