Skip to content
104 changes: 38 additions & 66 deletions packages/common-ui/src/components/StudySession.vue
Original file line number Diff line number Diff line change
Expand Up @@ -81,27 +81,17 @@ import {
StudyContentSource,
StudySessionItem,
docIsDeleted,
CardData,
CardHistory,
CardRecord,
DisplayableData,
isQuestionRecord,
CourseRegistrationDoc,
DataLayerProvider,
UserDBInterface,
ClassroomDBInterface,
} from '@vue-skuilder/db';
import { SessionController, StudySessionRecord } from '@vue-skuilder/db';
import { HydratedCard, SessionController, StudySessionRecord } from '@vue-skuilder/db';
import { newInterval } from '@vue-skuilder/db';
import {
adjustCourseScores,
CourseElo,
toCourseElo,
isCourseElo,
displayableDataToViewData,
ViewData,
Status,
} from '@vue-skuilder/common';
import { adjustCourseScores, CourseElo, toCourseElo, ViewData, Status } from '@vue-skuilder/common';
import confetti from 'canvas-confetti';
import moment from 'moment';

Expand Down Expand Up @@ -175,7 +165,7 @@ export default defineComponent({
card_elo: 1000,
courseNames: {} as { [courseID: string]: string },
cardCount: 1,
sessionController: null as SessionController | null,
sessionController: null as SessionController<ViewComponent> | null,
sessionPrepared: false,
sessionFinished: false,
sessionRecord: [] as StudySessionRecord[],
Expand Down Expand Up @@ -295,7 +285,7 @@ export default defineComponent({
}
})
)
).filter((s) => s !== null)
).filter((s: unknown) => s !== null)
);

this.timeRemaining = this.sessionTimeLimit * 60;
Expand All @@ -310,7 +300,14 @@ export default defineComponent({
// db.setChangeFcn(this.handleClassroomMessage());
});

this.sessionController = markRaw(new SessionController(this.sessionContentSources, 60 * this.sessionTimeLimit));
this.sessionController = markRaw(
new SessionController<ViewComponent>(
this.sessionContentSources,
60 * this.sessionTimeLimit,
this.dataLayer,
this.getViewComponent
)
);
this.sessionController.sessionRecord = this.sessionRecord;

await this.sessionController.prepareSession();
Expand Down Expand Up @@ -349,7 +346,7 @@ export default defineComponent({
if (this.sessionController) {
try {
this.$emit('session-started');
this.loadCard(this.sessionController.nextCard());
this.loadCard(await this.sessionController.nextCard());
} catch (error) {
console.error('[StudySession] Error loading next card:', error);
this.$emit('session-error', { message: 'Failed to load study card', error });
Expand Down Expand Up @@ -407,7 +404,7 @@ export default defineComponent({
const item: StudySessionItem = {
...this.currentCard.item,
};
this.loadCard(this.sessionController!.nextCard('dismiss-success'));
this.loadCard(await this.sessionController!.nextCard('dismiss-success'));

cardHistory.then((history: CardHistory<CardRecord>) => {
this.scheduleReview(history, item);
Expand All @@ -419,7 +416,7 @@ export default defineComponent({
}
});
} else {
this.loadCard(this.sessionController!.nextCard('marked-failed'));
this.loadCard(await this.sessionController!.nextCard('marked-failed'));
}
} else {
/* !r.isCorrect */
Expand All @@ -445,16 +442,16 @@ export default defineComponent({
if (this.currentCard.records.length >= view.maxAttemptsPerView) {
const sessionViews: number = this.countCardViews(this.courseID, this.cardID);
if (sessionViews >= view.maxSessionViews) {
this.loadCard(this.sessionController!.nextCard('dismiss-failed'));
this.loadCard(await this.sessionController!.nextCard('dismiss-failed'));
this.updateUserAndCardElo(0, this.courseID, this.cardID);
} else {
this.loadCard(this.sessionController!.nextCard('marked-failed'));
this.loadCard(await this.sessionController!.nextCard('marked-failed'));
}
}
}
}
} else {
this.loadCard(this.sessionController!.nextCard('dismiss-success'));
this.loadCard(await this.sessionController!.nextCard('dismiss-success'));
}

this.clearFeedbackShadow();
Expand Down Expand Up @@ -548,81 +545,56 @@ export default defineComponent({
});
},

async loadCard(item: StudySessionItem | null) {
async loadCard(card: HydratedCard | null) {
if (this.loading) {
console.warn(`Attempted to load card while loading another...`);
return;
}

console.log(`[StudySession] loading: ${JSON.stringify(item)}`);
if (item === null) {
console.log(`[StudySession] loading: ${JSON.stringify(card)}`);
if (card === null) {
this.sessionFinished = true;
this.$emit('session-finished', this.sessionRecord);
return;
}
this.cardType = item.status;
this.cardType = card.item.status;

this.loading = true;
const _courseID = item.courseID;
const _cardID = item.cardID;

console.log(`[StudySession] Now displaying: ${_courseID}::${_cardID}`);

try {
const tmpCardData = await this.dataLayer.getCourseDB(_courseID).getCourseDoc<CardData>(_cardID);

if (!isCourseElo(tmpCardData.elo)) {
tmpCardData.elo = toCourseElo(tmpCardData.elo);
}

const tmpView: ViewComponent = this.getViewComponent(tmpCardData.id_view);
const tmpDataDocs = tmpCardData.id_displayable_data.map((id) => {
return this.dataLayer.getCourseDB(_courseID).getCourseDoc<DisplayableData>(id, {
attachments: true,
binary: true,
});
});

const tmpData = [];

for (const docPromise of tmpDataDocs) {
const doc = await docPromise;
tmpData.unshift(displayableDataToViewData(doc));
}

this.cardCount++;
this.data = tmpData;
this.view = markRaw(tmpView);
this.cardID = _cardID;
this.courseID = _courseID;
this.card_elo = tmpCardData.elo.global.score;
this.data = card.data;
this.view = markRaw(card.view);
this.cardID = card.item.cardID;
this.courseID = card.item.courseID;
this.card_elo = card.item.elo || 1000;

this.sessionRecord.push({
card: {
course_id: _courseID,
card_id: _cardID,
card_elo: tmpCardData.elo.global.score,
course_id: card.item.courseID,
card_id: card.item.cardID,
card_elo: this.card_elo,
},
item: item,
item: card.item,
records: [],
});

this.$emit('card-loaded', {
courseID: _courseID,
cardID: _cardID,
courseID: card.item.courseID,
cardID: card.item.cardID,
cardCount: this.cardCount,
});
} catch (e) {
console.warn(`[StudySession] Error loading card ${JSON.stringify(item)}:\n\t${JSON.stringify(e)}, ${e}`);
console.warn(`[StudySession] Error loading card ${JSON.stringify(card)}:\n\t${JSON.stringify(e)}, ${e}`);
this.loading = false;

const err = e as Error;
if (docIsDeleted(err) && isReview(item)) {
console.warn(`Card was deleted: ${_courseID}::${_cardID}`);
this.user!.removeScheduledCardReview(item.reviewID);
if (docIsDeleted(err) && isReview(card.item)) {
console.warn(`Card was deleted: ${card.item.courseID}::${card.item.cardID}`);
this.user!.removeScheduledCardReview((card.item as any).reviewID);
}

this.loadCard(this.sessionController!.nextCard('dismiss-error'));
this.loadCard(await this.sessionController!.nextCard('dismiss-error'));
} finally {
this.loading = false;
}
Expand Down
Loading