diff --git a/packages/common/src/core/types/IHubCardViewModel.ts b/packages/common/src/core/types/IHubCardViewModel.ts index 7bd235ab44b..1245373da4b 100644 --- a/packages/common/src/core/types/IHubCardViewModel.ts +++ b/packages/common/src/core/types/IHubCardViewModel.ts @@ -23,8 +23,19 @@ export interface IHubCardViewModel { export interface IBadgeConfig { i18nKey?: string; label?: string; + /** + * whether the label or translated i18nKey + * should actually render or just be used + * for a11y purposes. By default, the label + * IS rendered + */ + hideLabel?: boolean; icon?: string; color: string; + tooltip?: { + i18nKey?: string; + label?: string; + }; } // structure defining the additional info for a hub card @@ -40,6 +51,11 @@ export interface ICardActionLink { href?: string; i18nKey?: string; label?: string; + /** + * whether the label or translated i18nKey + * should actually render or just be used + * for a11y purposes + */ showLabel?: boolean; icon?: string; buttonStyle?: "outline" | "outline-fill" | "solid" | "transparent"; diff --git a/packages/common/src/search/_internal/portalSearchGroupMembers.ts b/packages/common/src/search/_internal/portalSearchGroupMembers.ts index 2a05e58c364..d86bfd6abab 100644 --- a/packages/common/src/search/_internal/portalSearchGroupMembers.ts +++ b/packages/common/src/search/_internal/portalSearchGroupMembers.ts @@ -133,7 +133,7 @@ async function searchGroupMembers( // over the includes and requestOptions const fn = (member: IGroupMember) => { return memberToSearchResult( - member, + { ...member, isGroupOwner: resp.owner.username === member.username }, searchOptions.include, searchOptions.requestOptions ); @@ -179,7 +179,7 @@ interface IGroupMember { * @returns */ async function memberToSearchResult( - member: IGroupMember, + member: IGroupMember & { isGroupOwner: boolean }, include: string[] = [], requestOptions?: IHubRequestOptions ): Promise { @@ -199,6 +199,7 @@ async function memberToSearchResult( thumbnail: null, created: null, modified: null, + isGroupOwner: member.isGroupOwner, }; const fsGetUser = failSafe(getUser, user); diff --git a/packages/common/src/users/HubUsers.ts b/packages/common/src/users/HubUsers.ts index 51f46d67ad6..d941da796ef 100644 --- a/packages/common/src/users/HubUsers.ts +++ b/packages/common/src/users/HubUsers.ts @@ -26,6 +26,13 @@ export async function enrichUserSearchResult( access: user.access as AccessLevel, id: user.username, type: "User", + /** + * We need to return a valid IHubSearchResult, so we store + * IUser information where it makes the most sense - e.g. + * we store the user's full name under the "name" property, + * and since users don't have an owner, we fill that property + * with the user's username + */ name: user.fullName, owner: user.username, // A private user will not have a description prop at all @@ -42,9 +49,10 @@ export async function enrichUserSearchResult( thumbnail: null, }, }; - // Group Memberships need this prop + // Group Memberships need these additional properties if (user.memberType) { result.memberType = user.memberType; + result.isGroupOwner = user.isGroupOwner; } // Informal Enrichments - basically adding type-specific props diff --git a/packages/common/src/users/view.ts b/packages/common/src/users/view.ts index 3b2aebc89c2..df32e72cc31 100644 --- a/packages/common/src/users/view.ts +++ b/packages/common/src/users/view.ts @@ -1,6 +1,7 @@ import { IHubSearchResult } from ".."; import { ResultToCardModelFn } from "../core"; import { + IBadgeConfig, IConvertToCardModelOpts, IHubCardViewModel, } from "../core/types/IHubCardViewModel"; @@ -44,9 +45,45 @@ export const userResultToCardModel: ResultToCardModelFn = ( * @param locale internationalization locale */ const getSharedUserCardModel = (user: IHubSearchResult): IHubCardViewModel => { + const badges = [] as IBadgeConfig[]; + const memberType = user.memberType; + + /** + * for group members, we want to configure + * member type badges to render in the user + * card + */ + if (memberType) { + if (user.isGroupOwner) { + badges.push({ + icon: "user-key", + color: "gray", + i18nKey: "badges.members.owner", + hideLabel: true, + tooltip: { i18nKey: "badges.members.owner" }, + }); + } else if (memberType === "admin") { + badges.push({ + icon: "user-up", + color: "gray", + i18nKey: "badges.members.admin", + hideLabel: true, + tooltip: { i18nKey: "badges.members.admin" }, + }); + } else { + badges.push({ + icon: "user", + color: "gray", + i18nKey: "badges.members.member", + hideLabel: true, + tooltip: { i18nKey: "badges.members.member" }, + }); + } + } + return { access: user.access, - badges: [], + badges, family: user.family, id: user.id, source: user.name ? `@${user.id}` : undefined, diff --git a/packages/common/test/users/view.test.ts b/packages/common/test/users/view.test.ts index 6e9764d042e..cdc72a0d81c 100644 --- a/packages/common/test/users/view.test.ts +++ b/packages/common/test/users/view.test.ts @@ -58,5 +58,56 @@ describe("user view module:", () => { expect(result.title).toBe(`@${USER_HUB_SEARCH_RESULT.owner}`); expect(result.source).toBeFalsy(); }); + describe("membership badges", () => { + it("adds an owner badge if the user is the group owner", () => { + const GROUP_MEMBER_RESULT = cloneObject(USER_HUB_SEARCH_RESULT); + GROUP_MEMBER_RESULT.isGroupOwner = true; + GROUP_MEMBER_RESULT.memberType = "admin"; + + const result = userResultToCardModel(GROUP_MEMBER_RESULT); + + expect(result.badges).toEqual([ + { + icon: "user-key", + color: "gray", + i18nKey: "badges.members.owner", + hideLabel: true, + tooltip: { i18nKey: "badges.members.owner" }, + }, + ]); + }); + it("adds an amin badge if the user is a group admin", () => { + const GROUP_MEMBER_RESULT = cloneObject(USER_HUB_SEARCH_RESULT); + GROUP_MEMBER_RESULT.memberType = "admin"; + + const result = userResultToCardModel(GROUP_MEMBER_RESULT); + + expect(result.badges).toEqual([ + { + icon: "user-up", + color: "gray", + i18nKey: "badges.members.admin", + hideLabel: true, + tooltip: { i18nKey: "badges.members.admin" }, + }, + ]); + }); + it("adds a member badge if the user is a group member", () => { + const GROUP_MEMBER_RESULT = cloneObject(USER_HUB_SEARCH_RESULT); + GROUP_MEMBER_RESULT.memberType = "member"; + + const result = userResultToCardModel(GROUP_MEMBER_RESULT); + + expect(result.badges).toEqual([ + { + icon: "user", + color: "gray", + i18nKey: "badges.members.member", + hideLabel: true, + tooltip: { i18nKey: "badges.members.member" }, + }, + ]); + }); + }); }); });