From 940533c0f5bbc99f58afa9c8d811ae9cc4f34a35 Mon Sep 17 00:00:00 2001 From: drillprop Date: Thu, 29 Oct 2020 18:54:21 +0100 Subject: [PATCH 1/7] Create UIContextProvider --- apps/www/contexts/UIContextProvider.tsx | 81 +++++++++++++++++++++++++ apps/www/pages/_app.tsx | 7 ++- 2 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 apps/www/contexts/UIContextProvider.tsx diff --git a/apps/www/contexts/UIContextProvider.tsx b/apps/www/contexts/UIContextProvider.tsx new file mode 100644 index 00000000..4524cfa8 --- /dev/null +++ b/apps/www/contexts/UIContextProvider.tsx @@ -0,0 +1,81 @@ +import React, { Dispatch, SetStateAction, useCallback, useContext, useState } from 'react'; + +import { CommonModalProps } from '../components/modals/baseModal/BaseModal'; +import { Question } from '../redux/reducers/questions'; + +type ModalState = { + open: boolean; + data?: T; + onClose?: CommonModalProps['onClose']; +}; + +type UiContextType = { + isSidebarOpen: boolean; + setIsSidebarOpen: Dispatch>; + addQuestionModalState: ModalState; + openAddQuestionModal: () => void; + closeAddQuestionModal: () => void; + openEditQuestionModal: (question: Question, onClose?: CommonModalProps['onClose']) => void; + closeEditQuestionModal: () => void; + isAddQuestionConfirmationModalOpen: boolean; + setIsAddQuestionConfirmationModalOpen: Dispatch>; +}; + +const UIContext = React.createContext(undefined); + +const UIContextProvider: React.FC = ({ children }) => { + const [isSidebarOpen, setIsSidebarOpen] = useState(false); + const [addQuestionModalState, setAddQuestionModalState] = useState>({ + open: false, + }); + const [isAddQuestionConfirmationModalOpen, setIsAddQuestionConfirmationModalOpen] = useState( + false + ); + + const openAddQuestionModal = useCallback(() => { + setAddQuestionModalState({ open: true }); + }, []); + + const closeAddQuestionModal = useCallback(() => { + setAddQuestionModalState({ open: false }); + }, []); + + const openEditQuestionModal = useCallback( + (question: Question, onClose?: CommonModalProps['onClose']) => { + setAddQuestionModalState({ open: true, data: question, onClose }); + }, + [] + ); + + const closeEditQuestionModal = useCallback(() => { + setAddQuestionModalState({ open: false, data: undefined, onClose: undefined }); + }, []); + + return ( + + {children} + + ); +}; + +export const useUIContext = () => { + const ctx = useContext(UIContext); + if (ctx === undefined) { + throw new Error('useUIContext must be used within a UIContextProvider'); + } + return ctx; +}; + +export default UIContextProvider; diff --git a/apps/www/pages/_app.tsx b/apps/www/pages/_app.tsx index e755b273..4389980b 100644 --- a/apps/www/pages/_app.tsx +++ b/apps/www/pages/_app.tsx @@ -7,6 +7,7 @@ import { Provider } from 'react-redux'; import { ErrorBoundary } from '../components/errorBoundary/ErrorBoundary'; import { AppModals } from '../components/modals/appModals/AppModals'; +import UIContextProvider from '../contexts/UIContextProvider'; import { ActionCreators } from '../redux/actions'; import { AppState } from '../redux/reducers'; import { nextReduxWrapper } from '../redux/store'; @@ -108,8 +109,10 @@ const MyApp = ({ return ( - - + + + + ); From b07d86fd20ed9278f66a06f8fbffd81f2cd10ad7 Mon Sep 17 00:00:00 2001 From: drillprop Date: Fri, 30 Oct 2020 12:05:47 +0100 Subject: [PATCH 2/7] Remove ui reducer and actions --- apps/www/redux/actions.ts | 19 ------------- apps/www/redux/reducers/index.ts | 2 -- apps/www/redux/reducers/ui.ts | 49 -------------------------------- 3 files changed, 70 deletions(-) delete mode 100644 apps/www/redux/reducers/ui.ts diff --git a/apps/www/redux/actions.ts b/apps/www/redux/actions.ts index 1678eb30..898583cc 100644 --- a/apps/www/redux/actions.ts +++ b/apps/www/redux/actions.ts @@ -23,14 +23,6 @@ declare module 'redux' { } export enum ActionTypes { - UI_OPEN_SIDEBAR = 'UI_OPEN_SIDEBAR', - UI_CLOSE_SIDEBAR = 'UI_CLOSE_SIDEBAR', - UI_OPEN_ADD_QUESTION_MODAL = 'UI_OPEN_ADD_QUESTION_MODAL', - UI_CLOSE_ADD_QUESTION_MODAL = 'UI_CLOSE_ADD_QUESTION_MODAL', - UI_OPEN_EDIT_QUESTION_MODAL = 'UI_OPEN_EDIT_QUESTION_MODAL', - UI_CLOSE_EDIT_QUESTION_MODAL = 'UI_CLOSE_EDIT_QUESTION_MODAL', - UI_OPEN_ADD_QUESTION_CONFIRMATION_MODAL = 'UI_OPEN_ADD_QUESTION_CONFIRMATION_MODAL', - UI_CLOSE_ADD_QUESTION_CONFIRMATION_MODAL = 'UI_CLOSE_ADD_QUESTION_CONFIRMATION_MODAL', SELECT_LEVEL = 'SELECT_LEVEL', DESELECT_LEVEL = 'DESELECT_LEVEL', SELECT_QUESTION = 'SELECT_QUESTION', @@ -57,17 +49,6 @@ export enum ActionTypes { } const SyncActionCreators = { - uiOpenSidebar: () => createAction(ActionTypes.UI_OPEN_SIDEBAR), - uiCloseSidebar: () => createAction(ActionTypes.UI_CLOSE_SIDEBAR), - uiOpenAddQuestionModal: () => createAction(ActionTypes.UI_OPEN_ADD_QUESTION_MODAL), - uiCloseAddQuestionModal: () => createAction(ActionTypes.UI_CLOSE_ADD_QUESTION_MODAL), - uiOpenEditQuestionModal: (question: Question, onClose?: CommonModalProps['onClose']) => - createAction(ActionTypes.UI_OPEN_EDIT_QUESTION_MODAL, { question, onClose }), - uiCloseEditQuestionModal: () => createAction(ActionTypes.UI_CLOSE_EDIT_QUESTION_MODAL), - uiOpenAddQuestionConfirmationModal: () => - createAction(ActionTypes.UI_OPEN_ADD_QUESTION_CONFIRMATION_MODAL), - uiCloseAddQuestionConfirmationModal: () => - createAction(ActionTypes.UI_CLOSE_ADD_QUESTION_CONFIRMATION_MODAL), selectLevel: (level: LevelKey) => createAction(ActionTypes.SELECT_LEVEL, level), deselectLevel: (level: LevelKey) => createAction(ActionTypes.DESELECT_LEVEL, level), selectQuestion: (q: Question) => createAction(ActionTypes.SELECT_QUESTION, q), diff --git a/apps/www/redux/reducers/index.ts b/apps/www/redux/reducers/index.ts index 8e35cfeb..730fe6ca 100644 --- a/apps/www/redux/reducers/index.ts +++ b/apps/www/redux/reducers/index.ts @@ -6,13 +6,11 @@ import { questions } from './questions'; import { routeDetails } from './routeDetails'; import { selectedLevels } from './selectedLevels'; import { selectedQuestions } from './selectedQuestions'; -import { ui } from './ui'; const reducersObj = { questions, oneQuestion, selectedQuestions, - ui, selectedLevels, routeDetails, auth, diff --git a/apps/www/redux/reducers/ui.ts b/apps/www/redux/reducers/ui.ts deleted file mode 100644 index a6dc4b5d..00000000 --- a/apps/www/redux/reducers/ui.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { CommonModalProps } from '../../components/modals/baseModal/BaseModal'; -import { Actions, ActionTypes } from '../actions'; - -import { Question } from './questions'; - -type ModalState = { - open: boolean; - data?: T; - onClose?: CommonModalProps['onClose']; -}; - -const initialUiState = { - isSidebarOpen: false, - addQuestionModal: { open: false } as ModalState, - isAddQuestionConfirmationModalOpen: false, -}; - -export const ui = (ui = initialUiState, action: Actions): typeof initialUiState => { - switch (action.type) { - case ActionTypes.UI_OPEN_ADD_QUESTION_MODAL: - return { ...ui, addQuestionModal: { open: true } }; - case ActionTypes.UI_CLOSE_ADD_QUESTION_MODAL: - return { ...ui, addQuestionModal: { open: false } }; - case ActionTypes.UI_OPEN_EDIT_QUESTION_MODAL: - return { - ...ui, - addQuestionModal: { - open: true, - data: action.payload.question, - onClose: action.payload.onClose, - }, - }; - case ActionTypes.UI_CLOSE_EDIT_QUESTION_MODAL: - return { - ...ui, - addQuestionModal: { open: false, data: undefined, onClose: undefined }, - }; - case ActionTypes.UI_OPEN_ADD_QUESTION_CONFIRMATION_MODAL: - return { ...ui, isAddQuestionConfirmationModalOpen: true }; - case ActionTypes.UI_CLOSE_ADD_QUESTION_CONFIRMATION_MODAL: - return { ...ui, isAddQuestionConfirmationModalOpen: false }; - case ActionTypes.UI_OPEN_SIDEBAR: - return { ...ui, isSidebarOpen: true }; - case ActionTypes.UI_CLOSE_SIDEBAR: - return { ...ui, isSidebarOpen: false }; - default: - return ui; - } -}; From 6d6761630cc7731444ba723d9199816f7be4a3bf Mon Sep 17 00:00:00 2001 From: drillprop Date: Fri, 30 Oct 2020 12:10:15 +0100 Subject: [PATCH 3/7] Replace redux actions with UIContext methods --- .../adminQuestions/AdminQuestions.tsx | 6 +- .../headers/ctaHeader/CtaHeader.tsx | 133 +++++++++--------- .../addQuestionModal/AddQuestionModal.tsx | 20 ++- .../components/modals/appModals/AppModals.tsx | 27 ++-- .../questions/allQuestions/AllQuestions.tsx | 8 +- .../MobileActionButtons.tsx | 21 +-- .../questionsSidebar/QuestionsSidebar.tsx | 10 +- 7 files changed, 112 insertions(+), 113 deletions(-) diff --git a/apps/www/components/adminQuestions/AdminQuestions.tsx b/apps/www/components/adminQuestions/AdminQuestions.tsx index 96553f90..852c2f61 100644 --- a/apps/www/components/adminQuestions/AdminQuestions.tsx +++ b/apps/www/components/adminQuestions/AdminQuestions.tsx @@ -3,6 +3,7 @@ import { useDispatch, useSelector } from 'react-redux'; import spinnerStyles from '../../components/layout/appSpinner.module.scss'; import { TechnologyKey } from '../../constants/technology-icon-items'; +import { useUIContext } from '../../contexts/UIContextProvider'; import { ActionCreators } from '../../redux/actions'; import { Question } from '../../redux/reducers/questions'; import { Container } from '../container/Container'; @@ -25,6 +26,7 @@ const EmptyAdminQuestions = memo(({ questions }: { questions?: Question[] }) => }); const AdminQuestions = memo(() => { + const { openEditQuestionModal } = useUIContext(); const [status, setStatus] = useState<'pending' | 'accepted'>('pending'); const [technology] = useState(undefined); @@ -74,9 +76,9 @@ const AdminQuestions = memo(() => { return; } - dispatch(ActionCreators.uiOpenEditQuestionModal(question, onEditFinished)); + openEditQuestionModal(question, onEditFinished); }, - [dispatch, onEditFinished, questions.data] + [onEditFinished, openEditQuestionModal, questions.data] ); const updateStatus: React.ChangeEventHandler = useCallback((e) => { diff --git a/apps/www/components/headers/ctaHeader/CtaHeader.tsx b/apps/www/components/headers/ctaHeader/CtaHeader.tsx index a9129334..5e11ca2f 100644 --- a/apps/www/components/headers/ctaHeader/CtaHeader.tsx +++ b/apps/www/components/headers/ctaHeader/CtaHeader.tsx @@ -2,7 +2,7 @@ import classNames from 'classnames'; import React, { memo } from 'react'; import { connect } from 'react-redux'; -import { ActionCreators } from '../../../redux/actions'; +import { useUIContext } from '../../../contexts/UIContextProvider'; import { AppState } from '../../../redux/reducers/index'; import { getAreAnyQuestionSelected, @@ -14,59 +14,61 @@ import { Container } from '../../container/Container'; import styles from './ctaHeader.module.scss'; -export const CtaHeaderComponent: React.FC< - ReturnType & typeof mapDispatchToProps -> = memo(({ uiOpenAddQuestionModal, areAnyQuestionSelected, isAdmin }) => { - const onDownloadClick: React.MouseEventHandler = (_event) => { - reportEvent('Pobierz plik PDF'); - // @todo open DownloadSuccessModal - // @todo this.analyticsService.reportPdfDownload(this.selectedQuestionsService.getSelectedIds()); - }; +export const CtaHeaderComponent: React.FC> = memo( + ({ areAnyQuestionSelected, isAdmin }) => { + const { openAddQuestionModal } = useUIContext(); + const onDownloadClick: React.MouseEventHandler = (_event) => { + reportEvent('Pobierz plik PDF'); + // @todo open DownloadSuccessModal + // @todo this.analyticsService.reportPdfDownload(this.selectedQuestionsService.getSelectedIds()); + }; - const onOpenAddQuestionModalClick: React.MouseEventHandler = (_event) => { - reportEvent('Dodaj pytanie'); - uiOpenAddQuestionModal(); - }; + const onOpenAddQuestionModalClick: React.MouseEventHandler = (_event) => { + reportEvent('Dodaj pytanie'); + openAddQuestionModal(); + }; - const reportEvent = (action: string) => { - globalReportEvent(action, 'Menu'); - }; - return ( -
- - + + - -
- ); -}); + + + + + ); + } +); const mapStateToProps = (state: AppState) => { return { @@ -100,8 +103,4 @@ const mapStateToProps = (state: AppState) => { }; }; -const mapDispatchToProps = { - uiOpenAddQuestionModal: ActionCreators.uiOpenAddQuestionModal, -}; - -export const CtaHeader = connect(mapStateToProps, mapDispatchToProps)(CtaHeaderComponent); +export const CtaHeader = connect(mapStateToProps)(CtaHeaderComponent); diff --git a/apps/www/components/modals/addQuestionModal/AddQuestionModal.tsx b/apps/www/components/modals/addQuestionModal/AddQuestionModal.tsx index 5064bc19..3ea940b6 100644 --- a/apps/www/components/modals/addQuestionModal/AddQuestionModal.tsx +++ b/apps/www/components/modals/addQuestionModal/AddQuestionModal.tsx @@ -1,10 +1,9 @@ import { isEqual } from 'lodash'; -import React, { memo, useState, useEffect, useCallback, forwardRef } from 'react'; -import { useDispatch } from 'react-redux'; +import React, { forwardRef, memo, useCallback, useEffect, useState } from 'react'; import type { LevelKey } from '../../../constants/level'; import type { TechnologyKey } from '../../../constants/technology-icon-items'; -import { ActionCreators } from '../../../redux/actions'; +import { useUIContext } from '../../../contexts/UIContextProvider'; import { Question } from '../../../redux/reducers/questions'; import { Api } from '../../../services/Api'; import { useDidMount, useRenderProp } from '../../../utils/hooks'; @@ -24,6 +23,7 @@ type AddQuestionModalProps = AddQuestionModalOwnProps & CommonModalProps; export const AddQuestionModal = memo( forwardRef(({ onClose, originalQuestion }, ref) => { + const { setIsAddQuestionConfirmationModalOpen } = useUIContext(); const [editedQuestion, setEditedQuestion] = useState(); const [questionText, setQuestionText] = useState(''); const [level, setLevel] = useState(); @@ -31,8 +31,6 @@ export const AddQuestionModal = memo( const [isLoading, setIsLoading] = useState(false); const [valid, setValid] = useState(false); - const dispatch = useDispatch(); - const isValid = useCallback(() => Boolean(level && technology && questionText.trim()), [ level, questionText, @@ -101,11 +99,19 @@ export const AddQuestionModal = memo( return Api.createQuestion(body) .then(() => { onClose({ reason: 'submit' }); - dispatch(ActionCreators.uiOpenAddQuestionConfirmationModal()); + setIsAddQuestionConfirmationModalOpen(true); }) .finally(() => setIsLoading(false)); } - }, [dispatch, isValid, level, onClose, originalQuestion, questionText, technology]); + }, [ + isValid, + level, + onClose, + originalQuestion, + questionText, + setIsAddQuestionConfirmationModalOpen, + technology, + ]); const validate = useCallback(() => { setValid(isValid()); diff --git a/apps/www/components/modals/appModals/AppModals.tsx b/apps/www/components/modals/appModals/AppModals.tsx index aa79c6fe..b2040f60 100644 --- a/apps/www/components/modals/appModals/AppModals.tsx +++ b/apps/www/components/modals/appModals/AppModals.tsx @@ -1,8 +1,7 @@ -import React, { useRef, memo, useCallback } from 'react'; -import { useSelector, useDispatch } from 'react-redux'; +import React, { memo, useCallback, useRef } from 'react'; import { CSSTransition } from 'react-transition-group'; -import { ActionCreators } from '../../../redux/actions'; +import { useUIContext } from '../../../contexts/UIContextProvider'; import { AddQuestionConfirmationModal } from '../addQuestionConfirmationModal/AddQuestionConfirmationModal'; import { AddQuestionModal } from '../addQuestionModal/AddQuestionModal'; import { CommonModalProps } from '../baseModal/BaseModal'; @@ -14,11 +13,13 @@ export const AppModals = memo(() => { const addQuestionModalRef = useRef(null); const addQuestionConfirmationModalRef = useRef(null); - const dispatch = useDispatch(); - const addQuestionModalState = useSelector((state) => state.ui.addQuestionModal); - const isAddQuestionConfirmationModalOpen = useSelector( - (state) => state.ui.isAddQuestionConfirmationModalOpen - ); + const { + addQuestionModalState, + closeAddQuestionModal, + isAddQuestionConfirmationModalOpen, + closeEditQuestionModal, + setIsAddQuestionConfirmationModalOpen, + } = useUIContext(); const closeQuestionModal: CommonModalProps['onClose'] = useCallback( (args) => { @@ -26,19 +27,19 @@ export const AppModals = memo(() => { addQuestionModalState.onClose(args); } if (addQuestionModalState.data) { - dispatch(ActionCreators.uiCloseEditQuestionModal()); + closeEditQuestionModal(); } else { - dispatch(ActionCreators.uiCloseAddQuestionModal()); + closeAddQuestionModal(); } }, - [addQuestionModalState, dispatch] + [addQuestionModalState, closeAddQuestionModal, closeEditQuestionModal] ); const closeConfirmationModal: CommonModalProps['onClose'] = useCallback( (_args) => { - dispatch(ActionCreators.uiCloseAddQuestionConfirmationModal()); + setIsAddQuestionConfirmationModalOpen(false); }, - [dispatch] + [setIsAddQuestionConfirmationModalOpen] ); return ( diff --git a/apps/www/components/questions/allQuestions/AllQuestions.tsx b/apps/www/components/questions/allQuestions/AllQuestions.tsx index 7f30e8c7..62334b16 100644 --- a/apps/www/components/questions/allQuestions/AllQuestions.tsx +++ b/apps/www/components/questions/allQuestions/AllQuestions.tsx @@ -3,6 +3,7 @@ import { connect } from 'react-redux'; import { Level } from '../../../constants/level'; import { technologyIconItems, Technology } from '../../../constants/technology-icon-items'; +import { useUIContext } from '../../../contexts/UIContextProvider'; import { ActionCreators } from '../../../redux/actions'; import { AppState } from '../../../redux/reducers/index'; import { Question } from '../../../redux/reducers/questions'; @@ -29,10 +30,10 @@ const AllQuestionsComponent = React.memo( questions, selectedQuestionsIds, route, - uiOpenAddQuestionModal, selectQuestion, deselectQuestion, }) => { + const { openAddQuestionModal } = useUIContext(); const technologyIconItem = technologyIconItems.find((t) => t.name === technology); const category = (technologyIconItem && technologyIconItem.label) || ''; @@ -55,8 +56,8 @@ const AllQuestionsComponent = React.memo( const onAddNewClick = useCallback(() => { reportEvent('CTA Dodaj nowe pytanie'); - uiOpenAddQuestionModal(); - }, [uiOpenAddQuestionModal, reportEvent]); + openAddQuestionModal(); + }, [openAddQuestionModal, reportEvent]); const toggleQuestion = useCallback( (questionId: Question['id']) => { @@ -141,7 +142,6 @@ const mapStateToProps = (state: AppState) => { const mapDispatchToProps = { selectQuestion: ActionCreators.selectQuestion, deselectQuestion: ActionCreators.deselectQuestion, - uiOpenAddQuestionModal: ActionCreators.uiOpenAddQuestionModal, }; const AllQuestions = connect(mapStateToProps, mapDispatchToProps)(AllQuestionsComponent); diff --git a/apps/www/components/questions/mobileActionButtons/MobileActionButtons.tsx b/apps/www/components/questions/mobileActionButtons/MobileActionButtons.tsx index 101a3cca..b653c75d 100644 --- a/apps/www/components/questions/mobileActionButtons/MobileActionButtons.tsx +++ b/apps/www/components/questions/mobileActionButtons/MobileActionButtons.tsx @@ -2,7 +2,7 @@ import classNames from 'classnames'; import React from 'react'; import { connect } from 'react-redux'; -import { ActionCreators } from '../../../redux/actions'; +import { useUIContext } from '../../../contexts/UIContextProvider'; import { AppState } from '../../../redux/reducers'; import { getAreAnyQuestionSelected, getDownloadUrl } from '../../../redux/selectors/selectors'; @@ -13,8 +13,9 @@ interface MobileActionButtonsProps { } const MobileActionButtonsComponent = React.memo< - MobileActionButtonsProps & ReturnType & typeof mapDispatchToProps ->(({ justDownload, uiOpenSidebar, uiOpenAddQuestionModal }) => { + MobileActionButtonsProps & ReturnType +>(({ justDownload }) => { + const { setIsSidebarOpen, openAddQuestionModal } = useUIContext(); const onDownloadClick = () => { // @todo }; @@ -25,7 +26,7 @@ const MobileActionButtonsComponent = React.memo< className={classNames(styles.openSidebar, 'circle-button')} title="Filtruj wyniki" aria-label="Filtruj wyniki" - onClick={uiOpenSidebar} + onClick={() => setIsSidebarOpen(true)} /> )} {!justDownload && ( @@ -33,7 +34,7 @@ const MobileActionButtonsComponent = React.memo< className={classNames(styles.addQuestion, 'circle-button')} title="Dodaj pytanie" aria-label="Dodaj pytanie" - onClick={uiOpenAddQuestionModal} + onClick={openAddQuestionModal} /> )} {/* {!justDownload && ( @@ -71,13 +72,5 @@ const mapStateToProps = (state: AppState) => { }; }; -const mapDispatchToProps = { - uiOpenSidebar: ActionCreators.uiOpenSidebar, - uiOpenAddQuestionModal: ActionCreators.uiOpenAddQuestionModal, -}; - -const MobileActionButtons = connect( - mapStateToProps, - mapDispatchToProps -)(MobileActionButtonsComponent); +const MobileActionButtons = connect(mapStateToProps)(MobileActionButtonsComponent); export default MobileActionButtons; diff --git a/apps/www/components/questions/questionsSidebar/QuestionsSidebar.tsx b/apps/www/components/questions/questionsSidebar/QuestionsSidebar.tsx index c08fcb09..6f59ff15 100644 --- a/apps/www/components/questions/questionsSidebar/QuestionsSidebar.tsx +++ b/apps/www/components/questions/questionsSidebar/QuestionsSidebar.tsx @@ -1,16 +1,14 @@ import classNames from 'classnames'; import React from 'react'; -import { useSelector, useDispatch } from 'react-redux'; -import { ActionCreators } from '../../../redux/actions'; +import { useUIContext } from '../../../contexts/UIContextProvider'; import LevelFilter from './levelFilter/LevelFilter'; import styles from './questionsSidebar.module.scss'; import { TechnologyFilter } from './technologyFilter/TechnologyFilter'; const QuestionsSidebar = () => { - const isSidebarOpen = useSelector((state) => state.ui.isSidebarOpen); - const dispatch = useDispatch(); + const { isSidebarOpen, setIsSidebarOpen } = useUIContext(); return (
@@ -27,14 +25,14 @@ const QuestionsSidebar = () => { From a4b5f0ae9d37a3ea94b03ce371124a7b46c4ebc1 Mon Sep 17 00:00:00 2001 From: drillprop Date: Sat, 31 Oct 2020 13:40:58 +0100 Subject: [PATCH 4/7] Replace set... methods with open/close equivalents --- .../addQuestionModal/AddQuestionModal.tsx | 6 ++-- .../components/modals/appModals/AppModals.tsx | 6 ++-- .../MobileActionButtons.tsx | 4 +-- .../questionsSidebar/QuestionsSidebar.tsx | 10 ++---- apps/www/contexts/UIContextProvider.tsx | 32 +++++++++++++++---- apps/www/redux/actions.ts | 9 +++--- 6 files changed, 41 insertions(+), 26 deletions(-) diff --git a/apps/www/components/modals/addQuestionModal/AddQuestionModal.tsx b/apps/www/components/modals/addQuestionModal/AddQuestionModal.tsx index 3ea940b6..e0d98a81 100644 --- a/apps/www/components/modals/addQuestionModal/AddQuestionModal.tsx +++ b/apps/www/components/modals/addQuestionModal/AddQuestionModal.tsx @@ -23,7 +23,7 @@ type AddQuestionModalProps = AddQuestionModalOwnProps & CommonModalProps; export const AddQuestionModal = memo( forwardRef(({ onClose, originalQuestion }, ref) => { - const { setIsAddQuestionConfirmationModalOpen } = useUIContext(); + const { openAddQuestionConfirmationModal } = useUIContext(); const [editedQuestion, setEditedQuestion] = useState(); const [questionText, setQuestionText] = useState(''); const [level, setLevel] = useState(); @@ -99,7 +99,7 @@ export const AddQuestionModal = memo( return Api.createQuestion(body) .then(() => { onClose({ reason: 'submit' }); - setIsAddQuestionConfirmationModalOpen(true); + openAddQuestionConfirmationModal(); }) .finally(() => setIsLoading(false)); } @@ -107,9 +107,9 @@ export const AddQuestionModal = memo( isValid, level, onClose, + openAddQuestionConfirmationModal, originalQuestion, questionText, - setIsAddQuestionConfirmationModalOpen, technology, ]); diff --git a/apps/www/components/modals/appModals/AppModals.tsx b/apps/www/components/modals/appModals/AppModals.tsx index b2040f60..ec9bd6fa 100644 --- a/apps/www/components/modals/appModals/AppModals.tsx +++ b/apps/www/components/modals/appModals/AppModals.tsx @@ -18,7 +18,7 @@ export const AppModals = memo(() => { closeAddQuestionModal, isAddQuestionConfirmationModalOpen, closeEditQuestionModal, - setIsAddQuestionConfirmationModalOpen, + closeAddQuestionConfirmationModal, } = useUIContext(); const closeQuestionModal: CommonModalProps['onClose'] = useCallback( @@ -37,9 +37,9 @@ export const AppModals = memo(() => { const closeConfirmationModal: CommonModalProps['onClose'] = useCallback( (_args) => { - setIsAddQuestionConfirmationModalOpen(false); + closeAddQuestionConfirmationModal(); }, - [setIsAddQuestionConfirmationModalOpen] + [closeAddQuestionConfirmationModal] ); return ( diff --git a/apps/www/components/questions/mobileActionButtons/MobileActionButtons.tsx b/apps/www/components/questions/mobileActionButtons/MobileActionButtons.tsx index b653c75d..20bd4567 100644 --- a/apps/www/components/questions/mobileActionButtons/MobileActionButtons.tsx +++ b/apps/www/components/questions/mobileActionButtons/MobileActionButtons.tsx @@ -15,7 +15,7 @@ interface MobileActionButtonsProps { const MobileActionButtonsComponent = React.memo< MobileActionButtonsProps & ReturnType >(({ justDownload }) => { - const { setIsSidebarOpen, openAddQuestionModal } = useUIContext(); + const { openSideBar, openAddQuestionModal } = useUIContext(); const onDownloadClick = () => { // @todo }; @@ -26,7 +26,7 @@ const MobileActionButtonsComponent = React.memo< className={classNames(styles.openSidebar, 'circle-button')} title="Filtruj wyniki" aria-label="Filtruj wyniki" - onClick={() => setIsSidebarOpen(true)} + onClick={openSideBar} /> )} {!justDownload && ( diff --git a/apps/www/components/questions/questionsSidebar/QuestionsSidebar.tsx b/apps/www/components/questions/questionsSidebar/QuestionsSidebar.tsx index 6f59ff15..d1a41344 100644 --- a/apps/www/components/questions/questionsSidebar/QuestionsSidebar.tsx +++ b/apps/www/components/questions/questionsSidebar/QuestionsSidebar.tsx @@ -8,7 +8,7 @@ import styles from './questionsSidebar.module.scss'; import { TechnologyFilter } from './technologyFilter/TechnologyFilter'; const QuestionsSidebar = () => { - const { isSidebarOpen, setIsSidebarOpen } = useUIContext(); + const { isSidebarOpen, closeSidebar } = useUIContext(); return (
@@ -25,15 +25,11 @@ const QuestionsSidebar = () => { - diff --git a/apps/www/contexts/UIContextProvider.tsx b/apps/www/contexts/UIContextProvider.tsx index 4524cfa8..33945218 100644 --- a/apps/www/contexts/UIContextProvider.tsx +++ b/apps/www/contexts/UIContextProvider.tsx @@ -1,4 +1,4 @@ -import React, { Dispatch, SetStateAction, useCallback, useContext, useState } from 'react'; +import React, { useCallback, useContext, useState } from 'react'; import { CommonModalProps } from '../components/modals/baseModal/BaseModal'; import { Question } from '../redux/reducers/questions'; @@ -11,14 +11,16 @@ type ModalState = { type UiContextType = { isSidebarOpen: boolean; - setIsSidebarOpen: Dispatch>; + openSideBar: () => void; + closeSidebar: () => void; addQuestionModalState: ModalState; openAddQuestionModal: () => void; closeAddQuestionModal: () => void; openEditQuestionModal: (question: Question, onClose?: CommonModalProps['onClose']) => void; closeEditQuestionModal: () => void; isAddQuestionConfirmationModalOpen: boolean; - setIsAddQuestionConfirmationModalOpen: Dispatch>; + openAddQuestionConfirmationModal: () => void; + closeAddQuestionConfirmationModal: () => void; }; const UIContext = React.createContext(undefined); @@ -32,6 +34,14 @@ const UIContextProvider: React.FC = ({ children }) => { false ); + const openSideBar = useCallback(() => { + setIsSidebarOpen(true); + }, []); + + const closeSidebar = useCallback(() => { + setIsSidebarOpen(false); + }, []); + const openAddQuestionModal = useCallback(() => { setAddQuestionModalState({ open: true }); }, []); @@ -51,18 +61,28 @@ const UIContextProvider: React.FC = ({ children }) => { setAddQuestionModalState({ open: false, data: undefined, onClose: undefined }); }, []); + const openAddQuestionConfirmationModal = useCallback(() => { + setIsAddQuestionConfirmationModalOpen(true); + }, []); + + const closeAddQuestionConfirmationModal = useCallback(() => { + setIsAddQuestionConfirmationModalOpen(false); + }, []); + return ( {children} @@ -72,7 +92,7 @@ const UIContextProvider: React.FC = ({ children }) => { export const useUIContext = () => { const ctx = useContext(UIContext); - if (ctx === undefined) { + if (!ctx) { throw new Error('useUIContext must be used within a UIContextProvider'); } return ctx; diff --git a/apps/www/redux/actions.ts b/apps/www/redux/actions.ts index 898583cc..f986ac90 100644 --- a/apps/www/redux/actions.ts +++ b/apps/www/redux/actions.ts @@ -1,13 +1,12 @@ -import { CommonModalProps } from '../components/modals/baseModal/BaseModal'; import { LevelKey } from '../constants/level'; -import { TechnologyKey, SortBy } from '../constants/technology-icon-items'; -import { Api } from '../services/Api'; +import { SortBy, TechnologyKey } from '../constants/technology-icon-items'; import type { ApiResponse } from '../services/Api'; -import type { RouteDetails, AppStore, GetInitialPropsContext } from '../utils/types'; +import { Api } from '../services/Api'; +import type { AppStore, GetInitialPropsContext, RouteDetails } from '../utils/types'; import type { AuthData } from './reducers/auth'; import type { Question } from './reducers/questions'; -import { getTechnology, getQuestionId, getLoggedInUser } from './selectors/selectors'; +import { getLoggedInUser, getQuestionId, getTechnology } from './selectors/selectors'; import { ActionsUnion, createAction } from './types'; export type AsyncAction = ( From 5841c3697513c57a0de821cb815ef7aebdfc2034 Mon Sep 17 00:00:00 2001 From: drillprop Date: Sat, 31 Oct 2020 13:48:07 +0100 Subject: [PATCH 5/7] Place context's value inside useMemo --- apps/www/contexts/UIContextProvider.tsx | 49 +++++++++++++++---------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/apps/www/contexts/UIContextProvider.tsx b/apps/www/contexts/UIContextProvider.tsx index 33945218..e5061ed1 100644 --- a/apps/www/contexts/UIContextProvider.tsx +++ b/apps/www/contexts/UIContextProvider.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useContext, useState } from 'react'; +import React, { useCallback, useContext, useMemo, useState } from 'react'; import { CommonModalProps } from '../components/modals/baseModal/BaseModal'; import { Question } from '../redux/reducers/questions'; @@ -69,25 +69,36 @@ const UIContextProvider: React.FC = ({ children }) => { setIsAddQuestionConfirmationModalOpen(false); }, []); - return ( - - {children} - + const memoizedValue = useMemo( + () => ({ + isSidebarOpen, + openSideBar, + closeSidebar, + addQuestionModalState, + openAddQuestionModal, + closeAddQuestionModal, + openEditQuestionModal, + closeEditQuestionModal, + isAddQuestionConfirmationModalOpen, + openAddQuestionConfirmationModal, + closeAddQuestionConfirmationModal, + }), + [ + isSidebarOpen, + openSideBar, + closeSidebar, + addQuestionModalState, + openAddQuestionModal, + closeAddQuestionModal, + openEditQuestionModal, + closeEditQuestionModal, + isAddQuestionConfirmationModalOpen, + openAddQuestionConfirmationModal, + closeAddQuestionConfirmationModal, + ] ); + + return {children}; }; export const useUIContext = () => { From c2705b6a520afc6158fb18d7f36c5a161d617d8e Mon Sep 17 00:00:00 2001 From: drillprop Date: Sat, 31 Oct 2020 13:57:58 +0100 Subject: [PATCH 6/7] Fix useMemo --- apps/www/contexts/UIContextProvider.tsx | 42 +++++++++++-------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/apps/www/contexts/UIContextProvider.tsx b/apps/www/contexts/UIContextProvider.tsx index e5061ed1..be4b4368 100644 --- a/apps/www/contexts/UIContextProvider.tsx +++ b/apps/www/contexts/UIContextProvider.tsx @@ -69,36 +69,32 @@ const UIContextProvider: React.FC = ({ children }) => { setIsAddQuestionConfirmationModalOpen(false); }, []); - const memoizedValue = useMemo( + const memoizedState = useMemo( () => ({ isSidebarOpen, - openSideBar, - closeSidebar, addQuestionModalState, - openAddQuestionModal, - closeAddQuestionModal, - openEditQuestionModal, - closeEditQuestionModal, isAddQuestionConfirmationModalOpen, - openAddQuestionConfirmationModal, - closeAddQuestionConfirmationModal, }), - [ - isSidebarOpen, - openSideBar, - closeSidebar, - addQuestionModalState, - openAddQuestionModal, - closeAddQuestionModal, - openEditQuestionModal, - closeEditQuestionModal, - isAddQuestionConfirmationModalOpen, - openAddQuestionConfirmationModal, - closeAddQuestionConfirmationModal, - ] + [isSidebarOpen, addQuestionModalState, isAddQuestionConfirmationModalOpen] ); - return {children}; + return ( + + {children} + + ); }; export const useUIContext = () => { From 107a0e9c8f11376c382e1f950029a9619549b135 Mon Sep 17 00:00:00 2001 From: drillprop Date: Sat, 31 Oct 2020 15:31:50 +0100 Subject: [PATCH 7/7] Fix useMemo --- apps/www/contexts/UIContextProvider.tsx | 42 ++++++++++++++----------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/apps/www/contexts/UIContextProvider.tsx b/apps/www/contexts/UIContextProvider.tsx index be4b4368..ebecc9cd 100644 --- a/apps/www/contexts/UIContextProvider.tsx +++ b/apps/www/contexts/UIContextProvider.tsx @@ -69,32 +69,36 @@ const UIContextProvider: React.FC = ({ children }) => { setIsAddQuestionConfirmationModalOpen(false); }, []); - const memoizedState = useMemo( + const memoizedValue = useMemo( () => ({ + openSideBar, + closeSidebar, + openAddQuestionModal, + closeAddQuestionModal, + openEditQuestionModal, + closeEditQuestionModal, + openAddQuestionConfirmationModal, + closeAddQuestionConfirmationModal, isSidebarOpen, addQuestionModalState, isAddQuestionConfirmationModalOpen, }), - [isSidebarOpen, addQuestionModalState, isAddQuestionConfirmationModalOpen] + [ + openSideBar, + closeSidebar, + openAddQuestionModal, + closeAddQuestionModal, + openEditQuestionModal, + closeEditQuestionModal, + openAddQuestionConfirmationModal, + closeAddQuestionConfirmationModal, + isSidebarOpen, + addQuestionModalState, + isAddQuestionConfirmationModalOpen, + ] ); - return ( - - {children} - - ); + return {children}; }; export const useUIContext = () => {