2
0

first commit

This commit is contained in:
2024-08-09 00:39:27 +02:00
commit 79688abe2e
5698 changed files with 497838 additions and 0 deletions

View File

@@ -0,0 +1 @@
export { DefaultToast, ErrorToast, SuccessToast, WarningToast, showToast } from "./showToast";

View File

@@ -0,0 +1,110 @@
import classNames from "classnames";
import type { ToastOptions, Toast } from "react-hot-toast";
import toast from "react-hot-toast";
import { Icon } from "../..";
type IToast = {
message: string;
toastVisible: boolean;
toastId: string;
onClose: (toastId: string) => void;
};
export const SuccessToast = ({ message, toastVisible, onClose, toastId }: IToast) => (
<button
className={classNames(
"data-testid-toast-success bg-brand-default text-brand mb-2 flex h-auto space-x-2 rounded-md p-3 text-sm font-semibold shadow-md rtl:space-x-reverse md:max-w-sm",
toastVisible && "animate-fade-in-up cursor-pointer"
)}
onClick={() => onClose(toastId)}>
<span className="mt-0.5">
<Icon name="check" className="h-4 w-4" />
</span>
<p data-testid="toast-success" className="text-left">
{message}
</p>
</button>
);
export const ErrorToast = ({ message, toastVisible, onClose, toastId }: IToast) => (
<button
className={classNames(
"animate-fade-in-up bg-error text-error text-brand mb-2 flex h-auto space-x-2 rounded-md p-3 text-sm font-semibold shadow-md rtl:space-x-reverse md:max-w-sm",
toastVisible && "animate-fade-in-up cursor-pointer"
)}
onClick={() => onClose(toastId)}>
<span className="mt-0.5">
<Icon name="info" className="h-4 w-4" />
</span>
<p data-testid="toast-error" className="text-left">
{message}
</p>
</button>
);
export const WarningToast = ({ message, toastVisible, onClose, toastId }: IToast) => (
<button
className={classNames(
"animate-fade-in-up bg-brand-default text-brand mb-2 flex h-auto space-x-2 rounded-md p-3 text-sm font-semibold shadow-md rtl:space-x-reverse md:max-w-sm",
toastVisible && "animate-fade-in-up cursor-pointer"
)}
onClick={() => onClose(toastId)}>
<span className="mt-0.5">
<Icon name="info" className="h-4 w-4" />
</span>
<p data-testid="toast-warning" className="text-left">
{message}
</p>
</button>
);
export const DefaultToast = ({ message, toastVisible, onClose, toastId }: IToast) => (
<button
className={classNames(
"animate-fade-in-up bg-brand-default text-brand mb-2 flex h-auto space-x-2 rounded-md p-3 text-sm font-semibold shadow-md rtl:space-x-reverse md:max-w-sm",
toastVisible && "animate-fade-in-up cursor-pointer"
)}
onClick={() => onClose(toastId)}>
<span className="mt-0.5">
<Icon name="check" className="h-4 w-4" />
</span>
<p data-testid="toast-default" className="text-left">
{message}
</p>
</button>
);
const TOAST_VISIBLE_DURATION = 6000;
type ToastVariants = "success" | "warning" | "error";
export function showToast(
message: string,
variant: ToastVariants,
// Options or duration (duration for backwards compatibility reasons)
options: number | ToastOptions = TOAST_VISIBLE_DURATION
) {
//
const _options: ToastOptions = typeof options === "number" ? { duration: options } : options;
if (!_options.duration) _options.duration = TOAST_VISIBLE_DURATION;
if (!_options.position) _options.position = "bottom-center";
const onClose = (toastId: string) => {
toast.remove(toastId);
};
const toastElements: { [x in ToastVariants]: (t: Toast) => JSX.Element } = {
success: (t) => (
<SuccessToast message={message} toastVisible={t.visible} onClose={onClose} toastId={t.id} />
),
error: (t) => <ErrorToast message={message} toastVisible={t.visible} onClose={onClose} toastId={t.id} />,
warning: (t) => (
<WarningToast message={message} toastVisible={t.visible} onClose={onClose} toastId={t.id} />
),
};
return toast.custom(
toastElements[variant] ||
((t) => <DefaultToast message={message} toastVisible={t.visible} onClose={onClose} toastId={t.id} />),
_options
);
}

View File

@@ -0,0 +1,68 @@
import { Canvas, Meta, Story, ArgsTable } from "@storybook/addon-docs";
import {
Examples,
Example,
Note,
Title,
VariantsTable,
VariantColumn,
RowTitles,
CustomArgsTable,
VariantRow,
} from "@calcom/storybook/components";
import { SuccessToast, ErrorToast, WarningToast, DefaultToast } from "./";
<Meta title="UI/Toasts" component={DefaultToast} />
<Title title="Toasts" suffix="Brief" subtitle="Version 2.0 — Last Update: 22 Aug 2022" />
## Definition
Toasts are used to show an action has had a impact. If a user submits a form a toast should be shown to notify the user there has been a success
## Structure
<CustomArgsTable of={DefaultToast} />
<Examples title="Toasts">
<Example title="Default">
<DefaultToast message="Default Toast" toastVisible={true} />
</Example>
<Example title="Success">
<SuccessToast message="Success Toast" toastVisible={true} />
</Example>
<Example title="Warning">
<WarningToast message="Warning Toast" toastVisible={true} />
</Example>
<Example title="Error">
<ErrorToast message="Error Toast" toastVisible={true} />
</Example>
</Examples>
## Toast Story
<Canvas>
<Story
name="Default"
args={{
message: "Default Toast",
toastVisible: true,
}}
argTypes={{
message: { control: "text" },
toastVisible: { control: "boolean" },
}}>
{({ message, toastVisible }) => (
<VariantsTable titles={["Default", "Success", "Warning", "Error"]} columnMinWidth={150}>
<VariantRow variant="Default">
<DefaultToast message={message} toastVisible={toastVisible} />
<SuccessToast message={message} toastVisible={toastVisible} />
<WarningToast message={message} toastVisible={toastVisible} />
<ErrorToast message={message} toastVisible={toastVisible} />
</VariantRow>
</VariantsTable>
)}
</Story>
</Canvas>

View File

@@ -0,0 +1,33 @@
import { render, screen, fireEvent } from "@testing-library/react";
import { vi } from "vitest";
import { SuccessToast, ErrorToast, WarningToast, DefaultToast } from "./showToast";
describe("Tests for Toast Components", () => {
const testToastComponent = (Component: typeof DefaultToast, toastTestId: string) => {
const message = "This is a test message";
const toastId = "some-id";
const onCloseMock = vi.fn();
render(<Component message={message} toastVisible={true} onClose={onCloseMock} toastId={toastId} />);
const toast = screen.getByTestId(toastTestId);
expect(toast).toBeInTheDocument();
expect(toast.textContent).toContain(message);
const closeButton = screen.getByRole("button");
fireEvent.click(closeButton);
expect(onCloseMock).toHaveBeenCalledWith(toastId);
};
const toastComponents: [string, typeof DefaultToast, string][] = [
["SuccessToast", SuccessToast, "toast-success"],
["ErrorToast", ErrorToast, "toast-error"],
["WarningToast", WarningToast, "toast-warning"],
["DefaultToast", DefaultToast, "toast-default"],
];
test.each(toastComponents)("Should render and close %s component", (_, ToastComponent, expectedClass) => {
testToastComponent(ToastComponent, expectedClass);
});
});