@@ -17,8 +17,12 @@ import {
1717 DialogContentText ,
1818 DialogActions ,
1919 TextField ,
20+ Link ,
2021} from "@mui/material" ;
21- import { selectCsrfToken , selectProfile } from "../../context/selectors" ;
22+ import {
23+ selectCsrfToken ,
24+ selectActiveOrInactiveProfile ,
25+ } from "../../context/selectors" ;
2226import { AppContext } from "../../context/AppContext" ;
2327import { getAvatarURL } from "../../api/api" ;
2428import DateFnsUtils from "@date-io/date-fns" ;
@@ -49,7 +53,92 @@ const KudosCard = ({ kudos }) => {
4953 const { state, dispatch } = useContext ( AppContext ) ;
5054 const csrf = selectCsrfToken ( state ) ;
5155
52- const sender = selectProfile ( state , kudos . senderId ) ;
56+ const sender = selectActiveOrInactiveProfile ( state , kudos . senderId ) ;
57+
58+ const regexIndexOf = ( text , regex , start ) => {
59+ const indexInSuffix = text . slice ( start ) . search ( regex ) ;
60+ return indexInSuffix < 0 ? indexInSuffix : indexInSuffix + start ;
61+ } ;
62+
63+ const linkMember = ( member , name , message ) => {
64+ const components = [ ] ;
65+ let index = 0 ;
66+ do {
67+ index = regexIndexOf ( message ,
68+ new RegExp ( '\\b' + name + '\\b' , 'i' ) , index ) ;
69+ if ( index != - 1 ) {
70+ const link = < Link key = { `${ member . id } -${ index } ` }
71+ href = { `/profile/${ member . id } ` } >
72+ { name }
73+ </ Link > ;
74+ if ( index > 0 ) {
75+ components . push ( message . slice ( 0 , index ) ) ;
76+ }
77+ components . push ( link ) ;
78+ message = message . slice ( index + name . length ) ;
79+ }
80+ } while ( index != - 1 ) ;
81+ components . push ( message ) ;
82+ return components ;
83+ } ;
84+
85+ const searchNames = ( member , members ) => {
86+ const names = [ ] ;
87+ if ( member . middleName ) {
88+ names . push ( `${ member . firstName } ${ member . middleName } ${ member . lastName } ` ) ;
89+ }
90+ const firstAndLast = `${ member . firstName } ${ member . lastName } ` ;
91+ if ( ! members . some ( ( k ) => k . id != member . id &&
92+ firstAndLast != `${ k . firstName } ${ k . lastName } ` ) ) {
93+ names . push ( firstAndLast ) ;
94+ }
95+ if ( ! members . some ( ( k ) => k . id != member . id &&
96+ ( member . lastName == k . lastName ||
97+ member . lastName == k . firstName ) ) ) {
98+ // If there are no other recipients with a name that contains this
99+ // member's last name, we can replace based on that.
100+ names . push ( member . lastName ) ;
101+ }
102+ if ( ! members . some ( ( k ) => k . id != member . id &&
103+ ( member . firstName == k . lastName ||
104+ member . firstName == k . firstName ) ) ) {
105+ // If there are no other recipients with a name that contains this
106+ // member's first name, we can replace based on that.
107+ names . push ( member . firstName ) ;
108+ }
109+ return names ;
110+ } ;
111+
112+ const linkNames = ( kudos ) => {
113+ const components = [ kudos . message ] ;
114+ for ( let member of kudos . recipientMembers ) {
115+ const names = searchNames ( member , kudos . recipientMembers ) ;
116+ for ( let name of names ) {
117+ for ( let i = 0 ; i < components . length ; i ++ ) {
118+ const component = components [ i ] ;
119+ if ( typeof ( component ) === "string" ) {
120+ const built = linkMember ( member , name , component ) ;
121+ if ( built . length > 1 ) {
122+ components . splice ( i , 1 , ...built ) ;
123+ }
124+ }
125+ }
126+ }
127+ }
128+ return components ;
129+ } ;
130+
131+ const multiTooltip = ( num , list ) => {
132+ let tooltip = "" ;
133+ let prefix = "" ;
134+ for ( let member of list . slice ( - num ) ) {
135+ tooltip += prefix + `${ member . firstName } ${ member . lastName } ` ;
136+ prefix = ", " ;
137+ }
138+ return < Tooltip arrow title = { tooltip } >
139+ < Typography > { `+${ num } ` } </ Typography >
140+ </ Tooltip > ;
141+ } ;
53142
54143 const getRecipientComponent = useCallback ( ( ) => {
55144 if ( kudos . recipientTeam ) {
@@ -67,7 +156,9 @@ const KudosCard = ({ kudos }) => {
67156 }
68157
69158 return (
70- < AvatarGroup max = { 4 } >
159+ < AvatarGroup max = { 4 }
160+ renderSurplus = { ( extra ) => multiTooltip (
161+ extra , kudos . recipientMembers ) } >
71162 { kudos . recipientMembers . map ( ( member ) => (
72163 < Tooltip
73164 arrow
@@ -98,9 +189,13 @@ const KudosCard = ({ kudos }) => {
98189 subheaderTypographyProps = { { variant :"subtitle1" } }
99190 />
100191 < CardContent >
101- < Typography variant = "body1" > < em > { kudos . message } </ em > </ Typography >
192+ < Typography variant = "body1" >
193+ { linkNames ( kudos ) }
194+ </ Typography >
102195 { kudos . recipientTeam && (
103- < AvatarGroup max = { 12 } >
196+ < AvatarGroup max = { 12 }
197+ renderSurplus = { ( extra ) => multiTooltip (
198+ extra , kudos . recipientMembers ) } >
104199 { kudos . recipientMembers . map ( ( member ) => (
105200 < Tooltip
106201 arrow
0 commit comments