From ca906bbf6b83af751406a3d960efcd4e5a83fb27 Mon Sep 17 00:00:00 2001 From: nitin <142569587+ehconitin@users.noreply.github.com> Date: Fri, 27 Sep 2024 17:50:21 +0530 Subject: [PATCH] 5922 - UI Overlap and State Persistence in Filter Menus (#7270) fixes #5922 https://github.com/user-attachments/assets/07d088da-cefb-4d87-9016-e14cef18567d --- .../MultipleFiltersDropdownButton.tsx | 11 +- .../MultipleFiltersDropdownContent.tsx | 128 ++++++++++-------- .../ObjectFilterDropdownOperandButton.tsx | 8 -- .../components/ObjectSortDropdownButton.tsx | 118 +++++++++------- .../EditableFilterDropdownButton.tsx | 6 + 5 files changed, 154 insertions(+), 117 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownButton.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownButton.tsx index 885a6c8eb..b88f421c9 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownButton.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownButton.tsx @@ -2,6 +2,7 @@ import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdow import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; +import { useCallback } from 'react'; import { MultipleFiltersButton } from './MultipleFiltersButton'; import { MultipleFiltersDropdownContent } from './MultipleFiltersDropdownContent'; @@ -13,12 +14,18 @@ type MultipleFiltersDropdownButtonProps = { export const MultipleFiltersDropdownButton = ({ hotkeyScope, }: MultipleFiltersDropdownButtonProps) => { - const { resetFilter } = useFilterDropdown(); + const { resetFilter, setIsObjectFilterDropdownOperandSelectUnfolded } = + useFilterDropdown(); + + const handleDropdownClose = useCallback(() => { + resetFilter(); + setIsObjectFilterDropdownOperandSelectUnfolded(false); + }, [resetFilter, setIsObjectFilterDropdownOperandSelectUnfolded]); return ( } dropdownComponents={} dropdownHotkeyScope={hotkeyScope} diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownContent.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownContent.tsx index ec3df12f0..7638532ee 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/MultipleFiltersDropdownContent.tsx @@ -1,11 +1,9 @@ -import { useRecoilValue } from 'recoil'; - +import { ObjectFilterDropdownRatingInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput'; import { ObjectFilterDropdownSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSearchInput'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; -import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; - -import { ObjectFilterDropdownRatingInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput'; +import styled from '@emotion/styled'; +import { useRecoilValue } from 'recoil'; import { MultipleFiltersDropdownFilterOnFilterChangedEffect } from './MultipleFiltersDropdownFilterOnFilterChangedEffect'; import { ObjectFilterDropdownDateInput } from './ObjectFilterDropdownDateInput'; import { ObjectFilterDropdownFilterSelect } from './ObjectFilterDropdownFilterSelect'; @@ -16,6 +14,21 @@ import { ObjectFilterDropdownOptionSelect } from './ObjectFilterDropdownOptionSe import { ObjectFilterDropdownRecordSelect } from './ObjectFilterDropdownRecordSelect'; import { ObjectFilterDropdownTextSearchInput } from './ObjectFilterDropdownTextSearchInput'; +const StyledContainer = styled.div` + position: relative; +`; + +const StyledOperandSelectContainer = styled.div` + background: ${({ theme }) => theme.background.secondary}; + box-shadow: ${({ theme }) => theme.boxShadow.light}; + border-radius: ${({ theme }) => theme.border.radius.md}; + left: 10px; + position: absolute; + top: 10px; + width: 100%; + z-index: 1000; +`; + type MultipleFiltersDropdownContentProps = { filterDropdownId?: string; }; @@ -24,20 +37,23 @@ export const MultipleFiltersDropdownContent = ({ filterDropdownId, }: MultipleFiltersDropdownContentProps) => { const { - isObjectFilterDropdownOperandSelectUnfoldedState, filterDefinitionUsedInDropdownState, selectedOperandInDropdownState, + isObjectFilterDropdownOperandSelectUnfoldedState, } = useFilterDropdown({ filterDropdownId }); const isObjectFilterDropdownOperandSelectUnfolded = useRecoilValue( isObjectFilterDropdownOperandSelectUnfoldedState, ); + const filterDefinitionUsedInDropdown = useRecoilValue( filterDefinitionUsedInDropdownState, ); + const selectedOperandInDropdown = useRecoilValue( selectedOperandInDropdownState, ); + const isEmptyOperand = selectedOperandInDropdown && [ViewFilterOperand.IsEmpty, ViewFilterOperand.IsNotEmpty].includes( @@ -45,64 +61,64 @@ export const MultipleFiltersDropdownContent = ({ ); return ( - <> + {!filterDefinitionUsedInDropdown ? ( - ) : isObjectFilterDropdownOperandSelectUnfolded ? ( - - ) : isEmptyOperand ? ( - ) : ( - selectedOperandInDropdown && ( - <> - - - {[ - 'TEXT', - 'EMAIL', - 'EMAILS', - 'PHONE', - 'FULL_NAME', - 'LINK', - 'LINKS', - 'ADDRESS', - 'ACTOR', - 'ARRAY', - 'PHONES', - ].includes(filterDefinitionUsedInDropdown.type) && ( - - )} - {['NUMBER', 'CURRENCY'].includes( - filterDefinitionUsedInDropdown.type, - ) && } - {filterDefinitionUsedInDropdown.type === 'RATING' && ( - - )} - {['DATE_TIME', 'DATE'].includes( - filterDefinitionUsedInDropdown.type, - ) && } - {filterDefinitionUsedInDropdown.type === 'RELATION' && ( - <> - - - - - )} - {filterDefinitionUsedInDropdown.type === 'SELECT' && ( - <> - - - - - )} - - ) + <> + + {isObjectFilterDropdownOperandSelectUnfolded && ( + + + + )} + {!isEmptyOperand && selectedOperandInDropdown && ( + <> + {[ + 'TEXT', + 'EMAIL', + 'EMAILS', + 'PHONE', + 'FULL_NAME', + 'LINK', + 'LINKS', + 'ADDRESS', + 'ACTOR', + 'ARRAY', + 'PHONES', + ].includes(filterDefinitionUsedInDropdown.type) && ( + + )} + {['NUMBER', 'CURRENCY'].includes( + filterDefinitionUsedInDropdown.type, + ) && } + {filterDefinitionUsedInDropdown.type === 'RATING' && ( + + )} + {['DATE_TIME', 'DATE'].includes( + filterDefinitionUsedInDropdown.type, + ) && } + {filterDefinitionUsedInDropdown.type === 'RELATION' && ( + <> + + + + )} + {filterDefinitionUsedInDropdown.type === 'SELECT' && ( + <> + + + + )} + + )} + )} - + ); }; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandButton.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandButton.tsx index 4aa675ec3..3931c7654 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandButton.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownOperandButton.tsx @@ -10,19 +10,11 @@ export const ObjectFilterDropdownOperandButton = () => { const { selectedOperandInDropdownState, setIsObjectFilterDropdownOperandSelectUnfolded, - isObjectFilterDropdownOperandSelectUnfoldedState, } = useFilterDropdown(); const selectedOperandInDropdown = useRecoilValue( selectedOperandInDropdownState, ); - const isObjectFilterDropdownOperandSelectUnfolded = useRecoilValue( - isObjectFilterDropdownOperandSelectUnfoldedState, - ); - - if (isObjectFilterDropdownOperandSelectUnfolded) { - return null; - } return ( theme.background.secondary}; + box-shadow: ${({ theme }) => theme.boxShadow.light}; + border-radius: ${({ theme }) => theme.border.radius.md}; + left: 10px; + position: absolute; + top: 10px; + width: 100%; + z-index: 1000; +`; + export type ObjectSortDropdownButtonProps = { sortDropdownId: string; hotkeyScope: HotkeyScope; @@ -95,60 +110,61 @@ export const ObjectSortDropdownButton = ({ } dropdownComponents={ <> - {isSortDirectionMenuUnfolded ? ( - - {SORT_DIRECTIONS.map((sortOrder, index) => ( - { - setSelectedSortDirection(sortOrder); - setIsSortDirectionMenuUnfolded(false); - }} - text={sortOrder === 'asc' ? 'Ascending' : 'Descending'} - /> - ))} - - ) : ( - <> - setIsSortDirectionMenuUnfolded(true)} - > - {selectedSortDirection === 'asc' ? 'Ascending' : 'Descending'} - - - setObjectSortDropdownSearchInput(event.target.value) - } - /> + {isSortDirectionMenuUnfolded && ( + - {[...availableSortDefinitions] - .sort((a, b) => a.label.localeCompare(b.label)) - .filter((item) => - item.label - .toLocaleLowerCase() - .includes( - objectSortDropdownSearchInput.toLocaleLowerCase(), - ), - ) - .map((availableSortDefinition, index) => ( - { - setObjectSortDropdownSearchInput(''); - handleAddSort(availableSortDefinition); - }} - LeftIcon={getIcon(availableSortDefinition.iconName)} - text={availableSortDefinition.label} - /> - ))} + {SORT_DIRECTIONS.map((sortOrder, index) => ( + { + setSelectedSortDirection(sortOrder); + setIsSortDirectionMenuUnfolded(false); + }} + text={sortOrder === 'asc' ? 'Ascending' : 'Descending'} + /> + ))} - + )} + + setIsSortDirectionMenuUnfolded(true)} + > + {selectedSortDirection === 'asc' ? 'Ascending' : 'Descending'} + + + setObjectSortDropdownSearchInput(event.target.value) + } + /> + + {[...availableSortDefinitions] + .sort((a, b) => a.label.localeCompare(b.label)) + .filter((item) => + item.label + .toLocaleLowerCase() + .includes( + objectSortDropdownSearchInput.toLocaleLowerCase(), + ), + ) + .map((availableSortDefinition, index) => ( + { + setObjectSortDropdownSearchInput(''); + handleAddSort(availableSortDefinition); + }} + LeftIcon={getIcon(availableSortDefinition.iconName)} + text={availableSortDefinition.label} + /> + ))} + + } onClose={handleDropdownButtonClose} diff --git a/packages/twenty-front/src/modules/views/components/EditableFilterDropdownButton.tsx b/packages/twenty-front/src/modules/views/components/EditableFilterDropdownButton.tsx index bbaa9af31..45c974eca 100644 --- a/packages/twenty-front/src/modules/views/components/EditableFilterDropdownButton.tsx +++ b/packages/twenty-front/src/modules/views/components/EditableFilterDropdownButton.tsx @@ -29,6 +29,7 @@ export const EditableFilterDropdownButton = ({ setFilterDefinitionUsedInDropdown, setSelectedOperandInDropdown, setSelectedFilter, + setIsObjectFilterDropdownOperandSelectUnfolded, } = useFilterDropdown({ filterDropdownId: viewFilterDropdownId, }); @@ -79,6 +80,10 @@ export const EditableFilterDropdownButton = ({ } }, [viewFilter, deleteCombinedViewFilter]); + const handleDropdownClose = useCallback(() => { + setIsObjectFilterDropdownOperandSelectUnfolded(false); + }, [setIsObjectFilterDropdownOperandSelectUnfolded]); + return ( ); };