2026-04-16 10:55:41 +08:00
|
|
|
|
import { Link } from 'react-router-dom'
|
2026-04-15 22:56:50 +08:00
|
|
|
|
import { getTeamDisplayName } from '../lib/match'
|
|
|
|
|
|
import type { LoadStatus, RoundGroup } from '../types'
|
|
|
|
|
|
|
|
|
|
|
|
type TeamSelectionPageProps = {
|
|
|
|
|
|
areaAInput: string
|
|
|
|
|
|
areaBInput: string
|
|
|
|
|
|
groups: RoundGroup[]
|
|
|
|
|
|
groupSource: 'idle' | 'db' | 'manual'
|
|
|
|
|
|
loadMessage: string
|
|
|
|
|
|
loadStatus: LoadStatus
|
|
|
|
|
|
selectedGroupId: number | null
|
|
|
|
|
|
targetDate: string
|
|
|
|
|
|
onAreaAInputChange: (value: string) => void
|
|
|
|
|
|
onAreaBInputChange: (value: string) => void
|
|
|
|
|
|
onGenerateManualGroups: () => void
|
|
|
|
|
|
onLoadGroupsFromDb: () => void
|
|
|
|
|
|
onTargetDateChange: (value: string) => void
|
|
|
|
|
|
onUseGroup: (groupId: number) => void
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function TeamSelectionPage({
|
|
|
|
|
|
areaAInput,
|
|
|
|
|
|
areaBInput,
|
|
|
|
|
|
groups,
|
|
|
|
|
|
groupSource,
|
|
|
|
|
|
loadMessage,
|
|
|
|
|
|
loadStatus,
|
|
|
|
|
|
selectedGroupId,
|
|
|
|
|
|
targetDate,
|
|
|
|
|
|
onAreaAInputChange,
|
|
|
|
|
|
onAreaBInputChange,
|
|
|
|
|
|
onGenerateManualGroups,
|
|
|
|
|
|
onLoadGroupsFromDb,
|
|
|
|
|
|
onTargetDateChange,
|
|
|
|
|
|
onUseGroup,
|
|
|
|
|
|
}: TeamSelectionPageProps) {
|
2026-04-16 10:55:41 +08:00
|
|
|
|
const hasGroups = groups.length > 0
|
|
|
|
|
|
const showInlineStatus = loadStatus !== 'idle' && loadStatus !== 'loaded' && Boolean(loadMessage)
|
|
|
|
|
|
const sourceLabel =
|
|
|
|
|
|
groupSource === 'db' ? '資料庫載入' : groupSource === 'manual' ? '手動產生' : '尚未建立'
|
2026-04-15 22:56:50 +08:00
|
|
|
|
|
|
|
|
|
|
return (
|
2026-04-16 10:55:41 +08:00
|
|
|
|
<section className="page-grid">
|
|
|
|
|
|
{loadStatus === 'loaded' && loadMessage ? (
|
|
|
|
|
|
<div className="floating-status-bubble" role="status" aria-live="polite">
|
|
|
|
|
|
{loadMessage}
|
2026-04-15 22:56:50 +08:00
|
|
|
|
</div>
|
2026-04-16 10:55:41 +08:00
|
|
|
|
) : null}
|
2026-04-15 22:56:50 +08:00
|
|
|
|
|
|
|
|
|
|
<article className="panel">
|
2026-04-16 10:55:41 +08:00
|
|
|
|
<div className="selection-shell">
|
2026-04-15 22:56:50 +08:00
|
|
|
|
<div className="selection-toolbar">
|
|
|
|
|
|
<label className="field">
|
|
|
|
|
|
<span>指定日期</span>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="date"
|
|
|
|
|
|
value={targetDate}
|
|
|
|
|
|
onChange={(event) => onTargetDateChange(event.target.value)}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="button-stack">
|
|
|
|
|
|
<button className="primary-button" type="button" onClick={onLoadGroupsFromDb}>
|
2026-04-16 10:55:41 +08:00
|
|
|
|
從資料庫讀取
|
2026-04-15 22:56:50 +08:00
|
|
|
|
</button>
|
|
|
|
|
|
<button className="secondary-button" type="button" onClick={onGenerateManualGroups}>
|
2026-04-16 10:55:41 +08:00
|
|
|
|
手動產生分組
|
2026-04-15 22:56:50 +08:00
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-04-16 10:55:41 +08:00
|
|
|
|
{showInlineStatus ? (
|
|
|
|
|
|
<div className={`status-banner status-banner-${loadStatus}`}>{loadMessage}</div>
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
|
2026-04-15 22:56:50 +08:00
|
|
|
|
<div className="double-grid">
|
|
|
|
|
|
<label className="field">
|
|
|
|
|
|
<span>A 區名單</span>
|
|
|
|
|
|
<textarea
|
2026-04-16 10:55:41 +08:00
|
|
|
|
placeholder="每行一位球員"
|
2026-04-15 22:56:50 +08:00
|
|
|
|
value={areaAInput}
|
|
|
|
|
|
onChange={(event) => onAreaAInputChange(event.target.value)}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
|
|
|
|
|
|
<label className="field">
|
|
|
|
|
|
<span>B 區名單</span>
|
|
|
|
|
|
<textarea
|
2026-04-16 10:55:41 +08:00
|
|
|
|
placeholder="每行一位球員"
|
2026-04-15 22:56:50 +08:00
|
|
|
|
value={areaBInput}
|
|
|
|
|
|
onChange={(event) => onAreaBInputChange(event.target.value)}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="selection-hint">
|
2026-04-16 10:55:41 +08:00
|
|
|
|
<span>分組來源:{sourceLabel}</span>
|
2026-04-15 22:56:50 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</article>
|
|
|
|
|
|
|
2026-04-16 10:55:41 +08:00
|
|
|
|
<article className="panel">
|
|
|
|
|
|
<div className="group-head">
|
2026-04-15 22:56:50 +08:00
|
|
|
|
<div>
|
2026-04-16 10:55:41 +08:00
|
|
|
|
<p className="panel-kicker">Step 2</p>
|
|
|
|
|
|
<h2>選擇要上場的組別</h2>
|
2026-04-15 22:56:50 +08:00
|
|
|
|
</div>
|
2026-04-16 10:55:41 +08:00
|
|
|
|
{selectedGroupId ? <span className="winner-badge">目前第 {selectedGroupId} 組</span> : null}
|
2026-04-15 22:56:50 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-04-16 10:55:41 +08:00
|
|
|
|
<div className="group-board">
|
|
|
|
|
|
{hasGroups ? (
|
|
|
|
|
|
groups.map((group) => (
|
2026-04-15 22:56:50 +08:00
|
|
|
|
<article
|
|
|
|
|
|
key={group.id}
|
2026-04-16 10:55:41 +08:00
|
|
|
|
className={`group-card ${selectedGroupId === group.id ? 'group-card-active' : ''}`}
|
2026-04-15 22:56:50 +08:00
|
|
|
|
>
|
|
|
|
|
|
<div className="group-head">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<p className="panel-kicker">第 {group.id} 組</p>
|
2026-04-16 10:55:41 +08:00
|
|
|
|
<h3>本組對戰名單</h3>
|
2026-04-15 22:56:50 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div className="group-actions">
|
2026-04-16 10:55:41 +08:00
|
|
|
|
<Link className="primary-button inline-link" to="/scoreboard" onClick={() => onUseGroup(group.id)}>
|
|
|
|
|
|
進入記分板
|
|
|
|
|
|
</Link>
|
2026-04-15 22:56:50 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="team-stage-grid">
|
|
|
|
|
|
{group.teams.map((team) => (
|
2026-04-16 10:55:41 +08:00
|
|
|
|
<article key={`${group.id}-${team.id}`} className="team-stage-card">
|
|
|
|
|
|
<span className="team-index">隊伍 {team.id}</span>
|
|
|
|
|
|
<div className="team-name">{getTeamDisplayName(team)}</div>
|
2026-04-15 22:56:50 +08:00
|
|
|
|
</article>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</article>
|
2026-04-16 10:55:41 +08:00
|
|
|
|
))
|
|
|
|
|
|
) : (
|
|
|
|
|
|
<div className="empty-state">
|
|
|
|
|
|
<h3>目前還沒有分組</h3>
|
|
|
|
|
|
<p>先從資料庫讀取指定日期,或輸入 A、B 區名單後手動建立。</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
2026-04-15 22:56:50 +08:00
|
|
|
|
</article>
|
|
|
|
|
|
</section>
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|