Moved stickers state to redux. Removed unneded type definitions. Refactored components to accomdate changes in types and interfaces.

This commit is contained in:
Lucid Kobold
2022-06-13 15:24:59 -05:00
parent 8654d7ac79
commit 06df367277
13 changed files with 156 additions and 157 deletions

View File

@@ -1,61 +0,0 @@
import React, { createContext, useState, ReactNode } from "react";
import { format, getDate, isSameDay } from "date-fns";
import stickersSeeder from "../data/stickerSeeder";
const StickersContext = createContext({} as StickersContextState);
const StickersContextProvider = ({
children
}: {
children: ReactNode;
}): JSX.Element => {
const [stickersMonth, setStickersMonth] = useState<StickerDays>(
stickersSeeder()
);
// TODO: Add stickers functions here. (Add and edit stickers).
const addEditSticker = (date: Date, sticker: ValidStickerVal): Sticker => {
const newStickersMonth = stickersMonth.slice();
const index = getDate(date) - 1;
const currDate = newStickersMonth[index];
const edited = currDate.edited
? true
: isSameDay(currDate.date, new Date())
? false
: true;
currDate.edited = edited;
// Add manual here when necessary.
const id = format(date, "yyyyddLL") + sticker;
const newSticker: Sticker = {
id: id,
date: date,
sticker: sticker,
edited: edited,
manual: false
};
newStickersMonth[index] = newSticker;
setStickersMonth(newStickersMonth.slice());
return newSticker;
};
// TODO: Add stickers validation function here.
const stickersContextValues = {
stickersMonth,
addEditSticker
};
return (
<StickersContext.Provider value={stickersContextValues}>
{children}
</StickersContext.Provider>
);
};
export { StickersContextProvider, StickersContext };

View File

@@ -1,4 +1,10 @@
import { format, getDaysInMonth, isBefore, setDate } from "date-fns";
import {
format,
getDaysInMonth,
isBefore,
setDate,
startOfDay
} from "date-fns";
/**
* This seeder is to simulate the date and sticker info from the database.
@@ -23,7 +29,7 @@ const generateSticker = (): -2 | -1 | 0 | 1 | 2 => {
const stickersSeeder = (): StickerDays => {
const stickers = [] as Sticker[];
const now = new Date();
const now = startOfDay(new Date());
const daysOfThisMonth = getDaysInMonth(now);
for (let i = 1; i <= daysOfThisMonth; i++) {
@@ -36,7 +42,7 @@ const stickersSeeder = (): StickerDays => {
const newSticker: Sticker = {
id: id,
date: currDate,
date: currDate.toJSON(),
sticker: sticker,
edited: false,
manual: false

View File

@@ -1,9 +1,11 @@
import { configureStore } from "@reduxjs/toolkit";
import calenderReducer from "../features/calender/calender";
import stickersReducer from "../features/calender/stickers";
export const store = configureStore({
reducer: {
calender: calenderReducer
calender: calenderReducer,
stickers: stickersReducer
}
});

View File

@@ -10,15 +10,16 @@ import {
} from "date-fns";
import router from "next/router";
import React, { Fragment, useState } from "react";
import { StickersContextProvider } from "../../../contexts/StickerContext";
import AddUpdateSticker from "./modals/AddUpdateSticker";
import DemoStickers from "./stickers/DemoStickers";
import { Provider } from "react-redux";
import { store } from "../../app/store";
interface DayProps {
isOverflow?: boolean;
overflowDirection?: "next" | "prev" | null;
sticker: StickerVal;
date: Date;
date: string;
selectedDate: string;
currDate: Date;
isToday: boolean;
@@ -26,12 +27,11 @@ interface DayProps {
/**
* The individual days in the calender component.
* @param props the props for this component.
* @param {boolean} props.isOverflow is the current date being given before or after the current month.
* @param {"next" | "prev" | null} props.overflowDirection the direction the overflow is. This will navigate the calender forward or backwards 1 month.
* @param {StickerVal} props.sticker the sticker for this date.
* @param {date} props.date the date for this day.
* @param {date} props.selectedDate the date for the selected month.
* @param {boolean} isOverflow is the current date being given before or after the current month.
* @param {"next" | "prev" | null} overflowDirection the direction the overflow is. This will navigate the calender forward or backwards 1 month.
* @param {StickerVal} sticker the sticker for this date.
* @param {date} string the date for this day.
* @param {date} selectedDate the date for the selected month.
*/
const Day = ({
isOverflow,
@@ -43,6 +43,7 @@ const Day = ({
isToday
}: DayProps): JSX.Element => {
const selectedDateObj = new Date(selectedDate);
const currDateObj = new Date(date);
const handleNav = (direction: "next" | "prev") => {
if (direction === "next") {
@@ -66,10 +67,6 @@ const Day = ({
// This handles the modal for the day.
const [isOpen, setIsOpen] = useState<boolean>(false);
// The current sticker to be displayed on the current date.
// * This is temporary. There should be no need for this once persistent storage is used. This is being used as a workaround to a bug.
const [stickerState, setStickerState] = useState<StickerVal>(sticker);
// The step the modal is at.
const [step, setStep] = useState<number>(0);
@@ -95,7 +92,9 @@ const Day = ({
w="100%"
h="100%"
_hover={{
cursor: isBefore(date, endOfDay(currDate)) ? "pointer" : "default",
cursor: isBefore(currDateObj, endOfDay(currDate))
? "pointer"
: "default",
background: "gray.700",
border: "1px solid #FFF",
color: "whiteAlpha.900"
@@ -107,15 +106,10 @@ const Day = ({
pt={2}
>
<Text w="auto" h="auto">
{`${getDate(date)}`}
{`${getDate(currDateObj)}`}
</Text>
<Box
key={stickerState === null ? Math.random() : stickerState}
fontSize="1.5rem"
>
<DemoStickers
stickerVal={stickerState === null ? null : stickerState}
/>
<Box key={sticker} fontSize="1.5rem">
<DemoStickers stickerVal={sticker} />
</Box>
</VStack>
)}
@@ -134,7 +128,9 @@ const Day = ({
justifyContent="flex-start"
pt={2}
_hover={{
cursor: isBefore(date, endOfDay(currDate)) ? "pointer" : "default",
cursor: isBefore(currDateObj, endOfDay(currDate))
? "pointer"
: "default",
background: "gray.700",
border: "1px solid #FFF"
}}
@@ -142,7 +138,7 @@ const Day = ({
<Text
p={
isToday
? getDate(date) > 10
? getDate(currDateObj) > 10
? "0px 6px 3px 6px"
: "0px 9px 3px 9px"
: "auto"
@@ -152,24 +148,18 @@ const Day = ({
border={isToday ? "1px solid #0068ff" : "0px"}
borderRadius={isToday ? "100px" : "0px"}
>
{`${getDate(date)}`}
{`${getDate(currDateObj)}`}
</Text>
<Box
key={stickerState === null ? Math.random() : stickerState}
fontSize="1.5rem"
>
<DemoStickers
stickerVal={stickerState === null ? null : stickerState}
/>
<Box key={sticker} fontSize="1.5rem">
<DemoStickers stickerVal={sticker} />
</Box>
<StickersContextProvider>
{isBefore(date, endOfDay(currDate)) && (
<Provider store={store}>
{isBefore(currDateObj, endOfDay(currDate)) && (
<AddUpdateSticker
date={date}
isOpen={isOpen}
updateIsOpen={setIsOpen}
updateSticker={setStickerState}
currSticker={stickerState}
currSticker={sticker}
step={step}
updateStep={setStep}
selectedSticker={selectedSticker}
@@ -177,7 +167,7 @@ const Day = ({
currDate={currDate}
/>
)}
</StickersContextProvider>
</Provider>
</VStack>
)}
</Fragment>

View File

@@ -1,25 +1,29 @@
import React, { useContext, useEffect } from "react";
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 { StickersContext } from "../../../contexts/StickerContext";
import CalenderNav from "./CalenderNav";
import Day from "./Day";
const Calender = (newDate?: UpdateCalendarProps): JSX.Element => {
// * Month * //
const currDate: string = useAppSelector((state) => state.calender.currDate);
const selectedDate = useAppSelector(
const selectedDate: SelectedDateInfo = useAppSelector(
(state) => state.calender.selectedDateInfo
);
const { layout } = selectedDate;
const dispatch = useAppDispatch();
const { stickersMonth } = useContext(StickersContext);
const currDateObj = new Date(currDate);
// * Stickers * //
const stickersMonth: StickerDays = useAppSelector(
(state) => state.stickers.stickersMonth
);
const dispatch = useAppDispatch();
useEffect(() => {
if (newDate && newDate.year && newDate.month && newDate.day) {
const { year, month, day } = newDate;
@@ -46,7 +50,7 @@ const Calender = (newDate?: UpdateCalendarProps): JSX.Element => {
}
}, [currDate, dispatch]);
// Simulated user settings context
// Simulated user settings.
const userSettings = {
theme: "default",
startOfWeek: "Sunday"
@@ -103,7 +107,9 @@ const Calender = (newDate?: UpdateCalendarProps): JSX.Element => {
let id = "";
stickersMonth.map((stickerDay) => {
if (isSameDay(stickerDay.date, toDateObj)) {
const { date: stickerDate } = stickerDay;
if (isSameDay(new Date(stickerDate), toDateObj)) {
sticker = stickerDay.sticker;
id = stickerDay.id;
@@ -115,7 +121,7 @@ const Calender = (newDate?: UpdateCalendarProps): JSX.Element => {
isOverflow={isOverflow}
overflowDirection={overflowDirection}
sticker={sticker}
date={toDateObj}
date={date}
selectedDate={selectedDate.date}
currDate={currDateObj}
isToday={isSameDay(currDateObj, toDateObj)}

View File

@@ -13,18 +13,18 @@ import {
SimpleGrid,
Box
} from "@chakra-ui/react";
import React, { useState, useContext, useRef } from "react";
import React, { useState, useRef } from "react";
import { format, isSameDay } from "date-fns";
import { Icon } from "@iconify/react";
import { StickersContext } from "../../../../contexts/StickerContext";
import StickerSelector from "./StickerSelector";
import DemoStickers from "../stickers/DemoStickers";
import { useAppDispatch } from "../../../app/hooks";
import { addEditSticker } from "../../../features/calender/stickers";
interface AddStickerProps {
isOpen: boolean;
updateIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
date: Date;
updateSticker: React.Dispatch<React.SetStateAction<StickerVal>>;
date: string;
currSticker: StickerVal;
step: number;
updateStep: React.Dispatch<React.SetStateAction<number>>;
@@ -37,8 +37,7 @@ interface AddStickerProps {
* Handles adding and modifying the stickers for the given month.
* @param {boolean} isOpen Tells the component when the modal should be open.
* @param {React.Dispatch<React.SetStateAction<boolean>>} updateIsOpen Used to close the modal.
* @param {date} date The date for which the sticker will be added or modified.
* @param {React.Dispatch<React.SetStateAction<StickerVal>>} updateSticker The react state function to update the sticker.
* @param {date} string The date for which the sticker will be added or modified.
* @param {StickerVal} currSticker The current sticker for the date.
* @param {number} step A numerical variable that represents the page the modal should be at.
* @param {React.Dispatch<React.SetStateAction<number>>} updateStep Used to navigate the pages of the modal by updating the step the modal is on.
@@ -48,7 +47,6 @@ const AddUpdateSticker = ({
isOpen,
updateIsOpen,
date,
updateSticker,
currSticker,
step,
updateStep,
@@ -56,14 +54,13 @@ const AddUpdateSticker = ({
updateSelectedSticker,
currDate
}: AddStickerProps): JSX.Element => {
// TODO: Import the stickers array from the calender context.
const { addEditSticker } = useContext(StickersContext);
const dispatch = useAppDispatch();
const currDateObj = new Date(date);
// ! Update these states to say "add" and "edit" for easier reading.
const [modalVariant] = useState<"currDate" | "notCurrDate">(
isSameDay(date, currDate) ? "currDate" : "notCurrDate"
isSameDay(currDateObj, currDate) ? "currDate" : "notCurrDate"
);
const handleClose = () => {
@@ -71,9 +68,8 @@ const AddUpdateSticker = ({
};
// TODO: Validate that the provided sticker is not the current sticker. Throw an error if the same sticker is attempted.
const handleSubmit = (sticker) => {
const newSticker: Sticker = addEditSticker(date, sticker);
updateSticker(newSticker.sticker);
const handleSubmit = (sticker: StickerVal) => {
dispatch(addEditSticker({ date, sticker }));
handleClose();
};
@@ -85,7 +81,10 @@ const AddUpdateSticker = ({
const variants = {
currDate: [
{
header: `Which sticker did you earn for ${format(date, "LLL d, y")}?`,
header: `Which sticker did you earn for ${format(
currDateObj,
"LLL d, y"
)}?`,
body: (
<VStack
w="100%"
@@ -122,7 +121,7 @@ const AddUpdateSticker = ({
notCurrDate: [
{
header: `Which sticker did you want to update for ${format(
date,
currDateObj,
"LLL d, y"
)}?`,
body: (
@@ -164,7 +163,7 @@ const AddUpdateSticker = ({
},
{
header: `Are you sure you want to change the sticker for ${format(
date,
currDateObj,
"M/d/y"
)}?`,
body: (

View File

@@ -1,6 +1,6 @@
import React, { FC } from "react";
// TODO: When themes are made import the theme from user settings context. Refactor to use whatever those SVGs are.
// TODO: When themes are made import the theme from user settings store. Refactor to use whatever those SVGs are.
interface DemoStickersProps {
stickerVal: StickerVal;
@@ -9,13 +9,19 @@ interface DemoStickersProps {
const DemoStickers: FC<DemoStickersProps> = ({
stickerVal
}: DemoStickersProps) => {
// If sticker is null return an empty space.
if (stickerVal === null) {
return <span aria-label="spacer">&nbsp;</span>;
}
interface StickerToEmoji {
[key: string]: JSX.Element;
}
/**
* ? Temporarily using values -1 to 1.
* ? In the full app the values will be between -2 and 2.
*/
let key = "0";
if (stickerVal > 0) {
@@ -24,6 +30,7 @@ const DemoStickers: FC<DemoStickersProps> = ({
key = "-1";
}
// Link value to an emoji representing a sticker.
const stickerToEmoji: StickerToEmoji = {
"1": (
<span role="img" aria-label="Sun">
@@ -42,6 +49,7 @@ const DemoStickers: FC<DemoStickersProps> = ({
)
};
// Return the appropriate sticker.
return stickerToEmoji[`${key}`];
};

View File

@@ -4,11 +4,7 @@ import populate from "../../../lib/populateMonth";
interface CalenderSlice {
currDate: string;
selectedDateInfo: {
date: string;
title: string;
layout: MonthLayout;
};
selectedDateInfo: SelectedDateInfo;
}
const getCurrDate = (): Date => new Date();

View File

@@ -0,0 +1,63 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { format, getDate, isSameDay } from "date-fns";
import stickersSeeder from "../../../data/stickerSeeder";
interface StickersSlice {
stickersMonth: StickerDays;
}
interface UpdateStickerSlicePayload {
date: string;
sticker: StickerVal;
}
const initialState: StickersSlice = {
stickersMonth: stickersSeeder()
};
const stickersSlice = createSlice({
name: "Stickers",
initialState,
reducers: {
addEditSticker(
state: StickersSlice,
actions: PayloadAction<UpdateStickerSlicePayload>
) {
const { date, sticker } = actions.payload;
const dateObj = new Date(date);
// Getting index for the stickers array, sticker from the stickers array, and the date from the sticker.
const index: number = getDate(dateObj) - 1;
const currSticker: Sticker = state.stickersMonth[index];
const { date: stickerDate } = currSticker;
// Updating the edited status by checking if the sticker date is today's date.
const edited = currSticker.edited
? true
: isSameDay(new Date(stickerDate), new Date())
? false
: true;
currSticker.edited = edited;
// TODO: Add manually added here.
// Updating the id of the sticker.
const id = format(dateObj, "yyyyddLL") + sticker;
// Updating the information of the sticker.
const newSticker: Sticker = {
id: id,
date: date,
sticker: sticker,
edited: edited,
manual: false
};
state.stickersMonth[index] = newSticker;
}
}
});
export const { addEditSticker } = stickersSlice.actions;
export default stickersSlice.reducer;

View File

@@ -15,7 +15,6 @@ import ErrorPage from "next/error";
import Calender from "../../components/calender";
import { Provider } from "react-redux";
import { store } from "../../app/store";
import { StickersContextProvider } from "../../../contexts/StickerContext";
const DateRoute: React.FC<unknown> = () => {
const router = useRouter();
@@ -198,11 +197,9 @@ const DateRoute: React.FC<unknown> = () => {
<ErrorPage statusCode={404} />
) : (
<Box textAlign="center" w="100%" h="auto" pt="50px" pb="10vh">
<StickersContextProvider>
<Provider store={store}>
<Calender {...date} />
</Provider>
</StickersContextProvider>
<Provider store={store}>
<Calender {...date} />
</Provider>
</Box>
);
};

View File

@@ -3,7 +3,6 @@ import { Box } from "@chakra-ui/react";
import { format } from "date-fns";
import { Provider } from "react-redux";
import { store } from "../app/store";
import { StickersContextProvider } from "../../contexts/StickerContext";
import Calender from "../components/calender";
const IndexPage = (): JSX.Element => {
@@ -15,11 +14,9 @@ const IndexPage = (): JSX.Element => {
return (
<Box textAlign="center" w="100%" h="auto" pt="50px" pb="10vh">
<StickersContextProvider>
<Provider store={store}>
<Calender {...date.current} />
</Provider>
</StickersContextProvider>
<Provider store={store}>
<Calender {...date.current} />
</Provider>
</Box>
);
};

View File

@@ -44,3 +44,9 @@ interface UpdateCalendarProps {
month: number;
day: number;
}
interface SelectedDateInfo {
date: string;
title: string;
layout: MonthLayout;
}

View File

@@ -1,8 +1,3 @@
interface StickersContextState {
stickersMonth: StickerDays;
addEditSticker: (date: Date, sticker: ValidStickerVal) => Sticker;
}
type StickerVal = -2 | -1 | 0 | 1 | 2 | null;
type ValidStickerVal = -2 | -1 | 0 | 1 | 2;
@@ -14,15 +9,10 @@ interface AddEditStickerProps {
interface Sticker {
id: string;
date: Date;
date: string;
sticker: StickerVal;
edited: boolean;
manual: boolean;
}
type StickerDays = Sticker[];
interface MonthSticker {
date: Date;
month: Sticker[];
}