Skip to content

Commit

Permalink
Switch from idb to localStorage for data persistence
Browse files Browse the repository at this point in the history
  • Loading branch information
Gyanreyer committed Jul 7, 2023
1 parent cf8dd88 commit 0ebccec
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 90 deletions.
14 changes: 12 additions & 2 deletions src/_components/current-score.webc
Expand Up @@ -60,15 +60,25 @@
<script webc:bucket="alpine">
Alpine.data("currentScoreDot", () => ({
init() {
this.$watch("$store.game.currentScore", (currentScore) => {
const onScoreUpdated = () => {
const geniusScoreThreshold = this.$store.game.geniusScoreThreshold;

if (!geniusScoreThreshold) {
return;
}

const currentScore = this.$store.game.currentScore;
this.$el.style.left = `${
100 * Math.min(1, currentScore / geniusScoreThreshold)
}%`;
const width = `${currentScore.toString().length + 1.2}ch`;
this.$el.style.width = width;
this.$el.style.height = width;
});
};

onScoreUpdated();
this.$watch("$store.game.currentScore", onScoreUpdated);
this.$watch("$store.game.geniusScoreThreshold", onScoreUpdated);
},
}));
</script>
Expand Down
66 changes: 34 additions & 32 deletions src/_components/previous-guess-modal.webc
Expand Up @@ -34,47 +34,49 @@
guessedWordPages: [],
panagramCount: 0,
init() {
this.$watch(
"$store.game.guessedWords",
const onGuessedWordsUpdated = () => {
/**
* @param {string[]} guessedWords
* @type {string[]}
*/
(guessedWords) => {
const panagramWordList = [];
const normalWordList = [];

guessedWords.forEach((word) => {
if (this.$store.game.getIsWordPanagram(word)) {
panagramWordList.push(word);
} else {
normalWordList.push(word);
}
});
const guessedWords = this.$store.game.guessedWords;

panagramWordList.sort();
normalWordList.sort();
const panagramWordList = [];
const normalWordList = [];

const combinedWordList = panagramWordList.concat(normalWordList);
guessedWords.forEach((word) => {
if (this.$store.game.getIsWordPanagram(word)) {
panagramWordList.push(word);
} else {
normalWordList.push(word);
}
});

const wordCount = combinedWordList.length;
panagramWordList.sort();
normalWordList.sort();

const pageCount = Math.ceil(wordCount / this.maxPageSize);
const guessedWordPages = new Array(pageCount);
const combinedWordList = panagramWordList.concat(normalWordList);

for (let i = 0; i < pageCount; ++i) {
guessedWordPages[i] = {
id: Math.random().toString(36),
words: combinedWordList.slice(
i * this.maxPageSize,
(i + 1) * this.maxPageSize
),
};
}
const wordCount = combinedWordList.length;

this.panagramCount = panagramWordList.length;
this.guessedWordPages = guessedWordPages;
const pageCount = Math.ceil(wordCount / this.maxPageSize);
const guessedWordPages = new Array(pageCount);

for (let i = 0; i < pageCount; ++i) {
guessedWordPages[i] = {
id: Math.random().toString(36),
words: combinedWordList.slice(
i * this.maxPageSize,
(i + 1) * this.maxPageSize
),
};
}
);

this.panagramCount = panagramWordList.length;
this.guessedWordPages = guessedWordPages;
};

onGuessedWordsUpdated();
this.$watch("$store.game.guessedWords", onGuessedWordsUpdated);

const wordPageWrapper = document.getElementById("word-page-wrapper");

Expand Down
11 changes: 8 additions & 3 deletions src/_components/previous-guesses.webc
Expand Up @@ -24,9 +24,14 @@
this.isInitialRender = false;
});

this.$watch("$store.game.guessedWords", (guessedWords) => {
this.mostRecentGuesses = guessedWords.slice().reverse();
});
const onGuessedWordsUpdated = () => {
this.mostRecentGuesses = this.$store.game.guessedWords
.slice()
.reverse();
};
onGuessedWordsUpdated();

this.$watch("$store.game.guessedWords", onGuessedWordsUpdated);
},
tmpl: {
"@click"() {
Expand Down
9 changes: 6 additions & 3 deletions src/_components/win-modal.webc
Expand Up @@ -26,12 +26,15 @@
window.fireConfetti("win-confetti");
},
init() {
// Open the win modal when the user reaches genius or master rank
this.$watch("$store.game.currentRank", () => {
const onCurrentRankUpdated = () => {
// Open the win modal when the user reaches genius or master rank
if (this.$store.game.isGenius) {
this.showModal();
}
});
};

onCurrentRankUpdated();
this.$watch("$store.game.currentRank", onCurrentRankUpdated);
},
}));
</script>
Expand Down
93 changes: 45 additions & 48 deletions src/js/game.mjs
Expand Up @@ -15,19 +15,6 @@ function shuffleArray(array) {
return arrayCopy;
}

const importIdb = import("https://cdn.jsdelivr.net/npm/idb@7/+esm");

async function openGameDB() {
const { openDB } = await importIdb;
return openDB("SpellingBee", 1, {
upgrade(db) {
db.createObjectStore("dailyGames", {
keyPath: "timestamp",
});
},
});
}

/**
* Loads our en.json word data set
*
Expand All @@ -46,6 +33,8 @@ async function loadWordData() {
);
}

const ONE_DAY_TIMESTAMP_MS = 86400000;

const GENIUS_PERCENT_THRESHOLD = 0.7;

const validWordSet = new Set();
Expand Down Expand Up @@ -148,11 +137,17 @@ Alpine.store("game", {

return wordLengthScore + this.getIsWordPanagram(word) * 7;
},
async syncWithDB() {
getTodayTimestampString() {
return this.timestamp.toString();
},
getYesterdayTimestampString() {
return (this.timestamp - ONE_DAY_TIMESTAMP_MS).toString();
},
async syncWithLocalStorage() {
try {
const gameDB = await openGameDB();
const gameData = await gameDB.get("dailyGames", this.timestamp);
gameDB.close();
const gameData = JSON.parse(
localStorage.getItem(this.getTodayTimestampString())
);

if (gameData) {
this.updateLetterSet(gameData.centerLetter, gameData.outerLetters);
Expand All @@ -169,7 +164,7 @@ Alpine.store("game", {
currentScore += this.getWordScore(word);
}
this.updateScore(currentScore);
this.updateDB();
this.updateLocalStorage();
} else {
await this.getNewLetterSet(this.timestamp);
}
Expand All @@ -181,29 +176,34 @@ Alpine.store("game", {
await this.getNewLetterSet(this.timestamp);
}
},
updateDB() {
updateLocalStorage() {
queueMicrotask(() => {
const timestamp = this.timestamp;
const centerLetter = this.centerLetter;
const outerLetters = this.outerLetters.slice();
const validWords = this.validWords.slice();
const guessedWords = this.guessedWords.slice();

openGameDB()
.then((gameDB) =>
gameDB
.put("dailyGames", {
timestamp,
centerLetter,
outerLetters,
validWords,
guessedWords,
})
.then(() => gameDB.close())
)
.catch((e) => console.error("Error updating DB", e));
localStorage.setItem(
this.getTodayTimestampString(),
JSON.stringify({
centerLetter: this.centerLetter,
outerLetters: this.outerLetters,
validWords: this.validWords,
guessedWords: this.guessedWords,
})
);
});
},
cleanUpLocalStorage() {
const todayTimestampString = this.getTodayTimestampString();
const yesterdayTimestampString = this.getYesterdayTimestampString();

for (let i = localStorage.length; i >= 0; --i) {
const key = localStorage.key(i);
if (
// Remove all entries that aren't for today or yesterday
key !== todayTimestampString &&
key !== yesterdayTimestampString
) {
localStorage.removeItem(key);
}
}
},
updateLetterSet(centerLetter, outerLetters) {
this.centerLetter = centerLetter;
this.outerLetters = outerLetters;
Expand All @@ -228,13 +228,9 @@ Alpine.store("game", {
);
},
async getPreviousGame() {
const yesterdayTimestamp = this.timestamp - 86400000;
const gameDB = await openGameDB();
const yesterdayGameData = await gameDB.get(
"dailyGames",
yesterdayTimestamp
const yesterdayGameData = JSON.parse(
localStorage.getItem(this.getYesterdayTimestampString())
);
gameDB.close();

if (yesterdayGameData) {
const guessedWordSet = new Set(yesterdayGameData.guessedWords);
Expand Down Expand Up @@ -290,12 +286,13 @@ Alpine.store("game", {
today.setHours(0, 0, 0, 0);
this.timestamp = today.getTime();

this.syncWithDB();
this.syncWithLocalStorage();
this.getPreviousGame();
this.cleanUpLocalStorage();

window.addEventListener("visibilitychange", () => {
if (document.visibilityState === "visible") {
this.syncWithDB();
this.syncWithLocalStorage();
}
});
},
Expand Down Expand Up @@ -393,7 +390,7 @@ Alpine.store("game", {
if (isValid) {
guessedWordSet.add(sanitizedWord);
this.guessedWords.push(sanitizedWord);
this.updateDB();
this.updateLocalStorage();

this.updateScore(this.currentScore + score);

Expand Down Expand Up @@ -464,6 +461,6 @@ Alpine.store("game", {
guessedWordSet.clear();
this.updateScore(0);

this.updateDB();
this.updateLocalStorage();
},
});
3 changes: 1 addition & 2 deletions src/pwa/serviceWorker.js
@@ -1,11 +1,10 @@
const cacheName = "open-spelling-bee-1.3.1";
const cacheName = "open-spelling-bee-1.3.2";
const cacheFiles = [
"/",
"/index.html",
"/words/en.json.gz",
// 3rd party libraries
"https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/module.esm.js/+esm",
"https://cdn.jsdelivr.net/npm/idb@7/+esm",
"https://cdn.jsdelivr.net/npm/tsparticles-confetti@2.9.3/tsparticles.confetti.bundle.min.js/+esm",
];

Expand Down

0 comments on commit 0ebccec

Please sign in to comment.