Skip to content

Commit

Permalink
feat(toasts): Add ability to add action (#164)
Browse files Browse the repository at this point in the history
  • Loading branch information
hachiojidev authored Feb 3, 2021
1 parent 6c2eb55 commit cbba5a4
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 20 deletions.
4 changes: 2 additions & 2 deletions src/__tests__/components/alert.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { renderWithTheme } from "../../testHelpers";
import { Alert } from "../../components/Alert";

it("renders correctly", () => {
const { asFragment } = renderWithTheme(<Alert title="Alert title" description="Alert description" />);
const { asFragment } = renderWithTheme(<Alert title="Alert title">Description</Alert>);

expect(asFragment()).toMatchInlineSnapshot(`
<DocumentFragment>
Expand Down Expand Up @@ -38,7 +38,7 @@ it("renders correctly", () => {
class="sc-gsTCUz doXHqk"
color="text"
>
Alert description
Description
</p>
</div>
</div>
Expand Down
6 changes: 3 additions & 3 deletions src/components/Alert/Alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,17 @@ const StyledAlert = styled(Flex)`
box-shadow: 0px 20px 36px -8px rgba(14, 14, 44, 0.1), 0px 1px 1px rgba(0, 0, 0, 0.05);
`;

const Alert: React.FC<AlertProps> = ({ title, description, variant, onClick }) => {
const Alert: React.FC<AlertProps> = ({ title, children, variant, onClick }) => {
const Icon = getIcon(variant);

return (
<StyledAlert>
<IconLabel variant={variant} hasDescription={!!description}>
<IconLabel variant={variant} hasDescription={!!children}>
<Icon color="currentColor" width="24px" />
</IconLabel>
<Details hasHandler={!!onClick}>
<Text bold>{title}</Text>
{description && <Text as="p">{description}</Text>}
{typeof children === "string" ? <Text as="p">{children}</Text> : children}
</Details>
{onClick && (
<CloseHandler>
Expand Down
28 changes: 17 additions & 11 deletions src/components/Alert/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import noop from "lodash/noop";
/* eslint-disable import/no-unresolved */
import { Meta } from "@storybook/react/types-6-0";
import Alert from "./Alert";
import { Text } from "../Text";

const Row = styled.div`
margin-bottom: 32px;
Expand All @@ -19,16 +20,24 @@ export const Default: React.FC = () => {
return (
<div style={{ padding: "32px", width: "400px" }}>
<Row>
<Alert title="Info" description="A description of the info alert" />
<Alert title="Info">
<Text as="p">This is a description</Text>
</Alert>
</Row>
<Row>
<Alert title="Success" description="A description of the success alert" variant="success" />
<Alert title="Success" variant="success">
<Text as="p">This is a description</Text>
</Alert>
</Row>
<Row>
<Alert title="Danger" description="A description of the danger alert" variant="danger" />
<Alert title="Warning" variant="warning">
<Text as="p">This is a description</Text>
</Alert>
</Row>
<Row>
<Alert title="Warning" description="A description of the warning alert" variant="warning" />
<Alert title="Danger" variant="danger">
<Text as="p">This is a description</Text>
</Alert>
</Row>
</div>
);
Expand All @@ -43,15 +52,12 @@ export const WithHandler: React.FC = () => {
<Alert onClick={handleClick} title="Info" />
</Row>
<Row>
<Alert
onClick={handleClick}
title="Success"
description="A description of the success alert"
variant="success"
/>
<Alert onClick={handleClick} title="Success" variant="success">
A description of the success alert
</Alert>
</Row>
<Row>
<Alert onClick={handleClick} title="Danger A description of the warning alert" variant="danger" />
<Alert onClick={handleClick} title="Danger A Long Title" variant="danger" />
</Row>
<Row>
<Alert onClick={handleClick} title="Warning" variant="warning" />
Expand Down
4 changes: 2 additions & 2 deletions src/components/Alert/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MouseEvent } from "react";
import { MouseEvent, ReactNode } from "react";

export type AlertTheme = {
background: string;
Expand All @@ -16,6 +16,6 @@ export type Variants = typeof variants[keyof typeof variants];
export interface AlertProps {
variant?: Variants;
title: string;
description?: string;
children?: ReactNode;
onClick?: (evt: MouseEvent<HTMLButtonElement>) => void;
}
17 changes: 15 additions & 2 deletions src/widgets/Toast/Toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React, { useCallback, useEffect, useRef } from "react";
import { CSSTransition } from "react-transition-group";
import styled from "styled-components";
import { Alert, alertVariants } from "../../components/Alert";
import { Text } from "../../components/Text";
import ToastAction from "./ToastAction";
import { ToastProps, types } from "./types";

const alertTypeMap = {
Expand All @@ -27,7 +29,7 @@ const Toast: React.FC<ToastProps> = ({ toast, onRemove, style, ttl, ...props })
const timer = useRef<number>();
const ref = useRef(null);
const removeHandler = useRef(onRemove);
const { id, title, description, type } = toast;
const { id, title, description, type, action } = toast;

const handleRemove = useCallback(() => removeHandler.current(id), [id, removeHandler]);

Expand Down Expand Up @@ -62,7 +64,18 @@ const Toast: React.FC<ToastProps> = ({ toast, onRemove, style, ttl, ...props })
return (
<CSSTransition nodeRef={ref} timeout={250} style={style} {...props}>
<StyledToast ref={ref} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
<Alert title={title} description={description} variant={alertTypeMap[type]} onClick={handleRemove} />
<Alert title={title} variant={alertTypeMap[type]} onClick={handleRemove}>
{action ? (
<>
<Text as="p" mb="8px">
{description}
</Text>
<ToastAction action={action} />
</>
) : (
description
)}
</Alert>
</StyledToast>
</CSSTransition>
);
Expand Down
27 changes: 27 additions & 0 deletions src/widgets/Toast/ToastAction.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from "react";
import { Link } from "react-router-dom";
import getExternalLinkProps from "../../util/getExternalLinkProps";
import { Button } from "../../components/Button";
import { ToastAction as Action } from "./types";

interface ToastActionProps {
action: Action;
}

const ToastAction: React.FC<ToastActionProps> = ({ action }) => {
if (action.url.startsWith("http")) {
return (
<Button as="a" size="sm" href={action.url} {...getExternalLinkProps()}>
{action.text}
</Button>
);
}

return (
<Button as={Link} size="sm" to={action.url}>
{action.text}
</Button>
);
};

export default ToastAction;
33 changes: 33 additions & 0 deletions src/widgets/Toast/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,36 @@ export const Default: React.FC = () => {
</div>
);
};

export const WithAction: React.FC = () => {
const [toasts, setToasts] = useState([]);

const handleClick = () => {
const now = Date.now();
const randomToast = {
id: `id-${now}`,
title: `Title: ${now}`,
description: "A description of a toast with a call to action",
action: {
text: "Action Button",
url: "https://pancakeswap.finance",
},
type: alertVariants[sample(Object.keys(alertVariants))],
};

setToasts((prevToasts) => [randomToast, ...prevToasts]);
};

const handleRemove = (id: string) => {
setToasts((prevToasts) => prevToasts.filter((prevToast) => prevToast.id !== id));
};

return (
<div>
<Button type="button" variant="success" ml="8px" onClick={() => handleClick()}>
Random Toast with Action Button
</Button>
<ToastContainer toasts={toasts} onRemove={handleRemove} />
</div>
);
};
6 changes: 6 additions & 0 deletions src/widgets/Toast/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,17 @@ export const types = {

export type Types = typeof types[keyof typeof types];

export interface ToastAction {
text: string;
url: string;
}

export interface Toast {
id: string;
type: Types;
title: string;
description?: string;
action?: ToastAction;
}

export interface ToastContainerProps {
Expand Down

0 comments on commit cbba5a4

Please sign in to comment.