Skip to content

Commit e5e41ce

Browse files
committed
fix(frontend): 🐛 mounts component before accessing local storage
Only access localStorage on the client side (in the browser) after the component has mounted.
1 parent 3396c29 commit e5e41ce

File tree

3 files changed

+118
-84
lines changed

3 files changed

+118
-84
lines changed

apps/frontend/src/app/collaboration/[id]/page.tsx

Lines changed: 82 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,18 @@ import CollaborativeEditor, {
3131
} from "@/components/CollaborativeEditor/CollaborativeEditor";
3232
import { CreateHistory } from "@/app/services/history";
3333
import { WebrtcProvider } from "y-webrtc";
34-
import { ExecuteVisibleAndCustomTests, ExecuteVisibleAndHiddenTestsAndSubmit, ExecutionResults, GetVisibleTests, isTestResult, SubmissionHiddenTestResultsAndStatus, SubmissionResults, Test, TestData, TestResult } from "@/app/services/execute";
34+
import {
35+
ExecuteVisibleAndCustomTests,
36+
ExecuteVisibleAndHiddenTestsAndSubmit,
37+
ExecutionResults,
38+
GetVisibleTests,
39+
isTestResult,
40+
SubmissionHiddenTestResultsAndStatus,
41+
SubmissionResults,
42+
Test,
43+
TestData,
44+
TestResult,
45+
} from "@/app/services/execute";
3546
import { QuestionDetailFull } from "@/components/question/QuestionDetailFull/QuestionDetailFull";
3647
import VideoPanel from "@/components/VideoPanel/VideoPanel";
3748

@@ -69,15 +80,17 @@ export default function CollaborationPage(props: CollaborationProps) {
6980
);
7081
const [currentUser, setCurrentUser] = useState<string | undefined>(undefined);
7182
const [matchedUser, setMatchedUser] = useState<string>("Loading...");
72-
const [sessionDuration, setSessionDuration] = useState<number>(() => {
73-
const storedTime = localStorage.getItem("session-duration");
74-
return storedTime ? parseInt(storedTime) : 0;
75-
}); // State for count-up timer (TODO: currently using localstorage to store time, change to db stored time in the future)
83+
const [sessionDuration, setSessionDuration] = useState<number>(0); // State for count-up timer (TODO: currently using localstorage to store time, change to db stored time in the future)
7684
const stopwatchRef = useRef<NodeJS.Timeout | null>(null);
7785
const [matchedTopics, setMatchedTopics] = useState<string[] | undefined>(
7886
undefined
7987
);
8088

89+
useEffect(() => {
90+
const storedTime = localStorage.getItem("session-duration");
91+
setSessionDuration(storedTime ? parseInt(storedTime) : 0);
92+
}, []);
93+
8194
// Chat states
8295
const [messageToSend, setMessageToSend] = useState<string | undefined>(
8396
undefined
@@ -89,8 +102,12 @@ export default function CollaborationPage(props: CollaborationProps) {
89102
);
90103
const [visibleTestCases, setVisibleTestCases] = useState<Test[]>([]);
91104
const [isLoadingTestCase, setIsLoadingTestCase] = useState<boolean>(false);
92-
const [isLoadingSubmission, setIsLoadingSubmission] = useState<boolean>(false);
93-
const [submissionHiddenTestResultsAndStatus, setSubmissionHiddenTestResultsAndStatus] = useState<SubmissionHiddenTestResultsAndStatus | undefined>(undefined);
105+
const [isLoadingSubmission, setIsLoadingSubmission] =
106+
useState<boolean>(false);
107+
const [
108+
submissionHiddenTestResultsAndStatus,
109+
setSubmissionHiddenTestResultsAndStatus,
110+
] = useState<SubmissionHiddenTestResultsAndStatus | undefined>(undefined);
94111

95112
// End Button Modal state
96113
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
@@ -151,7 +168,7 @@ export default function CollaborationPage(props: CollaborationProps) {
151168
type: "info",
152169
content: message,
153170
});
154-
}
171+
};
155172

156173
const sendSubmissionResultsToMatchedUser = (data: SubmissionResults) => {
157174
if (!providerRef.current) {
@@ -161,7 +178,7 @@ export default function CollaborationPage(props: CollaborationProps) {
161178
submissionResults: data,
162179
id: Date.now(),
163180
});
164-
}
181+
};
165182

166183
const sendExecutingStateToMatchedUser = (executing: boolean) => {
167184
if (!providerRef.current) {
@@ -171,7 +188,7 @@ export default function CollaborationPage(props: CollaborationProps) {
171188
executing: executing,
172189
id: Date.now(),
173190
});
174-
}
191+
};
175192

176193
const sendSubmittingStateToMatchedUser = (submitting: boolean) => {
177194
if (!providerRef.current) {
@@ -181,7 +198,7 @@ export default function CollaborationPage(props: CollaborationProps) {
181198
submitting: submitting,
182199
id: Date.now(),
183200
});
184-
}
201+
};
185202

186203
const sendExecutionResultsToMatchedUser = (data: ExecutionResults) => {
187204
if (!providerRef.current) {
@@ -191,60 +208,54 @@ export default function CollaborationPage(props: CollaborationProps) {
191208
executionResults: data,
192209
id: Date.now(),
193210
});
194-
}
211+
};
195212

196213
const updateSubmissionResults = (data: SubmissionResults) => {
197214
setSubmissionHiddenTestResultsAndStatus({
198215
hiddenTestResults: data.hiddenTestResults,
199216
status: data.status,
200217
});
201218
setVisibleTestCases(data.visibleTestResults);
202-
}
219+
};
203220

204221
const updateExecutionResults = (data: ExecutionResults) => {
205222
setVisibleTestCases(data.visibleTestResults);
206-
}
223+
};
207224

208225
const handleRunTestCases = async () => {
209226
if (!questionDocRefId) {
210227
throw new Error("Question ID not found");
211228
}
212229
setIsLoadingTestCase(true);
213230
sendExecutingStateToMatchedUser(true);
214-
const data = await ExecuteVisibleAndCustomTests(
215-
questionDocRefId,
216-
{
217-
code: code,
218-
language: selectedLanguage,
219-
customTestCases: "",
220-
}
221-
);
231+
const data = await ExecuteVisibleAndCustomTests(questionDocRefId, {
232+
code: code,
233+
language: selectedLanguage,
234+
customTestCases: "",
235+
});
222236
setVisibleTestCases(data.visibleTestResults);
223-
infoMessage("Test cases executed. Review the results below.")
237+
infoMessage("Test cases executed. Review the results below.");
224238
sendExecutionResultsToMatchedUser(data);
225239
setIsLoadingTestCase(false);
226240
sendExecutingStateToMatchedUser(false);
227-
}
241+
};
228242

229243
const handleSubmitCode = async () => {
230244
if (!questionDocRefId) {
231245
throw new Error("Question ID not found");
232246
}
233247
setIsLoadingSubmission(true);
234248
sendSubmittingStateToMatchedUser(true);
235-
const data = await ExecuteVisibleAndHiddenTestsAndSubmit(
236-
questionDocRefId,
237-
{
238-
code: code,
239-
language: selectedLanguage,
240-
user: currentUser ?? "",
241-
matchedUser: matchedUser ?? "",
242-
matchedTopics: matchedTopics ?? [],
243-
title: questionTitle ?? "",
244-
questionDifficulty: complexity ?? "",
245-
questionTopics: categories,
246-
}
247-
);
249+
const data = await ExecuteVisibleAndHiddenTestsAndSubmit(questionDocRefId, {
250+
code: code,
251+
language: selectedLanguage,
252+
user: currentUser ?? "",
253+
matchedUser: matchedUser ?? "",
254+
matchedTopics: matchedTopics ?? [],
255+
title: questionTitle ?? "",
256+
questionDifficulty: complexity ?? "",
257+
questionTopics: categories,
258+
});
248259
setVisibleTestCases(data.visibleTestResults);
249260
setSubmissionHiddenTestResultsAndStatus({
250261
hiddenTestResults: data.hiddenTestResults,
@@ -254,7 +265,7 @@ export default function CollaborationPage(props: CollaborationProps) {
254265
successMessage("Code saved successfully!");
255266
setIsLoadingSubmission(false);
256267
sendSubmittingStateToMatchedUser(false);
257-
}
268+
};
258269

259270
const handleCodeChange = (code: string) => {
260271
setCode(code);
@@ -317,9 +328,7 @@ export default function CollaborationPage(props: CollaborationProps) {
317328
label: (
318329
<span
319330
style={{
320-
color: !isTestResult(item)
321-
? ""
322-
: (item.passed ? "green" : "red"),
331+
color: !isTestResult(item) ? "" : item.passed ? "green" : "red",
323332
}}
324333
>
325334
Case {index + 1}
@@ -335,21 +344,20 @@ export default function CollaborationPage(props: CollaborationProps) {
335344
{isTestResult(item) && (
336345
<div className="test-result-container">
337346
<InfoCircleFilled className="hidden-test-icon" />
338-
<Typography.Text
339-
strong
347+
<Typography.Text
348+
strong
340349
style={{ color: item.passed ? "green" : "red" }}
341350
>
342351
{item.passed ? "Passed" : "Failed"}
343352
</Typography.Text>
344353
<br />
345-
<Typography.Text strong>Actual Output:</Typography.Text> {item.actual}
354+
<Typography.Text strong>Actual Output:</Typography.Text>{" "}
355+
{item.actual}
346356
<br />
347357
{item.error && (
348358
<>
349359
<Typography.Text strong>Error:</Typography.Text>
350-
<div className="error-message">
351-
{item.error}
352-
</div>
360+
<div className="error-message">{item.error}</div>
353361
</>
354362
)}
355363
</div>
@@ -487,31 +495,50 @@ export default function CollaborationPage(props: CollaborationProps) {
487495
)}
488496
<div className="hidden-test-results">
489497
<InfoCircleFilled className="hidden-test-icon" />
490-
<Typography.Text
498+
<Typography.Text
491499
strong
492500
style={{
493501
color: submissionHiddenTestResultsAndStatus
494-
? submissionHiddenTestResultsAndStatus.status === "Accepted"
502+
? submissionHiddenTestResultsAndStatus.status ===
503+
"Accepted"
495504
? "green"
496-
: submissionHiddenTestResultsAndStatus.status === "Attempted"
505+
: submissionHiddenTestResultsAndStatus.status ===
506+
"Attempted"
497507
? "orange"
498508
: "black" // default color for any other status
499509
: "gray", // color for "Not Attempted"
500510
}}
501511
>
502-
Session Status: {submissionHiddenTestResultsAndStatus ? submissionHiddenTestResultsAndStatus.status : "Not Attempted"}
512+
Session Status:{" "}
513+
{submissionHiddenTestResultsAndStatus
514+
? submissionHiddenTestResultsAndStatus.status
515+
: "Not Attempted"}
503516
</Typography.Text>
504517
<br />
505518
{submissionHiddenTestResultsAndStatus && (
506519
<Typography.Text
507520
strong
508521
style={{
509-
color: submissionHiddenTestResultsAndStatus.hiddenTestResults.passed === submissionHiddenTestResultsAndStatus.hiddenTestResults.total
510-
? "green" // All test cases passed
511-
: "red" // Some test cases failed
522+
color:
523+
submissionHiddenTestResultsAndStatus.hiddenTestResults
524+
.passed ===
525+
submissionHiddenTestResultsAndStatus.hiddenTestResults
526+
.total
527+
? "green" // All test cases passed
528+
: "red", // Some test cases failed
512529
}}
513530
>
514-
Passed {submissionHiddenTestResultsAndStatus.hiddenTestResults.passed} / {submissionHiddenTestResultsAndStatus.hiddenTestResults.total} hidden test cases
531+
Passed{" "}
532+
{
533+
submissionHiddenTestResultsAndStatus.hiddenTestResults
534+
.passed
535+
}{" "}
536+
/{" "}
537+
{
538+
submissionHiddenTestResultsAndStatus.hiddenTestResults
539+
.total
540+
}{" "}
541+
hidden test cases
515542
</Typography.Text>
516543
)}
517544
</div>

0 commit comments

Comments
 (0)