Files
Edu/apps/portal-shell/src/widgets/sidebar/term-switcher/index.tsx
SpecialX a28a6bd6ea feat(portal-shell): clean widget design tokens and fix lint:tokens (P1-6)
516 mechanical replacements across 25 widget files:
- spacing xs/sm/md/lg/xl to numeric 1/2/3/4/6
- text-heading-3 to text-lg font-semibold
- bg-danger to bg-destructive
- border border dedup

Fix .eslintrc.tokens.js to use typescript-eslint parser (was importing
uninstalled @typescript-eslint/parser). lint:tokens now passes.
2026-07-22 15:07:38 +08:00

58 lines
1.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
/**
* term-switchersidebar / side
*
* 通过 useTerms 查询 apollo-router → core-edu 子图的 terms 数据。
* 切换学期时写入 URL Search ParamstermId其他插件自动响应。
* 默认选中 isActive=true 的学期。
*
* 关联portal-shell spec §5.2.1 URL 驱动、M8 验收
*/
import { useRouter, useSearchParams } from "next/navigation";
import { useTerms } from "@/lib/api/sidebar";
import { PluginSkeleton } from "@/shell/PluginLoader";
import type { PluginProps } from "@/lib/types";
export default function TermSwitcher(_props: PluginProps): React.ReactElement {
const router = useRouter();
const searchParams = useSearchParams();
const currentTermId = searchParams.get("termId") ?? "";
const { data, loading } = useTerms();
const handleSelect = (termId: string): void => {
const params = new URLSearchParams(searchParams.toString());
params.set("termId", termId);
router.push(`?${params.toString()}`);
};
if (loading && !data) {
return <PluginSkeleton variant="list" />;
}
const terms = data ?? [];
const activeTerm = terms.find((t) => t.isActive);
// URL 未指定 termId 时默认选中当前激活学期
const selectedTermId = currentTermId || activeTerm?.id || "";
return (
<div>
<p className="text-sm text-muted-foreground"></p>
<select
value={selectedTermId}
onChange={(e) => handleSelect(e.target.value)}
className="mt-1 w-full rounded-md border bg-card px-2 py-1 text-sm text-foreground"
aria-label="选择学期"
>
<option value=""></option>
{terms.map((t) => (
<option key={t.id} value={t.id}>
{t.name}
</option>
))}
</select>
</div>
);
}