Moved completed tutorial states to session and local storage.
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"name": "lucid-creations-media-potty-chart",
|
"name": "lucid-creations-media-potty-chart",
|
||||||
"homepage": "https://lucidcreations.media/introducing-code-name-potty-chart/",
|
"homepage": "https://lucidcreations.media/introducing-code-name-potty-chart/",
|
||||||
"version": "v0.0.11-alpha",
|
"version": "0.0.11",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Lucid Creations Media",
|
"name": "Lucid Creations Media",
|
||||||
"url": "https://lucidcreations.media",
|
"url": "https://lucidcreations.media",
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import { configureStore } from "@reduxjs/toolkit";
|
import { configureStore } from "@reduxjs/toolkit";
|
||||||
import calenderReducer from "../features/calender/calender";
|
import calenderReducer from "../features/calender";
|
||||||
import stickersReducer from "../features/calender/stickers";
|
import stickersReducer from "../features/calender/stickers";
|
||||||
|
import tutorialReducer from "../features/tutorial";
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
calender: calenderReducer,
|
calender: calenderReducer,
|
||||||
stickers: stickersReducer
|
stickers: stickersReducer,
|
||||||
|
tutorial: tutorialReducer
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React, { useEffect } from "react";
|
|||||||
import { Box, HStack, SimpleGrid, Text, VStack } from "@chakra-ui/react";
|
import { Box, HStack, SimpleGrid, Text, VStack } from "@chakra-ui/react";
|
||||||
import { isSameDay, format } from "date-fns";
|
import { isSameDay, format } from "date-fns";
|
||||||
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||||
import { updateCurrDate, updateMonth } from "../../features/calender/calender";
|
import { updateCurrDate, updateMonth } from "../../features/calender";
|
||||||
import CalenderNav from "./CalenderNav";
|
import CalenderNav from "./CalenderNav";
|
||||||
import Day from "./Day";
|
import Day from "./Day";
|
||||||
|
|
||||||
@@ -43,12 +43,12 @@ const Calender = ({
|
|||||||
}, [dispatch, newDate]);
|
}, [dispatch, newDate]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.info("Check to update date.");
|
// console.info("Check to update date.");
|
||||||
|
|
||||||
const currDateObj = new Date(currDate);
|
const currDateObj = new Date(currDate);
|
||||||
|
|
||||||
if (!isSameDay(currDateObj, new Date())) {
|
if (!isSameDay(currDateObj, new Date())) {
|
||||||
console.info("Updated date.");
|
// console.info("Updated date.");
|
||||||
dispatch(updateCurrDate());
|
dispatch(updateCurrDate());
|
||||||
}
|
}
|
||||||
}, [currDate, dispatch]);
|
}, [currDate, dispatch]);
|
||||||
|
|||||||
@@ -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";
|
import React from "react";
|
||||||
|
|
||||||
interface TutorialProps {
|
interface TutorialProps {
|
||||||
setTutorialCookie: (bool: boolean) => void;
|
setTutorialComplete: () => void;
|
||||||
|
setTempTutorialComplete: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Tutorial = ({ setTutorialCookie }: TutorialProps): JSX.Element => {
|
const Tutorial = ({
|
||||||
const handleSetCookieButton = (): void => {
|
setTutorialComplete,
|
||||||
setTutorialCookie(true);
|
setTempTutorialComplete
|
||||||
};
|
}: TutorialProps): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Heading>{"Tutorial Component"}</Heading>
|
<VStack
|
||||||
<Button type="button" onClick={() => handleSetCookieButton()}>
|
h="auto"
|
||||||
{"Complete Tutorial"}
|
w="100%"
|
||||||
</Button>
|
justifyContent="center"
|
||||||
|
alignContent="center"
|
||||||
|
spacing={6}
|
||||||
|
>
|
||||||
|
<Heading>{"Tutorial Component"}</Heading>
|
||||||
|
<HStack
|
||||||
|
h="auto"
|
||||||
|
w="80%"
|
||||||
|
justifyContent="space-between"
|
||||||
|
alignContent="center"
|
||||||
|
>
|
||||||
|
<Button type="button" onClick={() => setTutorialComplete()}>
|
||||||
|
{"Complete Tutorial (remember)"}
|
||||||
|
</Button>
|
||||||
|
<Button type="button" onClick={() => setTempTutorialComplete()}>
|
||||||
|
{"Complete Tutorial"}
|
||||||
|
</Button>
|
||||||
|
</HStack>
|
||||||
|
</VStack>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
109
src/features/tutorial/index.ts
Normal file
109
src/features/tutorial/index.ts
Normal file
@@ -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;
|
||||||
@@ -20,14 +20,16 @@ const DateRoute: React.FC<unknown> = () => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { date: slug } = router.query;
|
const { date: slug } = router.query;
|
||||||
|
|
||||||
const [date, setDate] = useState<UpdateCalendarProps | null>(null);
|
const [date, setDate] = useState<UpdateCalenderPropsDateLayout | null>(null);
|
||||||
|
|
||||||
const [error, setError] = useState<boolean>(false);
|
const [error, setError] = useState<boolean>(false);
|
||||||
|
|
||||||
// const dateRange = useRef(findValidDateRange());
|
// const dateRange = useRef(findValidDateRange());
|
||||||
// const validDateRange = Object.assign({}, dateRange.current);
|
// const validDateRange = Object.assign({}, dateRange.current);
|
||||||
|
|
||||||
const validateDateInput = (dateArr: number[]): UpdateCalendarProps => {
|
const validateDateInput = (
|
||||||
|
dateArr: number[]
|
||||||
|
): UpdateCalenderPropsDateLayout => {
|
||||||
if (!(dateArr.length >= 2) && !(dateArr.length <= 3)) {
|
if (!(dateArr.length >= 2) && !(dateArr.length <= 3)) {
|
||||||
return {
|
return {
|
||||||
year: 0,
|
year: 0,
|
||||||
@@ -198,7 +200,7 @@ const DateRoute: React.FC<unknown> = () => {
|
|||||||
) : (
|
) : (
|
||||||
<Box textAlign="center" w="100%" h="auto" pt="50px" pb="10vh">
|
<Box textAlign="center" w="100%" h="auto" pt="50px" pb="10vh">
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<Calender {...date} />
|
<Calender date={date} isLoading={false} />
|
||||||
</Provider>
|
</Provider>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,16 +1,27 @@
|
|||||||
import React, { Fragment, useEffect, useRef, useState } from "react";
|
import React, { Fragment, useEffect, useRef, useState } from "react";
|
||||||
import { Box } from "@chakra-ui/react";
|
import { Box } from "@chakra-ui/react";
|
||||||
import { addMonths, format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import Calender from "../components/calender";
|
import Calender from "../components/calender";
|
||||||
import Tutorial from "../components/tutorial";
|
import Tutorial from "../components/tutorial";
|
||||||
import LoadingOverlay from "../components/loading/LoadingOverlay";
|
import LoadingOverlay from "../components/loading/LoadingOverlay";
|
||||||
import { Provider } from "react-redux";
|
import { Provider } from "react-redux";
|
||||||
import { store } from "../app/store";
|
import { store } from "../app/store";
|
||||||
import { useAppDispatch, useAppSelector } from "../app/hooks";
|
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 IndexPage = (): JSX.Element => {
|
||||||
const isLoading = useAppSelector((state) => state.calender.isLoading);
|
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 dispatch = useAppDispatch();
|
||||||
|
|
||||||
const currDate = useRef<UpdateCalenderPropsDateLayout>({
|
const currDate = useRef<UpdateCalenderPropsDateLayout>({
|
||||||
@@ -19,25 +30,26 @@ const IndexPage = (): JSX.Element => {
|
|||||||
day: parseInt(format(new Date(), "d"))
|
day: parseInt(format(new Date(), "d"))
|
||||||
});
|
});
|
||||||
|
|
||||||
const [completedTutorial, setCompletedTutorial] = useState<boolean | null>(
|
const handleTempTutorialCompleted = (): void => {
|
||||||
null
|
dispatch(setTempTutorialComplete());
|
||||||
);
|
|
||||||
|
|
||||||
const getTutorialCookie = (): boolean => {
|
|
||||||
return JSON.parse(localStorage.getItem("tutorialCompleted")) || false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const setTutorialCookie = (bool: boolean): void => {
|
const handleTutorialCompleted = (): void => {
|
||||||
localStorage.setItem("tutorialCompleted", `${bool}`);
|
dispatch(setTutorialCompleted());
|
||||||
setCompletedTutorial(true);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (completedTutorial === null || tutorialCompletionInfo === null) {
|
||||||
|
dispatch(getAndSetTutorial());
|
||||||
|
dispatch(updateLoading(false));
|
||||||
|
}
|
||||||
|
|
||||||
if (completedTutorial !== null) {
|
if (completedTutorial !== null) {
|
||||||
dispatch(updateLoading(false));
|
dispatch(updateLoading(false));
|
||||||
}
|
}
|
||||||
setCompletedTutorial(getTutorialCookie());
|
|
||||||
}, [completedTutorial, dispatch]);
|
console.info("use effect", completedTutorial, tutorialCompletionInfo);
|
||||||
|
}, [completedTutorial, dispatch, tutorialCompletionInfo]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@@ -49,7 +61,7 @@ const IndexPage = (): JSX.Element => {
|
|||||||
minWidth="min-content"
|
minWidth="min-content"
|
||||||
>
|
>
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
{completedTutorial === null ? (
|
{isLoading === true ? (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<LoadingOverlay />
|
<LoadingOverlay />
|
||||||
<Calender date={currDate.current} isLoading={isLoading} />
|
<Calender date={currDate.current} isLoading={isLoading} />
|
||||||
@@ -57,7 +69,10 @@ const IndexPage = (): JSX.Element => {
|
|||||||
) : completedTutorial ? (
|
) : completedTutorial ? (
|
||||||
<Calender date={currDate.current} isLoading={isLoading} />
|
<Calender date={currDate.current} isLoading={isLoading} />
|
||||||
) : (
|
) : (
|
||||||
<Tutorial setTutorialCookie={setTutorialCookie} />
|
<Tutorial
|
||||||
|
setTutorialComplete={handleTutorialCompleted}
|
||||||
|
setTempTutorialComplete={handleTempTutorialCompleted}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</Provider>
|
</Provider>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import appLogo from "../../../public/images/logo.svg";
|
|||||||
|
|
||||||
const Header = (): JSX.Element => {
|
const Header = (): JSX.Element => {
|
||||||
const appName = "LCM Potty Chart";
|
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.
|
// Add transparency while not at the top of the page.
|
||||||
const [transparentNavbar, setTransparentNavbar] = useState<boolean>(false);
|
const [transparentNavbar, setTransparentNavbar] = useState<boolean>(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user