Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 77 additions & 1 deletion web-ui/src/components/kudos/PublicKudosCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
DialogContentText,
DialogActions,
TextField,
Link,
} from "@mui/material";
import { selectCsrfToken, selectProfile } from "../../context/selectors";
import { AppContext } from "../../context/AppContext";
Expand Down Expand Up @@ -51,6 +52,79 @@ const KudosCard = ({ kudos }) => {

const sender = selectProfile(state, kudos.senderId);

const regexIndexOf = (text, regex, start) => {
const indexInSuffix = text.slice(start).search(regex);
return indexInSuffix < 0 ? indexInSuffix : indexInSuffix + start;
};

const linkMember = (member, name, message) => {
const components = [];
let index = 0;
do {
index = regexIndexOf(message,
new RegExp('\\b' + name + '\\b', 'i'), index);
if (index != -1) {
const link = <Link key={`${member.id}-${index}`}
href={`/profile/${member.id}`}>
{name}
</Link>;
if (index > 0) {
components.push(message.slice(0, index));
}
components.push(link);
message = message.slice(index + name.length);
}
} while(index != -1);
components.push(message);
return components;
};

const searchNames = (member, members) => {
const names = [];
if (member.middleName) {
names.push(`${member.firstName} ${member.middleName} ${member.lastName}`);
}
const firstAndLast = `${member.firstName} ${member.lastName}`;
if (!members.some((k) => k.id != member.id &&
firstAndLast != `${k.firstName} ${k.lastName}`)) {
names.push(firstAndLast);
}
if (!members.some((k) => k.id != member.id &&
(member.lastName == k.lastName ||
member.lastName == k.firstName))) {
// If there are no other recipients with a name that contains this
// member's last name, we can replace based on that.
names.push(member.lastName);
}
if (!members.some((k) => k.id != member.id &&
(member.firstName == k.lastName ||
member.firstName == k.firstName))) {
// If there are no other recipients with a name that contains this
// member's first name, we can replace based on that.
names.push(member.firstName);
}
return names;
};

const linkNames = (kudos) => {
const components = [ kudos.message ];
for (let member of kudos.recipientMembers) {
const names = searchNames(member, kudos.recipientMembers);
for (let name of names) {
for (let i = 0; i < components.length; i++) {
const component = components[i];
if (typeof(component) === "string") {
const built = linkMember(member, name, component);
if (built.length > 1) {
components.splice(i, 1, ...built);
}
}
}
}
}
return components;
};

const multiTooltip = (num, list) => {
let tooltip = "";
let prefix = "";
Expand Down Expand Up @@ -112,7 +186,9 @@ const KudosCard = ({ kudos }) => {
subheaderTypographyProps={{variant:"subtitle1"}}
/>
<CardContent>
<Typography variant="body1"><em>{kudos.message}</em></Typography>
<Typography variant="body1">
{linkNames(kudos)}
</Typography>
{kudos.recipientTeam && (
<AvatarGroup max={12}
renderSurplus={(extra) => multiTooltip(
Expand Down
117 changes: 117 additions & 0 deletions web-ui/src/components/kudos/PublicKudosCard.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import React from 'react';
import PublicKudosCard from './PublicKudosCard';
import { AppContextProvider } from '../../context/AppContext';

const initialState = {
state: {
csrf: 'O_3eLX2-e05qpS_yOeg1ZVAs9nDhspEi',
teams: [],
userProfile: {
id: "1",
firstName: 'Jimmy',
lastName: 'Johnson',
role: ['MEMBER'],
},
memberProfiles: [
{
id: "1",
firstName: 'Jimmy',
lastName: 'Johnson',
role: ['MEMBER'],
},
{
id: "2",
firstName: 'Jimmy',
lastName: 'Olsen',
role: ['MEMBER'],
},
{
id: "3",
firstName: 'Clark',
lastName: 'Kent',
role: ['MEMBER'],
},
{
id: "4",
firstName: 'Kent',
lastName: 'Brockman',
role: ['MEMBER'],
},
{
id: "5",
firstName: 'Jerry',
lastName: 'Garcia',
role: ['MEMBER'],
},
{
id: "6",
firstName: 'Brock',
lastName: 'Smith',
role: ['MEMBER'],
},
{
id: "7",
firstName: 'Jimmy',
middleName: 'T.',
lastName: 'Olsen',
role: ['MEMBER'],
},
],
}
};

const kudos = {
id: 'test-kudos',
message: "Brock and Brockman did a great job helping Clark, Jimmy Olsen, Jimmy T. Olsen, and Johnson",
senderId: "5",
dateCreated: [ 2025, 2, 14 ],
recipientMembers: [
{
id: "1",
firstName: 'Jimmy',
lastName: 'Johnson',
role: ['MEMBER'],
},
{
id: "2",
firstName: 'Jimmy',
lastName: 'Olsen',
role: ['MEMBER'],
},
{
id: "3",
firstName: 'Clark',
lastName: 'Kent',
role: ['MEMBER'],
},
{
id: "6",
firstName: 'Brock',
lastName: 'Smith',
role: ['MEMBER'],
},
{
id: "4",
firstName: 'Kent',
lastName: 'Brockman',
role: ['MEMBER'],
},
{
id: "7",
firstName: 'Jimmy',
middleName: 'T.',
lastName: 'Olsen',
role: ['MEMBER'],
},
],
};

it('renders correctly', () => {
snapshot(
<AppContextProvider value={initialState}>
<PublicKudosCard
kudos={kudos}
/>
</AppContextProvider>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`renders correctly 1`] = `
<div>
<div
class="MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation1 MuiCard-root kudos-card css-bhp9pd-MuiPaper-root-MuiCard-root"
>
<div
class="MuiCardHeader-root css-185gdzj-MuiCardHeader-root"
>
<div
class="MuiCardHeader-avatar css-1ssile9-MuiCardHeader-avatar"
>
<div
class="MuiAvatarGroup-root css-1ytufz-MuiAvatarGroup-root"
>
<div
class="MuiAvatar-root MuiAvatar-circular MuiAvatar-colorDefault MuiAvatarGroup-avatar css-17o22dy-MuiAvatar-root"
>
<p
aria-label="Brock Smith, Kent Brockman, Jimmy Olsen"
class="MuiTypography-root MuiTypography-body1 css-ahj2mt-MuiTypography-root"
data-mui-internal-clone-element="true"
>
+3
</p>
</div>
<div
aria-label="Clark Kent"
class="MuiAvatar-root MuiAvatar-circular MuiAvatarGroup-avatar css-1wlk0hk-MuiAvatar-root"
data-mui-internal-clone-element="true"
>
<img
class="MuiAvatar-img css-1pqm26d-MuiAvatar-img"
src="http://localhost:8080/services/member-profiles/member-photos/undefined"
/>
</div>
<div
aria-label="Jimmy Olsen"
class="MuiAvatar-root MuiAvatar-circular MuiAvatarGroup-avatar css-1wlk0hk-MuiAvatar-root"
data-mui-internal-clone-element="true"
>
<img
class="MuiAvatar-img css-1pqm26d-MuiAvatar-img"
src="http://localhost:8080/services/member-profiles/member-photos/undefined"
/>
</div>
<div
aria-label="Jimmy Johnson"
class="MuiAvatar-root MuiAvatar-circular MuiAvatarGroup-avatar css-1wlk0hk-MuiAvatar-root"
data-mui-internal-clone-element="true"
>
<img
class="MuiAvatar-img css-1pqm26d-MuiAvatar-img"
src="http://localhost:8080/services/member-profiles/member-photos/undefined"
/>
</div>
</div>
</div>
<div
class="MuiCardHeader-content css-1qbkelo-MuiCardHeader-content"
>
<span
class="MuiTypography-root MuiTypography-h5 MuiCardHeader-title css-1qvr50w-MuiTypography-root"
>
Kudos!
</span>
<span
class="MuiTypography-root MuiTypography-subtitle1 MuiCardHeader-subheader css-1s216c8-MuiTypography-root"
>
from
<div
class="MuiChip-root MuiChip-filled MuiChip-sizeSmall MuiChip-colorDefault MuiChip-filledDefault css-13htn8f-MuiChip-root"
>
<div
class="MuiAvatar-root MuiAvatar-circular MuiChip-avatar MuiChip-avatarSmall MuiChip-avatarColorDefault css-1wlk0hk-MuiAvatar-root"
>
<img
class="MuiAvatar-img css-1pqm26d-MuiAvatar-img"
src="http://localhost:8080/services/member-profiles/member-photos/undefined"
/>
</div>
<span
class="MuiChip-label MuiChip-labelSmall css-wjsjww-MuiChip-label"
/>
</div>
</span>
</div>
</div>
<div
class="MuiCardContent-root css-46bh2p-MuiCardContent-root"
>
<p
class="MuiTypography-root MuiTypography-body1 css-ahj2mt-MuiTypography-root"
>
<a
class="MuiTypography-root MuiTypography-inherit MuiLink-root MuiLink-underlineAlways css-1xylxj1-MuiTypography-root-MuiLink-root"
href="/profile/6"
>
Brock
</a>
and
<a
class="MuiTypography-root MuiTypography-inherit MuiLink-root MuiLink-underlineAlways css-1xylxj1-MuiTypography-root-MuiLink-root"
href="/profile/4"
>
Brockman
</a>
did a great job helping
<a
class="MuiTypography-root MuiTypography-inherit MuiLink-root MuiLink-underlineAlways css-1xylxj1-MuiTypography-root-MuiLink-root"
href="/profile/3"
>
Clark
</a>
, Jimmy Olsen,
<a
class="MuiTypography-root MuiTypography-inherit MuiLink-root MuiLink-underlineAlways css-1xylxj1-MuiTypography-root-MuiLink-root"
href="/profile/7"
>
Jimmy T. Olsen
</a>
, and
<a
class="MuiTypography-root MuiTypography-inherit MuiLink-root MuiLink-underlineAlways css-1xylxj1-MuiTypography-root-MuiLink-root"
href="/profile/1"
>
Johnson
</a>
</p>
</div>
</div>
</div>
`;
Loading