124 lines
4.8 KiB
TypeScript
124 lines
4.8 KiB
TypeScript
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={['h-full min-h-0 w-1/2 shrink-0 overflow-y-auto px-6 pb-5 pt-3 pr-5 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">
|
|
{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>
|
|
)
|
|
}
|