platform/lms-adm-fe release promotion snapshot

This commit is contained in:
2026-08-20 04:26:53 +00:00
parent 551b5fe939
commit cf5baebdeb
4 changed files with 232 additions and 2 deletions
+28 -1
View File
@@ -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<string | null>(null);
const [selectedAssignmentGroupId, setSelectedAssignmentGroupId] = useState('');
const [assigningPlatformId, setAssigningPlatformId] = useState<string | null>(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={
<div className="flex items-center gap-2">
<button
className="inline-flex h-9 items-center gap-2 rounded-md border border-[#d1d9e6] bg-white px-3 text-[13px] font-bold text-[#475569] hover:bg-[#f8fafc] disabled:cursor-not-allowed disabled:opacity-60"
type="button"
onClick={handleSyncPlatformAccess}
disabled={syncingAccess}
>
{syncingAccess ? <Loader2 className="animate-spin" size={15} aria-hidden="true" /> : <RefreshCw size={15} aria-hidden="true" />}
접근 동기화
</button>
<button
className="inline-flex h-9 items-center gap-2 rounded-md border border-[#2563eb] bg-white px-3 text-[13px] font-bold text-[#2563eb] hover:bg-[#eff6ff]"
type="button"