From 9506e5b43c29125e3f243f6a85674b5ce52c3c03 Mon Sep 17 00:00:00 2001
From: Lucid Kobold <72232219+LucidKobold@users.noreply.github.com>
Date: Tue, 21 Jun 2022 16:16:17 -0500
Subject: [PATCH] Moved completed tutorial states to session and local storage.
---
package.json | 2 +-
src/app/store.ts | 6 +-
src/components/calender/index.tsx | 6 +-
src/components/tutorial/index.tsx | 39 +++++--
.../calender/{calender.ts => index.ts} | 0
src/features/tutorial/index.ts | 109 ++++++++++++++++++
src/pages/calendar/[...date].tsx | 8 +-
src/pages/index.tsx | 45 +++++---
src/theme/layout/Header.tsx | 2 +-
9 files changed, 182 insertions(+), 35 deletions(-)
rename src/features/calender/{calender.ts => index.ts} (100%)
create mode 100644 src/features/tutorial/index.ts
diff --git a/package.json b/package.json
index 6671530..c3dc022 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"private": true,
"name": "lucid-creations-media-potty-chart",
"homepage": "https://lucidcreations.media/introducing-code-name-potty-chart/",
- "version": "v0.0.11-alpha",
+ "version": "0.0.11",
"author": {
"name": "Lucid Creations Media",
"url": "https://lucidcreations.media",
diff --git a/src/app/store.ts b/src/app/store.ts
index db29048..0710a07 100644
--- a/src/app/store.ts
+++ b/src/app/store.ts
@@ -1,11 +1,13 @@
import { configureStore } from "@reduxjs/toolkit";
-import calenderReducer from "../features/calender/calender";
+import calenderReducer from "../features/calender";
import stickersReducer from "../features/calender/stickers";
+import tutorialReducer from "../features/tutorial";
export const store = configureStore({
reducer: {
calender: calenderReducer,
- stickers: stickersReducer
+ stickers: stickersReducer,
+ tutorial: tutorialReducer
}
});
diff --git a/src/components/calender/index.tsx b/src/components/calender/index.tsx
index 6ee7457..e6d697b 100644
--- a/src/components/calender/index.tsx
+++ b/src/components/calender/index.tsx
@@ -2,7 +2,7 @@ import React, { useEffect } from "react";
import { Box, HStack, SimpleGrid, Text, VStack } from "@chakra-ui/react";
import { isSameDay, format } from "date-fns";
import { useAppDispatch, useAppSelector } from "../../app/hooks";
-import { updateCurrDate, updateMonth } from "../../features/calender/calender";
+import { updateCurrDate, updateMonth } from "../../features/calender";
import CalenderNav from "./CalenderNav";
import Day from "./Day";
@@ -43,12 +43,12 @@ const Calender = ({
}, [dispatch, newDate]);
useEffect(() => {
- console.info("Check to update date.");
+ // console.info("Check to update date.");
const currDateObj = new Date(currDate);
if (!isSameDay(currDateObj, new Date())) {
- console.info("Updated date.");
+ // console.info("Updated date.");
dispatch(updateCurrDate());
}
}, [currDate, dispatch]);
diff --git a/src/components/tutorial/index.tsx b/src/components/tutorial/index.tsx
index 9f538fd..67090c8 100644
--- a/src/components/tutorial/index.tsx
+++ b/src/components/tutorial/index.tsx
@@ -1,20 +1,39 @@
-import { Box, Button, Heading } from "@chakra-ui/react";
+import { Box, Button, Heading, HStack, VStack } from "@chakra-ui/react";
import React from "react";
interface TutorialProps {
- setTutorialCookie: (bool: boolean) => void;
+ setTutorialComplete: () => void;
+ setTempTutorialComplete: () => void;
}
-const Tutorial = ({ setTutorialCookie }: TutorialProps): JSX.Element => {
- const handleSetCookieButton = (): void => {
- setTutorialCookie(true);
- };
+const Tutorial = ({
+ setTutorialComplete,
+ setTempTutorialComplete
+}: TutorialProps): JSX.Element => {
return (
- {"Tutorial Component"}
-
+
+ {"Tutorial Component"}
+
+
+
+
+
);
};
diff --git a/src/features/calender/calender.ts b/src/features/calender/index.ts
similarity index 100%
rename from src/features/calender/calender.ts
rename to src/features/calender/index.ts
diff --git a/src/features/tutorial/index.ts b/src/features/tutorial/index.ts
new file mode 100644
index 0000000..08b68b7
--- /dev/null
+++ b/src/features/tutorial/index.ts
@@ -0,0 +1,109 @@
+import { createSlice, PayloadAction } from "@reduxjs/toolkit";
+import { addMonths } from "date-fns";
+
+interface StorageState {
+ exp: string;
+ version: string;
+ completed: boolean;
+}
+
+// * Storage Helpers * //
+
+const setTempStorage = (storageState: StorageState): void => {
+ sessionStorage.setItem("completedTutorial", JSON.stringify(storageState));
+};
+
+const getTempStorage = (): StorageState | null => {
+ return JSON.parse(sessionStorage.getItem("completedTutorial"));
+};
+
+const clearTempStorage = (): void => {
+ sessionStorage.removeItem("completedTutorial");
+};
+
+const setStorage = (storageState: StorageState): void => {
+ localStorage.setItem("completedTutorial", JSON.stringify(storageState));
+};
+
+const getStorage = (): StorageState | null => {
+ return JSON.parse(localStorage.getItem("completedTutorial"));
+};
+
+const clearStorage = (): void => {
+ localStorage.removeItem("completedTutorial");
+};
+
+interface TutorialSlice {
+ completedTutorial: boolean | null;
+ storageState: StorageState | null;
+}
+
+const initialState: TutorialSlice = {
+ completedTutorial: null,
+ storageState: null
+};
+
+const tutorialSlice = createSlice({
+ name: "Tutorial",
+ initialState,
+ reducers: {
+ // Set temp complete
+ setTempTutorialComplete(state: TutorialSlice) {
+ const exp: string = addMonths(new Date(), 1).toJSON();
+ const version: string = process.env.NEXT_PUBLIC_APP_VERSION.split("-")[0];
+ const storageState: StorageState = {
+ exp,
+ version,
+ completed: true
+ };
+
+ setTempStorage(storageState);
+ state.storageState = storageState;
+ state.completedTutorial = true;
+ },
+ // Set completed (remember)
+ setTutorialCompleted(state: TutorialSlice) {
+ const exp: string = addMonths(new Date(), 1).toJSON();
+ const version: string = process.env.NEXT_PUBLIC_APP_VERSION.split("-")[0];
+ const storageState: StorageState = {
+ exp,
+ version,
+ completed: true
+ };
+
+ setStorage(storageState);
+ state.storageState = storageState;
+ state.completedTutorial = true;
+ },
+ // Clear states and storages
+ clearTutorialCompleted(state: TutorialSlice) {
+ clearTempStorage();
+ clearStorage();
+ state.storageState = null;
+ state.completedTutorial = null;
+ },
+ // Get and set states
+ getAndSetTutorial(state: TutorialSlice) {
+ console.log("get and set tutorial states");
+ const temp = getTempStorage();
+ const local = getStorage();
+
+ if (temp !== null || local !== null) {
+ state.storageState = temp !== null ? temp : local;
+ state.completedTutorial = temp !== null ? temp.completed : local.completed;
+ }
+
+ if (temp === null && local === null) {
+ state.completedTutorial = false;
+ }
+ }
+ }
+});
+
+export const {
+ setTempTutorialComplete,
+ setTutorialCompleted,
+ clearTutorialCompleted,
+ getAndSetTutorial
+} = tutorialSlice.actions;
+export default tutorialSlice.reducer;
diff --git a/src/pages/calendar/[...date].tsx b/src/pages/calendar/[...date].tsx
index 7f99984..0f519e9 100644
--- a/src/pages/calendar/[...date].tsx
+++ b/src/pages/calendar/[...date].tsx
@@ -20,14 +20,16 @@ const DateRoute: React.FC = () => {
const router = useRouter();
const { date: slug } = router.query;
- const [date, setDate] = useState(null);
+ const [date, setDate] = useState(null);
const [error, setError] = useState(false);
// const dateRange = useRef(findValidDateRange());
// const validDateRange = Object.assign({}, dateRange.current);
- const validateDateInput = (dateArr: number[]): UpdateCalendarProps => {
+ const validateDateInput = (
+ dateArr: number[]
+ ): UpdateCalenderPropsDateLayout => {
if (!(dateArr.length >= 2) && !(dateArr.length <= 3)) {
return {
year: 0,
@@ -198,7 +200,7 @@ const DateRoute: React.FC = () => {
) : (
-
+
);
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index 70f6319..37ec320 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -1,16 +1,27 @@
import React, { Fragment, useEffect, useRef, useState } from "react";
import { Box } from "@chakra-ui/react";
-import { addMonths, format } from "date-fns";
+import { format } from "date-fns";
import Calender from "../components/calender";
import Tutorial from "../components/tutorial";
import LoadingOverlay from "../components/loading/LoadingOverlay";
import { Provider } from "react-redux";
import { store } from "../app/store";
import { useAppDispatch, useAppSelector } from "../app/hooks";
-import { updateLoading } from "../features/calender/calender";
+import { updateLoading } from "../features/calender";
+import {
+ getAndSetTutorial,
+ setTempTutorialComplete,
+ setTutorialCompleted
+} from "../features/tutorial";
const IndexPage = (): JSX.Element => {
const isLoading = useAppSelector((state) => state.calender.isLoading);
+ const completedTutorial = useAppSelector(
+ (state) => state.tutorial.completedTutorial
+ );
+ const tutorialCompletionInfo = useAppSelector(
+ (state) => state.tutorial.storageState
+ );
const dispatch = useAppDispatch();
const currDate = useRef({
@@ -19,25 +30,26 @@ const IndexPage = (): JSX.Element => {
day: parseInt(format(new Date(), "d"))
});
- const [completedTutorial, setCompletedTutorial] = useState(
- null
- );
-
- const getTutorialCookie = (): boolean => {
- return JSON.parse(localStorage.getItem("tutorialCompleted")) || false;
+ const handleTempTutorialCompleted = (): void => {
+ dispatch(setTempTutorialComplete());
};
- const setTutorialCookie = (bool: boolean): void => {
- localStorage.setItem("tutorialCompleted", `${bool}`);
- setCompletedTutorial(true);
+ const handleTutorialCompleted = (): void => {
+ dispatch(setTutorialCompleted());
};
useEffect(() => {
+ if (completedTutorial === null || tutorialCompletionInfo === null) {
+ dispatch(getAndSetTutorial());
+ dispatch(updateLoading(false));
+ }
+
if (completedTutorial !== null) {
dispatch(updateLoading(false));
}
- setCompletedTutorial(getTutorialCookie());
- }, [completedTutorial, dispatch]);
+
+ console.info("use effect", completedTutorial, tutorialCompletionInfo);
+ }, [completedTutorial, dispatch, tutorialCompletionInfo]);
return (
{
minWidth="min-content"
>
- {completedTutorial === null ? (
+ {isLoading === true ? (
@@ -57,7 +69,10 @@ const IndexPage = (): JSX.Element => {
) : completedTutorial ? (
) : (
-
+
)}
diff --git a/src/theme/layout/Header.tsx b/src/theme/layout/Header.tsx
index 28bf10d..3165975 100644
--- a/src/theme/layout/Header.tsx
+++ b/src/theme/layout/Header.tsx
@@ -15,7 +15,7 @@ import appLogo from "../../../public/images/logo.svg";
const Header = (): JSX.Element => {
const appName = "LCM Potty Chart";
- const appVersion = "v0.0.11-alpha";
+ const appVersion = process.env.NEXT_PUBLIC_APP_VERSION || "";
// Add transparency while not at the top of the page.
const [transparentNavbar, setTransparentNavbar] = useState(false);