diff --git a/front/src/modules/activities/tasks/components/PageAddTaskButton.tsx b/front/src/modules/activities/tasks/components/PageAddTaskButton.tsx index 90bac700c..1a0349791 100644 --- a/front/src/modules/activities/tasks/components/PageAddTaskButton.tsx +++ b/front/src/modules/activities/tasks/components/PageAddTaskButton.tsx @@ -1,8 +1,6 @@ import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer'; import { TasksRecoilScopeContext } from '@/activities/states/recoil-scope-contexts/TasksRecoilScopeContext'; -import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext'; import { PageAddButton } from '@/ui/layout/components/PageAddButton'; -import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; import { filtersScopedState } from '@/ui/view-bar/states/filtersScopedState'; import { ActivityType } from '~/generated/graphql'; @@ -26,9 +24,5 @@ export const PageAddTaskButton = () => { }); }; - return ( - - - - ); + return ; }; diff --git a/front/src/modules/pipeline/components/PipelineAddButton.tsx b/front/src/modules/pipeline/components/PipelineAddButton.tsx index 4014c997f..300b455a4 100644 --- a/front/src/modules/pipeline/components/PipelineAddButton.tsx +++ b/front/src/modules/pipeline/components/PipelineAddButton.tsx @@ -14,7 +14,7 @@ export const PipelineAddButton = () => { const { enqueueSnackBar } = useSnackBar(); const { closeDropdown, toggleDropdown } = useDropdown({ - dropdownId: 'add-pipeline-progress', + dropdownScopeId: 'add-pipeline-progress', }); const createCompanyProgress = useCreateCompanyProgress(); diff --git a/front/src/modules/ui/board/components/BoardHeader.tsx b/front/src/modules/ui/board/components/BoardHeader.tsx index fd5bb906a..e2e3fc600 100644 --- a/front/src/modules/ui/board/components/BoardHeader.tsx +++ b/front/src/modules/ui/board/components/BoardHeader.tsx @@ -3,8 +3,6 @@ import { useSearchParams } from 'react-router-dom'; import { useRecoilCallback, useRecoilState, useRecoilValue } from 'recoil'; import { BoardContext } from '@/companies/states/contexts/BoardContext'; -import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext'; -import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId'; @@ -19,8 +17,8 @@ import { savedBoardColumnsState } from '../states/savedBoardColumnsState'; import { canPersistBoardCardFieldsScopedFamilySelector } from '../states/selectors/canPersistBoardCardFieldsScopedFamilySelector'; import { canPersistBoardColumnsSelector } from '../states/selectors/canPersistBoardColumnsSelector'; import { BoardColumnDefinition } from '../types/BoardColumnDefinition'; -import { BoardOptionsDropdownKey } from '../types/BoardOptionsDropdownKey'; import { BoardOptionsHotkeyScope } from '../types/BoardOptionsHotkeyScope'; +import { BoardScopeIds } from '../types/enums/BoardScopeIds'; import { BoardOptionsDropdown } from './BoardOptionsDropdown'; @@ -101,27 +99,25 @@ export const BoardHeader = ({ className, onStageAdd }: BoardHeaderProps) => { const canPersistView = canPersistBoardCardFields || canPersistBoardColumns; return ( - - - - } - optionsDropdownKey={BoardOptionsDropdownKey} - /> - - + + + } + optionsDropdownScopeId={BoardScopeIds.OptionsDropdown} + /> + ); }; diff --git a/front/src/modules/ui/board/components/BoardOptionsDropdown.tsx b/front/src/modules/ui/board/components/BoardOptionsDropdown.tsx index d7ef8d4de..f5fcb65c2 100644 --- a/front/src/modules/ui/board/components/BoardOptionsDropdown.tsx +++ b/front/src/modules/ui/board/components/BoardOptionsDropdown.tsx @@ -3,7 +3,7 @@ import { useResetRecoilState } from 'recoil'; import { ViewBarDropdownButton } from '@/ui/view-bar/components/ViewBarDropdownButton'; import { viewEditModeState } from '@/ui/view-bar/states/viewEditModeState'; -import { BoardOptionsDropdownKey } from '../types/BoardOptionsDropdownKey'; +import { BoardScopeIds } from '../types/enums/BoardScopeIds'; import { BoardOptionsDropdownButton } from './BoardOptionsDropdownButton'; import { @@ -32,7 +32,7 @@ export const BoardOptionsDropdown = ({ /> } dropdownHotkeyScope={customHotkeyScope} - dropdownId={BoardOptionsDropdownKey} + dropdownId={BoardScopeIds.OptionsDropdown} onClickOutside={resetViewEditMode} /> ); diff --git a/front/src/modules/ui/board/components/BoardOptionsDropdownButton.tsx b/front/src/modules/ui/board/components/BoardOptionsDropdownButton.tsx index c29167483..241af60f1 100644 --- a/front/src/modules/ui/board/components/BoardOptionsDropdownButton.tsx +++ b/front/src/modules/ui/board/components/BoardOptionsDropdownButton.tsx @@ -1,11 +1,11 @@ import { StyledHeaderDropdownButton } from '@/ui/dropdown/components/StyledHeaderDropdownButton'; import { useDropdown } from '@/ui/dropdown/hooks/useDropdown'; -import { BoardOptionsDropdownKey } from '../types/BoardOptionsDropdownKey'; +import { BoardScopeIds } from '../types/enums/BoardScopeIds'; export const BoardOptionsDropdownButton = () => { const { isDropdownOpen, toggleDropdown } = useDropdown({ - dropdownId: BoardOptionsDropdownKey, + dropdownScopeId: BoardScopeIds.OptionsDropdown, }); const handleClick = () => { diff --git a/front/src/modules/ui/board/components/BoardOptionsDropdownContent.tsx b/front/src/modules/ui/board/components/BoardOptionsDropdownContent.tsx index e113efc62..4449c6781 100644 --- a/front/src/modules/ui/board/components/BoardOptionsDropdownContent.tsx +++ b/front/src/modules/ui/board/components/BoardOptionsDropdownContent.tsx @@ -43,7 +43,6 @@ import { savedBoardCardFieldsFamilyState } from '../states/savedBoardCardFieldsF import { hiddenBoardCardFieldsScopedSelector } from '../states/selectors/hiddenBoardCardFieldsScopedSelector'; import { visibleBoardCardFieldsScopedSelector } from '../states/selectors/visibleBoardCardFieldsScopedSelector'; import { BoardColumnDefinition } from '../types/BoardColumnDefinition'; -import { BoardOptionsDropdownKey } from '../types/BoardOptionsDropdownKey'; export type BoardOptionsDropdownContentProps = { customHotkeyScope: HotkeyScope; @@ -144,9 +143,7 @@ export const BoardOptionsDropdownContent = ({ const { handleFieldVisibilityChange } = useBoardCardFields(); - const { closeDropdown } = useDropdown({ - dropdownId: BoardOptionsDropdownKey, - }); + const { closeDropdown } = useDropdown(); useScopedHotkeys( Key.Escape, diff --git a/front/src/modules/ui/board/components/__stories__/BoardOptionsDropdown.stories.tsx b/front/src/modules/ui/board/components/__stories__/BoardOptionsDropdown.stories.tsx index 9a95760c2..694ad549a 100644 --- a/front/src/modules/ui/board/components/__stories__/BoardOptionsDropdown.stories.tsx +++ b/front/src/modules/ui/board/components/__stories__/BoardOptionsDropdown.stories.tsx @@ -3,8 +3,6 @@ import { userEvent, within } from '@storybook/testing-library'; import { BoardContext } from '@/companies/states/contexts/BoardContext'; import { CompanyBoardRecoilScopeContext } from '@/companies/states/recoil-scope-contexts/CompanyBoardRecoilScopeContext'; -import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext'; -import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; import { ViewBarContext } from '@/ui/view-bar/contexts/ViewBarContext'; import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator'; import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator'; @@ -26,9 +24,7 @@ const meta: Meta = { ViewBarRecoilScopeContext: parameters.customRecoilScopeContext, }} > - - - + ), diff --git a/front/src/modules/ui/board/types/BoardOptionsDropdownKey.ts b/front/src/modules/ui/board/types/BoardOptionsDropdownKey.ts deleted file mode 100644 index 12c0f9aa6..000000000 --- a/front/src/modules/ui/board/types/BoardOptionsDropdownKey.ts +++ /dev/null @@ -1 +0,0 @@ -export const BoardOptionsDropdownKey = 'board-options'; diff --git a/front/src/modules/ui/board/types/enums/BoardScopeIds.ts b/front/src/modules/ui/board/types/enums/BoardScopeIds.ts new file mode 100644 index 000000000..be9c072fa --- /dev/null +++ b/front/src/modules/ui/board/types/enums/BoardScopeIds.ts @@ -0,0 +1,3 @@ +export enum BoardScopeIds { + OptionsDropdown = 'board-options', +} diff --git a/front/src/modules/ui/data-table/components/ColumnHeadWithDropdown.tsx b/front/src/modules/ui/data-table/components/ColumnHeadWithDropdown.tsx index 9c64535da..8f9a52c6e 100644 --- a/front/src/modules/ui/data-table/components/ColumnHeadWithDropdown.tsx +++ b/front/src/modules/ui/data-table/components/ColumnHeadWithDropdown.tsx @@ -1,4 +1,5 @@ import { DropdownMenu } from '@/ui/dropdown/components/DropdownMenu'; +import { DropdownScope } from '@/ui/dropdown/scopes/DropdownScope'; import { FieldMetadata } from '@/ui/field/types/FieldMetadata'; import { ColumnDefinition } from '../types/ColumnDefinition'; @@ -20,19 +21,20 @@ export const ColumnHeadWithDropdown = ({ primaryColumnKey, }: ColumnHeadWithDropdownProps) => { return ( - } - dropdownId={column.key + '-header'} - dropdownComponents={ - - } - dropdownHotkeyScope={{ scope: column.key + '-header' }} - dropdownOffset={{ x: 0, y: -8 }} - /> + + } + dropdownComponents={ + + } + dropdownHotkeyScope={{ scope: column.key + '-header' }} + dropdownOffset={{ x: 0, y: -8 }} + /> + ); }; diff --git a/front/src/modules/ui/data-table/components/DataTableColumnDropdownMenu.tsx b/front/src/modules/ui/data-table/components/DataTableColumnDropdownMenu.tsx index 215d83f4d..cb4e24495 100644 --- a/front/src/modules/ui/data-table/components/DataTableColumnDropdownMenu.tsx +++ b/front/src/modules/ui/data-table/components/DataTableColumnDropdownMenu.tsx @@ -26,7 +26,7 @@ export const DataTableColumnDropdownMenu = ({ useTableColumns(); const { closeDropdown } = useDropdown({ - dropdownId: ColumnHeadDropdownId, + dropdownScopeId: ColumnHeadDropdownId, }); const handleColumnMoveLeft = () => { diff --git a/front/src/modules/ui/data-table/components/DataTableHeader.tsx b/front/src/modules/ui/data-table/components/DataTableHeader.tsx index 217f9502b..50c93e1ef 100644 --- a/front/src/modules/ui/data-table/components/DataTableHeader.tsx +++ b/front/src/modules/ui/data-table/components/DataTableHeader.tsx @@ -3,10 +3,8 @@ import styled from '@emotion/styled'; import { useRecoilCallback, useRecoilState } from 'recoil'; import { IconButton } from '@/ui/button/components/IconButton'; -import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext'; import { IconPlus } from '@/ui/icon'; import { useTrackPointer } from '@/ui/utilities/pointer-event/hooks/useTrackPointer'; -import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; import { useTableColumns } from '../hooks/useTableColumns'; @@ -177,36 +175,33 @@ export const DataTableHeader = () => { > - - {visibleTableColumns.map((column, index) => ( - - - - - - { - setResizedFieldKey(column.key); - }} + {visibleTableColumns.map((column, index) => ( + + + - - ))} - + + { + setResizedFieldKey(column.key); + }} + /> + + ))} {hiddenTableColumns.length > 0 && ( diff --git a/front/src/modules/ui/data-table/options/components/TableOptionsDropdownButton.tsx b/front/src/modules/ui/data-table/options/components/TableOptionsDropdownButton.tsx index cb8fae9c7..5de5f62b0 100644 --- a/front/src/modules/ui/data-table/options/components/TableOptionsDropdownButton.tsx +++ b/front/src/modules/ui/data-table/options/components/TableOptionsDropdownButton.tsx @@ -4,7 +4,7 @@ import { useDropdown } from '@/ui/dropdown/hooks/useDropdown'; export const TableOptionsDropdownButton = () => { const { isDropdownOpen, toggleDropdown } = useDropdown({ - dropdownId: TableOptionsDropdownId, + dropdownScopeId: TableOptionsDropdownId, }); return ( diff --git a/front/src/modules/ui/data-table/options/components/TableOptionsDropdownContent.tsx b/front/src/modules/ui/data-table/options/components/TableOptionsDropdownContent.tsx index 7f7e4ebf8..1c9148fbf 100644 --- a/front/src/modules/ui/data-table/options/components/TableOptionsDropdownContent.tsx +++ b/front/src/modules/ui/data-table/options/components/TableOptionsDropdownContent.tsx @@ -22,7 +22,6 @@ import { currentViewScopedSelector } from '@/ui/view-bar/states/selectors/curren import { viewsByIdScopedSelector } from '@/ui/view-bar/states/selectors/viewsByIdScopedSelector'; import { viewEditModeState } from '@/ui/view-bar/states/viewEditModeState'; -import { TableOptionsDropdownId } from '../../constants/TableOptionsDropdownId'; import { useTableColumns } from '../../hooks/useTableColumns'; import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext'; import { savedTableColumnsFamilyState } from '../../states/savedTableColumnsFamilyState'; @@ -37,9 +36,7 @@ export const TableOptionsDropdownContent = () => { const scopeId = useRecoilScopeId(TableRecoilScopeContext); const { onImport } = useContext(ViewBarContext); - const { closeDropdown } = useDropdown({ - dropdownId: TableOptionsDropdownId, - }); + const { closeDropdown } = useDropdown(); const [currentMenu, setCurrentMenu] = useState( undefined, diff --git a/front/src/modules/ui/data-table/options/components/__stories__/TableOptionsDropdown.stories.tsx b/front/src/modules/ui/data-table/options/components/__stories__/TableOptionsDropdown.stories.tsx index fbd3e91bc..c13387060 100644 --- a/front/src/modules/ui/data-table/options/components/__stories__/TableOptionsDropdown.stories.tsx +++ b/front/src/modules/ui/data-table/options/components/__stories__/TableOptionsDropdown.stories.tsx @@ -1,7 +1,6 @@ import { Meta, StoryObj } from '@storybook/react'; import { userEvent, within } from '@storybook/testing-library'; -import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext'; import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; import { ViewBarContext } from '@/ui/view-bar/contexts/ViewBarContext'; import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator'; @@ -20,9 +19,7 @@ const meta: Meta = { ViewBarRecoilScopeContext: TableRecoilScopeContext, }} > - - - + ), diff --git a/front/src/modules/ui/data-table/table-header/components/TableHeader.tsx b/front/src/modules/ui/data-table/table-header/components/TableHeader.tsx index fa5a30581..f9ca7ad0b 100644 --- a/front/src/modules/ui/data-table/table-header/components/TableHeader.tsx +++ b/front/src/modules/ui/data-table/table-header/components/TableHeader.tsx @@ -2,8 +2,6 @@ import { useContext } from 'react'; import { useSearchParams } from 'react-router-dom'; import { useRecoilCallback } from 'recoil'; -import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext'; -import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId'; import { ViewBar } from '@/ui/view-bar/components/ViewBar'; import { ViewBarContext } from '@/ui/view-bar/contexts/ViewBarContext'; @@ -34,23 +32,21 @@ export const TableHeader = () => { ); return ( - - - - } - optionsDropdownKey={TableOptionsDropdownId} - /> - - + + + } + optionsDropdownScopeId={TableOptionsDropdownId} + /> + ); }; diff --git a/front/src/modules/ui/dropdown/components/DropdownMenu.tsx b/front/src/modules/ui/dropdown/components/DropdownMenu.tsx index b25dca8bd..0bc811b0f 100644 --- a/front/src/modules/ui/dropdown/components/DropdownMenu.tsx +++ b/front/src/modules/ui/dropdown/components/DropdownMenu.tsx @@ -16,7 +16,6 @@ import { DropdownToggleEffect } from './DropdownToggleEffect'; type DropdownMenuProps = { clickableComponent?: JSX.Element | JSX.Element[]; dropdownComponents: JSX.Element | JSX.Element[]; - dropdownId: string; hotkey?: { key: Keys; scope: string; @@ -32,7 +31,6 @@ type DropdownMenuProps = { export const DropdownMenu = ({ clickableComponent, dropdownComponents, - dropdownId, hotkey, dropdownHotkeyScope, dropdownPlacement = 'bottom-end', @@ -43,9 +41,7 @@ export const DropdownMenu = ({ }: DropdownMenuProps) => { const containerRef = useRef(null); - const { isDropdownOpen, toggleDropdown, closeDropdown } = useDropdown({ - dropdownId, - }); + const { isDropdownOpen, toggleDropdown, closeDropdown } = useDropdown(); const { refs, floatingStyles } = useFloating({ placement: dropdownPlacement, @@ -71,8 +67,7 @@ export const DropdownMenu = ({ }); useInternalHotkeyScopeManagement({ - dropdownId, - dropdownHotkeyScope, + dropdownHotkeyScopeFromParent: dropdownHotkeyScope, }); useScopedHotkeys( @@ -83,6 +78,7 @@ export const DropdownMenu = ({ dropdownHotkeyScope.scope, [closeDropdown], ); + return (
{clickableComponent && ( @@ -101,11 +97,7 @@ export const DropdownMenu = ({ {dropdownComponents}
)} - + ); }; diff --git a/front/src/modules/ui/dropdown/components/DropdownToggleEffect.tsx b/front/src/modules/ui/dropdown/components/DropdownToggleEffect.tsx index 47099e214..390e939c7 100644 --- a/front/src/modules/ui/dropdown/components/DropdownToggleEffect.tsx +++ b/front/src/modules/ui/dropdown/components/DropdownToggleEffect.tsx @@ -3,15 +3,13 @@ import { useEffect } from 'react'; import { useDropdown } from '@/ui/dropdown/hooks/useDropdown'; export const DropdownToggleEffect = ({ - dropdownId, onDropdownClose, onDropdownOpen, }: { - dropdownId: string; onDropdownClose?: () => void; onDropdownOpen?: () => void; }) => { - const { isDropdownOpen } = useDropdown({ dropdownId }); + const { isDropdownOpen } = useDropdown(); useEffect(() => { if (isDropdownOpen) { diff --git a/front/src/modules/ui/dropdown/hooks/useDropdown.ts b/front/src/modules/ui/dropdown/hooks/useDropdown.ts index 32b3def04..1e38288a0 100644 --- a/front/src/modules/ui/dropdown/hooks/useDropdown.ts +++ b/front/src/modules/ui/dropdown/hooks/useDropdown.ts @@ -1,47 +1,52 @@ import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope'; -import { useRecoilScopedFamilyState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState'; +import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; -import { dropdownButtonHotkeyScopeScopedFamilyState } from '../states/dropdownButtonHotkeyScopeScopedFamilyState'; -import { isDropdownButtonOpenScopedFamilyState } from '../states/isDropdownButtonOpenScopedFamilyState'; -import { DropdownRecoilScopeContext } from '../states/recoil-scope-contexts/DropdownRecoilScopeContext'; +import { DropdownScopeInternalContext } from '../scopes/scope-internal-context/DropdownScopeInternalContext'; -export const useDropdown = ({ dropdownId }: { dropdownId: string }) => { +import { useDropdownStates } from './useDropdownStates'; + +type UseDropdownProps = { + dropdownScopeId?: string; +}; + +export const useDropdown = (props?: UseDropdownProps) => { const { setHotkeyScopeAndMemorizePreviousScope, goBackToPreviousHotkeyScope, } = usePreviousHotkeyScope(); - const [isDropdownButtonOpen, setIsDropdownButtonOpen] = - useRecoilScopedFamilyState( - isDropdownButtonOpenScopedFamilyState, - dropdownId, - DropdownRecoilScopeContext, - ); - - const [dropdownButtonHotkeyScope] = useRecoilScopedFamilyState( - dropdownButtonHotkeyScopeScopedFamilyState, - dropdownId, - DropdownRecoilScopeContext, + const scopeId = useAvailableScopeIdOrThrow( + DropdownScopeInternalContext, + props?.dropdownScopeId, ); + const { + dropdownHotkeyScope, + setDropdownHotkeyScope, + isDropdownOpen, + setIsDropdownOpen, + } = useDropdownStates({ + scopeId, + }); + const closeDropdownButton = () => { goBackToPreviousHotkeyScope(); - setIsDropdownButtonOpen(false); + setIsDropdownOpen(false); }; const openDropdownButton = () => { - setIsDropdownButtonOpen(true); + setIsDropdownOpen(true); - if (dropdownButtonHotkeyScope) { + if (dropdownHotkeyScope) { setHotkeyScopeAndMemorizePreviousScope( - dropdownButtonHotkeyScope.scope, - dropdownButtonHotkeyScope.customScopes, + dropdownHotkeyScope.scope, + dropdownHotkeyScope.customScopes, ); } }; const toggleDropdownButton = () => { - if (isDropdownButtonOpen) { + if (isDropdownOpen) { closeDropdownButton(); } else { openDropdownButton(); @@ -49,9 +54,12 @@ export const useDropdown = ({ dropdownId }: { dropdownId: string }) => { }; return { - isDropdownOpen: isDropdownButtonOpen, + isDropdownOpen: isDropdownOpen, closeDropdown: closeDropdownButton, toggleDropdown: toggleDropdownButton, openDropdown: openDropdownButton, + scopeId, + dropdownHotkeyScope, + setDropdownHotkeyScope, }; }; diff --git a/front/src/modules/ui/dropdown/hooks/useDropdownStates.ts b/front/src/modules/ui/dropdown/hooks/useDropdownStates.ts new file mode 100644 index 000000000..d60ac3c55 --- /dev/null +++ b/front/src/modules/ui/dropdown/hooks/useDropdownStates.ts @@ -0,0 +1,23 @@ +import { useRecoilScopedStateV2 } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2'; + +import { dropdownHotkeyScopeScopedState } from '../states/dropdownHotkeyScopeScopedState'; +import { isDropdownOpenScopedState } from '../states/isDropdownOpenScopedState'; + +export const useDropdownStates = ({ scopeId }: { scopeId: string }) => { + const [isDropdownOpen, setIsDropdownOpen] = useRecoilScopedStateV2( + isDropdownOpenScopedState, + scopeId, + ); + + const [dropdownHotkeyScope, setDropdownHotkeyScope] = useRecoilScopedStateV2( + dropdownHotkeyScopeScopedState, + scopeId, + ); + + return { + isDropdownOpen, + setIsDropdownOpen, + dropdownHotkeyScope, + setDropdownHotkeyScope, + }; +}; diff --git a/front/src/modules/ui/dropdown/hooks/useInternalHotkeyScopeManagement.ts b/front/src/modules/ui/dropdown/hooks/useInternalHotkeyScopeManagement.ts index 51052c5a6..b63587ded 100644 --- a/front/src/modules/ui/dropdown/hooks/useInternalHotkeyScopeManagement.ts +++ b/front/src/modules/ui/dropdown/hooks/useInternalHotkeyScopeManagement.ts @@ -1,33 +1,24 @@ import { useEffect } from 'react'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; -import { useRecoilScopedFamilyState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; -import { dropdownButtonHotkeyScopeScopedFamilyState } from '../states/dropdownButtonHotkeyScopeScopedFamilyState'; -import { DropdownRecoilScopeContext } from '../states/recoil-scope-contexts/DropdownRecoilScopeContext'; +import { useDropdown } from './useDropdown'; export const useInternalHotkeyScopeManagement = ({ - dropdownId, - dropdownHotkeyScope, + dropdownHotkeyScopeFromParent, }: { - dropdownId: string; - dropdownHotkeyScope?: HotkeyScope; + dropdownHotkeyScopeFromParent?: HotkeyScope; }) => { - const [dropdownButtonHotkeyScope, setDropdownButtonHotkeyScope] = - useRecoilScopedFamilyState( - dropdownButtonHotkeyScopeScopedFamilyState, - dropdownId, - DropdownRecoilScopeContext, - ); + const { dropdownHotkeyScope, setDropdownHotkeyScope } = useDropdown(); useEffect(() => { - if (!isDeeplyEqual(dropdownButtonHotkeyScope, dropdownHotkeyScope)) { - setDropdownButtonHotkeyScope(dropdownHotkeyScope); + if (!isDeeplyEqual(dropdownHotkeyScopeFromParent, dropdownHotkeyScope)) { + setDropdownHotkeyScope(dropdownHotkeyScopeFromParent); } }, [ dropdownHotkeyScope, - dropdownButtonHotkeyScope, - setDropdownButtonHotkeyScope, + dropdownHotkeyScopeFromParent, + setDropdownHotkeyScope, ]); }; diff --git a/front/src/modules/ui/dropdown/scopes/DropdownScope.tsx b/front/src/modules/ui/dropdown/scopes/DropdownScope.tsx new file mode 100644 index 000000000..e6e53702d --- /dev/null +++ b/front/src/modules/ui/dropdown/scopes/DropdownScope.tsx @@ -0,0 +1,19 @@ +import { ReactNode } from 'react'; + +import { DropdownScopeInternalContext } from './scope-internal-context/DropdownScopeInternalContext'; + +type DropdownScopeProps = { + children: ReactNode; + dropdownScopeId: string; +}; + +export const DropdownScope = ({ + children, + dropdownScopeId, +}: DropdownScopeProps) => { + return ( + + {children} + + ); +}; diff --git a/front/src/modules/ui/dropdown/scopes/scope-internal-context/DropdownScopeInternalContext.ts b/front/src/modules/ui/dropdown/scopes/scope-internal-context/DropdownScopeInternalContext.ts new file mode 100644 index 000000000..7dbd1ce36 --- /dev/null +++ b/front/src/modules/ui/dropdown/scopes/scope-internal-context/DropdownScopeInternalContext.ts @@ -0,0 +1,9 @@ +import { ScopedStateKey } from '@/ui/utilities/recoil-scope/scopes-internal/types/ScopedStateKey'; +import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext'; + +type DropdownScopeInternalContextProps = ScopedStateKey & { + test?: string; +}; + +export const DropdownScopeInternalContext = + createScopeInternalContext(); diff --git a/front/src/modules/ui/dropdown/states/dropdownButtonHotkeyScopeScopedFamilyState.ts b/front/src/modules/ui/dropdown/states/dropdownButtonHotkeyScopeScopedFamilyState.ts deleted file mode 100644 index 67a5952cc..000000000 --- a/front/src/modules/ui/dropdown/states/dropdownButtonHotkeyScopeScopedFamilyState.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { atomFamily } from 'recoil'; - -import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; - -export const dropdownButtonHotkeyScopeScopedFamilyState = atomFamily< - HotkeyScope | null | undefined, - string ->({ - key: 'dropdownButtonHotkeyScopeScopedFamilyState', - default: null, -}); diff --git a/front/src/modules/ui/dropdown/states/dropdownHotkeyScopeScopedState.ts b/front/src/modules/ui/dropdown/states/dropdownHotkeyScopeScopedState.ts new file mode 100644 index 000000000..fbcac52b3 --- /dev/null +++ b/front/src/modules/ui/dropdown/states/dropdownHotkeyScopeScopedState.ts @@ -0,0 +1,9 @@ +import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; +import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState'; + +export const dropdownHotkeyScopeScopedState = createScopedState< + HotkeyScope | null | undefined +>({ + key: 'dropdownHotkeyScopeScopedState', + defaultValue: null, +}); diff --git a/front/src/modules/ui/dropdown/states/isDropdownButtonOpenScopedFamilyState.ts b/front/src/modules/ui/dropdown/states/isDropdownButtonOpenScopedFamilyState.ts deleted file mode 100644 index c81d0173f..000000000 --- a/front/src/modules/ui/dropdown/states/isDropdownButtonOpenScopedFamilyState.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { atomFamily } from 'recoil'; - -export const isDropdownButtonOpenScopedFamilyState = atomFamily< - boolean, - string ->({ - key: 'isDropdownButtonOpenScopedState', - default: false, -}); diff --git a/front/src/modules/ui/dropdown/states/isDropdownOpenScopedState.ts b/front/src/modules/ui/dropdown/states/isDropdownOpenScopedState.ts new file mode 100644 index 000000000..56d6f905e --- /dev/null +++ b/front/src/modules/ui/dropdown/states/isDropdownOpenScopedState.ts @@ -0,0 +1,6 @@ +import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState'; + +export const isDropdownOpenScopedState = createScopedState({ + key: 'isDropdownOpenScopedState', + defaultValue: false, +}); diff --git a/front/src/modules/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext.ts b/front/src/modules/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext.ts deleted file mode 100644 index 139778002..000000000 --- a/front/src/modules/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { createContext } from 'react'; - -export const DropdownRecoilScopeContext = createContext(null); diff --git a/front/src/modules/ui/input/components/CountryPickerDropdownButton.tsx b/front/src/modules/ui/input/components/CountryPickerDropdownButton.tsx index f75927184..5f80c8d86 100644 --- a/front/src/modules/ui/input/components/CountryPickerDropdownButton.tsx +++ b/front/src/modules/ui/input/components/CountryPickerDropdownButton.tsx @@ -8,6 +8,7 @@ import { CountryCallingCode } from 'libphonenumber-js'; import { DropdownMenu } from '@/ui/dropdown/components/DropdownMenu'; import { useDropdown } from '@/ui/dropdown/hooks/useDropdown'; +import { DropdownScope } from '@/ui/dropdown/scopes/DropdownScope'; import { IconChevronDown } from '@/ui/icon'; import { IconWorld } from '../constants/icons'; @@ -77,7 +78,7 @@ export const CountryPickerDropdownButton = ({ const [selectedCountry, setSelectedCountry] = useState(); const { isDropdownOpen, closeDropdown } = useDropdown({ - dropdownId: 'country-picker', + dropdownScopeId: 'country-picker', }); const handleChange = (countryCode: string) => { @@ -122,25 +123,26 @@ export const CountryPickerDropdownButton = ({ }, [countries, value]); return ( - - - {selectedCountry ? : } - - - - } - dropdownComponents={ - - } - dropdownOffset={{ x: -60, y: -34 }} - /> + + + + {selectedCountry ? : } + + + + } + dropdownComponents={ + + } + dropdownOffset={{ x: -60, y: -34 }} + /> + ); }; diff --git a/front/src/modules/ui/input/components/PhoneInput.tsx b/front/src/modules/ui/input/components/PhoneInput.tsx index a2cf8f833..bd7930508 100644 --- a/front/src/modules/ui/input/components/PhoneInput.tsx +++ b/front/src/modules/ui/input/components/PhoneInput.tsx @@ -2,9 +2,6 @@ import { useEffect, useRef, useState } from 'react'; import ReactPhoneNumberInput from 'react-phone-number-input'; import styled from '@emotion/styled'; -import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext'; -import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; - import { useRegisterInputEvents } from '../hooks/useRegisterInputEvents'; import { CountryPickerDropdownButton } from './CountryPickerDropdownButton'; @@ -86,17 +83,15 @@ export const PhoneInput = ({ return ( - - - + ); }; diff --git a/front/src/modules/ui/layout/show-page/components/ShowPageAddButton.tsx b/front/src/modules/ui/layout/show-page/components/ShowPageAddButton.tsx index 3ab821f94..c5adf075d 100644 --- a/front/src/modules/ui/layout/show-page/components/ShowPageAddButton.tsx +++ b/front/src/modules/ui/layout/show-page/components/ShowPageAddButton.tsx @@ -22,7 +22,7 @@ export const ShowPageAddButton = ({ entity: ActivityTargetableEntity; }) => { const { closeDropdown, toggleDropdown } = useDropdown({ - dropdownId: 'add-show-page', + dropdownScopeId: 'add-show-page', }); const openCreateActivity = useOpenCreateActivityDrawer(); diff --git a/front/src/modules/ui/utilities/recoil-scope/components/RecoilScope.tsx b/front/src/modules/ui/utilities/recoil-scope/components/RecoilScope.tsx index 102efc95e..0590d6edb 100644 --- a/front/src/modules/ui/utilities/recoil-scope/components/RecoilScope.tsx +++ b/front/src/modules/ui/utilities/recoil-scope/components/RecoilScope.tsx @@ -5,6 +5,10 @@ import { RecoilScopeContext as RecoilScopeContextType } from '@/types/RecoilScop import { RecoilScopeContext } from '../states/RecoilScopeContext'; +/** + * + * @deprecated Use a custom scope context instead, see example with DropdownScope + */ export const RecoilScope = ({ children, scopeId, diff --git a/front/src/modules/ui/utilities/recoil-scope/hooks/useContextScopeId.ts b/front/src/modules/ui/utilities/recoil-scope/hooks/useContextScopeId.ts index ab3d6b3cc..bf92b9de2 100644 --- a/front/src/modules/ui/utilities/recoil-scope/hooks/useContextScopeId.ts +++ b/front/src/modules/ui/utilities/recoil-scope/hooks/useContextScopeId.ts @@ -1,5 +1,9 @@ import { Context, useContext } from 'react'; +/** + * @deprecated use a custom scope instead and desctructure the scope id from the scope context + * Get the scope context with useScopeInternalContext + */ export const useContextScopeId = (SpecificContext: Context) => { const recoilScopeId = useContext(SpecificContext); diff --git a/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopeId.ts b/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopeId.ts index 2f259f394..f14486f1f 100644 --- a/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopeId.ts +++ b/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopeId.ts @@ -2,6 +2,9 @@ import { useContext } from 'react'; import { RecoilScopeContext } from '@/types/RecoilScopeContext'; +/** + * @deprecated Use a custom scope instead and desctructure the scope id from the scope context + */ export const useRecoilScopeId = (RecoilScopeContext: RecoilScopeContext) => { const recoilScopeId = useContext(RecoilScopeContext); diff --git a/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState.ts b/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState.ts index e5dbc7b68..4e135f86b 100644 --- a/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState.ts +++ b/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState.ts @@ -1,25 +1,21 @@ -import { Context, useContext } from 'react'; -import { RecoilState, useRecoilState } from 'recoil'; +import { RecoilState, SerializableParam, useRecoilState } from 'recoil'; -import { RecoilScopeContext } from '../states/RecoilScopeContext'; +import { ScopedFamilyStateKey } from '../scopes-internal/types/ScopedFamilyStateKey'; -export const useRecoilScopedFamilyState = ( - recoilState: (familyUniqueId: string) => RecoilState, - uniqueIdInRecoilScope: string, - CustomRecoilScopeContext?: Context, +export const useRecoilScopedFamilyState = < + StateType, + FamilyKey extends SerializableParam, +>( + recoilState: ( + scopedFamilyKey: ScopedFamilyStateKey, + ) => RecoilState, + scopeId: string, + familyKey: FamilyKey, ) => { - const recoilScopeId = useContext( - CustomRecoilScopeContext ?? RecoilScopeContext, + return useRecoilState( + recoilState({ + scopeId, + familyKey, + }), ); - - if (!recoilScopeId) - throw new Error( - `Using a scoped atom without a RecoilScope : ${ - recoilState('').key - }, verify that you are using a RecoilScope with a specific context if you intended to do so.`, - ); - - const familyUniqueId = recoilScopeId + uniqueIdInRecoilScope; - - return useRecoilState(recoilState(familyUniqueId)); }; diff --git a/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2.ts b/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2.ts new file mode 100644 index 000000000..8e81182f6 --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2.ts @@ -0,0 +1,14 @@ +import { RecoilState, useRecoilState } from 'recoil'; + +import { ScopedStateKey } from '../scopes-internal/types/ScopedStateKey'; + +export const useRecoilScopedStateV2 = ( + recoilState: (scopedKey: ScopedStateKey) => RecoilState, + scopeId: string, +) => { + return useRecoilState( + recoilState({ + scopeId, + }), + ); +}; diff --git a/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedValue.ts b/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedValue.ts index 484fd4102..413b55605 100644 --- a/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedValue.ts +++ b/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedValue.ts @@ -3,6 +3,9 @@ import { RecoilState, RecoilValueReadOnly, useRecoilValue } from 'recoil'; import { RecoilScopeContext } from '../states/RecoilScopeContext'; +/** + * @deprecated use useRecoilScopedStateV2 instead + */ export const useRecoilScopedValue = ( recoilState: (param: string) => RecoilState | RecoilValueReadOnly, CustomRecoilScopeContext?: Context, diff --git a/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedValueV2.ts b/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedValueV2.ts new file mode 100644 index 000000000..b3b2126b7 --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedValueV2.ts @@ -0,0 +1,14 @@ +import { RecoilState, useRecoilValue } from 'recoil'; + +import { ScopedStateKey } from '../scopes-internal/types/ScopedStateKey'; + +export const useRecoilScopedValueV2 = ( + recoilState: (scopedKey: ScopedStateKey) => RecoilState, + scopeId: string, +) => { + return useRecoilValue( + recoilState({ + scopeId, + }), + ); +}; diff --git a/front/src/modules/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId.ts b/front/src/modules/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId.ts new file mode 100644 index 000000000..6a747291e --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId.ts @@ -0,0 +1,20 @@ +import { ScopeInternalContext } from '../types/ScopeInternalContext'; + +import { useScopeInternalContext } from './useScopeInternalContext'; + +export const useAvailableScopeIdOrThrow = ( + Context: ScopeInternalContext, + scopeIdFromProps?: string, +): string => { + const scopeInternalContext = useScopeInternalContext(Context); + + const scopeIdFromContext = scopeInternalContext?.scopeId; + + if (scopeIdFromProps) { + return scopeIdFromProps; + } else if (scopeIdFromContext) { + return scopeIdFromContext; + } else { + throw new Error('Scope id is not provided and cannot be found in context.'); + } +}; diff --git a/front/src/modules/ui/utilities/recoil-scope/scopes-internal/hooks/useScopeInternalContext.ts b/front/src/modules/ui/utilities/recoil-scope/scopes-internal/hooks/useScopeInternalContext.ts new file mode 100644 index 000000000..7b4c4f1c4 --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/scopes-internal/hooks/useScopeInternalContext.ts @@ -0,0 +1,11 @@ +import { useContext } from 'react'; + +import { ScopeInternalContext } from '../types/ScopeInternalContext'; + +export const useScopeInternalContext = ( + Context: ScopeInternalContext, +) => { + const context = useContext(Context); + + return context; +}; diff --git a/front/src/modules/ui/utilities/recoil-scope/scopes-internal/hooks/useScopeInternalContextOrThrow.ts b/front/src/modules/ui/utilities/recoil-scope/scopes-internal/hooks/useScopeInternalContextOrThrow.ts new file mode 100644 index 000000000..876efdee2 --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/scopes-internal/hooks/useScopeInternalContextOrThrow.ts @@ -0,0 +1,19 @@ +import { useContext } from 'react'; + +import { isDefined } from '~/utils/isDefined'; + +import { ScopeInternalContext } from '../types/ScopeInternalContext'; + +export const useScopeInternalContextOrThrow = ( + Context: ScopeInternalContext, +) => { + const context = useContext(Context); + + if (!isDefined(context)) { + throw new Error( + `Using a scope context without a ScopeInternalContext.Provider wrapper for context : ${Context.displayName}.`, + ); + } + + return context; +}; diff --git a/front/src/modules/ui/utilities/recoil-scope/scopes-internal/types/ScopeInternalContext.ts b/front/src/modules/ui/utilities/recoil-scope/scopes-internal/types/ScopeInternalContext.ts new file mode 100644 index 000000000..bd6ff6ee4 --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/scopes-internal/types/ScopeInternalContext.ts @@ -0,0 +1,4 @@ +import { Context } from 'react'; + +export type ScopeInternalContext = + Context; diff --git a/front/src/modules/ui/utilities/recoil-scope/scopes-internal/types/ScopedFamilyStateKey.ts b/front/src/modules/ui/utilities/recoil-scope/scopes-internal/types/ScopedFamilyStateKey.ts new file mode 100644 index 000000000..2930aaed4 --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/scopes-internal/types/ScopedFamilyStateKey.ts @@ -0,0 +1,6 @@ +import { SerializableParam } from 'recoil'; + +export type ScopedFamilyStateKey = { + scopeId: string; + familyKey: FamilyKey; +}; diff --git a/front/src/modules/ui/utilities/recoil-scope/scopes-internal/types/ScopedStateKey.ts b/front/src/modules/ui/utilities/recoil-scope/scopes-internal/types/ScopedStateKey.ts new file mode 100644 index 000000000..e0904f87f --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/scopes-internal/types/ScopedStateKey.ts @@ -0,0 +1,3 @@ +export type ScopedStateKey = { + scopeId: string; +}; diff --git a/front/src/modules/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext.ts b/front/src/modules/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext.ts new file mode 100644 index 000000000..e5a3c0ab2 --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext.ts @@ -0,0 +1,13 @@ +import { Context, createContext } from 'react'; + +import { ScopedStateKey } from '../types/ScopedStateKey'; + +type ScopeInternalContext = Context; + +export const createScopeInternalContext = ( + initialValue?: T, +) => { + return createContext( + initialValue ?? null, + ) as ScopeInternalContext; +}; diff --git a/front/src/modules/ui/utilities/recoil-scope/utils/createScopedFamilyState.ts b/front/src/modules/ui/utilities/recoil-scope/utils/createScopedFamilyState.ts new file mode 100644 index 000000000..e73a891ef --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/utils/createScopedFamilyState.ts @@ -0,0 +1,19 @@ +import { atomFamily, SerializableParam } from 'recoil'; + +import { ScopedFamilyStateKey } from '../scopes-internal/types/ScopedFamilyStateKey'; + +export const createScopedFamilyState = < + ValueType, + FamilyKey extends SerializableParam, +>({ + key, + defaultValue, +}: { + key: string; + defaultValue: ValueType; +}) => { + return atomFamily>({ + key, + default: defaultValue, + }); +}; diff --git a/front/src/modules/ui/utilities/recoil-scope/utils/createScopedState.ts b/front/src/modules/ui/utilities/recoil-scope/utils/createScopedState.ts new file mode 100644 index 000000000..74d128ac0 --- /dev/null +++ b/front/src/modules/ui/utilities/recoil-scope/utils/createScopedState.ts @@ -0,0 +1,14 @@ +import { atomFamily } from 'recoil'; + +export const createScopedState = ({ + key, + defaultValue, +}: { + key: string; + defaultValue: ValueType; +}) => { + return atomFamily({ + key, + default: defaultValue, + }); +}; diff --git a/front/src/modules/ui/view-bar/components/AddFilterFromDetailsButton.tsx b/front/src/modules/ui/view-bar/components/AddFilterFromDetailsButton.tsx index 37f13118c..7249b29cc 100644 --- a/front/src/modules/ui/view-bar/components/AddFilterFromDetailsButton.tsx +++ b/front/src/modules/ui/view-bar/components/AddFilterFromDetailsButton.tsx @@ -6,7 +6,7 @@ import { FilterDropdownId } from '../constants/FilterDropdownId'; export const AddFilterFromDropdownButton = () => { const { toggleDropdown } = useDropdown({ - dropdownId: FilterDropdownId, + dropdownScopeId: FilterDropdownId, }); const handleClick = () => { diff --git a/front/src/modules/ui/view-bar/components/MultipleFiltersButton.tsx b/front/src/modules/ui/view-bar/components/MultipleFiltersButton.tsx index b9b5636b2..1ea61b300 100644 --- a/front/src/modules/ui/view-bar/components/MultipleFiltersButton.tsx +++ b/front/src/modules/ui/view-bar/components/MultipleFiltersButton.tsx @@ -13,7 +13,7 @@ export const MultipleFiltersButton = () => { const { ViewBarRecoilScopeContext } = useViewBarContext(); const { isDropdownOpen, toggleDropdown } = useDropdown({ - dropdownId: FilterDropdownId, + dropdownScopeId: FilterDropdownId, }); const [, setIsFilterDropdownOperandSelectUnfolded] = useRecoilScopedState( diff --git a/front/src/modules/ui/view-bar/components/SingleEntityFilterDropdownButton.tsx b/front/src/modules/ui/view-bar/components/SingleEntityFilterDropdownButton.tsx index decb80a7f..00a5e6a7a 100644 --- a/front/src/modules/ui/view-bar/components/SingleEntityFilterDropdownButton.tsx +++ b/front/src/modules/ui/view-bar/components/SingleEntityFilterDropdownButton.tsx @@ -1,22 +1,19 @@ import React from 'react'; import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; +import { DropdownMenu } from '@/ui/dropdown/components/DropdownMenu'; import { DropdownMenuContainer } from '@/ui/dropdown/components/DropdownMenuContainer'; -import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext'; -import { IconChevronDown } from '@/ui/icon'; -import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; +import { StyledHeaderDropdownButton } from '@/ui/dropdown/components/StyledHeaderDropdownButton'; +import { DropdownScope } from '@/ui/dropdown/scopes/DropdownScope'; +import { IconChevronDown } from '@/ui/icon/index'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; import { filterDefinitionUsedInDropdownScopedState } from '@/ui/view-bar/states/filterDefinitionUsedInDropdownScopedState'; -import { filterDropdownSearchInputScopedState } from '@/ui/view-bar/states/filterDropdownSearchInputScopedState'; import { selectedOperandInDropdownScopedState } from '@/ui/view-bar/states/selectedOperandInDropdownScopedState'; -import { StyledHeaderDropdownButton } from '../../dropdown/components/StyledHeaderDropdownButton'; import { useViewBarContext } from '../hooks/useViewBarContext'; import { availableFiltersScopedState } from '../states/availableFiltersScopedState'; import { filtersScopedState } from '../states/filtersScopedState'; -import { isFilterDropdownUnfoldedScopedState } from '../states/isFilterDropdownUnfoldedScopedState'; import { FilterOperand } from '../types/FilterOperand'; import { getOperandsForFilterType } from '../utils/getOperandsForFilterType'; @@ -24,19 +21,11 @@ import { FilterDropdownEntitySearchInput } from './FilterDropdownEntitySearchInp import { FilterDropdownEntitySelect } from './FilterDropdownEntitySelect'; import { GenericEntityFilterChip } from './GenericEntityFilterChip'; -const StyledDropdownButtonContainer = styled.div` - display: flex; - flex-direction: column; - position: relative; -`; - export const SingleEntityFilterDropdownButton = ({ hotkeyScope, }: { hotkeyScope: HotkeyScope; }) => { - const theme = useTheme(); - const { ViewBarRecoilScopeContext } = useViewBarContext(); const [availableFilters] = useRecoilScopedState( @@ -45,12 +34,6 @@ export const SingleEntityFilterDropdownButton = ({ ); const availableFilter = availableFilters[0]; - const [isFilterDropdownUnfolded, setIsFilterDropdownUnfolded] = - useRecoilScopedState( - isFilterDropdownUnfoldedScopedState, - DropdownRecoilScopeContext, - ); - const [filters] = useRecoilScopedState( filtersScopedState, ViewBarRecoilScopeContext, @@ -61,11 +44,6 @@ export const SingleEntityFilterDropdownButton = ({ ViewBarRecoilScopeContext, ); - const [, setFilterDropdownSearchInput] = useRecoilScopedState( - filterDropdownSearchInputScopedState, - ViewBarRecoilScopeContext, - ); - const [, setSelectedOperandInDropdown] = useRecoilScopedState( selectedOperandInDropdownScopedState, ViewBarRecoilScopeContext, @@ -81,45 +59,37 @@ export const SingleEntityFilterDropdownButton = ({ setSelectedOperandInDropdown, ]); - const setHotkeyScope = useSetHotkeyScope(); - - const handleIsUnfoldedChange = (newIsUnfolded: boolean) => { - if (newIsUnfolded) { - setHotkeyScope(hotkeyScope.scope, hotkeyScope.customScopes); - setIsFilterDropdownUnfolded(true); - } else { - setHotkeyScope(hotkeyScope.scope, hotkeyScope.customScopes); - setIsFilterDropdownUnfolded(false); - setFilterDropdownSearchInput(''); - } - }; + const theme = useTheme(); return ( - - handleIsUnfoldedChange(!isFilterDropdownUnfolded)} - > - {filters[0] ? ( - - ) : ( - 'Filter' - )} - - - {isFilterDropdownUnfolded && ( - handleIsUnfoldedChange(false)}> - - - - )} - + + + {filters[0] ? ( + + ) : ( + 'Filter' + )} + + + } + dropdownComponents={ + + + + + } + /> + ); }; diff --git a/front/src/modules/ui/view-bar/components/SortDropdownButton.tsx b/front/src/modules/ui/view-bar/components/SortDropdownButton.tsx index 0a92b0e16..d50301808 100644 --- a/front/src/modules/ui/view-bar/components/SortDropdownButton.tsx +++ b/front/src/modules/ui/view-bar/components/SortDropdownButton.tsx @@ -55,7 +55,7 @@ export const SortDropdownButton = ({ const isSortSelected = sorts.length > 0; const { toggleDropdown } = useDropdown({ - dropdownId: SortDropdownId, + dropdownScopeId: SortDropdownId, }); const handleButtonClick = () => { diff --git a/front/src/modules/ui/view-bar/components/ViewBar.tsx b/front/src/modules/ui/view-bar/components/ViewBar.tsx index 900596d37..4bc5a4094 100644 --- a/front/src/modules/ui/view-bar/components/ViewBar.tsx +++ b/front/src/modules/ui/view-bar/components/ViewBar.tsx @@ -15,16 +15,16 @@ import { ViewsDropdownButton } from './ViewsDropdownButton'; export type ViewBarProps = { className?: string; optionsDropdownButton: ReactNode; - optionsDropdownKey: string; + optionsDropdownScopeId: string; }; export const ViewBar = ({ className, optionsDropdownButton, - optionsDropdownKey, + optionsDropdownScopeId, }: ViewBarProps) => { const { openDropdown: openOptionsDropdownButton } = useDropdown({ - dropdownId: optionsDropdownKey, + dropdownScopeId: optionsDropdownScopeId, }); return ( diff --git a/front/src/modules/ui/view-bar/components/ViewBarDropdownButton.tsx b/front/src/modules/ui/view-bar/components/ViewBarDropdownButton.tsx index 998b7bb3d..9dcc60e68 100644 --- a/front/src/modules/ui/view-bar/components/ViewBarDropdownButton.tsx +++ b/front/src/modules/ui/view-bar/components/ViewBarDropdownButton.tsx @@ -2,6 +2,7 @@ import { Keys } from 'react-hotkeys-hook'; import { Placement } from '@floating-ui/react'; import { DropdownMenu } from '@/ui/dropdown/components/DropdownMenu'; +import { DropdownScope } from '@/ui/dropdown/scopes/DropdownScope'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; type ViewBarDropdownButtonProps = { @@ -31,17 +32,18 @@ export const ViewBarDropdownButton = ({ onOpen, }: ViewBarDropdownButtonProps) => { return ( - + + + ); }; diff --git a/front/src/modules/ui/view-bar/components/ViewsDropdownButton.tsx b/front/src/modules/ui/view-bar/components/ViewsDropdownButton.tsx index f3cc8839d..b1a1d2510 100644 --- a/front/src/modules/ui/view-bar/components/ViewsDropdownButton.tsx +++ b/front/src/modules/ui/view-bar/components/ViewsDropdownButton.tsx @@ -105,7 +105,7 @@ export const ViewsDropdownButton = ({ ); const { isDropdownOpen, closeDropdown } = useDropdown({ - dropdownId: ViewsDropdownId, + dropdownScopeId: ViewsDropdownId, }); const setViewEditMode = useSetRecoilState(viewEditModeState); diff --git a/front/src/pages/companies/Companies.tsx b/front/src/pages/companies/Companies.tsx index 52b7b09c1..e35a1f566 100644 --- a/front/src/pages/companies/Companies.tsx +++ b/front/src/pages/companies/Companies.tsx @@ -11,7 +11,6 @@ import { DataTableContextMenu } from '@/ui/data-table/context-menu/components/Da import { useUpsertDataTableItem } from '@/ui/data-table/hooks/useUpsertDataTableItem'; import { useUpsertTableRowId } from '@/ui/data-table/hooks/useUpsertTableRowId'; import { TableRecoilScopeContext } from '@/ui/data-table/states/recoil-scope-contexts/TableRecoilScopeContext'; -import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext'; import { IconBuildingSkyscraper } from '@/ui/icon'; import { PageAddButton } from '@/ui/layout/components/PageAddButton'; import { PageBody } from '@/ui/layout/components/PageBody'; @@ -58,10 +57,8 @@ export const Companies = () => { - - - - + + { hasBackButton Icon={IconBuildingSkyscraper} > - - - - + + diff --git a/front/src/pages/opportunities/Opportunities.tsx b/front/src/pages/opportunities/Opportunities.tsx index 9fbe1be21..b4bd84aba 100644 --- a/front/src/pages/opportunities/Opportunities.tsx +++ b/front/src/pages/opportunities/Opportunities.tsx @@ -3,7 +3,6 @@ import { CompanyBoardRecoilScopeContext } from '@/companies/states/recoil-scope- import { PipelineAddButton } from '@/pipeline/components/PipelineAddButton'; import { usePipelineStages } from '@/pipeline/hooks/usePipelineStages'; import { BoardOptionsContext } from '@/ui/board/contexts/BoardOptionsContext'; -import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext'; import { IconTargetArrow } from '@/ui/icon'; import { PageBody } from '@/ui/layout/components/PageBody'; import { PageContainer } from '@/ui/layout/components/PageContainer'; @@ -44,9 +43,7 @@ export const Opportunities = () => { - - - + diff --git a/front/src/pages/people/People.tsx b/front/src/pages/people/People.tsx index 76c18663e..e0a570ef9 100644 --- a/front/src/pages/people/People.tsx +++ b/front/src/pages/people/People.tsx @@ -9,7 +9,6 @@ import { DataTableContextMenu } from '@/ui/data-table/context-menu/components/Da import { useUpsertDataTableItem } from '@/ui/data-table/hooks/useUpsertDataTableItem'; import { useUpsertTableRowId } from '@/ui/data-table/hooks/useUpsertTableRowId'; import { TableRecoilScopeContext } from '@/ui/data-table/states/recoil-scope-contexts/TableRecoilScopeContext'; -import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext'; import { IconUser } from '@/ui/icon'; import { PageAddButton } from '@/ui/layout/components/PageAddButton'; import { PageBody } from '@/ui/layout/components/PageBody'; @@ -54,10 +53,8 @@ export const People = () => { - - - - + + { - - - - + + diff --git a/front/src/pages/tasks/Tasks.tsx b/front/src/pages/tasks/Tasks.tsx index ca8f80b1f..3e1ace410 100644 --- a/front/src/pages/tasks/Tasks.tsx +++ b/front/src/pages/tasks/Tasks.tsx @@ -3,7 +3,6 @@ import styled from '@emotion/styled'; import { TasksRecoilScopeContext } from '@/activities/states/recoil-scope-contexts/TasksRecoilScopeContext'; import { PageAddTaskButton } from '@/activities/tasks/components/PageAddTaskButton'; import { TaskGroups } from '@/activities/tasks/components/TaskGroups'; -import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext'; import { IconArchive, IconCheck, IconCheckbox } from '@/ui/icon/index'; import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope'; import { PageBody } from '@/ui/layout/components/PageBody'; @@ -48,43 +47,41 @@ export const Tasks = () => { return ( - - - - - - - - {/* TODO: we should refactor filters as a standalone module ? */} - - - - - - } - rightComponent={ - + + + + + + {/* TODO: we should refactor filters as a standalone module ? */} + + + + - } - /> - - - - - + + } + rightComponent={ + + } + /> + + + + ); diff --git a/front/src/types/ScopeContextProps.ts b/front/src/types/ScopeContextProps.ts new file mode 100644 index 000000000..dcb49f3c9 --- /dev/null +++ b/front/src/types/ScopeContextProps.ts @@ -0,0 +1,3 @@ +export type ScopeContextProps = { + scopeId: string; +} & T;