Signed-off-by: rgrgogu <obsequio.rus@gmail.com>
This commit is contained in:
rgrgogu
2026-07-24 23:34:26 +08:00
parent 9c560aa45c
commit a546a57c17
2 changed files with 15 additions and 2 deletions
+8 -1
View File
@@ -50,7 +50,14 @@ export default function CourseCheckout() {
// Handle PayPal return — capture
useEffect(() => {
if (!returnToken || capturingRef.current) return;
// A real PayPal cancel redirect carries BOTH `cancelled=true` (our own
// cancelUrl) and `token=<order_id>` (PayPal always appends its own token
// to whatever return/cancel URL it's given) — without this guard, both
// this effect and the cancellation effect below fired on the same load,
// racing a capture call against the cancel and surfacing a confusing
// "Pending purchase not found" error toast instead of a clean
// cancellation message.
if (!returnToken || wasCancelled || capturingRef.current) return;
capturingRef.current = true;
setCapturing(true);
captureCourseOrder(returnToken).then((result) => {
+7 -1
View File
@@ -175,8 +175,14 @@ const UnitReader = () => {
const stub = lessons.find((l) => l.lesson_id === selectedLessonId);
if (stub?.status === 'completed') return;
completedSessionRef.current.add(selectedLessonId);
// Trust the server's evaluated unit status, not a local "all fetched
// lessons read" re-derivation — that drifted from the real completion
// requirement (e.g. a unit needing its quiz passed too) and fired a
// premature "Unit complete!" toast. Same fix already applied to
// upsertLessonProgress's own unitDetail update; UnitList.jsx's
// handleMarkComplete already uses this authoritative pattern.
upsertLessonProgress(lesson.uuid, 'completed', uuid).then((result) => {
if (result?.unit && unitDetail && lessons.every((l) => l.lesson_id === selectedLessonId || l.status === 'completed')) {
if (result?.unit?.status === 'completed') {
toast.success('Unit complete!', { duration: 4000 });
}
});