Skip to content

Commit 5f07db4

Browse files
committed
2024-10-31 - external-recip jsx
1 parent 6ddafa2 commit 5f07db4

File tree

7 files changed

+423
-90
lines changed

7 files changed

+423
-90
lines changed

web-ui/src/api/feedback.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const feedbackSuggestionURL = '/services/feedback/suggestions';
55
const feedbackRequestURL = '/services/feedback/requests';
66
const answerURL = '/services/feedback/answers';
77
const questionAndAnswerURL = '/services/feedback/questions-and-answers';
8+
const feedbackExternalRecipientsURL = '/services/feedback/external/recipients';
89

910
export const findReviewRequestsByPeriodAndTeamMembers = async (
1011
period,
@@ -291,3 +292,10 @@ export const getFeedbackRequestsByRequestees = async (
291292
headers: { 'X-CSRF-Header': cookie, Accept: 'application/json' }
292293
});
293294
};
295+
296+
export const getExternalRecipients = async (cookie) => {
297+
return resolve({
298+
url: `${feedbackExternalRecipientsURL}/findAll`,
299+
headers: { 'X-CSRF-Header': cookie, Accept: 'application/json' }
300+
});
301+
};
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
.member-card {
2+
max-height: 20rem;
3+
width: 325px;
4+
display: flex;
5+
flex-direction: column;
6+
justify-content: space-between;
7+
cursor: pointer;
8+
margin: 0 2em 2em 0;
9+
}
10+
11+
.member-card .member-summary-avatar {
12+
height: 5rem;
13+
width: 5rem;
14+
margin-right: 1.25rem;
15+
}
16+
17+
.member-summary-parent {
18+
display: flex;
19+
align-items: center;
20+
}
21+
22+
.member-card .large {
23+
width: theme-spacing(10);
24+
height: theme-spacing(10);
25+
}
26+
27+
.member-card .info-container {
28+
padding: 0;
29+
}
30+
31+
.member-card .split-button {
32+
padding: 1rem;
33+
}
34+
35+
.member-card .MuiCardHeader-content h2 {
36+
overflow: hidden;
37+
text-overflow: ellipsis;
38+
white-space: nowrap;
39+
width: 225px;
40+
}
41+
42+
.member-card .MuiCardHeader-content h3 {
43+
overflow: hidden;
44+
text-overflow: ellipsis;
45+
white-space: nowrap;
46+
width: 225px;
47+
}
48+
49+
.reason {
50+
display: flex;
51+
flex-direction: column;
52+
align-items: center;
53+
justify-content: center;
54+
width: 100%;
55+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import React, { useContext } from 'react';
2+
import { styled } from '@mui/material/styles';
3+
import { AppContext } from '../../context/AppContext.jsx';
4+
import { selectProfileMap } from '../../context/selectors.js';
5+
import { getAvatarURL } from '../../api/api.js';
6+
import { Box, Card, CardHeader, CardContent, Container, Typography } from '@mui/material';
7+
import Avatar from '@mui/material/Avatar';
8+
import PriorityHighIcon from '@mui/icons-material/PriorityHigh';
9+
import { green } from '@mui/material/colors';
10+
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
11+
import Divider from '@mui/material/Divider';
12+
13+
import './FeedbackExternalRecipientCard.css';
14+
15+
const PREFIX = 'FeedbackExternalRecipientCard';
16+
const classes = {
17+
root: `${PREFIX}-root`,
18+
header: `${PREFIX}-header`,
19+
cardContent: `${PREFIX}-cardContent`,
20+
divider: `${PREFIX}-divider`,
21+
recommendationText: `${PREFIX}-recommendationText`
22+
};
23+
24+
const StyledBox = styled(Box)({
25+
[`&.${classes.root}`]: {
26+
// currently defined but not used
27+
minWidth: '10em',
28+
maxWidth: '20em',
29+
marginRight: '2em',
30+
marginBottom: '2em',
31+
cursor: 'pointer',
32+
'@media (max-width:767px)': {
33+
marginTop: '1em',
34+
height: '40%',
35+
width: '80%'
36+
}
37+
},
38+
[`& .${classes.header}`]: {
39+
cursor: 'pointer'
40+
},
41+
[`& .${classes.cardContent}`]: {
42+
// currently defined but not used
43+
display: 'flex',
44+
alignItems: 'center',
45+
alignContent: 'center',
46+
flexDirection: 'column',
47+
justifyContent: 'center',
48+
textAlign: 'center'
49+
},
50+
[`& .${classes.divider}`]: {
51+
backgroundColor: 'grey',
52+
width: '90%',
53+
marginBottom: '1em',
54+
marginTop: '1em'
55+
},
56+
[`& .${classes.recommendationText}`]: {
57+
color: '#333333'
58+
}
59+
});
60+
61+
const FeedbackExternalRecipientCard = ({
62+
recipientProfile,
63+
selected,
64+
reason = null,
65+
onClick
66+
}) => {
67+
const { state } = useContext(AppContext);
68+
const supervisorProfile = selectProfileMap(state)[recipientProfile?.supervisorid];
69+
const pdlProfile = selectProfileMap(state)[recipientProfile?.pdlId];
70+
71+
return (
72+
<StyledBox display="flex" flexWrap="wrap">
73+
<Card onClick={onClick} className="member-card" selected={selected}>
74+
<CardHeader
75+
className={classes.header}
76+
title={
77+
<Typography variant="h5" component="h2">
78+
{recipientProfile?.firstName} {recipientProfile?.lastName}
79+
</Typography>
80+
}
81+
action={
82+
selected ? (
83+
<CheckCircleIcon style={{ color: green[500] }}>
84+
checkmark-image
85+
</CheckCircleIcon>
86+
) : null
87+
}
88+
subheader={
89+
<Typography color="textSecondary" component="h3">
90+
{recipientProfile?.title}
91+
</Typography>
92+
}
93+
disableTypography
94+
avatar={
95+
!recipientProfile?.terminationDate ? (
96+
<Avatar
97+
className="large"
98+
src={getAvatarURL(recipientProfile?.email)}
99+
/>
100+
) : (
101+
<Avatar className="large">
102+
<PriorityHighIcon />
103+
</Avatar>
104+
)
105+
}
106+
/>
107+
<CardContent>
108+
<Container fixed className="info-container">
109+
<Typography variant="body2" color="textSecondary" component="p">
110+
<a
111+
href={`mailto:${recipientProfile?.email}`}
112+
target="_blank"
113+
rel="noopener noreferrer"
114+
>
115+
{recipientProfile?.email}
116+
</a>
117+
<br />
118+
Location: {recipientProfile?.location}
119+
<br />
120+
Supervisor: {supervisorProfile?.name}
121+
<br />
122+
PDL: {pdlProfile?.name}
123+
<br />
124+
</Typography>
125+
{reason && (
126+
<div className="reason">
127+
<Divider variant="middle" className={classes.divider} />
128+
<Typography
129+
id="rec_reason"
130+
name="rec_reason"
131+
component="p"
132+
className={classes.recommendationText}
133+
>
134+
{reason}
135+
</Typography>
136+
</div>
137+
)}
138+
</Container>
139+
</CardContent>
140+
</Card>
141+
</StyledBox>
142+
);
143+
};
144+
145+
export default FeedbackExternalRecipientCard;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import FeedbackExternalRecipientCard from './FeedbackExternalRecipientCard.jsx';
2+
import React, { useContext, useEffect } from 'react';
3+
import { AppContext, AppContextProvider } from '../../context/AppContext.jsx';
4+
import { UPDATE_MEMBER_PROFILES } from '../../context/actions.js';
5+
6+
export default {
7+
title: 'FeedbackReqs/FeedbackExternalRecipientCard',
8+
component: FeedbackExternalRecipientCard,
9+
decorators: [
10+
Story => {
11+
return (
12+
<AppContextProvider>
13+
<Story />
14+
</AppContextProvider>
15+
);
16+
}
17+
]
18+
};
19+
20+
const profile = {
21+
id: '12342345678',
22+
pdlID: 123,
23+
workEmail: '[email protected]',
24+
name: 'Bob Jones',
25+
title: 'Software Engineer'
26+
};
27+
28+
const SetProfiles = ({ profiles }) => {
29+
const { dispatch } = useContext(AppContext);
30+
useEffect(() => {
31+
dispatch({ type: UPDATE_MEMBER_PROFILES, payload: profiles });
32+
}, [profiles, dispatch]);
33+
return '';
34+
};
35+
36+
const Template = args => (
37+
<React.Fragment>
38+
<SetProfiles profiles={args.profiles} />
39+
<FeedbackExternalRecipientCard {...args} />
40+
</React.Fragment>
41+
);
42+
43+
export const DefaultUser = Template.bind({});
44+
DefaultUser.args = {
45+
profileId: profile.id,
46+
reason: 'Recommended for being a local opossum',
47+
profiles: [profile]
48+
};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import React from 'react';
2+
import FeedbackExternalRecipientCard from './FeedbackExternalRecipientCard.jsx';
3+
import { AppContextProvider } from '../../context/AppContext.jsx';
4+
import { BrowserRouter } from 'react-router-dom';
5+
6+
it('renders the recipient card', () => {
7+
snapshot(
8+
<AppContextProvider>
9+
<BrowserRouter>
10+
<FeedbackExternalRecipientCard />
11+
</BrowserRouter>
12+
</AppContextProvider>
13+
);
14+
});
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`renders the recipient card 1`] = `
4+
<div>
5+
<div
6+
class="MuiBox-root css-aznsb2"
7+
>
8+
<div
9+
class="MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation1 MuiCard-root member-card css-bhp9pd-MuiPaper-root-MuiCard-root"
10+
>
11+
<div
12+
class="MuiCardHeader-root FeedbackExternalRecipientCard-header css-185gdzj-MuiCardHeader-root"
13+
>
14+
<div
15+
class="MuiCardHeader-avatar css-1ssile9-MuiCardHeader-avatar"
16+
>
17+
<div
18+
class="MuiAvatar-root MuiAvatar-circular large css-1wlk0hk-MuiAvatar-root"
19+
>
20+
<img
21+
class="MuiAvatar-img css-1pqm26d-MuiAvatar-img"
22+
src="http://localhost:8080/services/member-profiles/member-photos/undefined"
23+
/>
24+
</div>
25+
</div>
26+
<div
27+
class="MuiCardHeader-content css-1qbkelo-MuiCardHeader-content"
28+
>
29+
<h2
30+
class="MuiTypography-root MuiTypography-h5 css-ag7rrr-MuiTypography-root"
31+
/>
32+
<h3
33+
class="MuiTypography-root MuiTypography-body1 css-1pnmrwp-MuiTypography-root"
34+
/>
35+
</div>
36+
</div>
37+
<div
38+
class="MuiCardContent-root css-46bh2p-MuiCardContent-root"
39+
>
40+
<div
41+
class="MuiContainer-root MuiContainer-maxWidthLg MuiContainer-fixed info-container css-1ss2ei0-MuiContainer-root"
42+
>
43+
<p
44+
class="MuiTypography-root MuiTypography-body2 css-r40f8v-MuiTypography-root"
45+
>
46+
<a
47+
href="mailto:undefined"
48+
rel="noopener noreferrer"
49+
target="_blank"
50+
/>
51+
<br />
52+
Location:
53+
<br />
54+
Supervisor:
55+
<br />
56+
PDL:
57+
<br />
58+
</p>
59+
</div>
60+
</div>
61+
</div>
62+
</div>
63+
</div>
64+
`;

0 commit comments

Comments
 (0)