106 lines
2.6 KiB
TypeScript
Raw Normal View History

import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import type { GoalProgress, GoalStatus } from '@/types/goals'
import { GOALS } from '@/data/goals'
import { useAppStore } from './app'
const STORAGE_KEY = 'archipelago-goal-progress'
export const useGoalStore = defineStore('goals', () => {
const progress = ref<Record<string, GoalProgress>>({})
function load() {
try {
const raw = localStorage.getItem(STORAGE_KEY)
if (raw) progress.value = JSON.parse(raw)
} catch {
/* ignore corrupt data */
}
}
function save() {
localStorage.setItem(STORAGE_KEY, JSON.stringify(progress.value))
}
function getGoalStatus(goalId: string): GoalStatus {
const goal = GOALS.find((g) => g.id === goalId)
if (!goal) return 'not-started'
// Goals with no required apps use manual progress tracking
if (goal.requiredApps.length === 0) {
return progress.value[goalId]?.status || 'not-started'
}
const appStore = useAppStore()
const packages = appStore.packages
const allRunning = goal.requiredApps.every((appId) =>
Object.entries(packages).some(
([pkgId, pkg]) => pkgId === appId && pkg.state === 'running',
),
)
if (allRunning) return 'completed'
const anyInstalled = goal.requiredApps.some((appId) =>
Object.keys(packages).some((pkgId) => pkgId === appId),
)
if (anyInstalled || progress.value[goalId]) return 'in-progress'
return 'not-started'
}
const goalStatuses = computed(() => {
const statuses: Record<string, GoalStatus> = {}
for (const goal of GOALS) {
statuses[goal.id] = getGoalStatus(goal.id)
}
return statuses
})
function startGoal(goalId: string) {
progress.value[goalId] = {
goalId,
status: 'in-progress',
currentStepIndex: 0,
completedSteps: [],
startedAt: Date.now(),
}
save()
}
function completeStep(goalId: string, stepId: string) {
const p = progress.value[goalId]
if (!p) return
if (!p.completedSteps.includes(stepId)) {
p.completedSteps.push(stepId)
}
const goal = GOALS.find((g) => g.id === goalId)
if (goal && p.completedSteps.length >= goal.steps.length) {
p.status = 'completed'
} else {
p.currentStepIndex = Math.min(p.currentStepIndex + 1, (goal?.steps.length ?? 1) - 1)
}
save()
}
function resetGoal(goalId: string) {
delete progress.value[goalId]
save()
}
// Load on store creation
load()
return {
progress,
goalStatuses,
getGoalStatus,
startGoal,
completeStep,
resetGoal,
}
})