Skip to content

Commit e2c1385

Browse files
authored
Merge pull request #34 from AtilaU19/task-2431
feat: capture feedback rating on page leave or unload
2 parents 308f1f5 + fc6424e commit e2c1385

File tree

4 files changed

+47
-25
lines changed

4 files changed

+47
-25
lines changed

backend/server.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ redisClient.on('error', (err) => logger.error('Redis Client Error', err));
4141

4242
await redisClient.connect();
4343

44+
app.use(bodyParser.text({ type: 'application/json' }));
4445
app.use(bodyParser.json());
4546
app.use(bodyParser.urlencoded({ extended: true }));
4647

@@ -197,6 +198,7 @@ app.post('/feedback/webhook', async (req, res) => {
197198
const userData = {
198199
name: user.name,
199200
id: user['internal-user-id'],
201+
external_id: user['external-user-id'],
200202
role: user.role,
201203
};
202204

@@ -233,7 +235,23 @@ app.post('/feedback/webhook', async (req, res) => {
233235
});
234236

235237
app.post('/feedback/submit', async (req, res) => {
236-
const { session, user, feedback, device, rating } = req.body;
238+
let body = req.body;
239+
if (typeof req.body === 'string') {
240+
try {
241+
body = JSON.parse(req.body);
242+
} catch (e) {
243+
logger.error('Error parsing feedback body:', e);
244+
return res.status(400).send();
245+
}
246+
}
247+
248+
const { session, user, feedback, device, rating } = body;
249+
250+
if (!session || !user) {
251+
logger.warn('Received feedback submission with missing session or user.', body);
252+
return res.status(400).json({ status: 'error', message: 'Missing session or user information' });
253+
}
254+
237255
try {
238256
const feedbackKey = `${KEY_PREFIX}:${session.sessionId}:${user.userId}`;
239257
const existingFeedback = await redisClient.get(feedbackKey);
@@ -243,7 +261,7 @@ app.post('/feedback/submit', async (req, res) => {
243261
// User redirect URL takes precedence over session redirect URL
244262
const redirectUrl = userData.redirect_url || sessionData.redirect_url;
245263

246-
const isFeedbackEmpty = Object.keys(feedback).length === 0 && !rating;
264+
const isFeedbackEmpty = (!feedback || Object.keys(feedback).length === 0) && (rating === undefined || rating === null);
247265
const essentialData = {
248266
session: { redirect_url: redirectUrl },
249267
}
@@ -259,7 +277,7 @@ app.post('/feedback/submit', async (req, res) => {
259277
return res.status(400).json({ status: 'error', message: 'Feedback already submitted' });
260278
}
261279

262-
logger.info(`Submitting feedback for userID: ${userData.id} meetingID: ${sessionData.session_id}`);
280+
logger.info(`Submitting feedback for userID: ${userData.id || user.userId} meetingID: ${sessionData.session_id || session.sessionId}`);
263281

264282
const completeFeedback = {
265283
rating,
@@ -274,6 +292,7 @@ app.post('/feedback/submit', async (req, res) => {
274292
user: {
275293
name: userData.name,
276294
id: userData.id,
295+
external_id: userData.external_id,
277296
role: userData.role,
278297
email: user.email
279298
},
@@ -283,7 +302,7 @@ app.post('/feedback/submit', async (req, res) => {
283302
const cleanFeedback = JSON.parse(JSON.stringify(completeFeedback, (key, value) => value === undefined ? undefined : value));
284303
const logLevel = logger.level;
285304

286-
if (cleanFeedback.rating) {
305+
if (cleanFeedback.rating !== undefined && cleanFeedback.rating !== null) {
287306
console.log(`${new Date().toISOString()} custom-feedback [${logLevel}] : CUSTOM FEEDBACK LOG: ${JSON.stringify(cleanFeedback)}`);
288307
} else {
289308
return logger.info(`Not logging feedback without rating`);

frontend/src/components/FeedbackFlow/FeedbackFlow.jsx

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -78,25 +78,24 @@ const FeedbackFlow = ({ intl }) => {
7878
}
7979
}, []);
8080

81-
const handleNext = (nextStep, data) => {
82-
const updatedFeedback = () => {
83-
let updatedFeedback = { ...feedback.current };
84-
85-
if (data.hasOwnProperty('rating')) {
86-
updatedFeedback = { ...updatedFeedback, rating: data.rating };
87-
} else if (data.hasOwnProperty('email')) {
88-
updatedFeedback.user.email = data.email;
89-
} else {
90-
updatedFeedback.feedback = { ...updatedFeedback.feedback, ...data };
91-
}
92-
93-
sessionStorage.setItem('feedbackData', JSON.stringify(updatedFeedback));
81+
const updateFeedback = (data) => {
82+
let updatedFeedbackData = { ...feedback.current };
83+
84+
if (data.hasOwnProperty('rating')) {
85+
updatedFeedbackData = { ...updatedFeedbackData, rating: data.rating };
86+
} else if (data.hasOwnProperty('email')) {
87+
updatedFeedbackData.user.email = data.email;
88+
} else {
89+
updatedFeedbackData.feedback = { ...updatedFeedbackData.feedback, ...data };
90+
}
9491

95-
return updatedFeedback;
96-
};
92+
feedback.current = updatedFeedbackData;
93+
sessionStorage.setItem('feedbackData', JSON.stringify(updatedFeedbackData));
94+
};
95+
96+
const handleNext = (nextStep, data) => {
97+
updateFeedback(data);
9798

98-
feedback.current = updatedFeedback();
99-
10099
if (!nextStep) {
101100
submitFeedback(feedback.current);
102101
}
@@ -111,7 +110,7 @@ const FeedbackFlow = ({ intl }) => {
111110

112111
switch (currentStep) {
113112
case 'rating':
114-
return <RatingStep onNext={handleNext} />;
113+
return <RatingStep onNext={handleNext} onUpdate={updateFeedback} />;
115114
case 'problem':
116115
case 'audioProblem':
117116
case 'cameraProblem':

frontend/src/components/RatingStep/RatingStep.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,18 @@ const messages = defineMessages({
1919
}
2020
});
2121

22-
const RatingStep = ({ onNext, intl }) => {
22+
const RatingStep = ({ onNext, onUpdate, intl }) => {
2323
const [rating, setRating] = useState(null);
2424
const [hover, setHover] = useState(null);
2525

2626
const handleRatingChange = (value) => {
2727
setRating(value);
28+
onUpdate({ rating: value });
2829
};
2930

3031
const handleLeave = () => {
31-
onNext(null, { });
32+
const data = rating ? { rating } : {};
33+
onNext(null, data);
3234
};
3335

3436
const nextStep = () => {

frontend/src/components/service.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ export const getRedirectTimeout = () => {
6565
export const handleBeforeUnload = async () => {
6666
const savedFeedback = sessionStorage.getItem('feedbackData');
6767
if (savedFeedback) {
68-
await submitFeedback(JSON.parse(savedFeedback));
68+
const feedback = JSON.parse(savedFeedback);
69+
const blob = new Blob([JSON.stringify(feedback)], { type: 'application/json; charset=UTF-8' });
70+
navigator.sendBeacon('/feedback/submit', blob);
6971
sessionStorage.removeItem('feedbackData');
7072
}
7173
};

0 commit comments

Comments
 (0)