feat: enhance lesson plan handling with new parser and color-coded room assignments
This commit is contained in:
46
src/App.tsx
46
src/App.tsx
@@ -58,6 +58,7 @@ import {
|
||||
diffSchedules,
|
||||
lessonKey,
|
||||
personalFilter,
|
||||
planFor,
|
||||
subgroupsOf,
|
||||
} from "../shared/lessons";
|
||||
import { placesFor, placesOn, type DayPlace } from "../shared/places";
|
||||
@@ -149,7 +150,33 @@ interface ListContext {
|
||||
/** Minutes since midnight when the list shows today; drives the live pair chip. */
|
||||
clock: number | null;
|
||||
isHidden: (lesson: Lesson) => boolean;
|
||||
/** The week shown, or only its colour for white or green Word rows; null for all rows. */
|
||||
week: { n: number | null; color: string } | null;
|
||||
}
|
||||
const unique = (list: string[]) => [...new Set(list)];
|
||||
const weeksLabel = (ranges: [number, number | null][]) =>
|
||||
"недели " + ranges.map(([a, b]) => (b === null ? `с ${a}` : a === b ? `${a}` : `${a}–${b}`)).join(", ");
|
||||
/**
|
||||
* Room and teacher of a lesson in a week, when Word names them by week ("1-9н. 502н",
|
||||
* "ауд.533н-б.н.,420н-з.н."). For all Word rows at once: the rooms of each week colour.
|
||||
*/
|
||||
function inWeek(lesson: Lesson, week: ListContext["week"]) {
|
||||
const planned = planFor(lesson.plan, week);
|
||||
const rooms = unique(planned.flatMap((p) => p.rooms)),
|
||||
teachers = unique(planned.flatMap((p) => p.teachers));
|
||||
const byColor = !week && !lesson.plan?.some((p) => p.weeks)
|
||||
? (lesson.plan || []).filter((p) => p.color && p.rooms.length).map((p) => `${p.rooms.join(", ")} (${p.color === "white" ? "бел." : "зел."} н.)`)
|
||||
: [];
|
||||
return {
|
||||
room: rooms.join(", ") || byColor.join(", ") || lesson.room,
|
||||
teacher: teachers.join(", ") || lesson.teacher,
|
||||
};
|
||||
}
|
||||
/** "533Н — белые недели", "502Н — недели 1–9": the plan for the details. */
|
||||
const planLine = (p: NonNullable<Lesson["plan"]>[number]) =>
|
||||
[p.rooms.join(", "), p.teachers.join(", ")].filter(Boolean).join(", ") +
|
||||
" — " +
|
||||
[p.weeks && weeksLabel(p.weeks), p.color && (p.color === "white" ? "белые недели" : "зелёные недели")].filter(Boolean).join(", ");
|
||||
const duration = (m: number) =>
|
||||
m < 60 ? `${m} мин` : `${Math.floor(m / 60)} ч${m % 60 ? ` ${m % 60} мин` : ""}`;
|
||||
function LessonCard({
|
||||
@@ -163,6 +190,7 @@ function LessonCard({
|
||||
}) {
|
||||
const theme = lessonTheme(lesson.type);
|
||||
const subgroup = lesson.subgroups.find((item) => item.group === ctx.group);
|
||||
const { room, teacher } = inWeek(lesson, ctx.week);
|
||||
const dates = ctx.calendar && hasWeekLimit(lesson) ? ctx.datesOf(lesson) : undefined;
|
||||
const hidden = ctx.isHidden(lesson);
|
||||
return (
|
||||
@@ -192,16 +220,16 @@ function LessonCard({
|
||||
</span>
|
||||
<strong>{lesson.subject}</strong>
|
||||
<span className="lesson-meta">
|
||||
{lesson.teacher && (
|
||||
{teacher && (
|
||||
<span>
|
||||
<Icon name="person" size={20} />
|
||||
{lesson.teacher}
|
||||
{teacher}
|
||||
</span>
|
||||
)}
|
||||
{(lesson.room || lesson.place) && (
|
||||
{(room || lesson.place) && (
|
||||
<span>
|
||||
<Icon name="location_on" size={20} />
|
||||
{whereLabel(lesson, "Ауд.")}
|
||||
{whereLabel({ ...lesson, room }, "Ауд.")}
|
||||
</span>
|
||||
)}
|
||||
{subgroup && (
|
||||
@@ -1062,6 +1090,11 @@ export default function App() {
|
||||
today,
|
||||
clock: showsToday ? clock : null,
|
||||
isHidden,
|
||||
week: calendarMode
|
||||
? { n: week!.n, color: week!.color }
|
||||
: mode === "upper" || mode === "lower"
|
||||
? { n: null, color: mode === "upper" ? "white" : "green" }
|
||||
: null,
|
||||
});
|
||||
const scheduleDated =
|
||||
!!schedule?.lessons.length && schedule.lessons.every((l) => l.date);
|
||||
@@ -2205,6 +2238,11 @@ export default function App() {
|
||||
<Icon name="location_on" size={20} />
|
||||
<small>Аудитория</small>
|
||||
<b>{details.room || "Не указана"}</b>
|
||||
{details.plan?.some((p) => p.rooms.length || p.teachers.length) && (
|
||||
<small className="detail-halves">
|
||||
{details.plan.filter((p) => p.rooms.length || p.teachers.length).map(planLine).join("; ")}
|
||||
</small>
|
||||
)}
|
||||
</span>
|
||||
{details.place && (
|
||||
<span>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { WeekRange } from "../shared/weeks";
|
||||
import type { PlaceNote } from "../shared/places";
|
||||
import type { PlanEntry } from "../shared/lessons";
|
||||
export interface Lesson {
|
||||
id: string;
|
||||
day: number;
|
||||
@@ -12,6 +13,8 @@ export interface Lesson {
|
||||
room: string;
|
||||
/** "Полоцк": the town, when the cell or the day's note names one (parser 14). */
|
||||
place?: string;
|
||||
/** Rooms and teachers by week number or colour: "1-9н. 502н", "ауд.533н-б.н.,420н-з.н.". */
|
||||
plan?: PlanEntry[];
|
||||
type: string;
|
||||
condition: string;
|
||||
groups: string[];
|
||||
|
||||
Reference in New Issue
Block a user