調整設定隊伍流程並支援勝利分數設定

This commit is contained in:
2026-04-16 08:53:05 +08:00
parent e903d3ae52
commit a1e0e0f16e
4 changed files with 399 additions and 129 deletions

View File

@@ -17,11 +17,11 @@ import { HistoryPage } from './pages/HistoryPage'
import { ScoreboardPage } from './pages/ScoreboardPage'
import { TeamSelectionPage } from './pages/TeamSelectionPage'
import type {
ActiveMatchup,
GroupTeam,
HistoryUploadPayload,
LoadStatus,
MatchHistoryItem,
Matchup,
PointHistoryEntry,
RoundGroup,
ScoreSide,
@@ -75,9 +75,9 @@ function App() {
const [loadStatus, setLoadStatus] = useState<LoadStatus>('idle')
const [loadMessage, setLoadMessage] = useState('')
const [selectedGroupId, setSelectedGroupId] = useState<number | null>(null)
const [matchup, setMatchup] = useState<Matchup>({
leftTeamId: null,
rightTeamId: null,
const [activeMatchup, setActiveMatchup] = useState<ActiveMatchup>({
leftTeam: null,
rightTeam: null,
})
const [scoreState, setScoreState] = useState<ScoreState>(initialScoreState)
const [scoreHistory, setScoreHistory] = useState<ScoreSnapshot[]>([])
@@ -94,10 +94,8 @@ function App() {
const parsedAreaA = useMemo(() => parseRoster(areaAInput), [areaAInput])
const parsedAreaB = useMemo(() => parseRoster(areaBInput), [areaBInput])
const selectedGroup = groups.find((group) => group.id === selectedGroupId) ?? null
const leftTeam =
selectedGroup?.teams.find((team) => team.id === matchup.leftTeamId) ?? null
const rightTeam =
selectedGroup?.teams.find((team) => team.id === matchup.rightTeamId) ?? null
const leftTeam = activeMatchup.leftTeam
const rightTeam = activeMatchup.rightTeam
useEffect(() => {
window.localStorage.setItem(STORAGE_KEYS.targetDate, targetDate)
@@ -132,19 +130,26 @@ function App() {
const secondTeam = nextGroup?.teams[1] ?? null
setSelectedGroupId(nextGroup?.id ?? null)
setMatchup({
leftTeamId: firstTeam?.id ?? null,
rightTeamId: secondTeam?.id ?? null,
setActiveMatchup({
leftTeam: firstTeam,
rightTeam: secondTeam,
})
resetScoring()
}
const applyMatchup = (leftTeamId: number, rightTeamId: number) => {
setMatchup({
leftTeamId,
rightTeamId,
const applyMatchup = (
leftTeam: GroupTeam,
rightTeam: GroupTeam,
targetScore: number,
) => {
setActiveMatchup({
leftTeam,
rightTeam,
})
resetScoring({
...initialScoreState,
targetScore,
})
resetScoring()
}
const loadGroupsFromDb = async () => {
@@ -163,7 +168,7 @@ function App() {
if (!record) {
setGroups([])
setSelectedGroupId(null)
setMatchup({ leftTeamId: null, rightTeamId: null })
setActiveMatchup({ leftTeam: null, rightTeam: null })
setGroupSource('idle')
setLoadStatus('empty')
setLoadMessage('指定日期沒有資料,請改用手動配對。')
@@ -181,7 +186,7 @@ function App() {
} catch (error) {
setGroups([])
setSelectedGroupId(null)
setMatchup({ leftTeamId: null, rightTeamId: null })
setActiveMatchup({ leftTeam: null, rightTeam: null })
setGroupSource('idle')
setLoadStatus('error')
setLoadMessage(error instanceof Error ? error.message : '讀取資料失敗。')
@@ -192,7 +197,7 @@ function App() {
if (parsedAreaA.length === 0 || parsedAreaB.length === 0) {
setGroups([])
setSelectedGroupId(null)
setMatchup({ leftTeamId: null, rightTeamId: null })
setActiveMatchup({ leftTeam: null, rightTeam: null })
setGroupSource('idle')
setLoadStatus('error')
setLoadMessage('A 區與 B 區至少都要有 1 位成員。')
@@ -212,9 +217,9 @@ function App() {
return
}
setMatchup((current) => ({
leftTeamId: current.rightTeamId,
rightTeamId: current.leftTeamId,
setActiveMatchup((current) => ({
leftTeam: current.rightTeam,
rightTeam: current.leftTeam,
}))
setScoreState((current) => ({
@@ -487,13 +492,13 @@ function App() {
path="/scoreboard"
element={
<ScoreboardPage
currentSelectionOrder={getSelectionOrder(leftTeam, rightTeam)}
finishDialogError={settlement.error}
finishDialogOpen={settlement.open}
finishDialogUploading={settlement.uploading}
groupSource={groupSource}
hasRecordedPoint={pointLog.length > 0}
leftTeam={leftTeam}
matchup={matchup}
rightTeam={rightTeam}
scoreState={scoreState}
selectedGroup={selectedGroup}
@@ -587,6 +592,19 @@ function formatPlayedAt(timestamp: number) {
return new Date(timestamp * 1000).toLocaleString('zh-TW', { hour12: false })
}
function getSelectionOrder(leftTeam: GroupTeam | null, rightTeam: GroupTeam | null) {
if (!leftTeam || !rightTeam) {
return []
}
return [
leftTeam.playerA,
leftTeam.playerB,
rightTeam.playerB,
rightTeam.playerA,
].filter((name) => name.trim().length > 0)
}
function loadStoredText(storageKey: string, fallback: string) {
const value = window.localStorage.getItem(storageKey)
return value && value.trim() ? value : fallback