Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DTRA-2034 / Kate / Expand Snackbar functionality #465

Merged
merged 2 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion lib/components/Snackbar/snackbar-standalone.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ const meta = {
},
onCloseAction: {
description:
"Optional. Only for standalone snackbar when you pass funciton for close button `onClick`.",
"Optional. Only for standalone snackbar when you pass function for close button `onClick`.",
},
onSnackbarRemove: {
description:
"Optional. Callback for removing snackbar, will be triggered on close button click, on action text click, on timeout expiry and on dismissing the snackbar.",
},
hasCloseButton: {
control: "boolean",
Expand Down Expand Up @@ -87,3 +91,11 @@ export const WithActionButton: Story = {
actionText: "Action",
},
};

export const WithRemoveCallback: Story = {
args: {
message: "Please, open the console",
actionText: "Action",
onSnackbarRemove: () => console.log("onSnackbarRemove was called"),
},
};
11 changes: 11 additions & 0 deletions lib/components/Snackbar/snackbar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ const meta = {
description:
"Optional. Must be included if we have actionText to trigger action and close snackbar.",
},
onSnackbarRemove: {
description:
"Optional. Callback for removing snackbar, will be triggered on close button click, on action text click, on timeout expiry and on dismissing the snackbar.",
},
hasCloseButton: {
control: "boolean",
description: "Optional. Set to true by default.",
Expand Down Expand Up @@ -238,3 +242,10 @@ SnackbarWithTwoLinesMessageWithActionButtonMobileOnly.args = {
hasCloseButton: false,
onActionClick: fn(),
};

export const SnackbarWithRemoveCallback = Template.bind(this) as Story;
SnackbarWithRemoveCallback.args = {
...meta.args,
message: "Please, open the console",
onSnackbarRemove: () => console.log("onSnackbarRemove was called"),
};
30 changes: 22 additions & 8 deletions lib/components/Snackbar/snackbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface SnackbarProps extends HTMLAttributes<HTMLDivElement> {
hasCloseButton?: boolean;
onActionClick?: () => void;
onCloseAction?: () => void;
onSnackbarRemove?: () => void;
delay?: number;
standalone?: boolean;
status?: "fail" | "neutral";
Expand All @@ -30,6 +31,7 @@ export const Snackbar = ({
actionText,
onActionClick,
onCloseAction,
onSnackbarRemove,
hasCloseButton = true,
delay,
standalone = true,
Expand All @@ -38,16 +40,28 @@ export const Snackbar = ({
}: SnackbarProps) => {
const { removeSnackbar } = useSnackbar();
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const snackbarDelayedRemove = (id: string, delay: number = 4000) => {
const snackbarDelayedRemove = ({
id,
onSnackbarRemove,
delay = 4000,
}: {
id: string;
onSnackbarRemove?: () => void;
delay?: number;
}) => {
return setTimeout(() => {
removeSnackbar(id);
removeSnackbar(id, onSnackbarRemove);
}, delay);
};

const ref = useRef<HTMLDivElement>(null);

useEffect(() => {
id && (timerRef.current = snackbarDelayedRemove(id));
id &&
(timerRef.current = snackbarDelayedRemove({
id,
onSnackbarRemove,
}));

return () => {
clearTimeout(timerRef.current ?? "");
Expand All @@ -57,25 +71,25 @@ export const Snackbar = ({
const handleClose = (delay: number = 100) => {
onCloseAction?.();
if (timerRef) clearTimeout(timerRef.current ?? "");
id && snackbarDelayedRemove(id, delay);
id && snackbarDelayedRemove({ id, onSnackbarRemove, delay });
};

const handleActionClick = () => {
onActionClick?.();
handleClose();
};

id && useOnClickOutside(ref, () => removeSnackbar(id));
id && useOnClickOutside(ref, () => removeSnackbar(id, onSnackbarRemove));

if (standalone && !isVisible) return null;

const color = {
neutral: "white-black",
fail: "white"
}
fail: "white",
};

const buttonColor = color[status] as TDefaultColor;

return (
<div
{...rest}
Expand Down
2 changes: 1 addition & 1 deletion lib/providers/snackbar/snackbarContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { createContext } from "react";
export type SnackbarContextValue = {
queue: SnackbarProps[];
addSnackbar: (props: Omit<SnackbarProps, "id" | "isVisible">) => void;
removeSnackbar: (id: string) => void;
removeSnackbar: (id: string, onSnackbarRemove?: () => void) => void;
};

export const SnackbarContext = createContext<SnackbarContextValue>({
Expand Down
3 changes: 2 additions & 1 deletion lib/providers/snackbar/snackbarProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ export const SnackbarProvider = ({
});
};

const removeSnackbar = (id: string) => {
const removeSnackbar = (id: string, onSnackbarRemove?: () => void) => {
setQueue((prevQueue: SnackbarProps[]) => {
return prevQueue.map((item, index) => {
if (index === 0) {
setTimeout(() => {
removeSnackbarFromQueue(id);
onSnackbarRemove?.();
}, 500);
return { ...item, isVisible: false };
}
Expand Down