197 lines
6.2 KiB
TypeScript
197 lines
6.2 KiB
TypeScript
|
|
import { useNavigate } from 'react-router-dom'
|
|||
|
|
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
|
|||
|
|
parsedAreaA: string[]
|
|||
|
|
parsedAreaB: string[]
|
|||
|
|
selectedGroupId: number | null
|
|||
|
|
targetDate: string
|
|||
|
|
onAreaAInputChange: (value: string) => void
|
|||
|
|
onAreaBInputChange: (value: string) => void
|
|||
|
|
onGenerateManualGroups: () => void
|
|||
|
|
onLoadGroupsFromDb: () => void
|
|||
|
|
onSelectGroup: (groupId: number) => void
|
|||
|
|
onTargetDateChange: (value: string) => void
|
|||
|
|
onUseGroup: (groupId: number) => void
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function TeamSelectionPage({
|
|||
|
|
areaAInput,
|
|||
|
|
areaBInput,
|
|||
|
|
groups,
|
|||
|
|
groupSource,
|
|||
|
|
loadMessage,
|
|||
|
|
loadStatus,
|
|||
|
|
parsedAreaA,
|
|||
|
|
parsedAreaB,
|
|||
|
|
selectedGroupId,
|
|||
|
|
targetDate,
|
|||
|
|
onAreaAInputChange,
|
|||
|
|
onAreaBInputChange,
|
|||
|
|
onGenerateManualGroups,
|
|||
|
|
onLoadGroupsFromDb,
|
|||
|
|
onSelectGroup,
|
|||
|
|
onTargetDateChange,
|
|||
|
|
onUseGroup,
|
|||
|
|
}: TeamSelectionPageProps) {
|
|||
|
|
const navigate = useNavigate()
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<section className="selection-shell">
|
|||
|
|
<article className="panel panel-hero selection-hero">
|
|||
|
|
<div>
|
|||
|
|
<p className="panel-kicker">步驟 1</p>
|
|||
|
|
<h2>載入分組與選擇組別</h2>
|
|||
|
|
<p className="panel-copy">
|
|||
|
|
先用日期從 DB 讀取分組;如果指定日期沒有資料,就改用 A 區與 B 區名單手動產生配對。
|
|||
|
|
</p>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div className="summary-grid">
|
|||
|
|
<article className="mini-stat">
|
|||
|
|
<span>A 區隊數</span>
|
|||
|
|
<strong>{parsedAreaA.length}</strong>
|
|||
|
|
</article>
|
|||
|
|
<article className="mini-stat">
|
|||
|
|
<span>B 區隊數</span>
|
|||
|
|
<strong>{parsedAreaB.length}</strong>
|
|||
|
|
</article>
|
|||
|
|
<article className="mini-stat">
|
|||
|
|
<span>目前組數</span>
|
|||
|
|
<strong>{groups.length}</strong>
|
|||
|
|
</article>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{loadMessage ? (
|
|||
|
|
<p className={`status-banner status-banner-${loadStatus}`}>{loadMessage}</p>
|
|||
|
|
) : null}
|
|||
|
|
</article>
|
|||
|
|
|
|||
|
|
<article className="panel">
|
|||
|
|
<div className="selection-form">
|
|||
|
|
<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}>
|
|||
|
|
讀取指定日期
|
|||
|
|
</button>
|
|||
|
|
<button className="secondary-button" type="button" onClick={onGenerateManualGroups}>
|
|||
|
|
手動產生配對
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div className="double-grid">
|
|||
|
|
<label className="field">
|
|||
|
|
<span>A 區名單</span>
|
|||
|
|
<textarea
|
|||
|
|
rows={8}
|
|||
|
|
value={areaAInput}
|
|||
|
|
onChange={(event) => onAreaAInputChange(event.target.value)}
|
|||
|
|
placeholder={'每行一隊,例如:\n柏威'}
|
|||
|
|
/>
|
|||
|
|
</label>
|
|||
|
|
|
|||
|
|
<label className="field">
|
|||
|
|
<span>B 區名單</span>
|
|||
|
|
<textarea
|
|||
|
|
rows={8}
|
|||
|
|
value={areaBInput}
|
|||
|
|
onChange={(event) => onAreaBInputChange(event.target.value)}
|
|||
|
|
placeholder={'每行一隊,例如:\nRURU'}
|
|||
|
|
/>
|
|||
|
|
</label>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div className="selection-hint">
|
|||
|
|
<span>
|
|||
|
|
來源:
|
|||
|
|
{groupSource === 'db' ? 'DB' : groupSource === 'manual' ? '手動配對' : '尚未載入'}
|
|||
|
|
</span>
|
|||
|
|
<span>從下方選擇要帶進記分板的第幾組。</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</article>
|
|||
|
|
|
|||
|
|
<article className="panel full-span">
|
|||
|
|
<div className="panel-heading">
|
|||
|
|
<div>
|
|||
|
|
<p className="panel-kicker">步驟 2</p>
|
|||
|
|
<h2>選擇第幾組帶進記分板</h2>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{groups.length === 0 ? (
|
|||
|
|
<div className="empty-state">
|
|||
|
|
<h3>目前還沒有分組</h3>
|
|||
|
|
<p>先讀取指定日期資料,或手動輸入名單後產生配對。</p>
|
|||
|
|
</div>
|
|||
|
|
) : (
|
|||
|
|
<div className="group-board">
|
|||
|
|
{groups.map((group) => (
|
|||
|
|
<article
|
|||
|
|
className={
|
|||
|
|
group.id === selectedGroupId
|
|||
|
|
? 'group-card group-card-active group-card-stage'
|
|||
|
|
: 'group-card group-card-stage'
|
|||
|
|
}
|
|||
|
|
key={group.id}
|
|||
|
|
>
|
|||
|
|
<div className="group-head">
|
|||
|
|
<div>
|
|||
|
|
<p className="panel-kicker">第 {group.id} 組</p>
|
|||
|
|
<h3>{group.teams.length} 隊可選</h3>
|
|||
|
|
</div>
|
|||
|
|
<div className="group-actions">
|
|||
|
|
<button
|
|||
|
|
className="secondary-button"
|
|||
|
|
type="button"
|
|||
|
|
onClick={() => onSelectGroup(group.id)}
|
|||
|
|
>
|
|||
|
|
先選這組
|
|||
|
|
</button>
|
|||
|
|
<button
|
|||
|
|
className="primary-button"
|
|||
|
|
type="button"
|
|||
|
|
onClick={() => {
|
|||
|
|
onUseGroup(group.id)
|
|||
|
|
navigate('/scoreboard')
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
帶進記分板
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div className="team-stage-grid">
|
|||
|
|
{group.teams.map((team) => (
|
|||
|
|
<article className="team-stage-card" key={`${group.id}-${team.id}`}>
|
|||
|
|
<span className="team-index">第 {team.id} 隊</span>
|
|||
|
|
<p className="team-name">{getTeamDisplayName(team)}</p>
|
|||
|
|
</article>
|
|||
|
|
))}
|
|||
|
|
</div>
|
|||
|
|
</article>
|
|||
|
|
))}
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
</article>
|
|||
|
|
</section>
|
|||
|
|
)
|
|||
|
|
}
|