유스케이스 TDD 16테마 스펙과 접근성 제품 결함 수정
- 지원 티켓 작성 UI 신설(설정)·관리자 해결 노트 입력 신설(Admin): 서버 계약은 있었으나 웹 진입점이 없던 2결함 - a11y: outline 채널 포커스 링(ui/shell css), 세션바 44px 터치 타깃, 청록 하드코딩 그라디언트를 테마 토큰으로 교체, 설정 라벨/헤딩/대비·리뷰 44px·모바일 오버플로 수정 - uc-*.spec.ts 16테마 239 시나리오 신규(수집 1109 tests/61 files), 기존 스펙 5종 계약 드리프트 교정 - breakpoint-sweep: widthsFor 솎아내기가 실기기 대표 폭(360/390/1024)을 탈락시키는 테스트 결함 수정 — keep 시드를 전체 DEVICE_WIDTHS로, 3연폭 예외는 솎아내기 발생 여부 기준으로 - 검증: tsc PASS, 병렬 게이트 1040 passed(데스크톱 밀도 충돌 1건 해소 후 focused 68/68 GREEN), 직렬 게이트 52/5/4 삼각화 — breakpoint(테스트 결함)·kb(낡은 dev API 재기동)·voice(일시적) 해소, 교사 재평가 2건은 엔진 구독 한도(resets 3pm)로 skip 후 재검증 대기 - 문서/SSOT: HANDOFF·TODO·대시보드·testing 가이드 동기화, 증거 usecase-tdd-2026-08-18.json, SSOT 체커 PASS(59)
This commit is contained in:
parent
4771b97c3a
commit
cf899b7f15
37 changed files with 11989 additions and 67 deletions
|
|
@ -406,6 +406,7 @@ interface TicketActionsProps {
|
|||
onUpdateStatus: (
|
||||
ticket: AdminSupportTicket,
|
||||
status: AdminSupportTicket["status"],
|
||||
resolutionNote?: string,
|
||||
) => Promise<void>;
|
||||
onUpdateParent: (
|
||||
ticket: AdminSupportTicket,
|
||||
|
|
@ -421,6 +422,8 @@ function TicketActions({
|
|||
onUpdateParent,
|
||||
}: TicketActionsProps) {
|
||||
const [pending, setPending] = useState(false);
|
||||
// 해결 노트 — 학습자 설정 화면(resolution_note)에 그대로 보이는 처리 메모.
|
||||
const [resolutionNote, setResolutionNote] = useState("");
|
||||
const pendingRef = useRef(false);
|
||||
|
||||
const run = (action: () => Promise<void>) => {
|
||||
|
|
@ -438,6 +441,16 @@ function TicketActions({
|
|||
|
||||
return (
|
||||
<div className="vgops-ticket__actions" aria-busy={pending}>
|
||||
<textarea
|
||||
className="vgops-ticket__note-input"
|
||||
rows={2}
|
||||
value={resolutionNote}
|
||||
aria-label="해결 노트"
|
||||
placeholder="해결 시 학습자에게 보일 처리 메모"
|
||||
maxLength={2000}
|
||||
disabled={pending}
|
||||
onChange={(event) => setResolutionNote(event.target.value)}
|
||||
/>
|
||||
{canLinkDuplicate ? (
|
||||
<Button
|
||||
size="sm"
|
||||
|
|
@ -469,7 +482,11 @@ function TicketActions({
|
|||
<Button
|
||||
size="sm"
|
||||
variant="primary"
|
||||
onClick={() => run(() => onUpdateStatus(ticket, "resolved"))}
|
||||
onClick={() =>
|
||||
run(() =>
|
||||
onUpdateStatus(ticket, "resolved", resolutionNote.trim() || undefined),
|
||||
)
|
||||
}
|
||||
disabled={pending}
|
||||
>
|
||||
해결
|
||||
|
|
@ -1073,9 +1090,13 @@ export default function Admin({ section = "overview" }: AdminProps) {
|
|||
const updateTicketStatus = async (
|
||||
ticket: AdminSupportTicket,
|
||||
status: AdminSupportTicket["status"],
|
||||
resolutionNote?: string,
|
||||
) => {
|
||||
try {
|
||||
const updated = await adminApi.updateTicket(ticket.ticket_id, { status });
|
||||
const updated = await adminApi.updateTicket(ticket.ticket_id, {
|
||||
status,
|
||||
...(resolutionNote ? { resolution_note: resolutionNote } : {}),
|
||||
});
|
||||
setTicketsError(null);
|
||||
setTickets((current) =>
|
||||
current
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue