File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
import { useState } from 'react'
import type { Org } from '../api/client'
import StatusBadge, { STATUS_DOT, STATUS_LABELS } from './StatusBadge'
interface Props {
orgs: Org[]
selectedId: number | null
onSelect: (id: number) => void
collapsed?: boolean
onToggle?: () => void
}
function Chevron({ left }: { left: boolean }) {
return (
<svg
className="h-4 w-4"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
{left ? <path d="M15 18l-6-6 6-6" /> : <path d="M9 18l6-6-6-6" />}
</svg>
)
}
export default function OrgList({ orgs, selectedId, onSelect, collapsed = false, onToggle }: Props) {
const [keyword, setKeyword] = useState('')
const visible = orgs.filter((org) => org.orgName.includes(keyword))
if (collapsed) {
// 접힌 상태: 연번 + 상태 점만. 이름은 툴팁으로 확인한다.
return (
<div className="flex h-full flex-col overflow-hidden">
<div className="flex justify-center border-b border-gray-200 p-2">
<button
type="button"
onClick={onToggle}
aria-label="기관 목록 펼치기"
title="기관 목록 펼치기"
className="rounded-md p-1.5 text-gray-500 hover:bg-gray-100"
>
<Chevron left={false} />
</button>
</div>
<ul className="flex-1 overflow-y-auto">
{orgs.map((org) => (
<li key={org.id}>
<button
type="button"
onClick={() => onSelect(org.id)}
title={`${org.orgNo} ${org.orgName} (${STATUS_LABELS[org.status]})`}
aria-label={`${org.orgNo} ${org.orgName}`}
className={`flex w-full flex-col items-center gap-1 py-2 hover:bg-gray-50 ${
selectedId === org.id ? 'bg-blue-50' : ''
}`}
>
<span className="w-14 text-center text-[11px] font-medium text-gray-600">
{org.orgNo}
</span>
<span className={`h-1.5 w-1.5 rounded-full ${STATUS_DOT[org.status]}`} />
</button>
</li>
))}
</ul>
</div>
)
}
return (
<div className="flex h-full flex-col overflow-hidden">
<div className="flex items-center gap-2 border-b border-gray-200 p-3">
<input
className="w-full min-w-0 rounded-md border border-gray-300 px-3 py-2 text-sm"
placeholder="기관명 검색"
aria-label="기관명 검색"
value={keyword}
onChange={(e) => setKeyword(e.target.value)}
/>
{onToggle && (
<button
type="button"
onClick={onToggle}
aria-label="기관 목록 접기"
title="기관 목록 접기"
className="shrink-0 rounded-md p-1.5 text-gray-500 hover:bg-gray-100"
>
<Chevron left />
</button>
)}
</div>
<ul className="flex-1 overflow-y-auto">
{visible.map((org) => (
<li key={org.id}>
<button
type="button"
onClick={() => onSelect(org.id)}
className={`flex w-full items-center gap-2 px-3 py-2 text-left hover:bg-gray-50 ${
selectedId === org.id ? 'bg-blue-50' : ''
}`}
>
<span className="w-14 shrink-0 text-xs text-gray-500">{org.orgNo}</span>
<span className="flex-1 truncate text-sm">{org.orgName}</span>
<StatusBadge status={org.status} />
</button>
</li>
))}
</ul>
</div>
)
}