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 };