From 0ad35f44d60c9a383afb7148499ef18b862b1e95 Mon Sep 17 00:00:00 2001 From: Hannah Park Date: Fri, 14 Jan 2022 22:05:57 -0500 Subject: [PATCH] add local storage, change alerts, add share functionality --- src/App.tsx | 25 +++++++++++++++++++++- src/components/alerts/Alert.tsx | 14 ++++++++++-- src/components/modals/WinModal.tsx | 16 +++++++++++--- src/lib/localStorage.ts | 18 ++++++++++++++++ src/lib/share.ts | 34 ++++++++++++++++++++++++++++++ src/lib/words.ts | 7 ++++-- 6 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 src/lib/localStorage.ts create mode 100644 src/lib/share.ts diff --git a/src/App.tsx b/src/App.tsx index c485839..313f857 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,9 +7,15 @@ import { AboutModal } from "./components/modals/AboutModal"; import { InfoModal } from "./components/modals/InfoModal"; import { WinModal } from "./components/modals/WinModal"; import { isWordInWordList, isWinningWord, solution } from "./lib/words"; +import { + loadGameStateFromLocalStorage, + saveGameStateToLocalStorage, +} from "./lib/localStorage"; function App() { - const [guesses, setGuesses] = useState([]); + const [guesses, setGuesses] = useState( + loadGameStateFromLocalStorage()?.guesses || [] + ); const [currentGuess, setCurrentGuess] = useState(""); const [isGameWon, setIsGameWon] = useState(false); const [isWinModalOpen, setIsWinModalOpen] = useState(false); @@ -17,6 +23,11 @@ function App() { const [isAboutModalOpen, setIsAboutModalOpen] = useState(false); const [isWordNotFoundAlertOpen, setIsWordNotFoundAlertOpen] = useState(false); const [isGameLost, setIsGameLost] = useState(false); + const [shareComplete, setShareComplete] = useState(false); + + useEffect(() => { + saveGameStateToLocalStorage(guesses); + }, [guesses]); useEffect(() => { if (isGameWon) { @@ -68,6 +79,11 @@ function App() { message={`You lost, the word was ${solution}`} isOpen={isGameLost} /> +

Not Wordle

setIsWinModalOpen(false)} guesses={guesses} + handleShare={() => { + setIsWinModalOpen(false); + setShareComplete(true); + return setTimeout(() => { + setShareComplete(false); + }, 2000); + }} /> { +export const Alert = ({ isOpen, message, variant = "warning" }: Props) => { + const classes = classNames( + "fixed top-2.5 left-1/2 transform -translate-x-1/2 max-w-sm w-full shadow-lg rounded-lg pointer-events-auto ring-1 ring-black ring-opacity-5 overflow-hidden", + { + "bg-rose-200": variant === "warning", + "bg-green-200": variant === "success", + } + ); + return ( { leaveFrom="opacity-100" leaveTo="opacity-0" > -
+

{message} diff --git a/src/components/modals/WinModal.tsx b/src/components/modals/WinModal.tsx index 9a08da2..ff6fb56 100644 --- a/src/components/modals/WinModal.tsx +++ b/src/components/modals/WinModal.tsx @@ -2,14 +2,21 @@ import { Fragment } from "react"; import { Dialog, Transition } from "@headlessui/react"; import { CheckIcon } from "@heroicons/react/outline"; import { MiniGrid } from "../mini-grid/MiniGrid"; +import { shareStatus } from "../../lib/share"; type Props = { isOpen: boolean; handleClose: () => void; guesses: string[]; + handleShare: () => void; }; -export const WinModal = ({ isOpen, handleClose, guesses }: Props) => { +export const WinModal = ({ + isOpen, + handleClose, + guesses, + handleShare, +}: Props) => { return (

{
diff --git a/src/lib/localStorage.ts b/src/lib/localStorage.ts new file mode 100644 index 0000000..1294ac3 --- /dev/null +++ b/src/lib/localStorage.ts @@ -0,0 +1,18 @@ +const gameStateKey = "gameState"; + +type StoredGameState = { + guesses: string[]; +}; + +export const saveGameStateToLocalStorage = (guesses: string[]) => { + const gameState = { + guesses, + }; + localStorage.setItem(gameStateKey, JSON.stringify(gameState)); +}; + +export const loadGameStateFromLocalStorage = () => { + const state = localStorage.getItem(gameStateKey); + + return state ? (JSON.parse(state) as StoredGameState) : null; +}; diff --git a/src/lib/share.ts b/src/lib/share.ts new file mode 100644 index 0000000..1d104f4 --- /dev/null +++ b/src/lib/share.ts @@ -0,0 +1,34 @@ +import { getGuessStatuses } from "./statuses"; +import { solutionIndex } from "./words"; + +export const shareStatus = (guesses: string[]) => { + navigator.clipboard.writeText( + "Wordle " + + solutionIndex + + " " + + guesses.length + + "/6\n\n" + + generateEmojiGrid(guesses) + ); +}; + +export const generateEmojiGrid = (guesses: string[]) => { + return guesses + .map((guess) => { + const status = getGuessStatuses(guess); + return guess + .split("") + .map((letter, i) => { + switch (status[i]) { + case "correct": + return "🟩"; + case "present": + return "🟨"; + default: + return "⬜"; + } + }) + .join(""); + }) + .join("\n"); +}; diff --git a/src/lib/words.ts b/src/lib/words.ts index 2afb7b8..2c78009 100644 --- a/src/lib/words.ts +++ b/src/lib/words.ts @@ -19,7 +19,10 @@ export const getWordOfDay = () => { const msInDay = 86400000; const index = Math.floor((now - epochMs) / msInDay); - return WORDS[index].toUpperCase(); + return { + solution: WORDS[index].toUpperCase(), + solutionIndex: index, + }; }; -export const solution = getWordOfDay(); +export const { solution, solutionIndex } = getWordOfDay();