회기 집계와 기록 복귀 및 감독 근거 링크 수정
Some checks failed
API contract / OpenAPI type drift (push) Failing after 4m46s
Some checks failed
API contract / OpenAPI type drift (push) Failing after 4m46s
This commit is contained in:
parent
aa951c6c4a
commit
1306c524c1
20 changed files with 4631 additions and 60 deletions
|
|
@ -126,6 +126,10 @@ interface LearnerHomeProps {
|
|||
view?: LearnerHomeView;
|
||||
}
|
||||
|
||||
function isHistoryFilter(value: string | null): value is HistoryFilter {
|
||||
return HISTORY_FILTERS.some((item) => item.value === value);
|
||||
}
|
||||
|
||||
export default function LearnerHome({ view = "dashboard" }: LearnerHomeProps) {
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
|
|
@ -168,8 +172,18 @@ export default function LearnerHome({ view = "dashboard" }: LearnerHomeProps) {
|
|||
);
|
||||
const [memoryLoadState, setMemoryLoadState] =
|
||||
useState<MemoryLoadState>("idle");
|
||||
const [historyFilter, setHistoryFilter] = useState<HistoryFilter>("all");
|
||||
const [historyQuery, setHistoryQuery] = useState("");
|
||||
const [localHistoryFilter, setLocalHistoryFilter] =
|
||||
useState<HistoryFilter>("all");
|
||||
const [localHistoryQuery, setLocalHistoryQuery] = useState("");
|
||||
const historyStatusParam = searchParams.get("status");
|
||||
const historyFilter =
|
||||
view === "history"
|
||||
? isHistoryFilter(historyStatusParam)
|
||||
? historyStatusParam
|
||||
: "all"
|
||||
: localHistoryFilter;
|
||||
const historyQuery =
|
||||
view === "history" ? (searchParams.get("q") ?? "") : localHistoryQuery;
|
||||
const [archiveBusyId, setArchiveBusyId] = useState<string | null>(null);
|
||||
const [archiveNotice, setArchiveNotice] = useState<string | null>(null);
|
||||
// 중간 폭(≤1180px)에서는 대시보드 섹션을 상단 가로 탭으로 전환한다(2026-07-15 소유자 피드백).
|
||||
|
|
@ -177,6 +191,46 @@ export default function LearnerHome({ view = "dashboard" }: LearnerHomeProps) {
|
|||
const [dashTab, setDashTab] = useState<DashboardTab>("today");
|
||||
const dashTabRefs = useRef<Array<HTMLButtonElement | null>>([]);
|
||||
|
||||
const updateHistorySearchParams = (
|
||||
update: (params: URLSearchParams) => void,
|
||||
) => {
|
||||
const params = new URLSearchParams(searchParams);
|
||||
update(params);
|
||||
const nextSearch = params.toString();
|
||||
navigate(
|
||||
{ search: nextSearch ? `?${nextSearch}` : "" },
|
||||
{ replace: true },
|
||||
);
|
||||
};
|
||||
|
||||
const setHistoryFilter = (nextFilter: HistoryFilter) => {
|
||||
if (view !== "history") {
|
||||
setLocalHistoryFilter(nextFilter);
|
||||
return;
|
||||
}
|
||||
updateHistorySearchParams((params) => {
|
||||
if (nextFilter === "all") {
|
||||
params.delete("status");
|
||||
} else {
|
||||
params.set("status", nextFilter);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const setHistoryQuery = (nextQuery: string) => {
|
||||
if (view !== "history") {
|
||||
setLocalHistoryQuery(nextQuery);
|
||||
return;
|
||||
}
|
||||
updateHistorySearchParams((params) => {
|
||||
if (nextQuery.trim()) {
|
||||
params.set("q", nextQuery);
|
||||
} else {
|
||||
params.delete("q");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function handleDashTabKeyDown(
|
||||
event: ReactKeyboardEvent<HTMLButtonElement>,
|
||||
currentIndex: number,
|
||||
|
|
|
|||
|
|
@ -78,6 +78,17 @@ function shortId(value: string | undefined, length = 12): string {
|
|||
return value.length > length ? `${value.slice(0, length)}…` : value;
|
||||
}
|
||||
|
||||
const LEGACY_TEACHER_SESSION_ROUTE =
|
||||
/^\/teacher\/sessions\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\/?$/i;
|
||||
|
||||
function normalizeDrilldownRoute(route: string): string {
|
||||
if (route === "/teacher/dashboard") return "/teach";
|
||||
const legacySession = LEGACY_TEACHER_SESSION_ROUTE.exec(route);
|
||||
return legacySession
|
||||
? `/teach/session/${legacySession[1]}/review`
|
||||
: route;
|
||||
}
|
||||
|
||||
function driftLabel(status: DriftStatus): string {
|
||||
if (status === "stable") return "안정";
|
||||
if (status === "drift_flagged") return "드리프트 확인 필요";
|
||||
|
|
@ -217,7 +228,9 @@ function AttentionWorkbench({ items }: { items: AttentionItem[] }) {
|
|||
}
|
||||
|
||||
const evidence = selected.evidence_pointer_ids.slice(0, 3);
|
||||
const drilldowns = selected.drilldown_routes.slice(0, 3);
|
||||
const drilldowns = selected.drilldown_routes
|
||||
.slice(0, 3)
|
||||
.map(normalizeDrilldownRoute);
|
||||
|
||||
return (
|
||||
<div className="g6-workbench">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue