Refator/sorts dropdown (#1568)
* WIP * Fixed lint * Ok for sorts * Fixed on dropdown toggle * Fix lint
This commit is contained in:
@ -2,11 +2,11 @@ import { LightButton } from '@/ui/button/components/LightButton';
|
||||
import { useDropdownButton } from '@/ui/dropdown/hooks/useDropdownButton';
|
||||
import { IconPlus } from '@/ui/icon';
|
||||
|
||||
import { FilterDropdownKey } from '../types/FilterDropdownKey';
|
||||
import { FilterDropdownId } from '../constants/FilterDropdownId';
|
||||
|
||||
export function AddFilterFromDropdownButton() {
|
||||
const { toggleDropdownButton } = useDropdownButton({
|
||||
key: FilterDropdownKey,
|
||||
dropdownId: FilterDropdownId,
|
||||
});
|
||||
|
||||
function handleClick() {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { Context } from 'react';
|
||||
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||
|
||||
import { availableFiltersScopedState } from '../states/availableFiltersScopedState';
|
||||
@ -9,12 +10,12 @@ import { SingleEntityFilterDropdownButton } from './SingleEntityFilterDropdownBu
|
||||
|
||||
type FilterDropdownButtonProps = {
|
||||
context: Context<string | null>;
|
||||
hotkeyScope: string;
|
||||
hotkeyScope: HotkeyScope;
|
||||
};
|
||||
|
||||
export function FilterDropdownButton({
|
||||
context,
|
||||
hotkeyScope,
|
||||
context,
|
||||
}: FilterDropdownButtonProps) {
|
||||
const [availableFilters] = useRecoilScopedState(
|
||||
availableFiltersScopedState,
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { StyledHeaderDropdownButton } from '@/ui/dropdown/components/StyledHeaderDropdownButton';
|
||||
import { useDropdownButton } from '@/ui/dropdown/hooks/useDropdownButton';
|
||||
|
||||
import { FilterDropdownKey } from '../types/FilterDropdownKey';
|
||||
import { FilterDropdownId } from '../constants/FilterDropdownId';
|
||||
|
||||
export function MultipleFiltersButton() {
|
||||
const { isDropdownButtonOpen, toggleDropdownButton } = useDropdownButton({
|
||||
key: FilterDropdownKey,
|
||||
dropdownId: FilterDropdownId,
|
||||
});
|
||||
|
||||
function handleClick() {
|
||||
|
||||
@ -1,24 +1,27 @@
|
||||
import { Context, useCallback } from 'react';
|
||||
import { Context, useCallback, useEffect } 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 { FilterDropdownKey } from '../types/FilterDropdownKey';
|
||||
|
||||
import { MultipleFiltersButton } from './MultipleFiltersButton';
|
||||
import { MultipleFiltersDropdownContent } from './MultipleFiltersDropdownContent';
|
||||
|
||||
type MultipleFiltersDropdownButtonProps = {
|
||||
context: Context<string | null>;
|
||||
hotkeyScope: string;
|
||||
hotkeyScope: HotkeyScope;
|
||||
};
|
||||
|
||||
export function MultipleFiltersDropdownButton({
|
||||
context,
|
||||
hotkeyScope,
|
||||
}: MultipleFiltersDropdownButtonProps) {
|
||||
const [, setIsFilterDropdownOperandSelectUnfolded] = useRecoilScopedState(
|
||||
isFilterDropdownOperandSelectUnfoldedScopedState,
|
||||
@ -40,6 +43,10 @@ export function MultipleFiltersDropdownButton({
|
||||
context,
|
||||
);
|
||||
|
||||
const { isDropdownButtonOpen } = useDropdownButton({
|
||||
dropdownId: FilterDropdownId,
|
||||
});
|
||||
|
||||
const resetState = useCallback(() => {
|
||||
setIsFilterDropdownOperandSelectUnfolded(false);
|
||||
setFilterDefinitionUsedInDropdown(null);
|
||||
@ -51,14 +58,19 @@ export function MultipleFiltersDropdownButton({
|
||||
setFilterDropdownSearchInput,
|
||||
setIsFilterDropdownOperandSelectUnfolded,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isDropdownButtonOpen) {
|
||||
resetState();
|
||||
}
|
||||
}, [isDropdownButtonOpen, resetState]);
|
||||
|
||||
return (
|
||||
<DropdownButton
|
||||
dropdownKey={FilterDropdownKey}
|
||||
dropdownId={FilterDropdownId}
|
||||
buttonComponents={<MultipleFiltersButton />}
|
||||
dropdownComponents={<MultipleFiltersDropdownContent context={context} />}
|
||||
onDropdownToggle={() => {
|
||||
resetState();
|
||||
}}
|
||||
dropdownHotkeyScope={hotkeyScope}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -39,6 +39,8 @@ export function MultipleFiltersDropdownContent({
|
||||
context,
|
||||
);
|
||||
|
||||
console.log('filterDefinitionUsedInDropdown', filterDefinitionUsedInDropdown);
|
||||
|
||||
return (
|
||||
<StyledDropdownMenu>
|
||||
<>
|
||||
|
||||
@ -6,6 +6,7 @@ import styled from '@emotion/styled';
|
||||
import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
||||
import { IconChevronDown } from '@/ui/icon';
|
||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||
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';
|
||||
@ -33,7 +34,7 @@ export function SingleEntityFilterDropdownButton({
|
||||
hotkeyScope,
|
||||
}: {
|
||||
context: Context<string | null>;
|
||||
hotkeyScope: string;
|
||||
hotkeyScope: HotkeyScope;
|
||||
}) {
|
||||
const theme = useTheme();
|
||||
|
||||
@ -80,10 +81,10 @@ export function SingleEntityFilterDropdownButton({
|
||||
|
||||
function handleIsUnfoldedChange(newIsUnfolded: boolean) {
|
||||
if (newIsUnfolded) {
|
||||
setHotkeyScope(hotkeyScope);
|
||||
setHotkeyScope(hotkeyScope.scope, hotkeyScope.customScopes);
|
||||
setIsFilterDropdownUnfolded(true);
|
||||
} else {
|
||||
setHotkeyScope(hotkeyScope);
|
||||
setHotkeyScope(hotkeyScope.scope, hotkeyScope.customScopes);
|
||||
setIsFilterDropdownUnfolded(false);
|
||||
setFilterDropdownSearchInput('');
|
||||
}
|
||||
|
||||
@ -1,120 +1,136 @@
|
||||
import { Context, useCallback, useState } from 'react';
|
||||
import { produce } from 'immer';
|
||||
|
||||
import { LightButton } from '@/ui/button/components/LightButton';
|
||||
import { DropdownButton } from '@/ui/dropdown/components/DropdownButton';
|
||||
import { DropdownMenuHeader } from '@/ui/dropdown/components/DropdownMenuHeader';
|
||||
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 } from '@/ui/icon';
|
||||
import { MenuItem } from '@/ui/menu-item/components/MenuItem';
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||
|
||||
import { SortDropdownId } from '../constants/SortDropdownId';
|
||||
import { availableSortsScopedState } from '../states/availableSortsScopedState';
|
||||
import { sortsScopedState } from '../states/sortsScopedState';
|
||||
import { FiltersHotkeyScope } from '../types/FiltersHotkeyScope';
|
||||
import { SelectedSortType, SortType } from '../types/interface';
|
||||
import { SortDefinition } from '../types/SortDefinition';
|
||||
import { SORT_DIRECTIONS, SortDirection } from '../types/SortDirection';
|
||||
|
||||
import DropdownButton from './DropdownButton';
|
||||
|
||||
export type SortDropdownButtonProps<SortField> = {
|
||||
availableSorts: SortType<SortField>[];
|
||||
hotkeyScope: FiltersHotkeyScope;
|
||||
export type SortDropdownButtonProps = {
|
||||
context: Context<string | null>;
|
||||
hotkeyScope: HotkeyScope;
|
||||
isPrimaryButton?: boolean;
|
||||
};
|
||||
|
||||
const options: Array<SelectedSortType<any>['order']> = ['asc', 'desc'];
|
||||
|
||||
export function SortDropdownButton<SortField>({
|
||||
context,
|
||||
availableSorts,
|
||||
export function SortDropdownButton({
|
||||
hotkeyScope,
|
||||
}: SortDropdownButtonProps<SortField>) {
|
||||
const [isUnfolded, setIsUnfolded] = useState(false);
|
||||
const [isOptionUnfolded, setIsOptionUnfolded] = useState(false);
|
||||
context,
|
||||
}: SortDropdownButtonProps) {
|
||||
const [isSortDirectionMenuUnfolded, setIsSortDirectionMenuUnfolded] =
|
||||
useState(false);
|
||||
|
||||
const [selectedSortDirection, setSelectedSortDirection] =
|
||||
useState<SelectedSortType<SortField>['order']>('asc');
|
||||
|
||||
const [sorts, setSorts] = useRecoilScopedState<SelectedSortType<SortField>[]>(
|
||||
sortsScopedState,
|
||||
context,
|
||||
);
|
||||
|
||||
const isSortSelected = sorts.length > 0;
|
||||
|
||||
const onSortItemSelect = useCallback(
|
||||
(sort: SortType<SortField>) => {
|
||||
const newSort = { ...sort, order: selectedSortDirection };
|
||||
const sortIndex = sorts.findIndex((sort) => sort.key === newSort.key);
|
||||
const newSorts = [...sorts];
|
||||
|
||||
if (sortIndex !== -1) {
|
||||
newSorts[sortIndex] = newSort;
|
||||
} else {
|
||||
newSorts.push(newSort);
|
||||
}
|
||||
|
||||
setSorts(newSorts);
|
||||
},
|
||||
[selectedSortDirection, setSorts, sorts],
|
||||
);
|
||||
useState<SortDirection>('asc');
|
||||
|
||||
const resetState = useCallback(() => {
|
||||
setIsOptionUnfolded(false);
|
||||
setIsSortDirectionMenuUnfolded(false);
|
||||
setSelectedSortDirection('asc');
|
||||
}, []);
|
||||
|
||||
function handleIsUnfoldedChange(newIsUnfolded: boolean) {
|
||||
setIsUnfolded(newIsUnfolded);
|
||||
if (!newIsUnfolded) resetState();
|
||||
const [availableSorts] = useRecoilScopedState(
|
||||
availableSortsScopedState,
|
||||
context,
|
||||
);
|
||||
|
||||
const [sorts, setSorts] = useRecoilScopedState(sortsScopedState, context);
|
||||
|
||||
const isSortSelected = sorts.length > 0;
|
||||
|
||||
const { toggleDropdownButton } = useDropdownButton({
|
||||
dropdownId: SortDropdownId,
|
||||
});
|
||||
|
||||
function handleButtonClick() {
|
||||
toggleDropdownButton();
|
||||
resetState();
|
||||
}
|
||||
|
||||
function handleAddSort(sort: SortType<SortField>) {
|
||||
setIsUnfolded(false);
|
||||
onSortItemSelect(sort);
|
||||
function handleAddSort(selectedSortDefinition: SortDefinition) {
|
||||
toggleDropdownButton();
|
||||
|
||||
setSorts(
|
||||
produce(sorts, (existingSortsDraft) => {
|
||||
const foundExistingSortIndex = existingSortsDraft.findIndex(
|
||||
(existingSort) => existingSort.key === selectedSortDefinition.key,
|
||||
);
|
||||
|
||||
if (foundExistingSortIndex !== -1) {
|
||||
existingSortsDraft[foundExistingSortIndex].direction =
|
||||
selectedSortDirection;
|
||||
} else {
|
||||
existingSortsDraft.push({
|
||||
key: selectedSortDefinition.key,
|
||||
direction: selectedSortDirection,
|
||||
definition: selectedSortDefinition,
|
||||
});
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<DropdownButton
|
||||
label="Sort"
|
||||
isActive={isSortSelected}
|
||||
isUnfolded={isUnfolded}
|
||||
onIsUnfoldedChange={handleIsUnfoldedChange}
|
||||
hotkeyScope={hotkeyScope}
|
||||
>
|
||||
{isOptionUnfolded ? (
|
||||
<StyledDropdownMenuItemsContainer>
|
||||
{options.map((option, index) => (
|
||||
<MenuItem
|
||||
key={index}
|
||||
onClick={() => {
|
||||
setSelectedSortDirection(option);
|
||||
setIsOptionUnfolded(false);
|
||||
}}
|
||||
text={option === 'asc' ? 'Ascending' : 'Descending'}
|
||||
/>
|
||||
))}
|
||||
</StyledDropdownMenuItemsContainer>
|
||||
) : (
|
||||
<>
|
||||
<DropdownMenuHeader
|
||||
EndIcon={IconChevronDown}
|
||||
onClick={() => setIsOptionUnfolded(true)}
|
||||
>
|
||||
{selectedSortDirection === 'asc' ? 'Ascending' : 'Descending'}
|
||||
</DropdownMenuHeader>
|
||||
<StyledDropdownMenuSeparator />
|
||||
|
||||
<StyledDropdownMenuItemsContainer>
|
||||
{availableSorts.map((sort, index) => (
|
||||
<MenuItem
|
||||
testId={`select-sort-${index}`}
|
||||
key={index}
|
||||
onClick={() => handleAddSort(sort)}
|
||||
LeftIcon={sort.Icon}
|
||||
text={sort.label}
|
||||
/>
|
||||
))}
|
||||
</StyledDropdownMenuItemsContainer>
|
||||
</>
|
||||
)}
|
||||
</DropdownButton>
|
||||
dropdownId={SortDropdownId}
|
||||
dropdownHotkeyScope={hotkeyScope}
|
||||
buttonComponents={
|
||||
<LightButton
|
||||
title="Sort"
|
||||
active={isSortSelected}
|
||||
onClick={handleButtonClick}
|
||||
/>
|
||||
}
|
||||
dropdownComponents={
|
||||
<StyledDropdownMenu>
|
||||
{isSortDirectionMenuUnfolded ? (
|
||||
<StyledDropdownMenuItemsContainer>
|
||||
{SORT_DIRECTIONS.map((sortOrder, index) => (
|
||||
<MenuItem
|
||||
key={index}
|
||||
onClick={() => {
|
||||
setSelectedSortDirection(sortOrder);
|
||||
setIsSortDirectionMenuUnfolded(false);
|
||||
}}
|
||||
text={sortOrder === 'asc' ? 'Ascending' : 'Descending'}
|
||||
/>
|
||||
))}
|
||||
</StyledDropdownMenuItemsContainer>
|
||||
) : (
|
||||
<>
|
||||
<DropdownMenuHeader
|
||||
EndIcon={IconChevronDown}
|
||||
onClick={() => setIsSortDirectionMenuUnfolded(true)}
|
||||
>
|
||||
{selectedSortDirection === 'asc' ? 'Ascending' : 'Descending'}
|
||||
</DropdownMenuHeader>
|
||||
<StyledDropdownMenuSeparator />
|
||||
<StyledDropdownMenuItemsContainer>
|
||||
{availableSorts.map((availableSort, index) => (
|
||||
<MenuItem
|
||||
testId={`select-sort-${index}`}
|
||||
key={index}
|
||||
onClick={() => handleAddSort(availableSort)}
|
||||
LeftIcon={availableSort.Icon}
|
||||
text={availableSort.label}
|
||||
/>
|
||||
))}
|
||||
</StyledDropdownMenuItemsContainer>
|
||||
</>
|
||||
)}
|
||||
</StyledDropdownMenu>
|
||||
}
|
||||
></DropdownButton>
|
||||
);
|
||||
}
|
||||
|
||||
@ -7,10 +7,7 @@ import { FiltersHotkeyScope } from '../types/FiltersHotkeyScope';
|
||||
import { ViewsHotkeyScope } from '../types/ViewsHotkeyScope';
|
||||
|
||||
import { FilterDropdownButton } from './FilterDropdownButton';
|
||||
import {
|
||||
SortDropdownButton,
|
||||
type SortDropdownButtonProps,
|
||||
} from './SortDropdownButton';
|
||||
import { SortDropdownButton } from './SortDropdownButton';
|
||||
import {
|
||||
UpdateViewButtonGroup,
|
||||
type UpdateViewButtonGroupProps,
|
||||
@ -21,7 +18,7 @@ import {
|
||||
type ViewsDropdownButtonProps,
|
||||
} from './ViewsDropdownButton';
|
||||
|
||||
export type ViewBarProps<SortField> = ComponentProps<'div'> & {
|
||||
export type ViewBarProps = ComponentProps<'div'> & {
|
||||
optionsDropdownButton: ReactNode;
|
||||
optionsDropdownKey: string;
|
||||
scopeContext: Context<string | null>;
|
||||
@ -29,12 +26,10 @@ export type ViewBarProps<SortField> = ComponentProps<'div'> & {
|
||||
ViewsDropdownButtonProps,
|
||||
'defaultViewName' | 'onViewsChange' | 'onViewSelect'
|
||||
> &
|
||||
Pick<SortDropdownButtonProps<SortField>, 'availableSorts'> &
|
||||
Pick<ViewBarDetailsProps, 'canPersistViewFields' | 'onReset'> &
|
||||
Pick<UpdateViewButtonGroupProps, 'onViewSubmit'>;
|
||||
|
||||
export const ViewBar = <SortField,>({
|
||||
availableSorts,
|
||||
export const ViewBar = ({
|
||||
canPersistViewFields,
|
||||
defaultViewName,
|
||||
onReset,
|
||||
@ -45,9 +40,9 @@ export const ViewBar = <SortField,>({
|
||||
optionsDropdownKey,
|
||||
scopeContext,
|
||||
...props
|
||||
}: ViewBarProps<SortField>) => {
|
||||
}: ViewBarProps) => {
|
||||
const { openDropdownButton: openOptionsDropdownButton } = useDropdownButton({
|
||||
key: optionsDropdownKey,
|
||||
dropdownId: optionsDropdownKey,
|
||||
});
|
||||
|
||||
return (
|
||||
@ -67,13 +62,12 @@ export const ViewBar = <SortField,>({
|
||||
rightComponent={
|
||||
<>
|
||||
<FilterDropdownButton
|
||||
hotkeyScope={{ scope: FiltersHotkeyScope.FilterDropdownButton }}
|
||||
context={scopeContext}
|
||||
hotkeyScope={FiltersHotkeyScope.FilterDropdownButton}
|
||||
/>
|
||||
<SortDropdownButton<SortField>
|
||||
<SortDropdownButton
|
||||
context={scopeContext}
|
||||
availableSorts={availableSorts}
|
||||
hotkeyScope={FiltersHotkeyScope.FilterDropdownButton}
|
||||
hotkeyScope={{ scope: FiltersHotkeyScope.FilterDropdownButton }}
|
||||
isPrimaryButton
|
||||
/>
|
||||
{optionsDropdownButton}
|
||||
|
||||
@ -15,7 +15,6 @@ import { isViewBarExpandedScopedState } from '../states/isViewBarExpandedScopedS
|
||||
import { canPersistFiltersScopedFamilySelector } from '../states/selectors/canPersistFiltersScopedFamilySelector';
|
||||
import { canPersistSortsScopedFamilySelector } from '../states/selectors/canPersistSortsScopedFamilySelector';
|
||||
import { sortsScopedState } from '../states/sortsScopedState';
|
||||
import { SelectedSortType } from '../types/interface';
|
||||
import { getOperandLabelShort } from '../utils/getOperandLabel';
|
||||
|
||||
import { AddFilterFromDropdownButton } from './AddFilterFromDetailsButton';
|
||||
@ -97,7 +96,7 @@ const StyledAddFilterContainer = styled.div`
|
||||
z-index: 5;
|
||||
`;
|
||||
|
||||
function ViewBarDetails<SortField>({
|
||||
function ViewBarDetails({
|
||||
canPersistViewFields,
|
||||
context,
|
||||
hasFilterButton = false,
|
||||
@ -120,10 +119,8 @@ function ViewBarDetails<SortField>({
|
||||
canPersistFiltersScopedFamilySelector([recoilScopeId, currentViewId]),
|
||||
);
|
||||
|
||||
const [sorts, setSorts] = useRecoilScopedState<SelectedSortType<SortField>[]>(
|
||||
sortsScopedState,
|
||||
context,
|
||||
);
|
||||
const [sorts, setSorts] = useRecoilScopedState(sortsScopedState, context);
|
||||
|
||||
const canPersistSorts = useRecoilValue(
|
||||
canPersistSortsScopedFamilySelector([recoilScopeId, currentViewId]),
|
||||
);
|
||||
@ -177,9 +174,9 @@ function ViewBarDetails<SortField>({
|
||||
<SortOrFilterChip
|
||||
key={sort.key}
|
||||
testId={sort.key}
|
||||
labelValue={sort.label}
|
||||
labelValue={sort.definition.label}
|
||||
Icon={
|
||||
sort.order === 'desc'
|
||||
sort.direction === 'desc'
|
||||
? IconArrowNarrowDown
|
||||
: IconArrowNarrowUp
|
||||
}
|
||||
|
||||
@ -0,0 +1 @@
|
||||
export const FilterDropdownId = 'filter';
|
||||
@ -0,0 +1 @@
|
||||
export const SortDropdownId = 'sort-dropdown';
|
||||
@ -1,17 +0,0 @@
|
||||
import { SortOrder as Order_By } from '~/generated/graphql';
|
||||
|
||||
import { SelectedSortType } from './types/interface';
|
||||
|
||||
export const reduceSortsToOrderBy = <OrderByTemplate>(
|
||||
sorts: SelectedSortType<OrderByTemplate>[],
|
||||
): OrderByTemplate[] =>
|
||||
sorts
|
||||
.map((sort) => {
|
||||
const order = sort.order === 'asc' ? Order_By.Asc : Order_By.Desc;
|
||||
return (
|
||||
sort.orderByTemplate?.(order) || [
|
||||
{ [sort.key]: order } as OrderByTemplate,
|
||||
]
|
||||
);
|
||||
})
|
||||
.flat();
|
||||
@ -0,0 +1,8 @@
|
||||
import { atomFamily } from 'recoil';
|
||||
|
||||
import { SortDefinition } from '../types/SortDefinition';
|
||||
|
||||
export const availableSortsScopedState = atomFamily<SortDefinition[], string>({
|
||||
key: 'availableSortsScopedState',
|
||||
default: [],
|
||||
});
|
||||
@ -1,11 +1,8 @@
|
||||
import { atomFamily } from 'recoil';
|
||||
|
||||
import type { SelectedSortType } from '../types/interface';
|
||||
import { Sort } from '../types/Sort';
|
||||
|
||||
export const savedSortsFamilyState = atomFamily<
|
||||
SelectedSortType<any>[],
|
||||
string | undefined
|
||||
>({
|
||||
export const savedSortsFamilyState = atomFamily<Sort[], string | undefined>({
|
||||
key: 'savedSortsFamilyState',
|
||||
default: [],
|
||||
});
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { selectorFamily } from 'recoil';
|
||||
|
||||
import type { SelectedSortType } from '../../types/interface';
|
||||
import { Sort } from '../../types/Sort';
|
||||
import { savedSortsFamilyState } from '../savedSortsFamilyState';
|
||||
|
||||
export const savedSortsByKeyFamilySelector = selectorFamily({
|
||||
@ -8,7 +8,8 @@ export const savedSortsByKeyFamilySelector = selectorFamily({
|
||||
get:
|
||||
(viewId: string | undefined) =>
|
||||
({ get }) =>
|
||||
get(savedSortsFamilyState(viewId)).reduce<
|
||||
Record<string, SelectedSortType<any>>
|
||||
>((result, sort) => ({ ...result, [sort.key]: sort }), {}),
|
||||
get(savedSortsFamilyState(viewId)).reduce<Record<string, Sort>>(
|
||||
(result, sort) => ({ ...result, [sort.key]: sort }),
|
||||
{},
|
||||
),
|
||||
});
|
||||
|
||||
@ -2,7 +2,7 @@ import { selectorFamily } from 'recoil';
|
||||
|
||||
import { SortOrder } from '~/generated/graphql';
|
||||
|
||||
import { reduceSortsToOrderBy } from '../../helpers';
|
||||
import { reduceSortsToOrderBy } from '../../utils/helpers';
|
||||
import { sortsScopedState } from '../sortsScopedState';
|
||||
|
||||
export const sortsOrderByScopedSelector = selectorFamily({
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { atomFamily } from 'recoil';
|
||||
|
||||
import type { SelectedSortType } from '../types/interface';
|
||||
import { Sort } from '../types/Sort';
|
||||
|
||||
export const sortsScopedState = atomFamily<SelectedSortType<any>[], string>({
|
||||
export const sortsScopedState = atomFamily<Sort[], string>({
|
||||
key: 'sortsScopedState',
|
||||
default: [],
|
||||
});
|
||||
|
||||
@ -1 +0,0 @@
|
||||
export const FilterDropdownKey = 'filter';
|
||||
8
front/src/modules/ui/view-bar/types/Sort.ts
Normal file
8
front/src/modules/ui/view-bar/types/Sort.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { SortDefinition } from './SortDefinition';
|
||||
import { SortDirection } from './SortDirection';
|
||||
|
||||
export type Sort = {
|
||||
key: string;
|
||||
direction: SortDirection;
|
||||
definition: SortDefinition;
|
||||
};
|
||||
10
front/src/modules/ui/view-bar/types/SortDefinition.ts
Normal file
10
front/src/modules/ui/view-bar/types/SortDefinition.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { IconComponent } from '@/ui/icon/types/IconComponent';
|
||||
|
||||
import { SortDirection } from './SortDirection';
|
||||
|
||||
export type SortDefinition = {
|
||||
key: string;
|
||||
label: string;
|
||||
Icon?: IconComponent;
|
||||
getOrderByTemplate?: (direction: SortDirection) => any[];
|
||||
};
|
||||
3
front/src/modules/ui/view-bar/types/SortDirection.ts
Normal file
3
front/src/modules/ui/view-bar/types/SortDirection.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export const SORT_DIRECTIONS = ['asc', 'desc'] as const;
|
||||
|
||||
export type SortDirection = (typeof SORT_DIRECTIONS)[number];
|
||||
16
front/src/modules/ui/view-bar/utils/helpers.ts
Normal file
16
front/src/modules/ui/view-bar/utils/helpers.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { SortOrder as Order_By } from '~/generated/graphql';
|
||||
|
||||
import { Sort } from '../types/Sort';
|
||||
|
||||
export const reduceSortsToOrderBy = (sorts: Sort[]): any[] =>
|
||||
sorts
|
||||
.map((sort) => {
|
||||
const direction = sort.direction === 'asc' ? Order_By.Asc : Order_By.Desc;
|
||||
|
||||
if (sort.definition.getOrderByTemplate) {
|
||||
return sort.definition.getOrderByTemplate(direction);
|
||||
} else {
|
||||
return [{ [sort.definition.key]: direction }];
|
||||
}
|
||||
})
|
||||
.flat();
|
||||
Reference in New Issue
Block a user