feat: add Opportunities Views dropdown (#1503)
* feat: add Opportunities Views dropdown Closes #1454 * feat: persist Opportunities view filters and sorts Closes #1456 * feat: create/edit/delete Opportunities views Closes #1455, Closes #1457 * fix: add missing Opportunities view mock --------- Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
import { useRef, useState } from 'react';
|
||||
import { type Context, useRef, useState } from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { Key } from 'ts-key-enum';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
@ -22,14 +22,21 @@ import { MenuItemNavigate } from '@/ui/menu-item/components/MenuItemNavigate';
|
||||
import { ThemeColor } from '@/ui/theme/constants/colors';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||
import { useUpsertView } from '@/ui/view-bar/hooks/useUpsertView';
|
||||
import { viewsByIdScopedSelector } from '@/ui/view-bar/states/selectors/viewsByIdScopedSelector';
|
||||
import { viewEditModeState } from '@/ui/view-bar/states/viewEditModeState';
|
||||
import type { View } from '@/ui/view-bar/types/View';
|
||||
|
||||
import { boardColumnsState } from '../states/boardColumnsState';
|
||||
import type { BoardColumnDefinition } from '../types/BoardColumnDefinition';
|
||||
import { BoardOptionsDropdownKey } from '../types/BoardOptionsDropdownKey';
|
||||
|
||||
type BoardOptionsDropdownContentProps = {
|
||||
export type BoardOptionsDropdownContentProps = {
|
||||
customHotkeyScope: HotkeyScope;
|
||||
onStageAdd?: (boardColumn: BoardColumnDefinition) => void;
|
||||
onViewsChange?: (views: View[]) => void | Promise<void>;
|
||||
scopeContext: Context<string | null>;
|
||||
};
|
||||
|
||||
const StyledIconSettings = styled(IconSettings)`
|
||||
@ -51,10 +58,13 @@ type ColumnForCreate = {
|
||||
export function BoardOptionsDropdownContent({
|
||||
customHotkeyScope,
|
||||
onStageAdd,
|
||||
onViewsChange,
|
||||
scopeContext,
|
||||
}: BoardOptionsDropdownContentProps) {
|
||||
const theme = useTheme();
|
||||
|
||||
const stageInputRef = useRef<HTMLInputElement>(null);
|
||||
const viewEditInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const [currentMenu, setCurrentMenu] = useState<
|
||||
BoardOptionsMenu | undefined
|
||||
@ -62,7 +72,8 @@ export function BoardOptionsDropdownContent({
|
||||
|
||||
const [boardColumns, setBoardColumns] = useRecoilState(boardColumnsState);
|
||||
|
||||
const resetMenu = () => setCurrentMenu(undefined);
|
||||
const viewsById = useRecoilScopedValue(viewsByIdScopedSelector, scopeContext);
|
||||
const viewEditMode = useRecoilValue(viewEditModeState);
|
||||
|
||||
const handleStageSubmit = () => {
|
||||
if (
|
||||
@ -85,6 +96,23 @@ export function BoardOptionsDropdownContent({
|
||||
onStageAdd?.(columnToCreate);
|
||||
};
|
||||
|
||||
const { upsertView } = useUpsertView({
|
||||
onViewsChange,
|
||||
scopeContext,
|
||||
});
|
||||
|
||||
const handleViewNameSubmit = async () => {
|
||||
const name = viewEditInputRef.current?.value;
|
||||
await upsertView(name);
|
||||
};
|
||||
|
||||
const resetMenu = () => setCurrentMenu(undefined);
|
||||
|
||||
const handleMenuNavigate = (menu: BoardOptionsMenu) => {
|
||||
handleViewNameSubmit();
|
||||
setCurrentMenu(menu);
|
||||
};
|
||||
|
||||
const { closeDropdownButton } = useDropdownButton({
|
||||
key: BoardOptionsDropdownKey,
|
||||
});
|
||||
@ -101,6 +129,7 @@ export function BoardOptionsDropdownContent({
|
||||
Key.Enter,
|
||||
() => {
|
||||
handleStageSubmit();
|
||||
handleViewNameSubmit();
|
||||
closeDropdownButton();
|
||||
},
|
||||
customHotkeyScope.scope,
|
||||
@ -110,14 +139,29 @@ export function BoardOptionsDropdownContent({
|
||||
<StyledDropdownMenu>
|
||||
{!currentMenu && (
|
||||
<>
|
||||
<DropdownMenuHeader>
|
||||
<StyledIconSettings size={theme.icon.size.md} />
|
||||
Settings
|
||||
</DropdownMenuHeader>
|
||||
{!!viewEditMode.mode ? (
|
||||
<DropdownMenuInput
|
||||
ref={viewEditInputRef}
|
||||
autoFocus
|
||||
placeholder={
|
||||
viewEditMode.mode === 'create' ? 'New view' : 'View name'
|
||||
}
|
||||
defaultValue={
|
||||
viewEditMode.viewId
|
||||
? viewsById[viewEditMode.viewId]?.name
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<DropdownMenuHeader>
|
||||
<StyledIconSettings size={theme.icon.size.md} />
|
||||
Settings
|
||||
</DropdownMenuHeader>
|
||||
)}
|
||||
<StyledDropdownMenuSeparator />
|
||||
<StyledDropdownMenuItemsContainer>
|
||||
<MenuItemNavigate
|
||||
onClick={() => setCurrentMenu(BoardOptionsMenu.Stages)}
|
||||
onClick={() => handleMenuNavigate(BoardOptionsMenu.Stages)}
|
||||
LeftIcon={IconLayoutKanban}
|
||||
text="Stages"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user