From 73a0820b1d612f25314281ceccf22f1587da6e0a Mon Sep 17 00:00:00 2001 From: chyoo Date: Thu, 13 Aug 2026 09:53:45 +0900 Subject: [PATCH] feat: add platform access sync action --- src/lib/platforms.ts | 12 +++++++++++ src/pages/platforms/PlatformsPage.tsx | 29 ++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/lib/platforms.ts b/src/lib/platforms.ts index b045ede..15215de 100644 --- a/src/lib/platforms.ts +++ b/src/lib/platforms.ts @@ -269,6 +269,18 @@ export async function assignInstructorPlatform( return response.json() as Promise; } +export async function syncInstructorPlatformAccess(accessToken: string): Promise<{ ok: boolean; assignmentCount: number; syncedAt: string }> { + const response = await fetch(`${LMS_API_BASE_URL}/instructor/platforms/access-sync`, { + method: 'POST', + headers: { Authorization: `Bearer ${accessToken}` }, + }); + + if (!response.ok) { + throw new Error(await platformErrorMessage(response, '플랫폼 접근 설정을 동기화하지 못했습니다.')); + } + return response.json() as Promise<{ ok: boolean; assignmentCount: number; syncedAt: string }>; +} + async function platformErrorMessage(response: Response, fallback: string) { const payload = await response.json().catch((): null => null); return platformErrorMessageFromPayload(response, payload, fallback); diff --git a/src/pages/platforms/PlatformsPage.tsx b/src/pages/platforms/PlatformsPage.tsx index 8259ede..9c420e9 100644 --- a/src/pages/platforms/PlatformsPage.tsx +++ b/src/pages/platforms/PlatformsPage.tsx @@ -1,6 +1,6 @@ import { useEffect, useMemo, useState, type ReactNode } from 'react'; import { createPortal } from 'react-dom'; -import { Activity, Battery, Car, CircleAlert, KeyRound, Loader2, Plus, Search, Settings, ShieldAlert, Timer, Trash2, Users, X, type LucideIcon } from 'lucide-react'; +import { Activity, Battery, Car, CircleAlert, KeyRound, Loader2, Plus, RefreshCw, Search, Settings, ShieldAlert, Timer, Trash2, Users, X, type LucideIcon } from 'lucide-react'; import { ConfirmDialog } from '../../components/ConfirmDialog'; import { PageHeader } from '../../components/PageHeader'; import { PaginationBar } from '../../components/PaginationBar'; @@ -12,6 +12,7 @@ import { listInstructorPlatformAgents, listInstructorPlatforms, issueInstructorPlatformRegistration, + syncInstructorPlatformAccess, PlatformInUseError, updateInstructorPlatform, type InstructorPlatform, @@ -95,6 +96,7 @@ export function PlatformsPage({ session }: { session: AuthSession }) { const [assignmentGroupsError, setAssignmentGroupsError] = useState(null); const [selectedAssignmentGroupId, setSelectedAssignmentGroupId] = useState(''); const [assigningPlatformId, setAssigningPlatformId] = useState(null); + const [syncingAccess, setSyncingAccess] = useState(false); const [forceAssignmentTarget, setForceAssignmentTarget] = useState<{ platform: InstructorPlatform; group: InstructorGroup | null; session: PlatformInUseError['activeSession'] } | null>(null); const filteredPlatforms = useMemo(() => { @@ -262,6 +264,22 @@ export function PlatformsPage({ session }: { session: AuthSession }) { } }; + const handleSyncPlatformAccess = async () => { + setSyncingAccess(true); + setError(null); + try { + const result = await syncInstructorPlatformAccess(session.accessToken); + showToast({ + title: '플랫폼 접근 설정을 동기화했습니다.', + message: `현재 배정 기준 ${result.assignmentCount}개 플랫폼을 반영했습니다.`, + }); + } catch (reason) { + setError(reason instanceof Error ? reason.message : '플랫폼 접근 설정을 동기화하지 못했습니다.'); + } finally { + setSyncingAccess(false); + } + }; + const handleDeletePlatform = async (platform: InstructorPlatform, force = false) => { setDeletingPlatformId(platform.id); setError(null); @@ -378,6 +396,15 @@ export function PlatformsPage({ session }: { session: AuthSession }) { route="platforms" action={
+