Files
game-marathon/desktop/src/renderer/store/marathon.ts

124 lines
3.7 KiB
TypeScript
Raw Normal View History

2026-01-10 08:24:55 +07:00
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
import type { MarathonResponse, AssignmentResponse } from '@shared/types'
interface MarathonState {
marathons: MarathonResponse[]
selectedMarathonId: number | null
currentAssignment: AssignmentResponse | null
isLoading: boolean
error: string | null
loadMarathons: () => Promise<void>
selectMarathon: (marathonId: number) => Promise<void>
loadCurrentAssignment: () => Promise<void>
syncTime: (minutes: number) => Promise<void>
reset: () => void
}
export const useMarathonStore = create<MarathonState>()(
persist(
(set, get) => ({
marathons: [],
selectedMarathonId: null,
currentAssignment: null,
isLoading: false,
error: null,
loadMarathons: async () => {
set({ isLoading: true, error: null })
const result = await window.electronAPI.apiRequest<MarathonResponse[]>('GET', '/marathons')
if (!result.success) {
set({ isLoading: false, error: result.error || 'Failed to load marathons' })
return
}
const marathons = result.data || []
const activeMarathons = marathons.filter(m => m.status === 'active')
set({ marathons: activeMarathons, isLoading: false })
// If we have a selected marathon, verify it's still valid
const { selectedMarathonId } = get()
if (selectedMarathonId) {
const stillExists = activeMarathons.some(m => m.id === selectedMarathonId)
if (!stillExists && activeMarathons.length > 0) {
// Select first available marathon
await get().selectMarathon(activeMarathons[0].id)
} else if (stillExists) {
// Reload assignment for current selection
await get().loadCurrentAssignment()
}
} else if (activeMarathons.length > 0) {
// No selection, select first marathon
await get().selectMarathon(activeMarathons[0].id)
}
},
selectMarathon: async (marathonId: number) => {
set({ selectedMarathonId: marathonId, currentAssignment: null })
await get().loadCurrentAssignment()
},
loadCurrentAssignment: async () => {
const { selectedMarathonId } = get()
if (!selectedMarathonId) {
set({ currentAssignment: null })
return
}
const result = await window.electronAPI.apiRequest<AssignmentResponse | null>(
'GET',
`/marathons/${selectedMarathonId}/current-assignment`
)
if (result.success) {
set({ currentAssignment: result.data ?? null })
} else {
// User might not be participant of this marathon
set({ currentAssignment: null, error: result.error })
}
},
syncTime: async (minutes: number) => {
const { currentAssignment } = get()
if (!currentAssignment || currentAssignment.status !== 'active') {
return
}
const result = await window.electronAPI.apiRequest(
'PATCH',
`/assignments/${currentAssignment.id}/track-time`,
{ minutes }
)
if (result.success) {
// Update local assignment with new tracked time
set({
currentAssignment: {
...currentAssignment,
tracked_time_minutes: minutes
}
})
}
},
reset: () => {
set({
marathons: [],
selectedMarathonId: null,
currentAssignment: null,
isLoading: false,
error: null
})
}
}),
{
name: 'marathon-storage',
partialize: (state) => ({ selectedMarathonId: state.selectedMarathonId })
}
)
)