Commit 6968c5da authored by Kantz's avatar Kantz
Browse files

subsection keys update

parent a2044e3f
...@@ -79,11 +79,12 @@ You can open a socratic chat directly with URL query parameters: ...@@ -79,11 +79,12 @@ You can open a socratic chat directly with URL query parameters:
Example: Example:
`http://localhost:5173/chat?orchestrator=socratic&subsection_key=quadratische%20gleichungen` `http://localhost:5173/chat?orchestrator=socratic&subsection_key=quadratische-gleichungen`
Notes: Notes:
- `subsection_key` must match an existing subsection entry from the task catalog. - `subsection_key` must match an existing subsection entry from the task catalog.
- The links use hyphenated subsection slugs in the URL, while the app resolves them back to the catalog key.
- The socratic subsection list in the UI is built from `backend/sources/tasks/_subsection_map.json` and the `subsections` arrays in the task files. - The socratic subsection list in the UI is built from `backend/sources/tasks/_subsection_map.json` and the `subsections` arrays in the task files.
- If the link is invalid, the frontend falls back to `/select-socratic`. - If the link is invalid, the frontend falls back to `/select-socratic`.
- The socratic dialog is not locked by deep link, so users can still switch subsections afterwards. - The socratic dialog is not locked by deep link, so users can still switch subsections afterwards.
......
...@@ -14,6 +14,7 @@ import { selectSubsection, selectTask } from "../api/taskApi"; ...@@ -14,6 +14,7 @@ import { selectSubsection, selectTask } from "../api/taskApi";
import { t } from "../i18n"; import { t } from "../i18n";
import { createSessionId, useTutorSession } from "../state/tutorSession"; import { createSessionId, useTutorSession } from "../state/tutorSession";
import { getSelectionRouteForOrchestrator, isSocraticOrchestrator } from "../utils/orchestratorRoutes"; import { getSelectionRouteForOrchestrator, isSocraticOrchestrator } from "../utils/orchestratorRoutes";
import { normalizeSubsectionKey } from "../utils/subsectionKey";
import sumintLogo from "../../SuMINT-Logo.png"; import sumintLogo from "../../SuMINT-Logo.png";
const initialMessages: ChatMessage[] = []; const initialMessages: ChatMessage[] = [];
...@@ -232,7 +233,7 @@ export default function ChatPage() { ...@@ -232,7 +233,7 @@ export default function ChatPage() {
/^\d{1,2}$/.test(rawTaskId) && rawTaskId.length < 2 /^\d{1,2}$/.test(rawTaskId) && rawTaskId.length < 2
? rawTaskId.padStart(2, "0") ? rawTaskId.padStart(2, "0")
: rawTaskId; : rawTaskId;
const subsectionKey = rawSubsectionKey; const subsectionKey = rawSubsectionKey ? normalizeSubsectionKey(rawSubsectionKey) : "";
const hasFileId = Boolean(fileId); const hasFileId = Boolean(fileId);
const hasTaskId = Boolean(taskId); const hasTaskId = Boolean(taskId);
const hasSubsectionKey = Boolean(subsectionKey); const hasSubsectionKey = Boolean(subsectionKey);
......
...@@ -6,6 +6,7 @@ import OrchestratorSelect from "../components/Orchestrator/OrchestratorSelect"; ...@@ -6,6 +6,7 @@ import OrchestratorSelect from "../components/Orchestrator/OrchestratorSelect";
import { t } from "../i18n"; import { t } from "../i18n";
import { useTutorSession } from "../state/tutorSession"; import { useTutorSession } from "../state/tutorSession";
import { getSelectionRouteForOrchestrator } from "../utils/orchestratorRoutes"; import { getSelectionRouteForOrchestrator } from "../utils/orchestratorRoutes";
import { subsectionKeyToSlug } from "../utils/subsectionKey";
import "../styles/theme.css"; import "../styles/theme.css";
import sumintLogo from "../../SuMINT-Logo.png"; import sumintLogo from "../../SuMINT-Logo.png";
...@@ -18,6 +19,7 @@ type SocraticLinkGroup = { ...@@ -18,6 +19,7 @@ type SocraticLinkGroup = {
type SocraticLinkEntry = { type SocraticLinkEntry = {
subsectionKey: string; subsectionKey: string;
slug: string;
label: string; label: string;
summary: string; summary: string;
refsText: string; refsText: string;
...@@ -83,10 +85,11 @@ export default function SocraticSelectionPage() { ...@@ -83,10 +85,11 @@ export default function SocraticSelectionPage() {
const refsText = option.refs.map((ref) => ref.join(":")).join(", "); const refsText = option.refs.map((ref) => ref.join(":")).join(", ");
const entry: SocraticLinkEntry = { const entry: SocraticLinkEntry = {
subsectionKey: option.subsection_key, subsectionKey: option.subsection_key,
slug: subsectionKeyToSlug(option.subsection_key),
label: option.label || option.subsection_key, label: option.label || option.subsection_key,
summary: option.summary || "", summary: option.summary || "",
refsText, refsText,
href: buildSocraticHref(option.subsection_key), href: buildSocraticHref(subsectionKeyToSlug(option.subsection_key)),
}; };
const existing = groupIndex.get(groupKey); const existing = groupIndex.get(groupKey);
...@@ -274,7 +277,7 @@ export default function SocraticSelectionPage() { ...@@ -274,7 +277,7 @@ export default function SocraticSelectionPage() {
{group.entries.map((entry) => ( {group.entries.map((entry) => (
<Link key={entry.subsectionKey} className="socratic-link-item" to={entry.href}> <Link key={entry.subsectionKey} className="socratic-link-item" to={entry.href}>
<span className="socratic-link-item-title">{entry.label}</span> <span className="socratic-link-item-title">{entry.label}</span>
<span className="socratic-link-item-key">{entry.subsectionKey}</span> <span className="socratic-link-item-key">{entry.slug}</span>
{entry.refsText ? ( {entry.refsText ? (
<span className="socratic-link-item-meta">{entry.refsText}</span> <span className="socratic-link-item-meta">{entry.refsText}</span>
) : null} ) : null}
......
const collapseWhitespace = (value: string): string => value.replace(/\s+/g, " ").trim();
export const normalizeSubsectionKey = (value: string): string =>
collapseWhitespace(String(value).replace(/[-_]+/g, " ").toLowerCase());
export const subsectionKeyToSlug = (value: string): string =>
normalizeSubsectionKey(value).replace(/\s+/g, "-");
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment