Skip to content

Commit 985a199

Browse files
committed
Merge branch 'develop' into feature-2795/toggle-pulse-report
2 parents a50dc16 + 988c2c9 commit 985a199

File tree

12 files changed

+127
-65
lines changed

12 files changed

+127
-65
lines changed

server/src/main/java/com/objectcomputing/checkins/services/pulseresponse/PulseResponse.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public class PulseResponse {
5252

5353
@Column(name="teammemberid")
5454
@TypeDef(type=DataType.STRING)
55-
@NotNull
55+
@Nullable
5656
@Schema(description = "id of the teamMember this entry is associated with")
5757
private UUID teamMemberId;
5858

@@ -77,7 +77,7 @@ public class PulseResponse {
7777
protected PulseResponse() {
7878
}
7979

80-
public PulseResponse(UUID id, Integer internalScore, Integer externalScore, LocalDate submissionDate, UUID teamMemberId, String internalFeelings, String externalFeelings) {
80+
public PulseResponse(UUID id, Integer internalScore, Integer externalScore, LocalDate submissionDate, @Nullable UUID teamMemberId, String internalFeelings, String externalFeelings) {
8181
this.id = id;
8282
this.internalScore = internalScore;
8383
this.externalScore = externalScore;
@@ -88,7 +88,7 @@ public PulseResponse(UUID id, Integer internalScore, Integer externalScore, Loca
8888
}
8989

9090
public PulseResponse(Integer internalScore, Integer externalScore, LocalDate submissionDate, UUID teamMemberId, String internalFeelings, String externalFeelings) {
91-
this(null,internalScore, externalScore, submissionDate, teamMemberId, internalFeelings, externalFeelings);
91+
this(null, internalScore, externalScore, submissionDate, teamMemberId, internalFeelings, externalFeelings);
9292
}
9393

9494
public UUID getId() {

server/src/main/java/com/objectcomputing/checkins/services/pulseresponse/PulseResponseCreateDTO.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public class PulseResponseCreateDTO {
2727
@Schema(description = "date for submissionDate")
2828
private LocalDate submissionDate;
2929

30-
@NotNull
30+
@Nullable
3131
@Schema(description = "id of the associated member")
3232
private UUID teamMemberId;
3333

server/src/main/java/com/objectcomputing/checkins/services/pulseresponse/PulseResponseServicesImpl.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,14 @@ public PulseResponse save(PulseResponse pulseResponse) {
5555
LocalDate pulseSubDate = pulseResponse.getSubmissionDate();
5656
if (pulseResponse.getId() != null) {
5757
throw new BadArgException(String.format("Found unexpected id for pulseresponse %s", pulseResponse.getId()));
58-
} else if (memberRepo.findById(memberId).isEmpty()) {
58+
} else if (memberId != null &&
59+
memberRepo.findById(memberId).isEmpty()) {
5960
throw new BadArgException(String.format("Member %s doesn't exists", memberId));
6061
} else if (pulseSubDate.isBefore(LocalDate.EPOCH) || pulseSubDate.isAfter(LocalDate.MAX)) {
6162
throw new BadArgException(String.format("Invalid date for pulseresponse submission date %s", memberId));
62-
} else if (!currentUserId.equals(memberId) && !isSubordinateTo(memberId, currentUserId)) {
63+
} else if (memberId != null &&
64+
!currentUserId.equals(memberId) &&
65+
!isSubordinateTo(memberId, currentUserId)) {
6366
throw new BadArgException(String.format("User %s does not have permission to create pulse response for user %s", currentUserId, memberId));
6467
}
6568
pulseResponseRet = pulseResponseRepo.save(pulseResponse);
@@ -94,7 +97,7 @@ public PulseResponse update(PulseResponse pulseResponse) {
9497
} else if (memberRepo.findById(memberId).isEmpty()) {
9598
throw new BadArgException(String.format("Member %s doesn't exist", memberId));
9699
} else if (memberId == null) {
97-
throw new BadArgException(String.format("Invalid pulseresponse %s", pulseResponse));
100+
throw new BadArgException("Cannot update anonymous pulse response");
98101
} else if (pulseSubDate.isBefore(LocalDate.EPOCH) || pulseSubDate.isAfter(LocalDate.MAX)) {
99102
throw new BadArgException(String.format("Invalid date for pulseresponse submission date %s", memberId));
100103
} else if (!currentUserId.equals(memberId) && !isSubordinateTo(memberId, currentUserId)) {
@@ -191,4 +194,4 @@ public void sendPulseLowScoreEmail(PulseResponse pulseResponse) {
191194
emailSender.sendEmail(null, null, subject, bodyBuilder.toString(), recipients.toArray(new String[0]));
192195
}
193196
}
194-
}
197+
}

server/src/test/java/com/objectcomputing/checkins/services/pulseresponse/PulseResponseControllerTest.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,12 @@ void testCreateAnInvalidPulseResponse() {
7676
JsonNode body = responseException.getResponse().getBody(JsonNode.class).orElse(null);
7777
JsonNode errors = Objects.requireNonNull(body).get("_embedded").get("errors");
7878
JsonNode href = Objects.requireNonNull(body).get("_links").get("self").get("href");
79-
List<String> errorList = Stream.of(errors.get(0).get("message").asText(), errors.get(1).get("message").asText(), errors.get(2).get("message").asText()).sorted().collect(Collectors.toList());
80-
assertEquals(3, errorList.size());
79+
List<String> errorList = Stream.of(
80+
errors.get(0).get("message").asText(),
81+
errors.get(1).get("message").asText()
82+
).sorted().collect(Collectors.toList());
83+
84+
assertEquals(2, errorList.size());
8185
assertEquals(request.getPath(), href.asText());
8286
assertEquals(HttpStatus.BAD_REQUEST, responseException.getStatus());
8387
}
@@ -523,4 +527,4 @@ private MemberProfile profile(String key) {
523527
private UUID id(String key) {
524528
return profile(key).getId();
525529
}
526-
}
530+
}

server/src/test/java/com/objectcomputing/checkins/services/pulseresponse/PulseResponseCreateDTOTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ void testConstraintViolation() {
3535
PulseResponseCreateDTO dto = new PulseResponseCreateDTO();
3636

3737
Set<ConstraintViolation<PulseResponseCreateDTO>> violations = validator.validate(dto);
38-
assertEquals(3, violations.size());
38+
assertEquals(2, violations.size());
3939
for (ConstraintViolation<PulseResponseCreateDTO> violation : violations) {
4040
assertEquals("must not be null", violation.getMessage());
4141
}

web-ui/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"fuse.js": "^6.4.6",
2929
"html-react-parser": "^5.1.12",
3030
"isomorphic-fetch": "^3.0.0",
31+
"js-cookie": "^3.0.5",
3132
"js-file-download": "^0.4.12",
3233
"lodash": "^4.17.21",
3334
"markdown-builder": "^0.9.0",

web-ui/src/components/member-directory/MemberModal.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ const MemberModal = ({ member, open, onSave, onClose }) => {
144144
});
145145
} else if (required && inputsFeasible) {
146146
onSave(editedMember).then(() => {
147-
if (isNewMember.current) {
147+
if (isNewMember) {
148148
setMember({ emptyMember });
149149
setIsNewMember(true);
150150
}

web-ui/src/pages/PulsePage.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,9 @@
1212
text-align: center;
1313
}
1414
}
15+
16+
.submit-row {
17+
align-items: center;
18+
display: flex;
19+
margin-top: 2rem; /* This is the default top margin for Buttons */
20+
}

web-ui/src/pages/PulsePage.jsx

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
import Cookies from 'js-cookie';
12
import { format } from 'date-fns';
23
import React, { useContext, useEffect, useState } from 'react';
34
import { useHistory } from 'react-router-dom';
4-
import { Button, Typography } from '@mui/material';
5-
import { resolve } from '../api/api.js';
5+
import { Button, Checkbox, Typography } from '@mui/material';
6+
import { downloadData, initiate } from '../api/generic.js';
67
import Pulse from '../components/pulse/Pulse.jsx';
78
import { AppContext } from '../context/AppContext';
89
import { selectCsrfToken, selectCurrentUser } from '../context/selectors';
@@ -15,17 +16,26 @@ const PulsePage = () => {
1516
const { state } = useContext(AppContext);
1617
const currentUser = selectCurrentUser(state);
1718
const csrf = selectCsrfToken(state);
18-
const history = useHistory();
1919

2020
const [externalComment, setExternalComment] = useState('');
2121
const [externalScore, setExternalScore] = useState(center);
2222
const [internalComment, setInternalComment] = useState('');
2323
const [internalScore, setInternalScore] = useState(center);
2424
const [pulse, setPulse] = useState(null);
2525
const [submittedToday, setSubmittedToday] = useState(false);
26+
const [submitAnonymously, setSubmitAnonymously] = useState(false);
27+
2628
const today = format(new Date(), 'yyyy-MM-dd');
29+
const cookieName = "pulse_submitted_anonymously";
30+
const pulseURL = '/services/pulse-responses';
2731

2832
useEffect(() => {
33+
const submitted = Cookies.get(cookieName);
34+
if (submitted) {
35+
setSubmittedToday(true);
36+
return;
37+
}
38+
2939
if (!pulse) return;
3040

3141
const now = new Date();
@@ -52,19 +62,8 @@ const PulsePage = () => {
5262
dateTo: today,
5363
teamMemberId: currentUser.id
5464
};
55-
const queryString = Object.entries(query)
56-
.map(([key, value]) => `${key}=${value}`)
57-
.join('&');
58-
59-
const res = await resolve({
60-
method: 'GET',
61-
url: `/services/pulse-responses?${queryString}`,
62-
headers: {
63-
'X-CSRF-Header': csrf,
64-
Accept: 'application/json',
65-
'Content-Type': 'application/json;charset=UTF-8'
66-
}
67-
});
65+
66+
const res = await downloadData(pulseURL, csrf, query);
6867
if (res.error) return;
6968

7069
// Sort pulse responses by date, latest to earliest
@@ -97,22 +96,15 @@ const PulsePage = () => {
9796
internalScore: internalScore + 1, // converts to 1-based
9897
submissionDate: today,
9998
updatedDate: today,
100-
teamMemberId: myId
99+
teamMemberId: submitAnonymously ? null : myId,
101100
};
102-
const res = await resolve({
103-
method: 'POST',
104-
url: '/services/pulse-responses',
105-
headers: {
106-
'X-CSRF-Header': csrf,
107-
Accept: 'application/json',
108-
'Content-Type': 'application/json;charset=UTF-8'
109-
},
110-
data
111-
});
101+
const res = await initiate(pulseURL, csrf, data);
112102
if (res.error) return;
113103

114-
// Refresh browser to show that pulses where already submitted today.
115-
history.go(0);
104+
setSubmittedToday(true);
105+
if (submitAnonymously) {
106+
Cookies.set(cookieName, 'true', { expires: 1 });
107+
}
116108
};
117109

118110
return (
@@ -141,9 +133,25 @@ const PulsePage = () => {
141133
setScore={setExternalScore}
142134
title="How are you feeling about life outside of work?"
143135
/>
144-
<Button onClick={submit} variant="contained">
145-
Submit
146-
</Button>
136+
<div className="submit-row">
137+
<Button
138+
style={{ marginTop: 0 }}
139+
onClick={submit}
140+
variant="contained">
141+
Submit
142+
</Button>
143+
<div style={{ padding: '.3rem' }}/>
144+
<label>
145+
<Checkbox
146+
disableRipple
147+
id="submit-anonymously"
148+
type="checkbox"
149+
checked={submitAnonymously}
150+
onChange={(event) => setSubmitAnonymously(event.target.checked)}
151+
/>
152+
Submit Anonymously
153+
</label>
154+
</div>
147155
</>
148156
)}
149157
</div>

web-ui/src/pages/PulseReportPage.jsx

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ const PulseReportPage = () => {
173173

174174
for (const pulse of pulses) {
175175
const memberId = pulse.teamMemberId;
176-
if (!teamMemberIds.includes(memberId)) continue;
176+
if (memberId && !teamMemberIds.includes(memberId)) continue;
177177

178178
const { externalScore, internalScore, submissionDate } = pulse;
179179
const [year, month, day] = submissionDate;
@@ -193,18 +193,21 @@ const PulseReportPage = () => {
193193
frequencies[internalScore - 1].internal++;
194194
frequencies[externalScore - 1].external++;
195195

196-
const member = memberMap[memberId];
197-
const { supervisorid } = member;
198-
const memberIdToUse = managerMode ? supervisorid : memberId;
199-
200-
/* For debugging ...
201-
if (supervisorid) {
202-
const supervisor = memberMap[supervisorid];
203-
console.log(`The supervisor of ${member.name} is ${supervisor.name}`);
204-
} else {
205-
console.log(`${member.name} has no supervisor`);
196+
let memberIdToUse;
197+
if (memberId) {
198+
const member = memberMap[memberId];
199+
const { supervisorid } = member;
200+
memberIdToUse = managerMode ? supervisorid : memberId;
201+
202+
/* For debugging ...
203+
if (supervisorid) {
204+
const supervisor = memberMap[supervisorid];
205+
console.log(`The supervisor of ${member.name} is ${supervisor.name}`);
206+
} else {
207+
console.log(`${member.name} has no supervisor`);
208+
}
209+
*/
206210
}
207-
*/
208211

209212
// When in manager mode, if the member
210213
// doesn't have a supervisor then skip this data.

0 commit comments

Comments
 (0)