import {
  Meta,
  Preview,
  Props,
  Story,
  SourceState,
} from "@storybook/addon-docs/blocks";
import { ComponentHeading } from "../../storybook-components";
import { ORIENTATION } from "../../types";
import { Button } from "../Button";
import { ICON_TYPE } from "../Icon";
import { Stack } from "../Stack";
import { Snackbar, useSnackbar, showSnackbar } from "./Snackbar";

<Meta title="Components/Feedback/Snackbar" component={Snackbar} />

<ComponentHeading
  componentName="Snackbar"
  description="Snackbars provide brief messages about app processes"
  sourcePath="src/components/Snackbar/Snackbar.tsx"
/>

Snackbar is similar to Toast, but mainly for brief, loading-style messages.

The Snackbar component doesn’t get called directly. Instead use either
`showSnackbar` or `useSnackbar` hook to create the component and make it appear
on-screen. You will need a way to dynamically set the `isVisible` prop in order
to show and hide the Snackbar on demand.

The Snackbar will appear at the bottom-left of the screen. This is not
configurable.

```jsx
import { useSnackbar, showSnackbar } from "@aptible/arrow-ds";
```

Here is a preview of how the Snackbar could look in its three different states.
Don’t copy these examples because a Snackbar should be implemented using the
`useSnackbar` hook, which is detailed below.

<Preview withSource={SourceState.NONE}>
  <Story name="Snackbar">
    <Stack orientation={ORIENTATION.VERTICAL}>
      <Snackbar message="I am the default snackbar" />
      <Snackbar message="I am a snackbar without a close button" disableClose />
      <Snackbar
        message="I am a snackbar with an action"
        action={{
          label: "Action",
          onClick: () => {
            // eslint-disable-next-line no-alert
            alert("Action clicked");
          },
        }}
      />
      <Snackbar
        message="I am a snackbar with an anchor link"
        action={{
          label: "Link",
          href: "https://www.aptible.com/",
          external: true,
        }}
      />
      <Snackbar message="I am a snackbar with an icon" icon={ICON_TYPE.CHECK} />
      <Snackbar
        message="I am a snackbar with a loading icon"
        icon={ICON_TYPE.SPINNER}
      />
      <Snackbar
        message="I am a snackbar with a loading icon and action"
        icon={ICON_TYPE.SPINNER}
        action={{
          label: "Action",
          onClick: () => {
            // eslint-disable-next-line no-alert
            alert("Action clicked");
          },
        }}
      />
    </Stack>
  </Story>
</Preview>

## showSnackbar

Using `showSnackbar` with a duration.

<Preview withSource={SourceState.OPEN}>
  <Story name="showSnackbar function">
    {() => {
      const onClick = () => {
        showSnackbar({
          message: "Show a snackbar for 5 seconds",
          duration: 5000,
        });
      };
      return <Button onClick={onClick}>Show Snackbar</Button>;
    }}
  </Story>
</Preview>

## showSnackbar with action

Using `showSnackbar` with an action. This Snackbar will stay on screen
indefinitely until it is closed via the action.

A duration can be used with an action if necessary.

<Preview withSource={SourceState.OPEN}>
  <Story name="showSnackbar function with action">
    {() => {
      const onClick = () => {
        showSnackbar({
          message: "Show a snackbar with an action",
          action: {
            label: "Action",
            onClick: () => {
              // eslint-disable-next-line no-alert
              alert("Action clicked");
            },
          },
        });
      };
      return <Button onClick={onClick}>Show Snackbar</Button>;
    }}
  </Story>
</Preview>

## useSnackbar

Here’s a contrived example of how to implement the hook `useSnackbar` to show and
hide the Snackbar with `useState` and `setTimeout`.

<Preview withSource={SourceState.OPEN}>
  <Story name="Snackbar hook">
    {() => {
      const [isVisible, setIsVisible] = React.useState(false);
      const onClick = () => {
        setIsVisible(true);
        setTimeout(() => {
          setIsVisible(false);
        }, 3000);
      };
      useSnackbar({
        message: "Ok, here’s your snackbar",
        isVisible,
      });
      return (
        <Button disabled={isVisible} onClick={onClick}>
          I’m hungry
        </Button>
      );
    }}
  </Story>
</Preview>

## Creating a loader

A more practical use of Snackbar is to monitor API calls and show the Snackbar
when a process is in progress and hide it when done. This example uses
`useState` and `setTimeout` to create a fake API call. It also demonstrates how
you might create an custom instance of the hook that can be re-used.

When a Snackbar used in this manner, the close button should be hidden via the
`disableClose` prop. The Snackbar should disappear automatically when the thing
happening is done.

<Preview withSource={SourceState.OPEN}>
  <Story name="Snackbar loader">
    {() => {
      // Create an custom loader instance that can be re-used
      const useLoadingSnackbar = ({ message, isVisible }) =>
        useSnackbar({
          message,
          isVisible,
          icon: ICON_TYPE.SPINNER,
          disableClose: true,
        });
      const API_STATUS = {
        IDLE: "IDLE",
        FETCHING: "FETCHING",
        COMPLETED: "COMPLETED",
      };
      const [status, setStatus] = React.useState(API_STATUS.IDLE);
      const fauxFetch = () => {
        setStatus(API_STATUS.FETCHING);
        setTimeout(() => {
          setStatus(API_STATUS.COMPLETED);
        }, 3000);
      };
      useLoadingSnackbar({
        message: "Fetching data…",
        isVisible: status === API_STATUS.FETCHING,
      });
      return (
        <Button disabled={status === API_STATUS.FETCHING} onClick={fauxFetch}>
          {status === API_STATUS.FETCHING ? "Fetching…" : "Fetch data"}
        </Button>
      );
    }}
  </Story>
</Preview>

## useSnackbar Props

<Props of={useSnackbar} />

## showSnackbar Props

<Props of={showSnackbar} />
