From 70c0fd4e0d1a2d18f41d27d732b27ec234993d19 Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Fri, 15 Sep 2023 00:33:45 +0200 Subject: [PATCH] Removed last old DropdownButton (#1573) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Removed last old DropdownButton * Update front/src/modules/ui/view-bar/components/SingleEntityFilterDropdownButton.tsx Co-authored-by: Thaïs * Fix CI --------- Co-authored-by: Charles Bochet Co-authored-by: Thaïs Co-authored-by: Charles Bochet --- .github/workflows/ci-front.yaml | 5 - .../ui/dropdown/components/DropdownButton.tsx | 25 +-- .../components/DropdownMenuContainer.tsx | 0 .../StyledDropdownButtonContainer.tsx | 27 +++ .../ui/dropdown/hooks/useDropdownButton.ts | 12 +- .../hooks/useInternalHotkeyScopeManagement.ts | 33 ++++ ...downButtonHotkeyScopeScopedFamilyState.ts} | 4 +- .../hooks/useRecoilScopedFamilyState.ts | 10 +- .../ui/view-bar/components/DropdownButton.tsx | 126 ------------- .../components/MultipleFiltersButton.tsx | 41 ++++- .../MultipleFiltersDropdownButton.tsx | 52 +----- .../SingleEntityFilterDropdownButton.tsx | 2 +- .../components/UpdateViewButtonGroup.tsx | 2 +- .../ui/view-bar/components/ViewBar.tsx | 2 +- .../components/ViewsDropdownButton.tsx | 166 +++++++++--------- .../ui/view-bar/constants/ViewsDropdownId.ts | 1 + 16 files changed, 204 insertions(+), 304 deletions(-) rename front/src/modules/ui/{view-bar => dropdown}/components/DropdownMenuContainer.tsx (100%) create mode 100644 front/src/modules/ui/dropdown/components/StyledDropdownButtonContainer.tsx create mode 100644 front/src/modules/ui/dropdown/hooks/useInternalHotkeyScopeManagement.ts rename front/src/modules/ui/dropdown/states/{dropdownButtonCustomHotkeyScopeScopedFamilyState.ts => dropdownButtonHotkeyScopeScopedFamilyState.ts} (57%) delete mode 100644 front/src/modules/ui/view-bar/components/DropdownButton.tsx create mode 100644 front/src/modules/ui/view-bar/constants/ViewsDropdownId.ts diff --git a/.github/workflows/ci-front.yaml b/.github/workflows/ci-front.yaml index 51bb90329..b95960b42 100644 --- a/.github/workflows/ci-front.yaml +++ b/.github/workflows/ci-front.yaml @@ -11,13 +11,8 @@ jobs: REACT_APP_SERVER_BASE_URL: http://localhost:3000 steps: - uses: actions/checkout@v3 - if: github.event_name == 'push' with: ref: ${{ github.head_ref || github.ref_name }} - - uses: actions/checkout@v3 - if: github.event_name == 'pull_request_target' - with: - ref: "refs/pull/${{ github.event.number }}/merge" - name: Setup Node.js uses: actions/setup-node@v3 with: diff --git a/front/src/modules/ui/dropdown/components/DropdownButton.tsx b/front/src/modules/ui/dropdown/components/DropdownButton.tsx index eb5214784..edfe28fd5 100644 --- a/front/src/modules/ui/dropdown/components/DropdownButton.tsx +++ b/front/src/modules/ui/dropdown/components/DropdownButton.tsx @@ -1,16 +1,13 @@ -import { useEffect, useRef } from 'react'; +import { useRef } from 'react'; import { Keys } from 'react-hotkeys-hook'; import { flip, offset, Placement, useFloating } from '@floating-ui/react'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; -import { useRecoilScopedFamilyState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState'; -import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; import { HotkeyEffect } from '../../utilities/hotkey/components/HotkeyEffect'; import { useDropdownButton } from '../hooks/useDropdownButton'; -import { dropdownButtonCustomHotkeyScopeScopedFamilyState } from '../states/dropdownButtonCustomHotkeyScopeScopedFamilyState'; -import { DropdownRecoilScopeContext } from '../states/recoil-scope-contexts/DropdownRecoilScopeContext'; +import { useInternalHotkeyScopeManagement } from '../hooks/useInternalHotkeyScopeManagement'; type OwnProps = { buttonComponents: JSX.Element | JSX.Element[]; @@ -57,22 +54,10 @@ export function DropdownButton({ }, }); - const [dropdownButtonCustomHotkeyScope, setDropdownButtonCustomHotkeyScope] = - useRecoilScopedFamilyState( - dropdownButtonCustomHotkeyScopeScopedFamilyState, - dropdownId, - DropdownRecoilScopeContext, - ); - - useEffect(() => { - if (!isDeeplyEqual(dropdownButtonCustomHotkeyScope, dropdownHotkeyScope)) { - setDropdownButtonCustomHotkeyScope(dropdownHotkeyScope); - } - }, [ + useInternalHotkeyScopeManagement({ + dropdownId, dropdownHotkeyScope, - dropdownButtonCustomHotkeyScope, - setDropdownButtonCustomHotkeyScope, - ]); + }); return (
diff --git a/front/src/modules/ui/view-bar/components/DropdownMenuContainer.tsx b/front/src/modules/ui/dropdown/components/DropdownMenuContainer.tsx similarity index 100% rename from front/src/modules/ui/view-bar/components/DropdownMenuContainer.tsx rename to front/src/modules/ui/dropdown/components/DropdownMenuContainer.tsx diff --git a/front/src/modules/ui/dropdown/components/StyledDropdownButtonContainer.tsx b/front/src/modules/ui/dropdown/components/StyledDropdownButtonContainer.tsx new file mode 100644 index 000000000..20c4f0f70 --- /dev/null +++ b/front/src/modules/ui/dropdown/components/StyledDropdownButtonContainer.tsx @@ -0,0 +1,27 @@ +import styled from '@emotion/styled'; + +type StyledDropdownButtonProps = { + isUnfolded: boolean; + isActive?: boolean; +}; + +export const StyledDropdownButtonContainer = styled.div` + align-items: center; + background: ${({ theme }) => theme.background.primary}; + border-radius: ${({ theme }) => theme.border.radius.sm}; + color: ${({ isActive, theme, color }) => + color ?? (isActive ? theme.color.blue : 'none')}; + cursor: pointer; + display: flex; + filter: ${(props) => (props.isUnfolded ? 'brightness(0.95)' : 'none')}; + + padding: ${({ theme }) => theme.spacing(1)}; + padding-left: ${({ theme }) => theme.spacing(2)}; + + padding-right: ${({ theme }) => theme.spacing(2)}; + user-select: none; + + &:hover { + filter: brightness(0.95); + } +`; diff --git a/front/src/modules/ui/dropdown/hooks/useDropdownButton.ts b/front/src/modules/ui/dropdown/hooks/useDropdownButton.ts index 895626182..939959534 100644 --- a/front/src/modules/ui/dropdown/hooks/useDropdownButton.ts +++ b/front/src/modules/ui/dropdown/hooks/useDropdownButton.ts @@ -1,7 +1,7 @@ import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope'; import { useRecoilScopedFamilyState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState'; -import { dropdownButtonCustomHotkeyScopeScopedFamilyState } from '../states/dropdownButtonCustomHotkeyScopeScopedFamilyState'; +import { dropdownButtonHotkeyScopeScopedFamilyState } from '../states/dropdownButtonHotkeyScopeScopedFamilyState'; import { isDropdownButtonOpenScopedFamilyState } from '../states/isDropdownButtonOpenScopedFamilyState'; import { DropdownRecoilScopeContext } from '../states/recoil-scope-contexts/DropdownRecoilScopeContext'; @@ -18,8 +18,8 @@ export function useDropdownButton({ dropdownId }: { dropdownId: string }) { DropdownRecoilScopeContext, ); - const [dropdownButtonCustomHotkeyScope] = useRecoilScopedFamilyState( - dropdownButtonCustomHotkeyScopeScopedFamilyState, + const [dropdownButtonHotkeyScope] = useRecoilScopedFamilyState( + dropdownButtonHotkeyScopeScopedFamilyState, dropdownId, DropdownRecoilScopeContext, ); @@ -32,10 +32,10 @@ export function useDropdownButton({ dropdownId }: { dropdownId: string }) { function openDropdownButton() { setIsDropdownButtonOpen(true); - if (dropdownButtonCustomHotkeyScope) { + if (dropdownButtonHotkeyScope) { setHotkeyScopeAndMemorizePreviousScope( - dropdownButtonCustomHotkeyScope.scope, - dropdownButtonCustomHotkeyScope.customScopes, + dropdownButtonHotkeyScope.scope, + dropdownButtonHotkeyScope.customScopes, ); } } diff --git a/front/src/modules/ui/dropdown/hooks/useInternalHotkeyScopeManagement.ts b/front/src/modules/ui/dropdown/hooks/useInternalHotkeyScopeManagement.ts new file mode 100644 index 000000000..51052c5a6 --- /dev/null +++ b/front/src/modules/ui/dropdown/hooks/useInternalHotkeyScopeManagement.ts @@ -0,0 +1,33 @@ +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'; + +export const useInternalHotkeyScopeManagement = ({ + dropdownId, + dropdownHotkeyScope, +}: { + dropdownId: string; + dropdownHotkeyScope?: HotkeyScope; +}) => { + const [dropdownButtonHotkeyScope, setDropdownButtonHotkeyScope] = + useRecoilScopedFamilyState( + dropdownButtonHotkeyScopeScopedFamilyState, + dropdownId, + DropdownRecoilScopeContext, + ); + + useEffect(() => { + if (!isDeeplyEqual(dropdownButtonHotkeyScope, dropdownHotkeyScope)) { + setDropdownButtonHotkeyScope(dropdownHotkeyScope); + } + }, [ + dropdownHotkeyScope, + dropdownButtonHotkeyScope, + setDropdownButtonHotkeyScope, + ]); +}; diff --git a/front/src/modules/ui/dropdown/states/dropdownButtonCustomHotkeyScopeScopedFamilyState.ts b/front/src/modules/ui/dropdown/states/dropdownButtonHotkeyScopeScopedFamilyState.ts similarity index 57% rename from front/src/modules/ui/dropdown/states/dropdownButtonCustomHotkeyScopeScopedFamilyState.ts rename to front/src/modules/ui/dropdown/states/dropdownButtonHotkeyScopeScopedFamilyState.ts index 2e73d7f82..67a5952cc 100644 --- a/front/src/modules/ui/dropdown/states/dropdownButtonCustomHotkeyScopeScopedFamilyState.ts +++ b/front/src/modules/ui/dropdown/states/dropdownButtonHotkeyScopeScopedFamilyState.ts @@ -2,10 +2,10 @@ import { atomFamily } from 'recoil'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; -export const dropdownButtonCustomHotkeyScopeScopedFamilyState = atomFamily< +export const dropdownButtonHotkeyScopeScopedFamilyState = atomFamily< HotkeyScope | null | undefined, string >({ - key: 'dropdownButtonCustomHotkeyScopeScopedState', + key: 'dropdownButtonHotkeyScopeScopedFamilyState', default: null, }); 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 4245d06b2..b7881d3dc 100644 --- a/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState.ts +++ b/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState.ts @@ -4,8 +4,8 @@ import { RecoilState, useRecoilState } from 'recoil'; import { RecoilScopeContext } from '../states/RecoilScopeContext'; export function useRecoilScopedFamilyState( - recoilState: (param: string) => RecoilState, - stateKey: string, + recoilState: (familyUniqueId: string) => RecoilState, + uniqueIdInRecoilScope: string, SpecificContext?: Context, ) { const recoilScopeId = useContext(SpecificContext ?? RecoilScopeContext); @@ -13,9 +13,11 @@ export function useRecoilScopedFamilyState( if (!recoilScopeId) throw new Error( `Using a scoped atom without a RecoilScope : ${ - recoilState(stateKey).key + recoilState('').key }, verify that you are using a RecoilScope with a specific context if you intended to do so.`, ); - return useRecoilState(recoilState(recoilScopeId + stateKey)); + const familyUniqueId = recoilScopeId + uniqueIdInRecoilScope; + + return useRecoilState(recoilState(familyUniqueId)); } diff --git a/front/src/modules/ui/view-bar/components/DropdownButton.tsx b/front/src/modules/ui/view-bar/components/DropdownButton.tsx deleted file mode 100644 index 5ede64927..000000000 --- a/front/src/modules/ui/view-bar/components/DropdownButton.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import { ReactNode } from 'react'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { Key } from 'ts-key-enum'; - -import { IconComponent } from '@/ui/icon/types/IconComponent'; -import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; - -import { DropdownMenuContainer } from './DropdownMenuContainer'; - -type DropdownButtonProps = { - anchor?: 'left' | 'right'; - label: ReactNode; - isActive: boolean; - children?: ReactNode; - isUnfolded?: boolean; - Icon?: IconComponent; - onIsUnfoldedChange?: (newIsUnfolded: boolean) => void; - resetState?: () => void; - hotkeyScope: string; - color?: string; - menuWidth?: `${string}px` | 'auto' | number; -}; - -const StyledDropdownButtonContainer = styled.div` - display: flex; - flex-direction: column; -`; - -const StyledDropdownButtonIcon = styled.div` - display: flex; - justify-content: center; - margin-right: ${({ theme }) => theme.spacing(1)}; -`; - -type StyledDropdownButtonProps = { - isUnfolded: boolean; - isActive: boolean; -}; - -const StyledDropdownButton = styled.div` - align-items: center; - background: ${({ theme }) => theme.background.primary}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - color: ${({ isActive, theme, color }) => - color ?? (isActive ? theme.color.blue : 'none')}; - cursor: pointer; - display: flex; - filter: ${(props) => (props.isUnfolded ? 'brightness(0.95)' : 'none')}; - - padding: ${({ theme }) => theme.spacing(1)}; - padding-left: ${({ theme }) => theme.spacing(2)}; - - padding-right: ${({ theme }) => theme.spacing(2)}; - user-select: none; - - &:hover { - filter: brightness(0.95); - } -`; - -/** - * - * @deprecated use ui/dropdown/components/DropdownButton.tsx instead - */ -function DropdownButton({ - anchor, - label, - isActive, - children, - isUnfolded = false, - onIsUnfoldedChange, - Icon, - hotkeyScope, - color, - menuWidth, -}: DropdownButtonProps) { - useScopedHotkeys( - [Key.Enter, Key.Escape], - () => { - onIsUnfoldedChange?.(false); - }, - hotkeyScope, - [onIsUnfoldedChange], - ); - - const onButtonClick = () => { - onIsUnfoldedChange?.(!isUnfolded); - }; - - const onOutsideClick = () => { - onIsUnfoldedChange?.(false); - }; - - const theme = useTheme(); - - return ( - - - {Icon && ( - - {} - - )} - {label} - - {isUnfolded && ( - - {children} - - )} - - ); -} - -export default DropdownButton; diff --git a/front/src/modules/ui/view-bar/components/MultipleFiltersButton.tsx b/front/src/modules/ui/view-bar/components/MultipleFiltersButton.tsx index 25e8a0aaa..3195da139 100644 --- a/front/src/modules/ui/view-bar/components/MultipleFiltersButton.tsx +++ b/front/src/modules/ui/view-bar/components/MultipleFiltersButton.tsx @@ -1,15 +1,54 @@ +import { Context } from 'react'; + import { StyledHeaderDropdownButton } from '@/ui/dropdown/components/StyledHeaderDropdownButton'; import { useDropdownButton } from '@/ui/dropdown/hooks/useDropdownButton'; +import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; import { FilterDropdownId } from '../constants/FilterDropdownId'; +import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState'; +import { filterDropdownSearchInputScopedState } from '../states/filterDropdownSearchInputScopedState'; +import { isFilterDropdownOperandSelectUnfoldedScopedState } from '../states/isFilterDropdownOperandSelectUnfoldedScopedState'; +import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState'; -export function MultipleFiltersButton() { +type OwnProps = { + context: Context; +}; + +export function MultipleFiltersButton({ context }: OwnProps) { const { isDropdownButtonOpen, toggleDropdownButton } = useDropdownButton({ dropdownId: FilterDropdownId, }); + const [, setIsFilterDropdownOperandSelectUnfolded] = useRecoilScopedState( + isFilterDropdownOperandSelectUnfoldedScopedState, + context, + ); + + const [, setFilterDefinitionUsedInDropdown] = useRecoilScopedState( + filterDefinitionUsedInDropdownScopedState, + context, + ); + + const [, setFilterDropdownSearchInput] = useRecoilScopedState( + filterDropdownSearchInputScopedState, + context, + ); + + const [, setSelectedOperandInDropdown] = useRecoilScopedState( + selectedOperandInDropdownScopedState, + context, + ); + + const resetState = () => { + setIsFilterDropdownOperandSelectUnfolded(false); + setFilterDefinitionUsedInDropdown(null); + setSelectedOperandInDropdown(null); + setFilterDropdownSearchInput(''); + }; + function handleClick() { toggleDropdownButton(); + resetState(); } return ( diff --git a/front/src/modules/ui/view-bar/components/MultipleFiltersDropdownButton.tsx b/front/src/modules/ui/view-bar/components/MultipleFiltersDropdownButton.tsx index 667670264..572bcc2ee 100644 --- a/front/src/modules/ui/view-bar/components/MultipleFiltersDropdownButton.tsx +++ b/front/src/modules/ui/view-bar/components/MultipleFiltersDropdownButton.tsx @@ -1,15 +1,9 @@ -import { Context, useCallback, useEffect } from 'react'; +import { Context } from 'react'; import { DropdownButton } from '@/ui/dropdown/components/DropdownButton'; -import { useDropdownButton } from '@/ui/dropdown/hooks/useDropdownButton'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; -import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; import { FilterDropdownId } from '../constants/FilterDropdownId'; -import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState'; -import { filterDropdownSearchInputScopedState } from '../states/filterDropdownSearchInputScopedState'; -import { isFilterDropdownOperandSelectUnfoldedScopedState } from '../states/isFilterDropdownOperandSelectUnfoldedScopedState'; -import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState'; import { MultipleFiltersButton } from './MultipleFiltersButton'; import { MultipleFiltersDropdownContent } from './MultipleFiltersDropdownContent'; @@ -23,52 +17,10 @@ export function MultipleFiltersDropdownButton({ context, hotkeyScope, }: MultipleFiltersDropdownButtonProps) { - const [, setIsFilterDropdownOperandSelectUnfolded] = useRecoilScopedState( - isFilterDropdownOperandSelectUnfoldedScopedState, - context, - ); - - const [, setFilterDefinitionUsedInDropdown] = useRecoilScopedState( - filterDefinitionUsedInDropdownScopedState, - context, - ); - - const [, setFilterDropdownSearchInput] = useRecoilScopedState( - filterDropdownSearchInputScopedState, - context, - ); - - const [, setSelectedOperandInDropdown] = useRecoilScopedState( - selectedOperandInDropdownScopedState, - context, - ); - - const { isDropdownButtonOpen } = useDropdownButton({ - dropdownId: FilterDropdownId, - }); - - const resetState = useCallback(() => { - setIsFilterDropdownOperandSelectUnfolded(false); - setFilterDefinitionUsedInDropdown(null); - setSelectedOperandInDropdown(null); - setFilterDropdownSearchInput(''); - }, [ - setFilterDefinitionUsedInDropdown, - setSelectedOperandInDropdown, - setFilterDropdownSearchInput, - setIsFilterDropdownOperandSelectUnfolded, - ]); - - useEffect(() => { - if (!isDropdownButtonOpen) { - resetState(); - } - }, [isDropdownButtonOpen, resetState]); - return ( } + buttonComponents={} dropdownComponents={} dropdownHotkeyScope={hotkeyScope} /> diff --git a/front/src/modules/ui/view-bar/components/SingleEntityFilterDropdownButton.tsx b/front/src/modules/ui/view-bar/components/SingleEntityFilterDropdownButton.tsx index 509c2832c..11adfac23 100644 --- a/front/src/modules/ui/view-bar/components/SingleEntityFilterDropdownButton.tsx +++ b/front/src/modules/ui/view-bar/components/SingleEntityFilterDropdownButton.tsx @@ -3,6 +3,7 @@ import React from 'react'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; +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'; @@ -18,7 +19,6 @@ import { filtersScopedState } from '../states/filtersScopedState'; import { isFilterDropdownUnfoldedScopedState } from '../states/isFilterDropdownUnfoldedScopedState'; import { getOperandsForFilterType } from '../utils/getOperandsForFilterType'; -import { DropdownMenuContainer } from './DropdownMenuContainer'; import { FilterDropdownEntitySearchInput } from './FilterDropdownEntitySearchInput'; import { FilterDropdownEntitySelect } from './FilterDropdownEntitySelect'; import { GenericEntityFilterChip } from './GenericEntityFilterChip'; diff --git a/front/src/modules/ui/view-bar/components/UpdateViewButtonGroup.tsx b/front/src/modules/ui/view-bar/components/UpdateViewButtonGroup.tsx index ec3d242b3..4457fe5f8 100644 --- a/front/src/modules/ui/view-bar/components/UpdateViewButtonGroup.tsx +++ b/front/src/modules/ui/view-bar/components/UpdateViewButtonGroup.tsx @@ -5,13 +5,13 @@ import { Key } from 'ts-key-enum'; import { Button } from '@/ui/button/components/Button'; import { ButtonGroup } from '@/ui/button/components/ButtonGroup'; +import { DropdownMenuContainer } from '@/ui/dropdown/components/DropdownMenuContainer'; import { StyledDropdownMenuItemsContainer } from '@/ui/dropdown/components/StyledDropdownMenuItemsContainer'; import { IconChevronDown, IconPlus } from '@/ui/icon'; import { MenuItem } from '@/ui/menu-item/components/MenuItem'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; import { useContextScopeId } from '@/ui/utilities/recoil-scope/hooks/useContextScopeId'; import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; -import { DropdownMenuContainer } from '@/ui/view-bar/components/DropdownMenuContainer'; import { currentViewIdScopedState } from '@/ui/view-bar/states/currentViewIdScopedState'; import { filtersScopedState } from '@/ui/view-bar/states/filtersScopedState'; import { savedFiltersFamilyState } from '@/ui/view-bar/states/savedFiltersFamilyState'; diff --git a/front/src/modules/ui/view-bar/components/ViewBar.tsx b/front/src/modules/ui/view-bar/components/ViewBar.tsx index 3dc27cd33..3f5cef062 100644 --- a/front/src/modules/ui/view-bar/components/ViewBar.tsx +++ b/front/src/modules/ui/view-bar/components/ViewBar.tsx @@ -35,7 +35,7 @@ export const ViewBar = ({ leftComponent={ } diff --git a/front/src/modules/ui/view-bar/components/ViewsDropdownButton.tsx b/front/src/modules/ui/view-bar/components/ViewsDropdownButton.tsx index 280363b10..3f8136fab 100644 --- a/front/src/modules/ui/view-bar/components/ViewsDropdownButton.tsx +++ b/front/src/modules/ui/view-bar/components/ViewsDropdownButton.tsx @@ -1,17 +1,14 @@ -import { - type Context, - type MouseEvent, - useCallback, - useContext, - useEffect, - useState, -} from 'react'; +import { type Context, type MouseEvent, useContext } from 'react'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useRecoilCallback, useSetRecoilState } from 'recoil'; +import { DropdownButton } from '@/ui/dropdown/components/DropdownButton'; +import { StyledDropdownButtonContainer } from '@/ui/dropdown/components/StyledDropdownButtonContainer'; +import { StyledDropdownMenu } from '@/ui/dropdown/components/StyledDropdownMenu'; import { StyledDropdownMenuItemsContainer } from '@/ui/dropdown/components/StyledDropdownMenuItemsContainer'; import { StyledDropdownMenuSeparator } from '@/ui/dropdown/components/StyledDropdownMenuSeparator'; +import { useDropdownButton } from '@/ui/dropdown/hooks/useDropdownButton'; import { IconChevronDown, IconList, @@ -21,10 +18,10 @@ import { } from '@/ui/icon'; import { MenuItem } from '@/ui/menu-item/components/MenuItem'; import { MOBILE_VIEWPORT } from '@/ui/theme/constants/theme'; -import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope'; +import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; import { useContextScopeId } from '@/ui/utilities/recoil-scope/hooks/useContextScopeId'; +import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; -import DropdownButton from '@/ui/view-bar/components/DropdownButton'; import { currentViewIdScopedState } from '@/ui/view-bar/states/currentViewIdScopedState'; import { filtersScopedState } from '@/ui/view-bar/states/filtersScopedState'; import { savedFiltersFamilyState } from '@/ui/view-bar/states/savedFiltersFamilyState'; @@ -33,9 +30,9 @@ import { currentViewScopedSelector } from '@/ui/view-bar/states/selectors/curren import { sortsScopedState } from '@/ui/view-bar/states/sortsScopedState'; import { viewEditModeState } from '@/ui/view-bar/states/viewEditModeState'; import { viewsScopedState } from '@/ui/view-bar/states/viewsScopedState'; -import { ViewsHotkeyScope } from '@/ui/view-bar/types/ViewsHotkeyScope'; import { assertNotNull } from '~/utils/assert'; +import { ViewsDropdownId } from '../constants/ViewsDropdownId'; import { ViewBarContext } from '../contexts/ViewBarContext'; import { useRemoveView } from '../hooks/useRemoveView'; @@ -73,7 +70,7 @@ const StyledViewName = styled.span` `; export type ViewsDropdownButtonProps = { - hotkeyScope: ViewsHotkeyScope; + hotkeyScope: HotkeyScope; onViewEditModeChange?: () => void; scopeContext: Context; }; @@ -88,24 +85,24 @@ export const ViewsDropdownButton = ({ const { defaultViewName, onViewSelect } = useContext(ViewBarContext); const recoilScopeId = useContextScopeId(scopeContext); - const [isUnfolded, setIsUnfolded] = useState(false); - const currentView = useRecoilScopedValue( currentViewScopedSelector, scopeContext, ); - const views = useRecoilScopedValue(viewsScopedState, scopeContext); - const setViewEditMode = useSetRecoilState(viewEditModeState); + const [views] = useRecoilScopedState(viewsScopedState, scopeContext); - const { - goBackToPreviousHotkeyScope, - setHotkeyScopeAndMemorizePreviousScope, - } = usePreviousHotkeyScope(); + const { isDropdownButtonOpen, closeDropdownButton, toggleDropdownButton } = + useDropdownButton({ + dropdownId: ViewsDropdownId, + }); + + const setViewEditMode = useSetRecoilState(viewEditModeState); const handleViewSelect = useRecoilCallback( ({ set, snapshot }) => async (viewId: string) => { await onViewSelect?.(viewId); + const savedFilters = await snapshot.getPromise( savedFiltersFamilyState(viewId), ); @@ -116,26 +113,26 @@ export const ViewsDropdownButton = ({ set(filtersScopedState(recoilScopeId), savedFilters); set(sortsScopedState(recoilScopeId), savedSorts); set(currentViewIdScopedState(recoilScopeId), viewId); - setIsUnfolded(false); + closeDropdownButton(); }, - [onViewSelect, recoilScopeId], + [onViewSelect, recoilScopeId, closeDropdownButton], ); - const handleAddViewButtonClick = useCallback(() => { + const handleAddViewButtonClick = () => { setViewEditMode({ mode: 'create', viewId: undefined }); onViewEditModeChange?.(); - setIsUnfolded(false); - }, [setViewEditMode, onViewEditModeChange]); + closeDropdownButton(); + }; - const handleEditViewButtonClick = useCallback( - (event: MouseEvent, viewId: string) => { - event.stopPropagation(); - setViewEditMode({ mode: 'edit', viewId }); - onViewEditModeChange?.(); - setIsUnfolded(false); - }, - [setViewEditMode, onViewEditModeChange], - ); + const handleEditViewButtonClick = ( + event: MouseEvent, + viewId: string, + ) => { + event.stopPropagation(); + setViewEditMode({ mode: 'edit', viewId }); + onViewEditModeChange?.(); + closeDropdownButton(); + }; const { removeView } = useRemoveView({ scopeContext }); @@ -146,24 +143,22 @@ export const ViewsDropdownButton = ({ event.stopPropagation(); await removeView(viewId); - setIsUnfolded(false); + closeDropdownButton(); }; - useEffect(() => { - isUnfolded - ? setHotkeyScopeAndMemorizePreviousScope(hotkeyScope) - : goBackToPreviousHotkeyScope(); - }, [ - hotkeyScope, - goBackToPreviousHotkeyScope, - isUnfolded, - setHotkeyScopeAndMemorizePreviousScope, - ]); + const handleViewButtonClick = () => { + toggleDropdownButton(); + }; return ( + dropdownId={ViewsDropdownId} + dropdownHotkeyScope={hotkeyScope} + buttonComponents={ + {currentView?.name || defaultViewName} @@ -171,47 +166,44 @@ export const ViewsDropdownButton = ({ · {views.length} - + } - isActive={false} - isUnfolded={isUnfolded} - onIsUnfoldedChange={setIsUnfolded} - anchor="left" - hotkeyScope={hotkeyScope} - menuWidth="auto" - > - - {views.map((view) => ( - ) => - handleEditViewButtonClick(event, view.id), - }, - views.length > 1 - ? { - Icon: IconTrash, + dropdownComponents={ + + + {views.map((view) => ( + ) => - handleDeleteViewButtonClick(event, view.id), - } - : null, - ].filter(assertNotNull)} - onClick={() => handleViewSelect(view.id)} - LeftIcon={IconList} - text={view.name} - /> - ))} - - - - - - + handleEditViewButtonClick(event, view.id), + }, + views.length > 1 + ? { + Icon: IconTrash, + onClick: (event: MouseEvent) => + handleDeleteViewButtonClick(event, view.id), + } + : null, + ].filter(assertNotNull)} + onClick={() => handleViewSelect(view.id)} + LeftIcon={IconList} + text={view.name} + /> + ))} + + + + + + + } + /> ); }; diff --git a/front/src/modules/ui/view-bar/constants/ViewsDropdownId.ts b/front/src/modules/ui/view-bar/constants/ViewsDropdownId.ts new file mode 100644 index 000000000..390e32277 --- /dev/null +++ b/front/src/modules/ui/view-bar/constants/ViewsDropdownId.ts @@ -0,0 +1 @@ +export const ViewsDropdownId = 'views';