import React, { FC, ReactNode } from 'react' import styled, { css } from 'styled-components' import { isEmpty } from 'fp-ts/lib/Array' import { Colors } from '@monorail/helpers/color' import { PopOverToggleProps } from '@monorail/metaComponents/popOver/PopOver' import { isFalsy, isNil } from '@monorail/sharedHelpers/typeGuards' import { ActionsMenu, ActionsMenuProps as ActionsMenuProps_, MenuAction, } from '@monorail/visualComponents/actionsMenu/ActionsMenu' import { Button, ButtonProps } from '@monorail/visualComponents/buttons/Button' import { ButtonDisplay, ButtonSize, } from '@monorail/visualComponents/buttons/buttonTypes' import { DropdownButton, DropdownButtonListItem as DropdownButtonListItem_, Props as DropdownButtonProps_, } from '@monorail/visualComponents/buttons/DropdownButton' import { IconButton, IconButtonProps as IconButtonProps_, } from '@monorail/visualComponents/buttons/IconButton' import { Icon } from '@monorail/visualComponents/icon/Icon' import { TooltipMonorail } from '@monorail/visualComponents/tooltips/Tooltip' /** * CatalogEntryPermission is coppied from * src/catalog/shared/state/catalogStateTypes.ts */ export enum CatalogEntryPermission { Delete = 'delete', List = 'list', Read = 'read', Write = 'write', } export enum ActionButton { TextButton = 'TEXT_BUTTON', IconButton = 'ICON_BUTTON', ActionsMenu = 'ACTIONS_MENU', DropdownButton = 'DROPDOWN_BUTTON', InfoButton = 'INFO_BUTTON', } export type Check = { check: boolean } /** * Regular ol' button * Include the label field, since buttons take children as the label */ export type TextButtonProps = Partial> & { label: string onClick: (event: React.MouseEvent) => void } export type TextButtonAction = { type: ActionButton.TextButton actionProps: TextButtonProps } export type TextButtonActionWithCheck = TextButtonAction & Check /** InfoButton */ export type InfoButtonProps = { info: string } export type InfoButtonAction = { type: ActionButton.InfoButton actionProps: InfoButtonProps } /** Icon button */ export type IconButtonProps = Partial export type IconButtonAction = { type: ActionButton.IconButton actionProps: IconButtonProps } export type IconButtonActionWithCheck = IconButtonAction & Check /** Dropdown button */ export type DropdownButtonListItem = { actionProps: DropdownButtonListItem_ } & Check export type DropdownButtonProps = Omit & { listItems: Array } export type DropdownButtonAction = { type: ActionButton.DropdownButton actionProps: DropdownButtonProps } /** Actions menu */ export type ActionsMenuListItem = { actionProps: MenuAction } & Check export type ActionsMenuProps = Omit & { actions: Array } export type ActionsMenuAction = { type: ActionButton.ActionsMenu actionProps: ActionsMenuProps } export type ActionsButtonsAction = | ActionsMenuAction | DropdownButtonAction | IconButtonActionWithCheck | InfoButtonAction | TextButtonActionWithCheck export type ActionsButtonsProps = { display?: ButtonDisplay actions?: Array size?: ButtonSize iconOnly?: boolean document?: Document toggle?: (props: PopOverToggleProps) => ReactNode onClick?: (evt: React.MouseEvent) => void } const ActionsButtonsBox = styled.div` display: flex; > * { margin-left: 8px; } ` const makeTextButton = ({ action, size, display, }: { action: TextButtonActionWithCheck size: ActionsButtonsProps['size'] display: ActionsButtonsProps['display'] }): JSX.Element | null => action.check ? ( ) : null const makeIconButton = ({ action, size, display, }: { action: IconButtonActionWithCheck | TextButtonActionWithCheck size: ActionsButtonsProps['size'] display: ActionsButtonsProps['display'] }): JSX.Element | null => { if (action.check) { switch (action.type) { case ActionButton.IconButton: return ( ) case ActionButton.TextButton: const icon = isNil(action.actionProps.iconLeft) ? action.actionProps.iconRight : action.actionProps.iconLeft return ( ) default: return null } } else { return null } } const makeDropdownButton = ( action: DropdownButtonAction, ): JSX.Element | null => { const accessibleListItems = action.actionProps.listItems.filter( action_ => action_.check, ) return isEmpty(accessibleListItems) ? null : ( listItem.actionProps)} disabled={action.actionProps.disabled} /> ) } const makeInfoButton = (action: InfoButtonAction) => { return ( ) } const ActionsMenu_ = ({ action, document, }: { action: ActionsMenuAction document: ActionsButtonsProps['document'] }) => { const accessibleActions = action.actionProps.actions.filter( action_ => action_.check, ) return isEmpty(accessibleActions) ? null : ( action_.actionProps)} /> ) } export const ActionsButtons: FC = ({ display, document, iconOnly, size, actions = [], onClick = () => {}, }) => { const { actionsMenus, dropdownButtons, iconButtons, infoButtons, textButtons, } = actions.reduce<{ textButtons: Array iconButtons: Array dropdownButtons: Array actionsMenus: Array infoButtons: Array }>( (acc, action, idx) => { switch (action.type) { case ActionButton.TextButton: if (isFalsy(iconOnly)) { const textButton = makeTextButton({ action, size, display }) return isNil(textButton) ? acc : { ...acc, textButtons: [...acc.textButtons, textButton] } } else { const textButtonIconOnly = makeIconButton({ action, size, display }) return isNil(textButtonIconOnly) ? acc : { ...acc, iconButtons: [...acc.iconButtons, textButtonIconOnly], } } case ActionButton.IconButton: const iconButton = makeIconButton({ action, size, display }) return isNil(iconButton) ? acc : { ...acc, iconButtons: [...acc.iconButtons, iconButton], } case ActionButton.DropdownButton: const dropdownButton = makeDropdownButton(action) return isNil(dropdownButton) ? acc : { ...acc, dropdownButtons: [...acc.dropdownButtons, dropdownButton], } case ActionButton.ActionsMenu: const actionsMenu = ( ) return isNil(actionsMenu) ? acc : { ...acc, actionsMenus: [...acc.actionsMenus, actionsMenu], } case ActionButton.InfoButton: const infoButton = makeInfoButton(action) return isNil(infoButton) ? acc : { ...acc, infoButtons: [...acc.infoButtons, infoButton] } } }, { textButtons: [], iconButtons: [], dropdownButtons: [], infoButtons: [], actionsMenus: [], }, ) return ( {textButtons} {iconButtons} {dropdownButtons} {infoButtons} {actionsMenus} ) } export const makeTextButtonAction = (props: { actionProps: TextButtonProps check: boolean }): TextButtonActionWithCheck => ({ type: ActionButton.TextButton, actionProps: props.actionProps, check: props.check, }) export const makeActionsMenuListItem = (props: { actionsProps: MenuAction check: boolean }): ActionsMenuListItem => ({ actionProps: props.actionsProps, check: props.check, }) export const makeActionsMenuAction = ( actions: Array, ): ActionsMenuAction => ({ type: ActionButton.ActionsMenu, actionProps: { actions }, })