feat: add LMS web client
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
import { CarFront, Laptop, Monitor } from 'lucide-react'
|
||||
import type { LucideIcon } from 'lucide-react'
|
||||
import type React from 'react'
|
||||
import { PlatformOptionCard, RunningPlatformCard } from './PlatformCards'
|
||||
import PlatformFilterTabs, { type PlatformFilter } from './PlatformFilterTabs'
|
||||
import type { PlatformOption } from './types'
|
||||
|
||||
const PLATFORM_ICONS: Record<string, LucideIcon> = {
|
||||
laptop: Laptop,
|
||||
monitor: Monitor,
|
||||
car: CarFront
|
||||
}
|
||||
|
||||
type PlatformSelectionPanelProps = {
|
||||
mode: 'select' | 'settings'
|
||||
runningPlatforms: PlatformOption[]
|
||||
filteredPlatforms: PlatformOption[]
|
||||
filter: PlatformFilter
|
||||
counts: Record<PlatformFilter, number>
|
||||
workspaceWeekTitle: string
|
||||
platformLoading: boolean
|
||||
isPlatformUnavailable: (platform: PlatformOption) => boolean
|
||||
getPlatformDotClass: (platform: PlatformOption) => string
|
||||
onFilterChange: (filter: PlatformFilter) => void
|
||||
onRunningOpen: (platform: PlatformOption) => void
|
||||
onRunningClose: (platform: PlatformOption) => void
|
||||
onPlatformAction: (platform: PlatformOption) => void
|
||||
onOpenSettings: (platform: PlatformOption) => void
|
||||
}
|
||||
|
||||
export default function PlatformSelectionPanel({
|
||||
mode,
|
||||
runningPlatforms,
|
||||
filteredPlatforms,
|
||||
filter,
|
||||
counts,
|
||||
workspaceWeekTitle,
|
||||
platformLoading,
|
||||
isPlatformUnavailable,
|
||||
getPlatformDotClass,
|
||||
onFilterChange,
|
||||
onRunningOpen,
|
||||
onRunningClose,
|
||||
onPlatformAction,
|
||||
onOpenSettings
|
||||
}: PlatformSelectionPanelProps): React.JSX.Element {
|
||||
return (
|
||||
<div className={['min-h-0 w-1/2 shrink-0 px-6 pb-5 pt-3 transition-opacity duration-300', mode === 'settings' ? 'opacity-0' : 'opacity-100'].join(' ')}>
|
||||
{runningPlatforms.length > 0 && (
|
||||
<div className="mb-4 pr-1">
|
||||
<p className="mb-2 text-[12px] font-black text-[#2563eb]">실행중인 플랫폼</p>
|
||||
<div className="grid gap-3">
|
||||
{runningPlatforms.map((platform) => {
|
||||
const Icon = PLATFORM_ICONS[platform.iconKey] ?? Monitor
|
||||
return (
|
||||
<RunningPlatformCard
|
||||
key={platform.id}
|
||||
platform={platform}
|
||||
Icon={Icon}
|
||||
dotClassName={getPlatformDotClass(platform)}
|
||||
weekTitle={workspaceWeekTitle}
|
||||
disabled={platformLoading}
|
||||
onOpen={() => onRunningOpen(platform)}
|
||||
onClose={() => onRunningClose(platform)}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{runningPlatforms.length > 0 && (
|
||||
<div className="mb-3 h-px bg-[#e5e8ef]" />
|
||||
)}
|
||||
<PlatformFilterTabs
|
||||
value={filter}
|
||||
counts={counts}
|
||||
onChange={onFilterChange}
|
||||
/>
|
||||
<div data-help="platform-list" className={[
|
||||
'grid content-start gap-3 overflow-y-auto pr-1',
|
||||
runningPlatforms.length > 0
|
||||
? 'min-h-[340px] max-h-[340px]'
|
||||
: 'min-h-[470px] max-h-[470px]'
|
||||
].join(' ')}>
|
||||
{filteredPlatforms.length ? filteredPlatforms.map((platform) => {
|
||||
const { id, status, action, state, iconKey } = platform
|
||||
const Icon = PLATFORM_ICONS[iconKey] ?? Monitor
|
||||
const locked = state === 'locked'
|
||||
const unavailable = isPlatformUnavailable(platform)
|
||||
const actionDisabled = locked || unavailable
|
||||
const runningInSelectionList = runningPlatforms.some((runningPlatform) => runningPlatform.id === platform.id)
|
||||
const displayStatus = unavailable && !status.includes('연결 끊김') && !status.includes('연결 불가')
|
||||
? '연결 끊김'
|
||||
: status
|
||||
const hasControl = platform.control?.status === 'ACTIVE'
|
||||
const primaryAction = hasControl ? '연결' : action
|
||||
const platformActionDisabled = runningInSelectionList || actionDisabled
|
||||
|
||||
return (
|
||||
<PlatformOptionCard
|
||||
key={id}
|
||||
platform={platform}
|
||||
Icon={Icon}
|
||||
dotClassName={getPlatformDotClass(platform)}
|
||||
unavailable={unavailable}
|
||||
displayStatus={displayStatus}
|
||||
primaryAction={primaryAction}
|
||||
actionDisabled={platformActionDisabled}
|
||||
running={runningInSelectionList}
|
||||
onAction={() => {
|
||||
if (runningInSelectionList) return
|
||||
onPlatformAction(platform)
|
||||
}}
|
||||
onSettings={() => onOpenSettings(platform)}
|
||||
/>
|
||||
)
|
||||
}) : (
|
||||
<div className="grid min-h-[220px] place-items-center rounded-lg border border-dashed border-[#d9deea] bg-[#fbfcff] px-6 text-center">
|
||||
<div>
|
||||
<strong className="block text-[15px] font-bold text-[#111520]">사용 가능한 플랫폼 데이터가 없습니다.</strong>
|
||||
<p className="mt-2 text-[13px] font-medium text-[#687284]">강의에 배정된 플랫폼을 불러오지 못했거나 아직 등록된 데이터가 없습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user