mirror of
https://github.com/alexmickelson/canvasManagement.git
synced 2026-03-26 23:58:31 -06:00
fixing authority on server quizzes still broken
This commit is contained in:
@@ -27,16 +27,14 @@ export default function EditLecture({ lectureDay }: { lectureDay: string }) {
|
|||||||
.flatMap(({ lectures }) => lectures.map((lecture) => lecture))
|
.flatMap(({ lectures }) => lectures.map((lecture) => lecture))
|
||||||
.find((l) => l.date === lectureDay);
|
.find((l) => l.date === lectureDay);
|
||||||
|
|
||||||
const serverVersionOfText = getLectureTextOrDefault(lecture, lectureDay);
|
const startingText = getLectureTextOrDefault(lecture, lectureDay);
|
||||||
|
|
||||||
const [text, setText] = useState(serverVersionOfText);
|
const [text, setText] = useState(startingText);
|
||||||
const [updateMonacoKey, setUpdateMonacoKey] = useState(1);
|
const [updateMonacoKey, setUpdateMonacoKey] = useState(1);
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
const [clientDataUpdatedAt, setClientDataUpdatedAt] =
|
const [clientDataUpdatedAt, setClientDataUpdatedAt] =
|
||||||
useState(serverDataUpdatedAt);
|
useState(serverDataUpdatedAt);
|
||||||
const clientIsAuthoritative = serverDataUpdatedAt <= clientDataUpdatedAt;
|
|
||||||
console.log("client it authoritative", clientIsAuthoritative);
|
|
||||||
|
|
||||||
const textUpdate = useCallback((t: string) => {
|
const textUpdate = useCallback((t: string) => {
|
||||||
setText(t);
|
setText(t);
|
||||||
@@ -45,6 +43,9 @@ export default function EditLecture({ lectureDay }: { lectureDay: string }) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const delay = 500;
|
const delay = 500;
|
||||||
|
const clientIsAuthoritative = serverDataUpdatedAt <= clientDataUpdatedAt;
|
||||||
|
console.log("client is authoritative", clientIsAuthoritative);
|
||||||
|
|
||||||
const handler = setTimeout(() => {
|
const handler = setTimeout(() => {
|
||||||
try {
|
try {
|
||||||
const parsed = parseLecture(text);
|
const parsed = parseLecture(text);
|
||||||
@@ -75,15 +76,7 @@ export default function EditLecture({ lectureDay }: { lectureDay: string }) {
|
|||||||
return () => {
|
return () => {
|
||||||
clearTimeout(handler);
|
clearTimeout(handler);
|
||||||
};
|
};
|
||||||
}, [
|
}, [courseName, lecture, settings, text, textUpdate, updateLecture]);
|
||||||
clientIsAuthoritative,
|
|
||||||
courseName,
|
|
||||||
lecture,
|
|
||||||
settings,
|
|
||||||
text,
|
|
||||||
textUpdate,
|
|
||||||
updateLecture,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex flex-col">
|
<div className="h-full flex flex-col">
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
LocalAssignment,
|
LocalAssignment,
|
||||||
localAssignmentMarkdown,
|
localAssignmentMarkdown,
|
||||||
} from "@/models/local/assignment/localAssignment";
|
} from "@/models/local/assignment/localAssignment";
|
||||||
import { useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import AssignmentPreview from "./AssignmentPreview";
|
import AssignmentPreview from "./AssignmentPreview";
|
||||||
import { getModuleItemUrl } from "@/services/urlUtils";
|
import { getModuleItemUrl } from "@/services/urlUtils";
|
||||||
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
|
import { useCourseContext } from "@/app/course/[courseName]/context/courseContext";
|
||||||
@@ -26,38 +26,35 @@ export default function EditAssignment({
|
|||||||
}: {
|
}: {
|
||||||
assignmentName: string;
|
assignmentName: string;
|
||||||
moduleName: string;
|
moduleName: string;
|
||||||
}) {
|
|
||||||
const [_, {dataUpdatedAt}] = useAssignmentQuery(moduleName, assignmentName);
|
|
||||||
return (
|
|
||||||
<InnerEditAssignment
|
|
||||||
key={dataUpdatedAt}
|
|
||||||
assignmentName={assignmentName}
|
|
||||||
moduleName={moduleName}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export function InnerEditAssignment({
|
|
||||||
moduleName,
|
|
||||||
assignmentName,
|
|
||||||
}: {
|
|
||||||
assignmentName: string;
|
|
||||||
moduleName: string;
|
|
||||||
}) {
|
}) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { courseName } = useCourseContext();
|
const { courseName } = useCourseContext();
|
||||||
const [settings] = useLocalCourseSettingsQuery();
|
const [settings] = useLocalCourseSettingsQuery();
|
||||||
const [assignment] = useAssignmentQuery(moduleName, assignmentName);
|
const [assignment, { dataUpdatedAt: serverDataUpdatedAt }] =
|
||||||
|
useAssignmentQuery(moduleName, assignmentName);
|
||||||
const updateAssignment = useUpdateAssignmentMutation();
|
const updateAssignment = useUpdateAssignmentMutation();
|
||||||
|
|
||||||
const [assignmentText, setAssignmentText] = useState(
|
const [assignmentText, setAssignmentText] = useState(
|
||||||
localAssignmentMarkdown.toMarkdown(assignment)
|
localAssignmentMarkdown.toMarkdown(assignment)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [updateMonacoKey, setUpdateMonacoKey] = useState(1);
|
||||||
|
const [clientDataUpdatedAt, setClientDataUpdatedAt] =
|
||||||
|
useState(serverDataUpdatedAt);
|
||||||
|
|
||||||
|
const textUpdate = useCallback((t: string) => {
|
||||||
|
setAssignmentText(t);
|
||||||
|
setClientDataUpdatedAt(Date.now());
|
||||||
|
}, []);
|
||||||
|
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
const [showHelp, setShowHelp] = useState(false);
|
const [showHelp, setShowHelp] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const delay = 500;
|
const delay = 500;
|
||||||
|
const clientIsAuthoritative = serverDataUpdatedAt <= clientDataUpdatedAt;
|
||||||
|
console.log("client is authoritative", clientIsAuthoritative);
|
||||||
|
|
||||||
const handler = setTimeout(() => {
|
const handler = setTimeout(() => {
|
||||||
try {
|
try {
|
||||||
const updatedAssignment: LocalAssignment =
|
const updatedAssignment: LocalAssignment =
|
||||||
@@ -66,6 +63,7 @@ export function InnerEditAssignment({
|
|||||||
localAssignmentMarkdown.toMarkdown(assignment) !==
|
localAssignmentMarkdown.toMarkdown(assignment) !==
|
||||||
localAssignmentMarkdown.toMarkdown(updatedAssignment)
|
localAssignmentMarkdown.toMarkdown(updatedAssignment)
|
||||||
) {
|
) {
|
||||||
|
if (clientIsAuthoritative) {
|
||||||
console.log("updating assignment");
|
console.log("updating assignment");
|
||||||
updateAssignment
|
updateAssignment
|
||||||
.mutateAsync({
|
.mutateAsync({
|
||||||
@@ -87,6 +85,13 @@ export function InnerEditAssignment({
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
"client not authoritative, updating client with server data"
|
||||||
|
);
|
||||||
|
textUpdate(localAssignmentMarkdown.toMarkdown(assignment));
|
||||||
|
setUpdateMonacoKey((k) => k + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setError("");
|
setError("");
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
@@ -116,7 +121,11 @@ export function InnerEditAssignment({
|
|||||||
</pre>
|
</pre>
|
||||||
)}
|
)}
|
||||||
<div className="flex-1 h-full">
|
<div className="flex-1 h-full">
|
||||||
<MonacoEditor value={assignmentText} onChange={setAssignmentText} />
|
<MonacoEditor
|
||||||
|
key={updateMonacoKey}
|
||||||
|
value={assignmentText}
|
||||||
|
onChange={textUpdate}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 h-full">
|
<div className="flex-1 h-full">
|
||||||
<div className="text-red-300">{error && error}</div>
|
<div className="text-red-300">{error && error}</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { MonacoEditor } from "@/components/editor/MonacoEditor";
|
import { MonacoEditor } from "@/components/editor/MonacoEditor";
|
||||||
import { quizMarkdownUtils } from "@/models/local/quiz/utils/quizMarkdownUtils";
|
import { quizMarkdownUtils } from "@/models/local/quiz/utils/quizMarkdownUtils";
|
||||||
import { useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import QuizPreview from "./QuizPreview";
|
import QuizPreview from "./QuizPreview";
|
||||||
import { QuizButtons } from "./QuizButton";
|
import { QuizButtons } from "./QuizButton";
|
||||||
import ClientOnly from "@/components/ClientOnly";
|
import ClientOnly from "@/components/ClientOnly";
|
||||||
@@ -80,25 +80,40 @@ export function InnerEditQuiz({
|
|||||||
}) {
|
}) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { courseName } = useCourseContext();
|
const { courseName } = useCourseContext();
|
||||||
const [quiz] = useQuizQuery(moduleName, quizName);
|
const [quiz, { dataUpdatedAt: serverDataUpdatedAt }] = useQuizQuery(
|
||||||
|
moduleName,
|
||||||
|
quizName
|
||||||
|
);
|
||||||
const updateQuizMutation = useUpdateQuizMutation();
|
const updateQuizMutation = useUpdateQuizMutation();
|
||||||
const [quizText, setQuizText] = useState(quizMarkdownUtils.toMarkdown(quiz));
|
const [quizText, setQuizText] = useState(quizMarkdownUtils.toMarkdown(quiz));
|
||||||
|
|
||||||
|
const [updateMonacoKey, setUpdateMonacoKey] = useState(1);
|
||||||
|
const [clientDataUpdatedAt, setClientDataUpdatedAt] =
|
||||||
|
useState(serverDataUpdatedAt);
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
const [showHelp, setShowHelp] = useState(false);
|
const [showHelp, setShowHelp] = useState(false);
|
||||||
|
|
||||||
|
const textUpdate = useCallback((t: string) => {
|
||||||
|
setQuizText(t);
|
||||||
|
setClientDataUpdatedAt(Date.now());
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const delay = 1000;
|
const delay = 1000;
|
||||||
|
const clientIsAuthoritative = serverDataUpdatedAt <= clientDataUpdatedAt;
|
||||||
|
console.log("client is authoritative", clientIsAuthoritative);
|
||||||
|
|
||||||
const handler = setTimeout(async () => {
|
const handler = setTimeout(async () => {
|
||||||
try {
|
try {
|
||||||
console.log("checking if the same...");
|
|
||||||
if (
|
if (
|
||||||
quizMarkdownUtils.toMarkdown(quiz) !==
|
quizMarkdownUtils.toMarkdown(quiz) !==
|
||||||
quizMarkdownUtils.toMarkdown(
|
quizMarkdownUtils.toMarkdown(
|
||||||
quizMarkdownUtils.parseMarkdown(quizText)
|
quizMarkdownUtils.parseMarkdown(quizText)
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
if (clientIsAuthoritative) {
|
||||||
const updatedQuiz = quizMarkdownUtils.parseMarkdown(quizText);
|
const updatedQuiz = quizMarkdownUtils.parseMarkdown(quizText);
|
||||||
updateQuizMutation
|
await updateQuizMutation
|
||||||
.mutateAsync({
|
.mutateAsync({
|
||||||
quiz: updatedQuiz,
|
quiz: updatedQuiz,
|
||||||
moduleName,
|
moduleName,
|
||||||
@@ -118,6 +133,13 @@ export function InnerEditQuiz({
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
"client not authoritative, updating client with server data"
|
||||||
|
);
|
||||||
|
textUpdate(quizMarkdownUtils.toMarkdown(quiz));
|
||||||
|
setUpdateMonacoKey((k) => k + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setError("");
|
setError("");
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
@@ -129,15 +151,19 @@ export function InnerEditQuiz({
|
|||||||
clearTimeout(handler);
|
clearTimeout(handler);
|
||||||
};
|
};
|
||||||
}, [
|
}, [
|
||||||
|
clientDataUpdatedAt,
|
||||||
courseName,
|
courseName,
|
||||||
moduleName,
|
moduleName,
|
||||||
quiz,
|
quiz,
|
||||||
quizName,
|
quizName,
|
||||||
quizText,
|
quizText,
|
||||||
router,
|
router,
|
||||||
|
serverDataUpdatedAt,
|
||||||
|
textUpdate,
|
||||||
updateQuizMutation,
|
updateQuizMutation,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
console.log("updateMonacoKey", updateMonacoKey);
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex flex-col align-middle px-1">
|
<div className="h-full flex flex-col align-middle px-1">
|
||||||
<div className={"min-h-96 h-full flex flex-row w-full"}>
|
<div className={"min-h-96 h-full flex flex-row w-full"}>
|
||||||
@@ -147,7 +173,11 @@ export function InnerEditQuiz({
|
|||||||
</pre>
|
</pre>
|
||||||
)}
|
)}
|
||||||
<div className="flex-1 h-full">
|
<div className="flex-1 h-full">
|
||||||
<MonacoEditor value={quizText} onChange={setQuizText} />
|
<MonacoEditor
|
||||||
|
key={updateMonacoKey}
|
||||||
|
value={quizText}
|
||||||
|
onChange={textUpdate}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 h-full">
|
<div className="flex-1 h-full">
|
||||||
<div className="text-red-300">{error && error}</div>
|
<div className="text-red-300">{error && error}</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user