Shared:Components:SaveCancelButtons: rewrite to typescript

This commit is contained in:
Timofey Boyko 2023-12-21 17:41:01 +03:00
parent a48ac24df4
commit e3c0b62078
11 changed files with 244 additions and 269 deletions

View File

@ -1,187 +0,0 @@
import React from "react";
import PropTypes from "prop-types";
import Button from "../button";
import Text from "../text";
import StyledSaveCancelButtons from "./styled-save-cancel-buttons";
import { isDesktop, isMobile } from "../utils/device";
const ButtonKeys = Object.freeze({
enter: 13,
esc: 27,
});
class SaveCancelButtons extends React.Component {
componentDidMount() {
document.addEventListener("keydown", this.onKeydown, false);
}
componentWillUnmount() {
document.removeEventListener("keydown", this.onKeydown, false);
}
onKeydown = (e: any) => {
// @ts-expect-error TS(2339): Property 'onSaveClick' does not exist on type 'Rea... Remove this comment to see the full error message
const { onSaveClick, onCancelClick, displaySettings } = this.props;
if (displaySettings) return;
switch (e.keyCode) {
case ButtonKeys.enter:
onSaveClick();
break;
case ButtonKeys.esc:
onCancelClick();
break;
default:
break;
}
};
render() {
const {
// @ts-expect-error TS(2339): Property 'onSaveClick' does not exist on type 'Rea... Remove this comment to see the full error message
onSaveClick,
// @ts-expect-error TS(2339): Property 'onCancelClick' does not exist on type 'R... Remove this comment to see the full error message
onCancelClick,
// @ts-expect-error TS(2339): Property 'displaySettings' does not exist on type ... Remove this comment to see the full error message
displaySettings,
// @ts-expect-error TS(2339): Property 'showReminder' does not exist on type 'Re... Remove this comment to see the full error message
showReminder,
// @ts-expect-error TS(2339): Property 'reminderText' does not exist on type 'Re... Remove this comment to see the full error message
reminderText,
// @ts-expect-error TS(2339): Property 'saveButtonLabel' does not exist on type ... Remove this comment to see the full error message
saveButtonLabel,
// @ts-expect-error TS(2339): Property 'cancelButtonLabel' does not exist on typ... Remove this comment to see the full error message
cancelButtonLabel,
// @ts-expect-error TS(2339): Property 'hasScroll' does not exist on type 'Reado... Remove this comment to see the full error message
hasScroll,
// @ts-expect-error TS(2339): Property 'disableRestoreToDefault' does not exist ... Remove this comment to see the full error message
disableRestoreToDefault,
// @ts-expect-error TS(2339): Property 'className' does not exist on type 'Reado... Remove this comment to see the full error message
className,
// @ts-expect-error TS(2339): Property 'id' does not exist on type 'Readonly<{}>... Remove this comment to see the full error message
id,
// @ts-expect-error TS(2339): Property 'isSaving' does not exist on type 'Readon... Remove this comment to see the full error message
isSaving,
// @ts-expect-error TS(2339): Property 'cancelEnable' does not exist on type 'Re... Remove this comment to see the full error message
cancelEnable,
// @ts-expect-error TS(2339): Property 'tabIndex' does not exist on type 'Readon... Remove this comment to see the full error message
tabIndex,
// @ts-expect-error TS(2339): Property 'saveButtonDisabled' does not exist on ty... Remove this comment to see the full error message
saveButtonDisabled,
// @ts-expect-error TS(2339): Property 'additionalClassSaveButton' does not exis... Remove this comment to see the full error message
additionalClassSaveButton,
// @ts-expect-error TS(2339): Property 'additionalClassCancelButton' does not ex... Remove this comment to see the full error message
additionalClassCancelButton,
// @ts-expect-error TS(2339): Property 'hideBorder' does not exist on type 'Read... Remove this comment to see the full error message
hideBorder,
} = this.props;
const cancelButtonDisabled = cancelEnable
? false
: typeof disableRestoreToDefault === "boolean"
? disableRestoreToDefault
: !showReminder;
const tabIndexSaveButton = tabIndex ? tabIndex : -1;
const tabIndexCancelButton = tabIndex ? tabIndex + 1 : -1;
const classNameSave = additionalClassSaveButton
? `save-button ` + additionalClassSaveButton
: `save-button`;
const classNameCancel = additionalClassCancelButton
? `cancel-button ` + additionalClassCancelButton
: `cancel-button`;
const buttonSize = isDesktop() ? "small" : "normal";
return (
<StyledSaveCancelButtons
className={className}
id={id}
// @ts-expect-error TS(2769): No overload matches this call.
displaySettings={displaySettings}
showReminder={showReminder}
hasScroll={hasScroll}
hideBorder={hideBorder}
>
<div className="buttons-flex">
<Button
// @ts-expect-error TS(2322): Type '{ tabIndex: any; className: string; size: st... Remove this comment to see the full error message
tabIndex={tabIndexSaveButton}
className={classNameSave}
size={buttonSize}
isDisabled={!showReminder || saveButtonDisabled}
primary
onClick={onSaveClick}
label={saveButtonLabel}
minwidth={displaySettings && "auto"}
isLoading={isSaving}
scale={isMobile()}
/>
<Button
// @ts-expect-error TS(2322): Type '{ tabIndex: any; className: string; size: st... Remove this comment to see the full error message
tabIndex={tabIndexCancelButton}
className={classNameCancel}
size={buttonSize}
isDisabled={cancelButtonDisabled || isSaving}
onClick={onCancelClick}
label={cancelButtonLabel}
minwidth={displaySettings && "auto"}
scale={isMobile()}
/>
</div>
{showReminder && reminderText && (
// @ts-expect-error TS(2322): Type '{ children: any; className: string; }' is no... Remove this comment to see the full error message
<Text className="unsaved-changes">{reminderText}</Text>
)}
</StyledSaveCancelButtons>
);
}
}
// @ts-expect-error TS(2339): Property 'propTypes' does not exist on type 'typeo... Remove this comment to see the full error message
SaveCancelButtons.propTypes = {
/** Accepts css id */
id: PropTypes.string,
/** Accepts css class */
className: PropTypes.string,
/** Message text that notifies of the unsaved changes */
reminderText: PropTypes.string,
/** Save button label */
saveButtonLabel: PropTypes.string,
/** Cancel button label */
cancelButtonLabel: PropTypes.string,
/** Sets a callback function that is triggered when the save button is clicked */
onSaveClick: PropTypes.func,
/** Sets a callback function that is triggered when the cancel button is clicked */
onCancelClick: PropTypes.func,
/** Reminder message that notifies of the unsaved changes (Only shown on desktops) */
showReminder: PropTypes.bool,
/** Sets save and cancel buttons block to 'position: static' instead of absolute */
displaySettings: PropTypes.bool,
/** Displays the scrollbar */
hasScroll: PropTypes.bool,
/** Sets the min width of the button */
minwidth: PropTypes.string,
/** Sets the Cancel button disabled by default */
disableRestoreToDefault: PropTypes.bool,
/** Sets the button to present a disabled state while executing an operation after clicking the save button */
isSaving: PropTypes.bool,
/** Activates the disabled button */
cancelEnable: PropTypes.bool,
/** Accepts css tab-index */
tabIndex: PropTypes.number,
/** Hide top border */
hideBorder: PropTypes.bool,
};
// @ts-expect-error TS(2339): Property 'defaultProps' does not exist on type 'ty... Remove this comment to see the full error message
SaveCancelButtons.defaultProps = {
saveButtonLabel: "Save",
cancelButtonLabel: "Cancel",
};
export default SaveCancelButtons;

View File

@ -1,57 +0,0 @@
import React from "react";
// @ts-expect-error TS(7016): Could not find a declaration file for module 'enzy... Remove this comment to see the full error message
import { mount } from "enzyme";
import SaveCancelButtons from ".";
// @ts-expect-error TS(2582): Cannot find name 'describe'. Do you need to instal... Remove this comment to see the full error message
describe("<MainButton />", () => {
// @ts-expect-error TS(2582): Cannot find name 'it'. Do you need to install type... Remove this comment to see the full error message
it("renders without error", () => {
const wrapper = mount(
<SaveCancelButtons
// @ts-expect-error TS(2769): No overload matches this call.
showReminder={true}
reminderText="You have unsaved changes"
saveButtonLabel="Save"
cancelButtonLabel="Cancel"
/>
);
// @ts-expect-error TS(2304): Cannot find name 'expect'.
expect(wrapper).toExist();
});
// @ts-expect-error TS(2582): Cannot find name 'it'. Do you need to install type... Remove this comment to see the full error message
it("accepts id", () => {
const wrapper = mount(
<SaveCancelButtons
// @ts-expect-error TS(2769): No overload matches this call.
showReminder={true}
reminderText="You have unsaved changes"
saveButtonLabel="Save"
cancelButtonLabel="Cancel"
id="testId"
/>
);
// @ts-expect-error TS(2304): Cannot find name 'expect'.
expect(wrapper.prop("id")).toEqual("testId");
});
// @ts-expect-error TS(2582): Cannot find name 'it'. Do you need to install type... Remove this comment to see the full error message
it("accepts className", () => {
const wrapper = mount(
<SaveCancelButtons
// @ts-expect-error TS(2769): No overload matches this call.
showReminder={true}
reminderText="You have unsaved changes"
saveButtonLabel="Save"
cancelButtonLabel="Cancel"
className="test"
/>
);
// @ts-expect-error TS(2304): Cannot find name 'expect'.
expect(wrapper.prop("className")).toEqual("test");
});
});

View File

@ -79,6 +79,7 @@ import TopLoaderService from "./top-loading-indicator";
import { SelectionArea } from "./selection-area";
import { ColorTheme } from "./color-theme";
import { SelectedItem } from "./selected-item";
import { SaveCancelButtons } from "./save-cancel-buttons";
export type {
TFallbackAxisSideDirection,
@ -91,6 +92,7 @@ export type {
};
export {
SaveCancelButtons,
SelectedItem,
ColorTheme,
SelectionArea,

View File

@ -1,20 +1,22 @@
import styled, { css } from "styled-components";
import Base from "../themes/base";
import { mobileMore, mobile } from "../utils/device";
import { Base } from "../../themes";
import { mobileMore, mobile } from "../../utils";
const displaySettings = css`
const displaySettings = css<{
hasScroll?: boolean;
showReminder?: boolean;
hideBorder?: boolean;
}>`
position: absolute;
display: block;
flex-direction: column-reverse;
align-items: flex-start;
border-top: ${(props) =>
// @ts-expect-error TS(2339): Property 'hasScroll' does not exist on type 'Theme... Remove this comment to see the full error message
props.hasScroll && !props.showReminder && !props.hideBorder
? "1px solid #ECEEF1"
: "none"};
${(props) =>
// @ts-expect-error TS(2339): Property 'hasScroll' does not exist on type 'Theme... Remove this comment to see the full error message
props.hasScroll &&
css`
bottom: auto;
@ -41,7 +43,6 @@ const displaySettings = css`
width: calc(100% - 32px);
bottom: 56px;
background-color: ${(props) =>
// @ts-expect-error TS(2339): Property 'hasScroll' does not exist on type 'Theme... Remove this comment to see the full error message
props.hasScroll
? props.theme.mainButtonMobile.buttonWrapper.background
: "none"};
@ -59,9 +60,7 @@ const displaySettings = css`
}
${(props) =>
// @ts-expect-error TS(2339): Property 'showReminder' does not exist on type 'Th... Remove this comment to see the full error message
props.showReminder &&
// @ts-expect-error TS(2339): Property 'hasScroll' does not exist on type 'Theme... Remove this comment to see the full error message
props.hasScroll &&
css`
.unsaved-changes {
@ -108,7 +107,12 @@ const tabletButtons = css`
}
`;
const StyledSaveCancelButtons = styled.div`
const StyledSaveCancelButtons = styled.div<{
displaySettings?: boolean;
showReminder?: boolean;
hasScroll?: boolean;
hideBorder?: boolean;
}>`
display: flex;
position: absolute;
justify-content: space-between;
@ -132,14 +136,11 @@ const StyledSaveCancelButtons = styled.div`
color: ${(props) => props.theme.saveCancelButtons.unsavedColor};
}
// @ts-expect-error TS(2339): Property 'displaySettings' does not exist on type ... Remove this comment to see the full error message
${(props) => props.displaySettings && displaySettings};
@media ${mobileMore} {
// @ts-expect-error TS(2339): Property 'displaySettings' does not exist on type ... Remove this comment to see the full error message
${(props) => props.displaySettings && tabletButtons}
${(props) =>
// @ts-expect-error TS(2339): Property 'displaySettings' does not exist on type ... Remove this comment to see the full error message
!props.displaySettings &&
`
justify-content: flex-end;

View File

@ -0,0 +1,118 @@
import React from "react";
import { ButtonKeys } from "../../enums";
import { isDesktop, isMobile } from "../../utils";
import { Button, ButtonSize } from "../button";
import { Text } from "../text";
import StyledSaveCancelButtons from "./SaveCancelButton.styled";
import { SaveCancelButtonProps } from "./SaveCancelButton.types";
const SaveCancelButtons = ({
id,
className,
reminderText,
saveButtonLabel = "Save",
cancelButtonLabel = "Cancel",
onCancelClick,
onSaveClick,
showReminder,
displaySettings,
disableRestoreToDefault,
hasScroll,
isSaving,
cancelEnable,
tabIndex,
hideBorder,
additionalClassSaveButton,
additionalClassCancelButton,
saveButtonDisabled,
}: SaveCancelButtonProps) => {
const onKeydown = React.useCallback(
(e: KeyboardEvent) => {
if (displaySettings) return;
switch (e.key) {
case ButtonKeys.enter:
onSaveClick?.();
break;
case ButtonKeys.esc:
onCancelClick?.();
break;
default:
break;
}
},
[displaySettings, onCancelClick, onSaveClick],
);
React.useEffect(() => {
document.addEventListener("keydown", onKeydown, false);
return () => {
document.removeEventListener("keydown", onKeydown, false);
};
}, [onKeydown]);
const cancelButtonDisabled = cancelEnable
? false
: typeof disableRestoreToDefault === "boolean"
? disableRestoreToDefault
: !showReminder;
const tabIndexSaveButton = tabIndex || -1;
const tabIndexCancelButton = tabIndex ? tabIndex + 1 : -1;
const classNameSave = additionalClassSaveButton
? `save-button ${additionalClassSaveButton}`
: `save-button`;
const classNameCancel = additionalClassCancelButton
? `cancel-button ${additionalClassCancelButton}`
: `cancel-button`;
const buttonSize = isDesktop() ? ButtonSize.small : ButtonSize.normal;
return (
<StyledSaveCancelButtons
className={className}
id={id}
displaySettings={displaySettings}
showReminder={showReminder}
hasScroll={hasScroll}
hideBorder={hideBorder}
data-testid="save-cancel-buttons"
>
<div className="buttons-flex">
<Button
tabIndex={tabIndexSaveButton}
className={classNameSave}
size={buttonSize}
isDisabled={!showReminder || saveButtonDisabled}
primary
onClick={onSaveClick}
label={saveButtonLabel}
minWidth={displaySettings ? "auto" : ""}
isLoading={isSaving}
scale={isMobile()}
/>
<Button
tabIndex={tabIndexCancelButton}
className={classNameCancel}
size={buttonSize}
isDisabled={cancelButtonDisabled || isSaving}
onClick={onCancelClick}
label={cancelButtonLabel}
minWidth={displaySettings ? "auto" : ""}
scale={isMobile()}
/>
</div>
{showReminder && reminderText && (
<Text className="unsaved-changes">{reminderText}</Text>
)}
</StyledSaveCancelButtons>
);
};
export { SaveCancelButtons };

View File

@ -0,0 +1,37 @@
export interface SaveCancelButtonProps {
/** Accepts css id */
id?: string;
/** Accepts css class */
className?: string;
/** Message text that notifies of the unsaved changes */
reminderText?: string;
/** Save button label */
saveButtonLabel?: string;
/** Cancel button label */
cancelButtonLabel?: string;
/** Sets a callback function that is triggered when the save button is clicked */
onSaveClick?: () => void;
/** Sets a callback function that is triggered when the cancel button is clicked */
onCancelClick?: () => void;
/** Reminder message that notifies of the unsaved changes (Only shown on desktops) */
showReminder?: boolean;
/** Sets save and cancel buttons block to 'position: static' instead of absolute */
displaySettings?: boolean;
/** Displays the scrollbar */
hasScroll?: boolean;
/** Sets the min width of the button */
minwidth?: string;
/** Sets the Cancel button disabled by default */
disableRestoreToDefault?: boolean;
/** Sets the button to present a disabled state while executing an operation after clicking the save button */
isSaving?: boolean;
/** Activates the disabled button */
cancelEnable?: boolean;
/** Accepts css tab-index */
tabIndex?: number;
/** Hide top border */
hideBorder?: boolean;
additionalClassSaveButton?: string;
additionalClassCancelButton?: string;
saveButtonDisabled?: boolean;
}

View File

@ -1,8 +1,11 @@
import React from "react";
import styled from "styled-components";
import SaveCancelButtons from "./";
import { Meta, StoryObj } from "@storybook/react";
export default {
import { SaveCancelButtons } from "./SaveCancelButton";
import { SaveCancelButtonProps } from "./SaveCancelButton.types";
const meta = {
title: "Components/SaveCancelButtons",
component: SaveCancelButtons,
parameters: {
@ -17,7 +20,10 @@ export default {
onSaveClick: { action: "onSaveClick" },
onCancelClick: { action: "onCancelClick" },
},
};
} satisfies Meta<typeof SaveCancelButtons>;
type Story = StoryObj<typeof meta>;
export default meta;
const StyledWrapper = styled.div`
position: relative;
@ -32,7 +38,7 @@ const Template = ({
onSaveClick,
onCancelClick,
...args
}: any) => {
}: SaveCancelButtonProps) => {
const isAutoDocs =
typeof window !== "undefined" && window?.location?.href.includes("docs");
@ -45,18 +51,19 @@ const Template = ({
? `positionAbsolute ${args.className}`
: args.className
}
onSaveClick={() => onSaveClick("on Save button clicked")}
onCancelClick={() => onCancelClick("on Cancel button clicked")}
onSaveClick={() => onSaveClick?.()}
onCancelClick={() => onCancelClick?.()}
/>
</StyledWrapper>
);
};
export const Default = Template.bind({});
// @ts-expect-error TS(2339): Property 'args' does not exist on type '({ onSaveC... Remove this comment to see the full error message
Default.args = {
showReminder: false,
reminderText: "You have unsaved changes",
saveButtonLabel: "Save",
cancelButtonLabel: "Cancel",
export const Default: Story = {
render: (args) => <Template {...args} />,
args: {
showReminder: false,
reminderText: "You have unsaved changes",
saveButtonLabel: "Save",
cancelButtonLabel: "Cancel",
},
};

View File

@ -0,0 +1,48 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import { SaveCancelButtons } from "./SaveCancelButton";
describe("<MainButton />", () => {
it("renders without error", () => {
render(
<SaveCancelButtons
showReminder
reminderText="You have unsaved changes"
saveButtonLabel="Save"
cancelButtonLabel="Cancel"
/>,
);
expect(screen.getByTestId("save-cancel-buttons")).toBeInTheDocument();
});
// it("accepts id", () => {
// const wrapper = mount(
// <SaveCancelButtons
// showReminder={true}
// reminderText="You have unsaved changes"
// saveButtonLabel="Save"
// cancelButtonLabel="Cancel"
// id="testId"
// />,
// );
// expect(wrapper.prop("id")).toEqual("testId");
// });
// it("accepts className", () => {
// const wrapper = mount(
// <SaveCancelButtons
// showReminder={true}
// reminderText="You have unsaved changes"
// saveButtonLabel="Save"
// cancelButtonLabel="Cancel"
// className="test"
// />,
// );
// expect(wrapper.prop("className")).toEqual("test");
// });
});

View File

@ -0,0 +1 @@
export { SaveCancelButtons } from "./SaveCancelButton";

View File

@ -4,6 +4,11 @@ export const enum ParseErrorTypes {
IncorrectEmail = 2,
}
export const enum ButtonKeys {
enter = "enter",
esc = "esc",
}
export const enum ErrorKeys {
LocalDomain = "LocalDomain",
IncorrectDomain = "IncorrectDomain",