fleet/frontend/components/TableContainer/DataTable/ActionButton/ActionButton.tsx
Jacob Shandling cb58849d95
Fleet Premium to Sandbox (#11372)
## Addresses #9371 
### Adds a suite of UI logic for premium features in the Sandbox
environment

For reviewer: please review the work for the below 3 substasks, which
are the only remaining subtasks encompassed by this PR that have not yet
passed review individually:
  - #10822 (9)
  - #10823 (10)
  - #10824 (11)

## Checklist for submitter
- [x] Changes file added for user-visible changes in `changes/`
- [x] Manual QA for all new/changed functionality

---------

Co-authored-by: Jacob Shandling <jacob@fleetdm.com>
Co-authored-by: Martin Angers <martin.n.angers@gmail.com>
2023-04-27 08:53:30 -07:00

108 lines
3.3 KiB
TypeScript

import React, { useCallback } from "react";
import { kebabCase } from "lodash";
import PremiumFeatureIconWithTooltip from "components/PremiumFeatureIconWithTooltip";
import { ButtonVariant } from "components/buttons/Button/Button";
import Button from "../../../buttons/Button";
import CloseIcon from "../../../../../assets/images/icon-close-vibrant-blue-16x16@2x.png";
import DeleteIcon from "../../../../../assets/images/icon-delete-vibrant-blue-12x14@2x.png";
import CheckIcon from "../../../../../assets/images/icon-action-check-16x15@2x.png";
import DisableIcon from "../../../../../assets/images/icon-action-disable-14x14@2x.png";
import TransferIcon from "../../../../../assets/images/icon-action-transfer-16x16@2x.png";
const baseClass = "action-button";
export interface IActionButtonProps {
name: string;
buttonText: string;
onActionButtonClick: (ids: number[]) => void | undefined;
targetIds?: number[]; // TODO figure out undefined case
variant?: ButtonVariant;
hideButton?: boolean | ((targetIds: number[]) => boolean);
icon?: string;
iconPosition?: string;
indicatePremiumFeature?: boolean;
}
function useActionCallback(
callbackFn: (targetIds: number[]) => void | undefined
) {
return useCallback(
(targetIds) => {
callbackFn(targetIds);
},
[callbackFn]
);
}
const ActionButton = (buttonProps: IActionButtonProps): JSX.Element | null => {
const {
name,
buttonText,
onActionButtonClick,
targetIds = [],
variant = "brand",
hideButton,
icon,
iconPosition,
indicatePremiumFeature,
} = buttonProps;
const onButtonClick = useActionCallback(onActionButtonClick);
const iconLink = ((iconProp) => {
// check if using pre-defined short-hand otherwise otherwise return the prop
switch (iconProp) {
case "close":
return CloseIcon;
case "remove":
return CloseIcon;
case "delete":
return DeleteIcon;
case "check":
return CheckIcon;
case "disable":
return DisableIcon;
case "transfer":
return TransferIcon;
default:
return null;
}
})(icon);
// hideButton is intended to provide a flexible way to specify show/hide conditions via a boolean or a function that evaluates to a boolean
// currently it is typed to accept an array of targetIds but this typing could easily be expanded to include other use cases
const isHidden = (
hideButtonProp: boolean | ((ids: number[]) => boolean) | undefined
) => {
if (typeof hideButtonProp === "function") {
return hideButtonProp(targetIds);
}
return Boolean(hideButtonProp);
};
if (isHidden(hideButton)) {
return null;
}
return (
<div className={`${baseClass} ${baseClass}__${kebabCase(name)}`}>
{indicatePremiumFeature && (
<PremiumFeatureIconWithTooltip tooltipDelayHide={500} />
)}
<Button
disabled={indicatePremiumFeature}
onClick={() => onButtonClick(targetIds)}
variant={variant}
>
<>
{iconPosition === "left" && iconLink && (
<img alt={`${name} icon`} src={iconLink} />
)}
{buttonText}
{iconPosition !== "left" && iconLink && (
<img alt={`${name} icon`} src={iconLink} />
)}
</>
</Button>
</div>
);
};
export default ActionButton;