diff --git a/app/components/DocumentListItem.js b/app/components/DocumentListItem.js index 08986eb81..610a1b48d 100644 --- a/app/components/DocumentListItem.js +++ b/app/components/DocumentListItem.js @@ -15,6 +15,7 @@ import Flex from "components/Flex"; import Highlight from "components/Highlight"; import StarButton, { AnimatedStar } from "components/Star"; import Tooltip from "components/Tooltip"; +import useBoolean from "hooks/useBoolean"; import useCurrentTeam from "hooks/useCurrentTeam"; import useCurrentUser from "hooks/useCurrentUser"; import useStores from "hooks/useStores"; @@ -46,7 +47,7 @@ function DocumentListItem(props: Props, ref) { const { policies } = useStores(); const currentUser = useCurrentUser(); const currentTeam = useCurrentTeam(); - const [menuOpen, setMenuOpen] = React.useState(false); + const [menuOpen, handleMenuOpen, handleMenuClose] = useBoolean(); const { document, showNestedDocuments, @@ -66,9 +67,6 @@ function DocumentListItem(props: Props, ref) { !document.isDraft && !document.isArchived && !document.isTemplate; const can = policies.abilities(currentTeam.id); - const handleMenuOpen = React.useCallback(() => setMenuOpen(true), []); - const handleMenuClosed = React.useCallback(() => setMenuOpen(false), []); - return ( diff --git a/app/components/Sidebar/components/CollectionLink.js b/app/components/Sidebar/components/CollectionLink.js index 5366fcd51..25284b124 100644 --- a/app/components/Sidebar/components/CollectionLink.js +++ b/app/components/Sidebar/components/CollectionLink.js @@ -12,6 +12,7 @@ import DropCursor from "./DropCursor"; import DropToImport from "./DropToImport"; import EditableTitle from "./EditableTitle"; import SidebarLink from "./SidebarLink"; +import useBoolean from "hooks/useBoolean"; import useStores from "hooks/useStores"; import CollectionMenu from "menus/CollectionMenu"; import CollectionSortMenu from "menus/CollectionSortMenu"; @@ -35,7 +36,7 @@ function CollectionLink({ isDraggingAnyCollection, onChangeDragging, }: Props) { - const [menuOpen, setMenuOpen] = React.useState(false); + const [menuOpen, handleMenuOpen, handleMenuClose] = useBoolean(); const handleTitleChange = React.useCallback( async (name: string) => { @@ -163,14 +164,14 @@ function CollectionLink({ {can.update && ( setMenuOpen(true)} - onClose={() => setMenuOpen(false)} + onOpen={handleMenuOpen} + onClose={handleMenuClose} /> )} setMenuOpen(true)} - onClose={() => setMenuOpen(false)} + onOpen={handleMenuOpen} + onClose={handleMenuClose} /> } diff --git a/app/components/Sidebar/components/DocumentLink.js b/app/components/Sidebar/components/DocumentLink.js index 689f04fc0..d813c08ea 100644 --- a/app/components/Sidebar/components/DocumentLink.js +++ b/app/components/Sidebar/components/DocumentLink.js @@ -12,6 +12,7 @@ import DropCursor from "./DropCursor"; import DropToImport from "./DropToImport"; import EditableTitle from "./EditableTitle"; import SidebarLink from "./SidebarLink"; +import useBoolean from "hooks/useBoolean"; import useStores from "hooks/useStores"; import DocumentMenu from "menus/DocumentMenu"; import { type NavigationNode } from "types"; @@ -120,7 +121,7 @@ function DocumentLink( [documents, document] ); - const [menuOpen, setMenuOpen] = React.useState(false); + const [menuOpen, handleMenuOpen, handleMenuClose] = useBoolean(); const isMoving = documents.movingDocumentId === node.id; const manualSort = collection?.sort.field === "index"; @@ -245,8 +246,8 @@ function DocumentLink( setMenuOpen(true)} - onClose={() => setMenuOpen(false)} + onOpen={handleMenuOpen} + onClose={handleMenuClose} /> ) : undefined diff --git a/app/hooks/useBoolean.js b/app/hooks/useBoolean.js new file mode 100644 index 000000000..252a5aebc --- /dev/null +++ b/app/hooks/useBoolean.js @@ -0,0 +1,23 @@ +// @flow +import * as React from "react"; + +type InitialState = boolean | (() => boolean); + +/** + * React hook to manage booleans + * + * @param initialState the initial boolean state value + */ +export default function useBoolean(initialState: InitialState = false) { + const [value, setValue] = React.useState(initialState); + + const setTrue = React.useCallback(() => { + setValue(true); + }, []); + + const setFalse = React.useCallback(() => { + setValue(false); + }, []); + + return [value, setTrue, setFalse]; +} diff --git a/app/menus/AccountMenu.js b/app/menus/AccountMenu.js index 8a2034bb0..e8bcdb579 100644 --- a/app/menus/AccountMenu.js +++ b/app/menus/AccountMenu.js @@ -19,6 +19,7 @@ import MenuItem, { MenuAnchor } from "components/ContextMenu/MenuItem"; import Separator from "components/ContextMenu/Separator"; import Flex from "components/Flex"; import Guide from "components/Guide"; +import useBoolean from "hooks/useBoolean"; import usePrevious from "hooks/usePrevious"; import useStores from "hooks/useStores"; @@ -78,9 +79,11 @@ function AccountMenu(props: Props) { const { auth, ui } = useStores(); const previousTheme = usePrevious(ui.theme); const { t } = useTranslation(); - const [keyboardShortcutsOpen, setKeyboardShortcutsOpen] = React.useState( - false - ); + const [ + keyboardShortcutsOpen, + handleKeyboardShortcutsOpen, + handleKeyboardShortcutsClose, + ] = useBoolean(); React.useEffect(() => { if (ui.theme !== previousTheme) { @@ -92,7 +95,7 @@ function AccountMenu(props: Props) { <> setKeyboardShortcutsOpen(false)} + onRequestClose={handleKeyboardShortcutsClose} title={t("Keyboard shortcuts")} > @@ -102,7 +105,7 @@ function AccountMenu(props: Props) { {t("Settings")} - setKeyboardShortcutsOpen(true)}> + {t("Keyboard shortcuts")} diff --git a/app/scenes/Collection.js b/app/scenes/Collection.js index 1099eaf4c..2021bb323 100644 --- a/app/scenes/Collection.js +++ b/app/scenes/Collection.js @@ -39,6 +39,7 @@ import Tabs from "components/Tabs"; import Tooltip from "components/Tooltip"; import Collection from "../models/Collection"; import { updateCollectionUrl } from "../utils/routeHelpers"; +import useBoolean from "hooks/useBoolean"; import useCurrentTeam from "hooks/useCurrentTeam"; import useImportDocument from "hooks/useImportDocument"; import useStores from "hooks/useStores"; @@ -54,7 +55,11 @@ function CollectionScene() { const team = useCurrentTeam(); const [isFetching, setFetching] = React.useState(); const [error, setError] = React.useState(); - const [permissionsModalOpen, setPermissionsModalOpen] = React.useState(false); + const [ + permissionsModalOpen, + handlePermissionsModalOpen, + handlePermissionsModalClose, + ] = useBoolean(); const id = params.id || ""; const collection: ?Collection = @@ -102,14 +107,6 @@ function CollectionScene() { load(); }, [collections, isFetching, collection, error, id, can]); - const handlePermissionsModalOpen = React.useCallback(() => { - setPermissionsModalOpen(true); - }, []); - - const handlePermissionsModalClose = React.useCallback(() => { - setPermissionsModalOpen(false); - }, []); - const handleRejection = React.useCallback(() => { ui.showToast( t("Document not supported – try Markdown, Plain text, HTML, or Word"), diff --git a/app/scenes/CollectionPermissions/index.js b/app/scenes/CollectionPermissions/index.js index cb84dfaca..d40bf163d 100644 --- a/app/scenes/CollectionPermissions/index.js +++ b/app/scenes/CollectionPermissions/index.js @@ -17,6 +17,7 @@ import AddGroupsToCollection from "./AddGroupsToCollection"; import AddPeopleToCollection from "./AddPeopleToCollection"; import CollectionGroupMemberListItem from "./components/CollectionGroupMemberListItem"; import MemberListItem from "./components/MemberListItem"; +import useBoolean from "hooks/useBoolean"; import useCurrentUser from "hooks/useCurrentUser"; import useStores from "hooks/useStores"; @@ -34,8 +35,16 @@ function CollectionPermissions({ collection }: Props) { users, groups, } = useStores(); - const [addGroupModalOpen, setAddGroupModalOpen] = React.useState(false); - const [addMemberModalOpen, setAddMemberModalOpen] = React.useState(false); + const [ + addGroupModalOpen, + handleAddGroupModalOpen, + handleAddGroupModalClose, + ] = useBoolean(); + const [ + addMemberModalOpen, + handleAddMemberModalOpen, + handleAddMemberModalClose, + ] = useBoolean(); const handleRemoveUser = React.useCallback( async (user) => { @@ -183,7 +192,7 @@ function CollectionPermissions({ collection }: Props) { {" "}