계약 DTO SSOT 3차

This commit is contained in:
Yun Chan 2026-06-27 18:27:30 +09:00
parent 1007eaf7d9
commit 480fbd543a
10 changed files with 90 additions and 162 deletions

View file

@ -291,7 +291,7 @@ export default function Professor() {
() => [
{
label: "검토 대기",
value: dashboard?.pending_reviews.length ?? 0,
value: dashboard?.pending_reviews?.length ?? 0,
hint: "종료 회기",
icon: "review" as const,
},
@ -303,13 +303,13 @@ export default function Professor() {
},
{
label: "최근 세션",
value: dashboard?.recent_sessions.length ?? 0,
value: dashboard?.recent_sessions?.length ?? 0,
hint: "종료 · 진행",
icon: "play" as const,
},
{
label: "위기 알림",
value: dashboard?.safety_alerts.length ?? 0,
value: dashboard?.safety_alerts?.length ?? 0,
hint: "109 확인",
icon: "alert" as const,
},
@ -328,12 +328,14 @@ export default function Professor() {
],
[dashboard, personaReviews.length],
);
const pendingCount = dashboard?.pending_reviews.length ?? 0;
const pendingCount = dashboard?.pending_reviews?.length ?? 0;
const hasPending = pendingCount > 0;
const totalSessions = (dashboard?.active_sessions ?? 0) + (dashboard?.ended_sessions ?? 0);
const personaReviewCount = personaReviews.length;
const safetyAlerts = dashboard?.safety_alerts ?? [];
const learnerGrowth = dashboard?.learner_growth ?? [];
const pendingReviews = dashboard?.pending_reviews ?? [];
const recentSessions = dashboard?.recent_sessions ?? [];
return (
<AppShell>
@ -630,13 +632,13 @@ export default function Professor() {
<Kicker> </Kicker>
<h2> </h2>
</div>
<Badge tone="accent">{dashboard?.pending_reviews.length ?? 0}</Badge>
<Badge tone="accent">{pendingReviews.length}</Badge>
</div>
<Card className="pf-panel">
{dashboard && dashboard.pending_reviews.length > 0 ? (
{pendingReviews.length > 0 ? (
<div className="pf-list">
{dashboard.pending_reviews.map((session) => (
{pendingReviews.map((session) => (
<article className="pf-session" key={session.session_id}>
<span className="pf-session__dot" aria-hidden="true" />
<div className="pf-session__main">
@ -647,7 +649,7 @@ export default function Professor() {
<code>{session.session_id}</code>
</div>
<div className="pf-session__meta">
<span>{formatDateTime(session.ended_at)}</span>
<span>{formatDateTime(session.ended_at ?? null)}</span>
<Badge tone="neutral"> </Badge>
</div>
</article>
@ -669,11 +671,11 @@ export default function Professor() {
<Kicker> </Kicker>
<h2> </h2>
</div>
<Badge tone="neutral">{dashboard?.recent_sessions.length ?? 0}</Badge>
<Badge tone="neutral">{recentSessions.length}</Badge>
</div>
<Card className="pf-panel">
{dashboard && dashboard.recent_sessions.length > 0 ? (
{recentSessions.length > 0 ? (
<div className="pf-recent-list">
<div className="pf-recent-head" aria-hidden="true">
<span></span>
@ -684,7 +686,7 @@ export default function Professor() {
<span></span>
<span></span>
</div>
{dashboard.recent_sessions.map((session) => (
{recentSessions.map((session) => (
<article
className="pf-recent-row"
key={session.session_id}
@ -712,7 +714,7 @@ export default function Professor() {
{formatDateTime(session.started_at)}
</span>
<span className="pf-recent__cell tabular" data-label="종료">
{formatDateTime(session.ended_at)}
{formatDateTime(session.ended_at ?? null)}
</span>
</article>
))}
@ -732,7 +734,9 @@ export default function Professor() {
}
function GrowthCard({ learner }: { learner: TeacherLearnerGrowth }) {
const recentPoints = learner.points.slice(-3).reverse();
const points = learner.points ?? [];
const topTechniques = learner.top_techniques ?? [];
const recentPoints = points.slice(-3).reverse();
return (
<article className={`pf-growth-card trend-${learner.trend}`}>
<div className="pf-growth-card__top">
@ -763,14 +767,14 @@ function GrowthCard({ learner }: { learner: TeacherLearnerGrowth }) {
</div>
<div className="pf-growth-bars" aria-label="회기별 적절성 추이">
{learner.points.map((point) => (
{points.map((point) => (
<GrowthBar point={point} key={point.session_id} />
))}
</div>
<div className="pf-growth-card__tags">
{learner.top_techniques.length > 0 ? (
learner.top_techniques.map((tag) => <span key={tag}>{tag}</span>)
{topTechniques.length > 0 ? (
topTechniques.map((tag) => <span key={tag}>{tag}</span>)
) : (
<span> </span>
)}
@ -1092,6 +1096,9 @@ const PF_CSS = `
background:linear-gradient(180deg,var(--bg-surface),color-mix(in srgb,var(--accent-tint) 18%,var(--bg-surface)));
}
.pf-growth-list{
max-height:min(540px,52vh);
overflow:auto;
scrollbar-gutter:stable;
display:grid;
grid-template-columns:repeat(3,minmax(0,1fr));
gap:12px;