diff --git a/web/app.react.js b/web/app.react.js --- a/web/app.react.js +++ b/web/app.react.js @@ -1,16 +1,14 @@ // @flow +import { config as faConfig } from '@fortawesome/fontawesome-svg-core'; import '@fontsource/inter'; import '@fontsource/inter/500.css'; import '@fontsource/inter/600.css'; - import '@fontsource/ibm-plex-sans'; import '@fontsource/ibm-plex-sans/500.css'; import '@fontsource/ibm-plex-sans/600.css'; - import 'basscss/css/basscss.min.css'; import './theme.css'; -import { config as faConfig } from '@fortawesome/fontawesome-svg-core'; import _isEqual from 'lodash/fp/isEqual'; import * as React from 'react'; import { DndProvider } from 'react-dnd'; @@ -35,6 +33,7 @@ import Chat from './chat/chat.react'; import InputStateContainer from './input/input-state-container.react'; import LoadingIndicator from './loading-indicator.react'; +import { ModalProvider, useModalContext } from './modals/modal-provider.react'; import DisconnectedBar from './redux/disconnected-bar'; import DisconnectedBarVisibilityHandler from './redux/disconnected-bar-visibility-handler'; import FocusHandler from './redux/focus-handler.react'; @@ -83,6 +82,7 @@ +activeThreadCurrentlyUnread: boolean, // Redux dispatch functions +dispatch: Dispatch, + +setModal: (?React.Node) => void, }; type State = { +modal: ?React.Node, @@ -182,7 +182,7 @@
{mainContent}
- + ); } @@ -199,46 +199,56 @@ updateCalendarQueryActionTypes, ); -const ConnectedApp: React.ComponentType = React.memo( - function ConnectedApp(props) { - const activeChatThreadID = useSelector( - state => state.navInfo.activeChatThreadID, - ); - const navInfo = useSelector(state => state.navInfo); - - const fetchEntriesLoadingStatus = useSelector( - fetchEntriesLoadingStatusSelector, - ); - const updateCalendarQueryLoadingStatus = useSelector( - updateCalendarQueryLoadingStatusSelector, - ); - const entriesLoadingStatus = combineLoadingStatuses( - fetchEntriesLoadingStatus, - updateCalendarQueryLoadingStatus, - ); - - const loggedIn = useSelector(isLoggedIn); - const mostRecentReadThread = useSelector(mostRecentReadThreadSelector); - const activeThreadCurrentlyUnread = useSelector( - state => - !activeChatThreadID || - !!state.threadStore.threadInfos[activeChatThreadID]?.currentUser.unread, - ); - - const dispatch = useDispatch(); +function ConnectedApp(props) { + const activeChatThreadID = useSelector( + state => state.navInfo.activeChatThreadID, + ); + const navInfo = useSelector(state => state.navInfo); + + const fetchEntriesLoadingStatus = useSelector( + fetchEntriesLoadingStatusSelector, + ); + const updateCalendarQueryLoadingStatus = useSelector( + updateCalendarQueryLoadingStatusSelector, + ); + const entriesLoadingStatus = combineLoadingStatuses( + fetchEntriesLoadingStatus, + updateCalendarQueryLoadingStatus, + ); + + const loggedIn = useSelector(isLoggedIn); + const mostRecentReadThread = useSelector(mostRecentReadThreadSelector); + const activeThreadCurrentlyUnread = useSelector( + state => + !activeChatThreadID || + !!state.threadStore.threadInfos[activeChatThreadID]?.currentUser.unread, + ); + + const dispatch = useDispatch(); + const modalContext = useModalContext(); + + return ( + + ); +} +const AppWithProvider: React.ComponentType = React.memo( + function AppWithProvider(props) { return ( - + + + ); }, ); -export default ConnectedApp; +export default AppWithProvider; diff --git a/web/modals/modal-provider.react.js b/web/modals/modal-provider.react.js new file mode 100644 --- /dev/null +++ b/web/modals/modal-provider.react.js @@ -0,0 +1,51 @@ +// @flow + +import invariant from 'invariant'; +import * as React from 'react'; + +type Props = { + +children: React.Node, +}; +type ModalContextType = { + +modal: ?React.Node, + +setModal: (?React.Node) => void, + +clearModal: () => void, +}; + +const ModalContext: React.Context = React.createContext( + { + modal: null, + setModal: () => {}, + clearModal: () => {}, + }, +); + +function ModalProvider(props: Props): React.Node { + const { children } = props; + const [modal, setModal] = React.useState(null); + const clearModal = React.useCallback(() => setModal(null), []); + const contextSetModal = React.useCallback((component: ?React.Node) => { + setModal(component); + }, []); + + const value = React.useMemo(() => { + return { + modal, + setModal: contextSetModal, + clearModal, + }; + }, [modal, contextSetModal, clearModal]); + + return ( + {children} + ); +} + +function useModalContext(): ModalContextType { + const context = React.useContext(ModalContext); + invariant(context, 'ModalContext not found'); + + return context; +} + +export { ModalProvider, useModalContext };