diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 230093f..373fe03 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -43,7 +43,7 @@ function makeDefaultState(players) { }; } -function applyAutoResets(raw, players) { +function applyAutoResets(raw, players, weekStartDay = 1) { const state = { ...makeDefaultState(players), ...raw }; // migrate old points field to gold @@ -137,9 +137,9 @@ function applyAutoResets(raw, players) { changed = true; } - if (state.weekKey !== weekKey()) { + if (state.weekKey !== weekKey(weekStartDay)) { state.weeklyDone = {}; - state.weekKey = weekKey(); + state.weekKey = weekKey(weekStartDay); state.weeklyGold = Object.fromEntries(players.map(p => [p.id, 0])); changed = true; } @@ -248,7 +248,7 @@ export default function App() { const stateRes = await fetch(`${API}/state`); const fetched = await stateRes.json(); - const { state: after, changed, penaltyMsgs } = applyAutoResets(fetched, cfg.players); + const { state: after, changed, penaltyMsgs } = applyAutoResets(fetched, cfg.players, cfg.weekStartDay ?? 1); if (changed) { await fetch(`${API}/state`, { @@ -273,7 +273,7 @@ export default function App() { try { const res = await fetch(`${API}/state`); const fetched = await res.json(); - const { state: after, changed } = applyAutoResets(fetched, players); + const { state: after, changed } = applyAutoResets(fetched, players, config?.weekStartDay ?? 1); if (changed) await saveState(after); setServerState(after); } catch (e) { @@ -677,7 +677,7 @@ export default function App() { const handleSetupComplete = useCallback(async (wizardConfig) => { const freshState = makeDefaultState(wizardConfig.players); - const { state: after } = applyAutoResets(freshState, wizardConfig.players); + const { state: after } = applyAutoResets(freshState, wizardConfig.players, wizardConfig.weekStartDay ?? 1); await Promise.all([ fetch(`${API}/config`, { method: 'POST', diff --git a/frontend/src/components/SetupWizard.jsx b/frontend/src/components/SetupWizard.jsx index 29843a6..4d3927a 100644 --- a/frontend/src/components/SetupWizard.jsx +++ b/frontend/src/components/SetupWizard.jsx @@ -110,7 +110,7 @@ function StepWelcome({ onNext }) {
QUESTBOARD

- Turn household chores into a pixel art RPG adventure. Each family member gets a hero and fights a monster every day — complete chores to deal damage and earn gold. + Turn household chores into a pixel art RPG adventure. Each family member gets a hero and fights a monster every day - complete chores to deal damage and earn gold.

@@ -222,7 +222,7 @@ function StepPlayerSetup({ player, playerIdx, total, onChange, onNext, onBack, o
Hero {playerIdx + 1} of {total} - {player.name && — {player.name}} + {player.name && - {player.name}}
{!canAdvance && ( @@ -342,7 +342,7 @@ function ChoreSection({ players, enabledChores, onToggle, choreOverrides, onOver { e.stopPropagation(); const next = WHO_CYCLE[(WHO_CYCLE.indexOf(who) + 1) % WHO_CYCLE.length]; onOverride(chore.id, { ...ov, who: next }); }} /> + ))} +
Retro CRT overlay effect
@@ -713,9 +725,24 @@ function TabPowerUps({ powerUpSettings, onChange }) { } // ── Edit tab: Display ───────────────────────────────────────────────────────── -function TabDisplay({ crtEnabled, onToggleCrt, uiScale, onChangeUiScale, animatedBg, onToggleAnimatedBg }) { +function TabDisplay({ crtEnabled, onToggleCrt, uiScale, onChangeUiScale, animatedBg, onToggleAnimatedBg, weekStartDay, onChangeWeekStartDay }) { return (
+
+
WEEK STARTS ON
+
+ {[{ id: 1, label: 'Monday' }, { id: 0, label: 'Sunday' }].map(opt => ( + + ))} +
+
Controls when weekly chores and gold reset
+
CRT EFFECT
@@ -781,6 +808,7 @@ export default function SetupWizard({ onComplete, onCancel, initialConfig }) { const [crtEnabled, setCrtEnabled] = useState(initialConfig?.crtEnabled ?? true); const [uiScale, setUiScale] = useState(initialConfig?.uiScale ?? 'mini'); const [animatedBg, setAnimatedBg] = useState(initialConfig?.animatedBg ?? true); + const [weekStartDay, setWeekStartDay] = useState(initialConfig?.weekStartDay ?? 1); const [powerUpSettings, setPowerUpSettings] = useState( initialConfig?.powerUpSettings ?? { ...DEFAULT_POWER_UP_SETTINGS } ); @@ -852,6 +880,7 @@ export default function SetupWizard({ onComplete, onCancel, initialConfig }) { crtEnabled, uiScale, animatedBg, + weekStartDay, powerUpSettings, }); } @@ -924,6 +953,7 @@ export default function SetupWizard({ onComplete, onCancel, initialConfig }) { crtEnabled={crtEnabled} onToggleCrt={() => setCrtEnabled(v => !v)} uiScale={uiScale} onChangeUiScale={setUiScale} animatedBg={animatedBg} onToggleAnimatedBg={() => setAnimatedBg(v => !v)} + weekStartDay={weekStartDay} onChangeWeekStartDay={setWeekStartDay} /> )}
@@ -999,6 +1029,8 @@ export default function SetupWizard({ onComplete, onCancel, initialConfig }) { onChangeUiScale={setUiScale} animatedBg={animatedBg} onToggleAnimatedBg={() => setAnimatedBg(v => !v)} + weekStartDay={weekStartDay} + onChangeWeekStartDay={setWeekStartDay} /> )}
diff --git a/frontend/src/logic.js b/frontend/src/logic.js index 8a4e71b..86a886d 100644 --- a/frontend/src/logic.js +++ b/frontend/src/logic.js @@ -202,10 +202,12 @@ export function todayKey() { return `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`; } -export function weekKey() { +export function weekKey(weekStartDay = 1) { const d = new Date(); const s = new Date(d); - s.setDate(d.getDate() - d.getDay()); + const dow = d.getDay(); + const diff = (dow - weekStartDay + 7) % 7; + s.setDate(d.getDate() - diff); return `${s.getFullYear()}-${s.getMonth()}-${s.getDate()}`; } diff --git a/questboard/DOCS.md b/questboard/DOCS.md index 16f6a6e..bb2e391 100644 --- a/questboard/DOCS.md +++ b/questboard/DOCS.md @@ -6,11 +6,11 @@ A pixel art RPG-themed chore tracker for the whole family. Complete household ch When you open Questboard for the first time, a setup wizard will guide you through: -1. **Add players** (1–6) — enter names and choose difficulty - - **Easy mode** — kid-appropriate chores, lower monster HP - - **Hard mode** — full adult chore list, tougher monsters -2. **Pick an avatar and class** — Knight, Sorceress, Ranger, and more -3. **Choose chores** — toggle individual chores on/off, add custom ones +1. **Add players** (1–6) - enter names and choose difficulty + - **Easy mode** - kid-appropriate chores, lower monster HP + - **Hard mode** - full adult chore list, tougher monsters +2. **Pick an avatar and class** - Knight, Sorceress, Ranger, and more +3. **Choose chores** - toggle individual chores on/off, add custom ones 4. **Start your adventure!** You can return to settings any time to add players, change chores, or adjust difficulty. @@ -18,7 +18,7 @@ You can return to settings any time to add players, change chores, or adjust dif ## How to Play - Tap a **player card** to select your hero -- Tap any **chore** to complete it — this deals damage to your monster +- Tap any **chore** to complete it - this deals damage to your monster - Fill the monster's HP bar to zero before midnight to **earn gold** - If you don't defeat it, the monster **attacks** and you lose gold - Spend gold in the **Reward Shop** on treats your family has agreed on @@ -35,7 +35,7 @@ Each chore has a chance to deal **double damage** (crit). Your base crit chance | Weekly | Every Sunday | | Monthly | 1st of each month | -XP and levels never reset — they carry over forever. +XP and levels never reset - they carry over forever. ## Support