diff --git a/package-lock.json b/package-lock.json index 575f2ff..b55ee7a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8168,11 +8168,6 @@ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" }, - "immer": { - "version": "7.0.14", - "resolved": "https://registry.npmjs.org/immer/-/immer-7.0.14.tgz", - "integrity": "sha512-BxCs6pJwhgSEUEOZjywW7OA8DXVzfHjkBelSEl0A+nEu0+zS4cFVdNOONvt55N4WOm8Pu4xqSPYxhm1Lv2iBBA==" - }, "import-cwd": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", diff --git a/package.json b/package.json index c782c6a..5d0e988 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,6 @@ "fitty": "^2.3.3", "i18next": "19.8.3", "i18next-browser-languagedetector": "6.0.1", - "immer": "7.0.14", "ionicons": "5.2.3", "lunr": "^2.3.9", "react": "17.0.1", diff --git a/src/App.tsx b/src/App.tsx index f372e34..c36138f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -29,12 +29,9 @@ import AboutPage from './pages/About'; import { SearchPage } from './pages/Search'; import { THEMES } from './utils/theme'; import { selectCurrentTheme } from './data/user/user.selector'; -import { RootState } from './store'; const App: React.FC = () => { - const currentTheme = useSelector((state) => - selectCurrentTheme(state as RootState), - ); + const currentTheme = useSelector(selectCurrentTheme); return ( diff --git a/src/components/Chapters/footer.tsx b/src/components/Chapters/footer.tsx index 8c63972..514e6d0 100644 --- a/src/components/Chapters/footer.tsx +++ b/src/components/Chapters/footer.tsx @@ -10,12 +10,8 @@ import { arrowBack, arrowForward, star, starOutline } from 'ionicons/icons'; import React from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory } from 'react-router'; -import { - addFavorite, - removeFavorite, -} from '../../data/chapter/chapter.actions'; -import { selectIsChapterFavorite } from '../../data/chapter/chapter.select'; -import { RootState } from '../../store'; +import { selectIsFavorite } from '../../data/user/user.selector'; +import { addFavorite, removeFavorite } from '../../data/user/user.slice'; type ContainerProps = { previousChapter: string; @@ -27,9 +23,8 @@ export const ChapterFooter: React.FC = (props) => { const history = useHistory(); const currentChapter = history.location.pathname; - const isFavorite = useSelector((state) => - selectIsChapterFavorite(state as RootState, currentChapter), - ); + + const isFavorite = useSelector(selectIsFavorite(currentChapter)); const dispatch = useDispatch(); const toggleFavorite = () => { diff --git a/src/components/SearchPopover/index.tsx b/src/components/SearchPopover/index.tsx index 8d0bec6..505a73e 100644 --- a/src/components/SearchPopover/index.tsx +++ b/src/components/SearchPopover/index.tsx @@ -13,7 +13,6 @@ import { import { ellipsisHorizontal, ellipsisVertical } from 'ionicons/icons'; import { useDispatch, useSelector } from 'react-redux'; import { setCurrentSearchView } from '../../data/user/user.slice'; -import { RootState } from '../../store'; import { selectCurrentSearchView } from '../../data/user/user.selector'; export const SearchPopover: React.FC = () => { @@ -23,9 +22,7 @@ export const SearchPopover: React.FC = () => { }); const dispatch = useDispatch(); - const currentSearchView = useSelector((state: RootState) => - selectCurrentSearchView(state), - ); + const currentSearchView = useSelector(selectCurrentSearchView); return ( <> diff --git a/src/data/chapter/chapter.actions.tsx b/src/data/chapter/chapter.actions.tsx deleted file mode 100644 index 87f4287..0000000 --- a/src/data/chapter/chapter.actions.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import ActionTypes from './chapter.constants'; - -export const addFavorite = (chapterId: string) => ({ - type: ActionTypes.ADD_FAVORITE, - payload: chapterId, -}); - -export const removeFavorite = (chapterId: string) => ({ - type: ActionTypes.REMOVE_FAVORITE, - payload: chapterId, -}); - -export const resetChapterState = () => ({ - type: ActionTypes.RESET_CHAPTER_STATE, -}); diff --git a/src/data/chapter/chapter.constants.tsx b/src/data/chapter/chapter.constants.tsx deleted file mode 100644 index 3408d30..0000000 --- a/src/data/chapter/chapter.constants.tsx +++ /dev/null @@ -1,7 +0,0 @@ -enum ActionTypes { - ADD_FAVORITE = 'app/chapters/ADD_FAVORITE', - REMOVE_FAVORITE = 'app/chapters/REMOVE_FAVORITE', - RESET_CHAPTER_STATE = 'app/chapters/RESET_CHAPTER_STATE', -} - -export default ActionTypes; diff --git a/src/data/chapter/chapter.reducer.tsx b/src/data/chapter/chapter.reducer.tsx deleted file mode 100644 index ca50d15..0000000 --- a/src/data/chapter/chapter.reducer.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import produce from 'immer'; -import ActionTypes from './chapter.constants'; - -interface ChapterActions { - readonly type: string; - readonly payload: any; -} - -export interface ChapterState { - readonly favorites: Array; -} - -const initState = { - favorites: [], -}; - -const chapterReducer = ( - state: ChapterState = initState, - action: ChapterActions, -) => - produce(state, (draft) => { - switch (action.type) { - case ActionTypes.ADD_FAVORITE: - draft.favorites = [...state.favorites, action.payload]; - break; - case ActionTypes.REMOVE_FAVORITE: - draft.favorites = state.favorites.filter( - (favorite) => !favorite.includes(action.payload), - ); - break; - case ActionTypes.RESET_CHAPTER_STATE: - draft = initState; - break; - } - }); - -export default chapterReducer; diff --git a/src/data/chapter/chapter.select.tsx b/src/data/chapter/chapter.select.tsx deleted file mode 100644 index 8eede5c..0000000 --- a/src/data/chapter/chapter.select.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { RootState } from '../../store'; - -export const selectChapterState = (state: RootState) => { - return state.chapter; -}; - -export const selectChapterFavorites = (state: RootState) => { - const chapterState = selectChapterState(state); - return chapterState.favorites; -}; - -export const selectIsChapterFavorite = ( - state: RootState, - chapterId: string, -): boolean => { - const chapterFavorites = selectChapterFavorites(state); - const isFavorite = chapterFavorites.includes(chapterId); - return isFavorite; -}; diff --git a/src/data/user/user.selector.ts b/src/data/user/user.selector.ts index 8eda732..7567bd0 100644 --- a/src/data/user/user.selector.ts +++ b/src/data/user/user.selector.ts @@ -19,3 +19,14 @@ export const selectHasSeenTutorial = createSelector( selfUserState, (state) => state.hasSeenTutorial, ); + +export const selectFavorites = createSelector( + selfUserState, + (state) => state.favorites, +); + +export const selectIsFavorite = (chapterId: string) => { + return createSelector(selectFavorites, (favorites) => + favorites.includes(chapterId), + ); +}; diff --git a/src/data/user/user.slice.ts b/src/data/user/user.slice.ts index cf16744..fc249ce 100644 --- a/src/data/user/user.slice.ts +++ b/src/data/user/user.slice.ts @@ -17,11 +17,13 @@ interface CurrentThemePayload { } type UserState = { + favorites: Array; hasSeenTutorial: boolean; } & CurrentSearchView & CurrentTheme; const initialState: UserState = { + favorites: [], currentSearchView: 'card', currentTheme: 'system', hasSeenTutorial: false, @@ -31,6 +33,14 @@ const userSlice = createSlice({ name: 'user', initialState, reducers: { + addFavorite(state, action: PayloadAction) { + state.favorites = [...state.favorites, action.payload]; + }, + removeFavorite(state, action: PayloadAction) { + state.favorites = state.favorites.filter( + (favorite) => !favorite.includes(action.payload), + ); + }, resetUserState() { return initialState; }, @@ -56,6 +66,8 @@ const userSlice = createSlice({ }); export const { + addFavorite, + removeFavorite, resetUserState, setCurrentSearchView, setCurrentTheme, diff --git a/src/pages/Settings/index.tsx b/src/pages/Settings/index.tsx index 782e5fb..84711d3 100644 --- a/src/pages/Settings/index.tsx +++ b/src/pages/Settings/index.tsx @@ -26,16 +26,13 @@ import { I18N_LANGUAGES_SUPPORTED } from '../../i18n'; import { colorPaletteOutline, languageOutline } from 'ionicons/icons'; import { THEMES } from '../../utils/theme'; import { selectCurrentTheme } from '../../data/user/user.selector'; -import { RootState } from '../../store'; import { resetUserState, setCurrentTheme } from '../../data/user/user.slice'; export const SettingsPage: React.FC = () => { const { t, i18n } = useTranslation(); const dispatch = useDispatch(); - const currentTheme = useSelector((state: RootState) => - selectCurrentTheme(state), - ); + const currentTheme = useSelector(selectCurrentTheme); return ( diff --git a/src/reducers.ts b/src/reducers.ts index 0d2870d..9b8962d 100644 --- a/src/reducers.ts +++ b/src/reducers.ts @@ -4,7 +4,6 @@ import { combineReducers, Reducer } from 'redux'; import { connectRouter } from 'connected-react-router'; -import chapterReducer from './data/chapter/chapter.reducer'; import history from './utils/history'; import userSlice from './data/user/user.slice'; @@ -13,7 +12,6 @@ import userSlice from './data/user/user.slice'; */ const createReducer = (injectedReducers = {}) => { const rootReducer = combineReducers({ - chapter: chapterReducer, user: userSlice, router: connectRouter(history) as Reducer, ...injectedReducers,