180 lines
5.6 KiB
TypeScript
180 lines
5.6 KiB
TypeScript
import { type MouseEvent, useCallback, useEffect, useState } from 'react';
|
|
import { useTheme } from '@emotion/react';
|
|
import styled from '@emotion/styled';
|
|
import { useSetRecoilState } from 'recoil';
|
|
|
|
import { IconButton } from '@/ui/button/components/IconButton';
|
|
import { DropdownMenuItem } from '@/ui/dropdown/components/DropdownMenuItem';
|
|
import { DropdownMenuItemsContainer } from '@/ui/dropdown/components/DropdownMenuItemsContainer';
|
|
import { DropdownMenuSeparator } from '@/ui/dropdown/components/DropdownMenuSeparator';
|
|
import DropdownButton from '@/ui/filter-n-sort/components/DropdownButton';
|
|
import {
|
|
IconChevronDown,
|
|
IconList,
|
|
IconPencil,
|
|
IconPlus,
|
|
IconTrash,
|
|
} from '@/ui/icon';
|
|
import {
|
|
currentTableViewIdState,
|
|
currentTableViewState,
|
|
type TableView,
|
|
tableViewEditModeState,
|
|
tableViewsState,
|
|
} from '@/ui/table/states/tableViewsState';
|
|
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
|
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
|
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
|
|
|
import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext';
|
|
import { TableViewsHotkeyScope } from '../../types/TableViewsHotkeyScope';
|
|
|
|
const StyledDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)`
|
|
font-weight: ${({ theme }) => theme.font.weight.regular};
|
|
`;
|
|
|
|
const StyledDropdownLabelAdornments = styled.span`
|
|
align-items: center;
|
|
color: ${({ theme }) => theme.grayScale.gray35};
|
|
display: inline-flex;
|
|
gap: ${({ theme }) => theme.spacing(1)};
|
|
margin-left: ${({ theme }) => theme.spacing(1)};
|
|
`;
|
|
|
|
const StyledViewIcon = styled(IconList)`
|
|
margin-right: ${({ theme }) => theme.spacing(1)};
|
|
`;
|
|
|
|
type TableViewsDropdownButtonProps = {
|
|
defaultViewName: string;
|
|
HotkeyScope: TableViewsHotkeyScope;
|
|
onViewsChange?: (views: TableView[]) => void;
|
|
};
|
|
|
|
export const TableViewsDropdownButton = ({
|
|
defaultViewName,
|
|
HotkeyScope,
|
|
onViewsChange,
|
|
}: TableViewsDropdownButtonProps) => {
|
|
const theme = useTheme();
|
|
const [isUnfolded, setIsUnfolded] = useState(false);
|
|
|
|
const currentView = useRecoilScopedValue(
|
|
currentTableViewState,
|
|
TableRecoilScopeContext,
|
|
);
|
|
const [views, setViews] = useRecoilScopedState(
|
|
tableViewsState,
|
|
TableRecoilScopeContext,
|
|
);
|
|
const [, setCurrentViewId] = useRecoilScopedState(
|
|
currentTableViewIdState,
|
|
TableRecoilScopeContext,
|
|
);
|
|
const setViewEditMode = useSetRecoilState(tableViewEditModeState);
|
|
|
|
const {
|
|
goBackToPreviousHotkeyScope,
|
|
setHotkeyScopeAndMemorizePreviousScope,
|
|
} = usePreviousHotkeyScope();
|
|
|
|
const handleViewSelect = useCallback(
|
|
(viewId?: string) => {
|
|
setCurrentViewId(viewId);
|
|
setIsUnfolded(false);
|
|
},
|
|
[setCurrentViewId],
|
|
);
|
|
|
|
const handleAddViewButtonClick = useCallback(() => {
|
|
setViewEditMode({ mode: 'create', viewId: undefined });
|
|
setIsUnfolded(false);
|
|
}, [setViewEditMode]);
|
|
|
|
const handleEditViewButtonClick = useCallback(
|
|
(event: MouseEvent<HTMLButtonElement>, viewId: string) => {
|
|
event.stopPropagation();
|
|
setViewEditMode({ mode: 'edit', viewId });
|
|
setIsUnfolded(false);
|
|
},
|
|
[setViewEditMode],
|
|
);
|
|
|
|
const handleDeleteViewButtonClick = useCallback(
|
|
(event: MouseEvent<HTMLButtonElement>, viewId: string) => {
|
|
event.stopPropagation();
|
|
|
|
if (currentView?.id === viewId) setCurrentViewId(undefined);
|
|
|
|
(onViewsChange ?? setViews)(views.filter((view) => view.id !== viewId));
|
|
setIsUnfolded(false);
|
|
},
|
|
[currentView?.id, onViewsChange, setCurrentViewId, setViews, views],
|
|
);
|
|
|
|
useEffect(() => {
|
|
isUnfolded
|
|
? setHotkeyScopeAndMemorizePreviousScope(HotkeyScope)
|
|
: goBackToPreviousHotkeyScope();
|
|
}, [
|
|
HotkeyScope,
|
|
goBackToPreviousHotkeyScope,
|
|
isUnfolded,
|
|
setHotkeyScopeAndMemorizePreviousScope,
|
|
]);
|
|
|
|
return (
|
|
<DropdownButton
|
|
label={
|
|
<>
|
|
<StyledViewIcon size={theme.icon.size.md} />
|
|
{currentView?.name || defaultViewName}{' '}
|
|
<StyledDropdownLabelAdornments>
|
|
· {views.length + 1} <IconChevronDown size={theme.icon.size.sm} />
|
|
</StyledDropdownLabelAdornments>
|
|
</>
|
|
}
|
|
isActive={false}
|
|
isUnfolded={isUnfolded}
|
|
onIsUnfoldedChange={setIsUnfolded}
|
|
anchor="left"
|
|
HotkeyScope={HotkeyScope}
|
|
>
|
|
<StyledDropdownMenuItemsContainer>
|
|
<DropdownMenuItem onClick={() => handleViewSelect(undefined)}>
|
|
<IconList size={theme.icon.size.md} />
|
|
{defaultViewName}
|
|
</DropdownMenuItem>
|
|
{views.map((view) => (
|
|
<DropdownMenuItem
|
|
key={view.id}
|
|
actions={[
|
|
<IconButton
|
|
key="edit"
|
|
onClick={(event) => handleEditViewButtonClick(event, view.id)}
|
|
icon={<IconPencil size={theme.icon.size.sm} />}
|
|
/>,
|
|
<IconButton
|
|
key="delete"
|
|
onClick={(event) => handleDeleteViewButtonClick(event, view.id)}
|
|
icon={<IconTrash size={theme.icon.size.sm} />}
|
|
/>,
|
|
]}
|
|
onClick={() => handleViewSelect(view.id)}
|
|
>
|
|
<IconList size={theme.icon.size.md} />
|
|
{view.name}
|
|
</DropdownMenuItem>
|
|
))}
|
|
</StyledDropdownMenuItemsContainer>
|
|
<DropdownMenuSeparator />
|
|
<StyledDropdownMenuItemsContainer>
|
|
<DropdownMenuItem onClick={handleAddViewButtonClick}>
|
|
<IconPlus size={theme.icon.size.md} />
|
|
Add view
|
|
</DropdownMenuItem>
|
|
</StyledDropdownMenuItemsContainer>
|
|
</DropdownButton>
|
|
);
|
|
};
|