feat: Enhance group selection logic to exclude duplicates for main schedules and past documents

This commit is contained in:
2026-10-19 19:53:03 +03:00
parent 5f7bffd6e4
commit db9a3f8243
3 changed files with 56 additions and 6 deletions

View File

@@ -382,8 +382,26 @@ export function examsOf(idx, group, faculty) {
export const groupKey = (s) =>
(s || "").toLowerCase().replace(/ё/g, "е").replace(/[\s\-–_.]/g, "");
/** Every group of every document, with the catalog place it came from. */
export function groupEntries(idx) {
/**
* Documents that only add to a group's timetable: their credits, exams and consultations reach
* the student through the session countdown (/api/exams), so the group picker offers them only
* when the group has nothing else.
*/
const SUPPLEMENTS = new Set(["Зачёты", "Экзаменационная сессия"]);
/** The last date of a document whose every lesson is dated ("Введение в высшее образование"), else null. */
function lastDate(schedule) {
const dates = schedule.lessons.flatMap((l) => (l.date ? [l.date] : l.dates || []));
return dates.length && schedule.lessons.every((l) => l.date || l.dates?.length)
? dates.sort().at(-1)
: null;
}
/**
* Every group of every document, with the catalog place it came from. A group with a main
* timetable is not offered its supplements, nor dated documents that are already over.
*/
export function groupEntries(idx, today = todayIso()) {
const list = [];
for (const { file, schedule } of idx.docs)
for (const group of schedule.groups)
@@ -397,8 +415,11 @@ export function groupEntries(idx) {
form: file.form || "",
period: schedule.period || "",
modified: file.modified || null,
over: (lastDate(schedule) ?? "9999") < today,
});
return list;
const secondary = (e) => SUPPLEMENTS.has(e.period) || e.over;
const main = new Set(list.filter((e) => !secondary(e)).map((e) => e.key));
return list.filter((e) => !secondary(e) || !main.has(e.key)).map(({ over, ...e }) => e);
}
const count = (items, pick) => {
@@ -416,8 +437,8 @@ const count = (items, pick) => {
* Groups matching a query and/or catalog filters. The query ignores filters on
* purpose: a student typing their group must find it in any faculty.
*/
export function findGroups(idx, { q = "", faculty = "", course = "", form = "" } = {}) {
const all = groupEntries(idx);
export function findGroups(idx, { q = "", faculty = "", course = "", form = "", today } = {}) {
const all = groupEntries(idx, today);
const key = groupKey(q);
let results;
if (key.length >= 2) {