Refactor action bar entries and context menu entries (#1608)

- refactored actionbar entries / context menu entries
This commit is contained in:
brendanlaschke
2023-09-15 18:51:02 +03:00
committed by GitHub
parent 955deaf878
commit 85a6d0aa12
16 changed files with 141 additions and 117 deletions

View File

@ -2,7 +2,6 @@ import { useSetRecoilState } from 'recoil';
import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds'; import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds';
import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity'; import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity';
import { ActionBarEntry } from '@/ui/action-bar/components/ActionBarEntry';
import { actionBarEntriesState } from '@/ui/action-bar/states/actionBarEntriesState'; import { actionBarEntriesState } from '@/ui/action-bar/states/actionBarEntriesState';
import { IconCheckbox, IconNotes, IconTrash } from '@/ui/icon'; import { IconCheckbox, IconNotes, IconTrash } from '@/ui/icon';
import { ActivityType } from '~/generated/graphql'; import { ActivityType } from '~/generated/graphql';
@ -23,25 +22,22 @@ export function useCompanyTableActionBarEntries() {
return { return {
setActionBarEntries: () => setActionBarEntries: () =>
setActionBarEntries([ setActionBarEntries([
<ActionBarEntry {
label="Note" label: 'Note',
Icon={IconNotes} Icon: IconNotes,
onClick={() => handleActivityClick(ActivityType.Note)} onClick: () => handleActivityClick(ActivityType.Note),
key="note" },
/>, {
<ActionBarEntry label: 'Task',
label="Task" Icon: IconCheckbox,
Icon={IconCheckbox} onClick: () => handleActivityClick(ActivityType.Task),
onClick={() => handleActivityClick(ActivityType.Task)} },
key="task" {
/>, label: 'Delete',
<ActionBarEntry Icon: IconTrash,
label="Delete" accent: 'danger',
Icon={IconTrash} onClick: () => deleteSelectedCompanies(),
type="danger" },
onClick={() => deleteSelectedCompanies()}
key="delete"
/>,
]), ]),
}; };
} }

View File

@ -2,7 +2,6 @@ import { useSetRecoilState } from 'recoil';
import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds'; import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds';
import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity'; import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity';
import { ContextMenuEntry } from '@/ui/context-menu/components/ContextMenuEntry';
import { contextMenuEntriesState } from '@/ui/context-menu/states/contextMenuEntriesState'; import { contextMenuEntriesState } from '@/ui/context-menu/states/contextMenuEntriesState';
import { IconCheckbox, IconNotes, IconTrash } from '@/ui/icon'; import { IconCheckbox, IconNotes, IconTrash } from '@/ui/icon';
import { ActivityType } from '~/generated/graphql'; import { ActivityType } from '~/generated/graphql';
@ -24,25 +23,22 @@ export function useCompanyTableContextMenuEntries() {
return { return {
setContextMenuEntries: () => setContextMenuEntries: () =>
setContextMenuEntries([ setContextMenuEntries([
<ContextMenuEntry {
label="Note" label: 'Note',
Icon={IconNotes} Icon: IconNotes,
onClick={() => handleButtonClick(ActivityType.Note)} onClick: () => handleButtonClick(ActivityType.Note),
key="note" },
/>, {
<ContextMenuEntry label: 'Task',
label="Task" Icon: IconCheckbox,
Icon={IconCheckbox} onClick: () => handleButtonClick(ActivityType.Task),
onClick={() => handleButtonClick(ActivityType.Task)} },
key="task" {
/>, label: 'Delete',
<ContextMenuEntry Icon: IconTrash,
label="Delete" accent: 'danger',
Icon={IconTrash} onClick: () => deleteSelectedCompanies(),
accent="danger" },
onClick={() => deleteSelectedCompanies()}
key="delete"
/>,
]), ]),
}; };
} }

View File

@ -3,7 +3,6 @@ import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds'; import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds';
import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity'; import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity';
import { ContextMenuEntry } from '@/ui/context-menu/components/ContextMenuEntry';
import { contextMenuEntriesState } from '@/ui/context-menu/states/contextMenuEntriesState'; import { contextMenuEntriesState } from '@/ui/context-menu/states/contextMenuEntriesState';
import { IconCheckbox, IconNotes, IconTrash } from '@/ui/icon'; import { IconCheckbox, IconNotes, IconTrash } from '@/ui/icon';
import { useResetTableRowSelection } from '@/ui/table/hooks/useResetTableRowSelection'; import { useResetTableRowSelection } from '@/ui/table/hooks/useResetTableRowSelection';
@ -58,25 +57,22 @@ export function usePersonTableContextMenuEntries() {
return { return {
setContextMenuEntries: () => setContextMenuEntries: () =>
setContextMenuEntries([ setContextMenuEntries([
<ContextMenuEntry {
label="Note" label: 'Note',
Icon={IconNotes} Icon: IconNotes,
onClick={() => handleActivityClick(ActivityType.Note)} onClick: () => handleActivityClick(ActivityType.Note),
key="note" },
/>, {
<ContextMenuEntry label: 'Task',
label="Task" Icon: IconCheckbox,
Icon={IconCheckbox} onClick: () => handleActivityClick(ActivityType.Task),
onClick={() => handleActivityClick(ActivityType.Task)} },
key="task" {
/>, label: 'Delete',
<ContextMenuEntry Icon: IconTrash,
label="Delete" accent: 'danger',
Icon={IconTrash} onClick: () => handleDeleteClick(),
accent="danger" },
onClick={handleDeleteClick}
key="delete"
/>,
]), ]),
}; };
} }

View File

@ -3,7 +3,6 @@ import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds'; import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds';
import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity'; import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity';
import { ActionBarEntry } from '@/ui/action-bar/components/ActionBarEntry';
import { actionBarEntriesState } from '@/ui/action-bar/states/actionBarEntriesState'; import { actionBarEntriesState } from '@/ui/action-bar/states/actionBarEntriesState';
import { IconCheckbox, IconNotes, IconTrash } from '@/ui/icon'; import { IconCheckbox, IconNotes, IconTrash } from '@/ui/icon';
import { useResetTableRowSelection } from '@/ui/table/hooks/useResetTableRowSelection'; import { useResetTableRowSelection } from '@/ui/table/hooks/useResetTableRowSelection';
@ -62,25 +61,22 @@ export function usePersonTableActionBarEntries() {
return { return {
setActionBarEntries: () => setActionBarEntries: () =>
setActionBarEntries([ setActionBarEntries([
<ActionBarEntry {
label="Note" label: 'Note',
Icon={IconNotes} Icon: IconNotes,
onClick={() => handleActivityClick(ActivityType.Note)} onClick: () => handleActivityClick(ActivityType.Note),
key="note" },
/>, {
<ActionBarEntry label: 'Task',
label="Task" Icon: IconCheckbox,
Icon={IconCheckbox} onClick: () => handleActivityClick(ActivityType.Task),
onClick={() => handleActivityClick(ActivityType.Task)} },
key="task" {
/>, label: 'Delete',
<ActionBarEntry Icon: IconTrash,
label="Delete" accent: 'danger',
Icon={IconTrash} onClick: () => handleDeleteClick(),
type="danger" },
onClick={handleDeleteClick}
key="delete"
/>,
]), ]),
}; };
} }

View File

@ -7,6 +7,8 @@ import { contextMenuIsOpenState } from '@/ui/context-menu/states/contextMenuIsOp
import { actionBarOpenState } from '../states/actionBarIsOpenState'; import { actionBarOpenState } from '../states/actionBarIsOpenState';
import { ActionBarItem } from './ActionBarItem';
type OwnProps = { type OwnProps = {
selectedIds: string[]; selectedIds: string[];
}; };
@ -42,7 +44,15 @@ export function ActionBar({ selectedIds }: OwnProps) {
} }
return ( return (
<StyledContainerActionBar className="action-bar" ref={wrapperRef}> <StyledContainerActionBar className="action-bar" ref={wrapperRef}>
{actionBarEntries} {actionBarEntries.map((item) => (
<ActionBarItem
Icon={item.Icon}
accent={item.accent}
label={item.label}
onClick={item.onClick}
key={item.label}
/>
))}
</StyledContainerActionBar> </StyledContainerActionBar>
); );
} }

View File

@ -3,21 +3,19 @@ import styled from '@emotion/styled';
import { IconComponent } from '@/ui/icon/types/IconComponent'; import { IconComponent } from '@/ui/icon/types/IconComponent';
import { ActionBarItemAccent } from '../types/ActionBarItemAccent';
type OwnProps = { type OwnProps = {
Icon: IconComponent; Icon: IconComponent;
label: string; label: string;
type?: 'standard' | 'danger'; accent?: ActionBarItemAccent;
onClick: () => void; onClick: () => void;
}; };
type StyledButtonProps = { const StyledButton = styled.div<{ accent: ActionBarItemAccent }>`
type: 'standard' | 'danger';
};
const StyledButton = styled.div<StyledButtonProps>`
border-radius: ${({ theme }) => theme.border.radius.sm}; border-radius: ${({ theme }) => theme.border.radius.sm};
color: ${(props) => color: ${(props) =>
props.type === 'danger' props.accent === 'danger'
? props.theme.color.red ? props.theme.color.red
: props.theme.font.color.secondary}; : props.theme.font.color.secondary};
cursor: pointer; cursor: pointer;
@ -29,8 +27,10 @@ const StyledButton = styled.div<StyledButtonProps>`
user-select: none; user-select: none;
&:hover { &:hover {
background: ${({ theme, type }) => background: ${({ theme, accent }) =>
type === 'danger' ? theme.tag.background.red : theme.background.tertiary}; accent === 'danger'
? theme.tag.background.red
: theme.background.tertiary};
} }
`; `;
@ -39,15 +39,15 @@ const StyledButtonLabel = styled.div`
margin-left: ${({ theme }) => theme.spacing(2)}; margin-left: ${({ theme }) => theme.spacing(2)};
`; `;
export function ActionBarEntry({ export function ActionBarItem({
label, label,
Icon, Icon,
type = 'standard', accent = 'standard',
onClick, onClick,
}: OwnProps) { }: OwnProps) {
const theme = useTheme(); const theme = useTheme();
return ( return (
<StyledButton type={type} onClick={onClick}> <StyledButton accent={accent} onClick={onClick}>
{Icon && <Icon size={theme.icon.size.md} />} {Icon && <Icon size={theme.icon.size.md} />}
<StyledButtonLabel>{label}</StyledButtonLabel> <StyledButtonLabel>{label}</StyledButtonLabel>
</StyledButton> </StyledButton>

View File

@ -1,7 +1,8 @@
import { ReactElement } from 'react';
import { atom } from 'recoil'; import { atom } from 'recoil';
export const actionBarEntriesState = atom<ReactElement[]>({ import { ActionBarEntry } from '../types/ActionBarEntry';
export const actionBarEntriesState = atom<ActionBarEntry[]>({
key: 'actionBarEntriesState', key: 'actionBarEntriesState',
default: [], default: [],
}); });

View File

@ -0,0 +1,10 @@
import { IconComponent } from '@/ui/icon/types/IconComponent';
import { ActionBarItemAccent } from './ActionBarItemAccent';
export type ActionBarEntry = {
label: string;
Icon: IconComponent;
accent?: ActionBarItemAccent;
onClick: () => void;
};

View File

@ -0,0 +1 @@
export type ActionBarItemAccent = 'standard' | 'danger';

View File

@ -1,6 +1,5 @@
import { useSetRecoilState } from 'recoil'; import { useSetRecoilState } from 'recoil';
import { ActionBarEntry } from '@/ui/action-bar/components/ActionBarEntry';
import { actionBarEntriesState } from '@/ui/action-bar/states/actionBarEntriesState'; import { actionBarEntriesState } from '@/ui/action-bar/states/actionBarEntriesState';
import { IconTrash } from '@/ui/icon'; import { IconTrash } from '@/ui/icon';
@ -14,13 +13,12 @@ export function useBoardActionBarEntries() {
return { return {
setActionBarEntries: () => setActionBarEntries: () =>
setActionBarEntries([ setActionBarEntries([
<ActionBarEntry {
label="Delete" label: 'Delete',
Icon={IconTrash} Icon: IconTrash,
type="danger" accent: 'danger',
onClick={deleteSelectedBoardCards} onClick: deleteSelectedBoardCards,
key="delete" },
/>,
]), ]),
}; };
} }

View File

@ -1,6 +1,5 @@
import { useSetRecoilState } from 'recoil'; import { useSetRecoilState } from 'recoil';
import { ContextMenuEntry } from '@/ui/context-menu/components/ContextMenuEntry';
import { contextMenuEntriesState } from '@/ui/context-menu/states/contextMenuEntriesState'; import { contextMenuEntriesState } from '@/ui/context-menu/states/contextMenuEntriesState';
import { IconTrash } from '@/ui/icon'; import { IconTrash } from '@/ui/icon';
@ -14,13 +13,12 @@ export function useBoardContextMenuEntries() {
return { return {
setContextMenuEntries: () => setContextMenuEntries: () =>
setContextMenuEntries([ setContextMenuEntries([
<ContextMenuEntry {
label="Delete" label: 'Delete',
Icon={IconTrash} Icon: IconTrash,
accent="danger" accent: 'danger',
onClick={() => deleteSelectedBoardCards()} onClick: () => deleteSelectedBoardCards(),
key="delete" },
/>,
]), ]),
}; };
} }

View File

@ -12,6 +12,8 @@ import { contextMenuEntriesState } from '../states/contextMenuEntriesState';
import { contextMenuIsOpenState } from '../states/contextMenuIsOpenState'; import { contextMenuIsOpenState } from '../states/contextMenuIsOpenState';
import { PositionType } from '../types/PositionType'; import { PositionType } from '../types/PositionType';
import { ContextMenuItem } from './ContextMenuItem';
type OwnProps = { type OwnProps = {
selectedIds: string[]; selectedIds: string[];
}; };
@ -66,7 +68,15 @@ export function ContextMenu({ selectedIds }: OwnProps) {
> >
<StyledDropdownMenu> <StyledDropdownMenu>
<StyledDropdownMenuItemsContainer> <StyledDropdownMenuItemsContainer>
{contextMenuEntries} {contextMenuEntries.map((item) => (
<ContextMenuItem
Icon={item.Icon}
label={item.label}
accent={item.accent}
onClick={item.onClick}
key={item.label}
/>
))}
</StyledDropdownMenuItemsContainer> </StyledDropdownMenuItemsContainer>
</StyledDropdownMenu> </StyledDropdownMenu>
</StyledContainerContextMenu> </StyledContainerContextMenu>

View File

@ -1,16 +1,16 @@
import { IconComponent } from '@/ui/icon/types/IconComponent'; import { IconComponent } from '@/ui/icon/types/IconComponent';
import { MenuItem } from '@/ui/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/menu-item/components/MenuItem';
type ContextMenuEntryAccent = 'default' | 'danger'; import { ContextMenuItemAccent } from '../types/ContextMenuItemAccent';
type OwnProps = { type OwnProps = {
Icon: IconComponent; Icon: IconComponent;
label: string; label: string;
accent?: ContextMenuEntryAccent; accent?: ContextMenuItemAccent;
onClick: () => void; onClick: () => void;
}; };
export function ContextMenuEntry({ export function ContextMenuItem({
label, label,
Icon, Icon,
accent = 'default', accent = 'default',

View File

@ -1,7 +1,8 @@
import { ReactElement } from 'react';
import { atom } from 'recoil'; import { atom } from 'recoil';
export const contextMenuEntriesState = atom<ReactElement[]>({ import { ContextMenuEntry } from '../types/ContextMenuEntry';
export const contextMenuEntriesState = atom<ContextMenuEntry[]>({
key: 'contextMenuEntriesState', key: 'contextMenuEntriesState',
default: [], default: [],
}); });

View File

@ -0,0 +1,10 @@
import { IconComponent } from '@/ui/icon/types/IconComponent';
import { ContextMenuItemAccent } from './ContextMenuItemAccent';
export type ContextMenuEntry = {
label: string;
Icon: IconComponent;
accent?: ContextMenuItemAccent;
onClick: () => void;
};

View File

@ -0,0 +1 @@
export type ContextMenuItemAccent = 'default' | 'danger';