Skip to content

Commit 7633384

Browse files
committed
fixing question order bug
1 parent b2fefdc commit 7633384

File tree

2 files changed

+192
-57
lines changed

2 files changed

+192
-57
lines changed

apps/web/app/author/(components)/AuthorQuestionsPage/index.tsx

Lines changed: 50 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -345,53 +345,58 @@ const AuthorQuestionsPage: FC<Props> = ({
345345
};
346346

347347
const questions: QuestionAuthorStore[] =
348-
assignment.questions?.map(
349-
(question: QuestionAuthorStore, index: number) => {
350-
//unify scoring rubrics
351-
const unifiedQuestionScoring = unifyScoringRubrics(
352-
question.scoring,
353-
question.question,
354-
);
355-
//sort criteria by points
356-
unifiedQuestionScoring.rubrics?.forEach((rubric: Rubric) => {
357-
rubric.criteria.sort(
358-
(a: Criteria, b: Criteria) => a.points - b.points,
348+
assignment.questions
349+
?.sort(
350+
(a: QuestionAuthorStore, b: QuestionAuthorStore) =>
351+
(a.index || 0) - (b.index || 0),
352+
)
353+
.map(
354+
(question: QuestionAuthorStore, index: number) => {
355+
//unify scoring rubrics
356+
const unifiedQuestionScoring = unifyScoringRubrics(
357+
question.scoring,
358+
question.question,
359359
);
360-
});
361-
362-
const parsedVariants: QuestionVariants[] =
363-
question.variants?.map((variant: QuestionVariants) => {
364-
const unifiedVariantScoring = unifyScoringRubrics(
365-
variant.scoring,
366-
variant.variantContent ?? question.question,
367-
);
368-
unifiedVariantScoring.rubrics?.forEach(
369-
(rubric: Rubric) => {
370-
rubric.criteria.sort(
371-
(a: Criteria, b: Criteria) => a.points - b.points,
372-
);
373-
},
360+
//sort criteria by points
361+
unifiedQuestionScoring.rubrics?.forEach((rubric: Rubric) => {
362+
rubric.criteria.sort(
363+
(a: Criteria, b: Criteria) => a.points - b.points,
374364
);
375-
376-
return {
377-
...variant,
378-
choices:
379-
typeof variant.choices === "string"
380-
? (JSON.parse(variant.choices) as Choice[])
381-
: variant.choices,
382-
scoring: unifiedVariantScoring,
383-
};
384-
}) ?? [];
385-
386-
return {
387-
...question,
388-
alreadyInBackend: true,
389-
index: index + 1,
390-
variants: parsedVariants,
391-
scoring: unifiedQuestionScoring,
392-
};
393-
},
394-
) ?? [];
365+
});
366+
367+
const parsedVariants: QuestionVariants[] =
368+
question.variants?.map((variant: QuestionVariants) => {
369+
const unifiedVariantScoring = unifyScoringRubrics(
370+
variant.scoring,
371+
variant.variantContent ?? question.question,
372+
);
373+
unifiedVariantScoring.rubrics?.forEach(
374+
(rubric: Rubric) => {
375+
rubric.criteria.sort(
376+
(a: Criteria, b: Criteria) => a.points - b.points,
377+
);
378+
},
379+
);
380+
381+
return {
382+
...variant,
383+
choices:
384+
typeof variant.choices === "string"
385+
? (JSON.parse(variant.choices) as Choice[])
386+
: variant.choices,
387+
scoring: unifiedVariantScoring,
388+
};
389+
}) ?? [];
390+
391+
return {
392+
...question,
393+
alreadyInBackend: true,
394+
index: index + 1,
395+
variants: parsedVariants,
396+
scoring: unifiedQuestionScoring,
397+
};
398+
},
399+
) ?? [];
395400

396401
if (questions.length > 0) {
397402
setQuestions(questions);

apps/web/stores/author.ts

Lines changed: 142 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,10 @@ export type AuthorActions = {
271271
setVersions: (versions: VersionSummary[]) => void;
272272
setCurrentVersion: (version?: VersionSummary) => void;
273273
setCheckedOutVersion: (version?: VersionSummary) => void;
274-
checkoutVersion: (versionId: number) => Promise<boolean>;
274+
checkoutVersion: (
275+
versionId: number,
276+
versionNumber?: string | number,
277+
) => Promise<boolean>;
275278
setSelectedVersion: (version?: VersionSummary) => void;
276279
setVersionComparison: (comparison?: VersionComparison) => void;
277280
setIsLoadingVersions: (loading: boolean) => void;
@@ -1744,14 +1747,25 @@ export const useAuthorStore = createWithEqualityFn<
17441747
const currentVersion = versions.find((v) => v.isActive);
17451748
const currentState = get();
17461749

1747-
let checkedOutVersion = currentVersion;
1748-
if (currentState.checkedOutVersion) {
1750+
// Preserve the current checkedOutVersion if it exists and is still in the version list
1751+
// This ensures that when versions are refreshed, we don't lose the user's current checkout
1752+
let checkedOutVersion = currentState.checkedOutVersion;
1753+
1754+
if (checkedOutVersion) {
1755+
// Find the updated version object from the fresh list
17491756
const existingCheckedOut = versions.find(
1750-
(v) => v.id === currentState.checkedOutVersion.id,
1757+
(v) => v.id === checkedOutVersion.id,
17511758
);
17521759
if (existingCheckedOut) {
1760+
// Use the fresh version object from the API
17531761
checkedOutVersion = existingCheckedOut;
1762+
} else {
1763+
// If the checked out version no longer exists, fall back to current version
1764+
checkedOutVersion = currentVersion;
17541765
}
1766+
} else {
1767+
// If no version is checked out, default to the current active version
1768+
checkedOutVersion = currentVersion;
17551769
}
17561770

17571771
set({
@@ -1945,7 +1959,10 @@ export const useAuthorStore = createWithEqualityFn<
19451959
});
19461960
},
19471961

1948-
checkoutVersion: async (versionId: number) => {
1962+
checkoutVersion: async (
1963+
versionId: number,
1964+
versionNumber?: string | number,
1965+
) => {
19491966
const state = get();
19501967
if (!state.activeAssignmentId) return false;
19511968

@@ -1977,7 +1994,86 @@ export const useAuthorStore = createWithEqualityFn<
19771994
updateConfigStores,
19781995
} = get();
19791996

1980-
const processedQuestions = rawQuestions.map(
1997+
// Sort questions by their index before processing to ensure correct order
1998+
const questionOrderArray: number[] =
1999+
versionData.questionOrder && Array.isArray(versionData.questionOrder)
2000+
? (versionData.questionOrder
2001+
.map((value: unknown) => {
2002+
if (typeof value === "number" && Number.isFinite(value)) {
2003+
return value;
2004+
}
2005+
2006+
if (typeof value === "string") {
2007+
const parsed = Number.parseInt(value, 10);
2008+
if (!Number.isNaN(parsed)) {
2009+
return parsed;
2010+
}
2011+
}
2012+
2013+
return null;
2014+
})
2015+
.filter((value: number | null): value is number => value !== null) as number[])
2016+
: [];
2017+
2018+
const questionOrderMap = questionOrderArray.reduce(
2019+
(acc: Map<number, number>, questionId: number, orderIndex: number) => {
2020+
acc.set(questionId, orderIndex);
2021+
return acc;
2022+
},
2023+
new Map<number, number>(),
2024+
);
2025+
2026+
const resolveQuestionId = (questionVersion: any): number | undefined => {
2027+
if (typeof questionVersion?.questionId === "number") {
2028+
return questionVersion.questionId;
2029+
}
2030+
2031+
if (typeof questionVersion?.id === "number") {
2032+
return questionVersion.id;
2033+
}
2034+
2035+
if (questionVersion?.question && typeof questionVersion.question.id === "number") {
2036+
return questionVersion.question.id;
2037+
}
2038+
2039+
return undefined;
2040+
};
2041+
2042+
const getQuestionOrder = (questionVersion: any, fallbackIndex: number) => {
2043+
const displayOrder = questionVersion?.displayOrder;
2044+
if (typeof displayOrder === "number" && Number.isFinite(displayOrder)) {
2045+
return displayOrder;
2046+
}
2047+
2048+
const questionId =
2049+
resolveQuestionId(questionVersion);
2050+
2051+
if (
2052+
questionId !== undefined &&
2053+
questionOrderMap.has(questionId)
2054+
) {
2055+
return (questionOrderMap.get(questionId) ?? fallbackIndex) + 1;
2056+
}
2057+
2058+
if (typeof questionVersion?.index === "number") {
2059+
return questionVersion.index;
2060+
}
2061+
2062+
return fallbackIndex + 1;
2063+
};
2064+
2065+
const originalOrderMap = new Map<any, number>();
2066+
rawQuestions.forEach((question: any, index: number) => {
2067+
originalOrderMap.set(question, index);
2068+
});
2069+
2070+
const sortedQuestions = [...rawQuestions].sort((a: any, b: any) => {
2071+
const orderA = getQuestionOrder(a, originalOrderMap.get(a) ?? 0);
2072+
const orderB = getQuestionOrder(b, originalOrderMap.get(b) ?? 0);
2073+
return orderA - orderB;
2074+
});
2075+
2076+
const processedQuestions = sortedQuestions.map(
19812077
(questionVersion: any, index: number) =>
19822078
processQuestionVersion(
19832079
questionVersion,
@@ -1988,21 +2084,32 @@ export const useAuthorStore = createWithEqualityFn<
19882084
),
19892085
);
19902086

2087+
const finalQuestionOrder =
2088+
sortedQuestions
2089+
.map((questionVersion: any) => resolveQuestionId(questionVersion))
2090+
.filter((id: number | undefined): id is number => typeof id === "number");
2091+
2092+
// Update the store with the version data
19912093
set({
19922094
name: versionData.name,
19932095
introduction: versionData.introduction,
19942096
instructions: versionData.instructions,
19952097
gradingCriteriaOverview: versionData.gradingCriteriaOverview,
19962098
questions: processedQuestions,
19972099
questionOrder:
1998-
versionData.questionOrder ||
1999-
processedQuestions.map((q) => q.id),
2100+
finalQuestionOrder.length > 0
2101+
? finalQuestionOrder
2102+
: questionOrderArray.length > 0
2103+
? questionOrderArray
2104+
: processedQuestions.map((q) => q.id),
20002105
checkedOutVersion: versionToCheckout,
20012106
hasUnsavedChanges: false,
20022107
});
20032108

20042109
await updateConfigStores(versionData);
20052110

2111+
console.log("✅ Checked out version:", versionToCheckout.versionNumber, "ID:", versionToCheckout.id);
2112+
20062113
return true;
20072114
} catch (error) {
20082115
console.error("💥 Error checking out version:", error);
@@ -2147,16 +2254,39 @@ export const useAuthorStore = createWithEqualityFn<
21472254
updatedVersions = [newVersion, ...state.versions];
21482255
}
21492256

2257+
// First update the versions array
21502258
set({
21512259
versions: updatedVersions,
21522260
currentVersion: newVersion.isActive
21532261
? newVersion
21542262
: state.currentVersion,
2155-
// Clear checkedOutVersion so BottomVersionBar shows the latest version
2156-
// When user creates a new version, they should see that version in the bar
2157-
checkedOutVersion: newVersion,
2158-
hasUnsavedChanges: false,
21592263
});
2264+
2265+
console.log(
2266+
"📦 Published version:",
2267+
newVersion.versionNumber,
2268+
"ID:",
2269+
newVersion.id,
2270+
);
2271+
2272+
if (!isDraft) {
2273+
console.log("🔄 Auto-checking out to published version...");
2274+
2275+
// Then automatically checkout to the published version to reflect its content
2276+
// This will update checkedOutVersion and load the version data
2277+
const checkoutSuccess = await get().checkoutVersion(
2278+
newVersion.id,
2279+
);
2280+
2281+
if (checkoutSuccess) {
2282+
console.log("✅ Successfully checked out to published version");
2283+
} else {
2284+
console.warn(
2285+
"⚠️ Checkout failed after publishing, setting checkedOutVersion manually",
2286+
);
2287+
set({ checkedOutVersion: newVersion });
2288+
}
2289+
}
21602290
}
21612291

21622292
return newVersion;

0 commit comments

Comments
 (0)