better buttonboxing

This commit is contained in:
legop3
2026-06-29 02:18:53 -04:00
parent 8843bd6acf
commit f118f6456a
22 changed files with 350 additions and 76 deletions
+45 -1
View File
@@ -22,8 +22,12 @@ function createButtonBoxStore(deps) {
count: 0,
rewardId: null,
rewardName: null,
rewardDescription: null,
dailyLimited: false,
rewardNumber: null,
goal: null,
dailyDate: null,
dailyCount: 0,
lastIncrementAt: null,
lastRewardAt: null,
};
@@ -67,9 +71,18 @@ function createButtonBoxStore(deps) {
button.rewardId = reward.id;
button.rewardName = reward.name || null;
button.rewardDescription = reward.description || null;
button.dailyLimited = reward.dailyLimited === true;
button.rewardNumber = reward.number;
button.goal = reward.goal;
button.count = 0;
/*
A new reward starts a fresh earning window for the button. Resetting the
daily bucket here prevents leftover progress from the previous reward from
making the newly assigned reward appear capped before anyone presses it.
*/
button.dailyDate = null;
button.dailyCount = 0;
}
function ensureRewardAssignments() {
@@ -80,11 +93,19 @@ function createButtonBoxStore(deps) {
if (reward && !seen.has(reward.id)) {
seen.add(reward.id);
button.rewardName = reward.name || null;
button.rewardDescription = reward.description || null;
button.dailyLimited = reward.dailyLimited === true;
button.rewardNumber = reward.number;
button.goal = reward.goal;
if (!Number.isFinite(button.count) || button.count < 0) {
button.count = 0;
}
if (typeof button.dailyDate !== 'string' || !button.dailyDate) {
button.dailyDate = null;
}
if (!Number.isFinite(button.dailyCount) || button.dailyCount < 0) {
button.dailyCount = 0;
}
return;
}
assignNewReward(button);
@@ -104,8 +125,12 @@ function createButtonBoxStore(deps) {
count: Number.isFinite(loaded.count) ? Math.max(0, Math.floor(loaded.count)) : 0,
rewardId: typeof loaded.rewardId === 'string' ? loaded.rewardId : null,
rewardName: typeof loaded.rewardName === 'string' ? loaded.rewardName : null,
rewardDescription: typeof loaded.rewardDescription === 'string' ? loaded.rewardDescription : null,
dailyLimited: loaded.dailyLimited === true,
rewardNumber: Number.isFinite(loaded.rewardNumber) ? Math.floor(loaded.rewardNumber) : null,
goal: Number.isFinite(loaded.goal) ? Math.max(1, Math.floor(loaded.goal)) : null,
dailyDate: typeof loaded.dailyDate === 'string' && loaded.dailyDate ? loaded.dailyDate : null,
dailyCount: Number.isFinite(loaded.dailyCount) ? Math.max(0, Math.floor(loaded.dailyCount)) : 0,
lastIncrementAt: Number.isFinite(loaded.lastIncrementAt) ? loaded.lastIncrementAt : null,
lastRewardAt: Number.isFinite(loaded.lastRewardAt) ? loaded.lastRewardAt : null,
};
@@ -153,8 +178,27 @@ function createButtonBoxStore(deps) {
return state;
}
function getDailyLimit(button) {
/*
The persisted file stores only the source values. The public snapshot adds
this derived limit so clients can render daily status without duplicating
button-box reward math in React components.
*/
if (button?.dailyLimited !== true) {
return null;
}
const goal = Number.isFinite(button?.goal) ? Math.max(1, Math.floor(button.goal)) : 1;
return Math.max(1, Math.ceil(goal / 5));
}
function getStateClone() {
return clone({ buttons: getState().buttons });
const current = getState();
return clone({
buttons: current.buttons.map((button) => ({
...button,
dailyLimit: getDailyLimit(button),
})),
});
}
return {