Skip to content

Commit

Permalink
Fix toast issues
Browse files Browse the repository at this point in the history
  • Loading branch information
aweell committed Nov 19, 2024
1 parent bf3daf4 commit e45e742
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 36 deletions.
37 changes: 25 additions & 12 deletions src/pages/advent-calendar-2024/components/toast-wrapper.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { useState, useEffect } from "react";
import Toast from "./toast"; // Assuming your Toast component is already implemented
import { Stack } from "@telefonica/mistica";

const ToastWrapper = ({ toasts, removeToast }) => {
const totalToasts = toasts.length;

return (
<div
style={{
Expand All @@ -10,18 +13,28 @@ const ToastWrapper = ({ toasts, removeToast }) => {
right: "16px",
}}
>
<div style={{ position: "relative" }}>
{toasts.map((toast, index) => (
<Toast
id={toast.id}
key={toast.id}
title={toast.name}
description={toast.message}
icon={toast.icon}
onClose={() => removeToast(toast.id)} // Dismiss the toast by `id`
/>
))}
</div>
<Stack space={8}>
{toasts.map((toast, index) => {
const scaleValue = 1 - index * 0.2;
console.log(`scale(${scaleValue})`); // Log the scale value

return (
<Toast
id={toast.id}
key={toast.id}
title={toast.name}
description={toast.message}
icon={toast.icon}
onClose={() => removeToast(toast.id)} // Dismiss the toast by `id`
style={{
right: "16px",
zIndex: 1000 + index,
}}
delay={(totalToasts - index - 1) * 1000} // Last toast will have the longest delay
/>
);
})}
</Stack>
</div>
);
};
Expand Down
63 changes: 39 additions & 24 deletions src/pages/advent-calendar-2024/components/toast.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState, useRef } from "react";
import { useState, useEffect, useRef } from "react";
import {
Stack,
Text3,
Expand All @@ -9,16 +9,19 @@ import {
IconButton,
IconCloseRegular,
} from "@telefonica/mistica";
import styles from "./toast.module.css";

const Toast = ({
title,
description,
icon: Icon,
duration = 3000,
style,
delay = 0,
onClose,
style,
}) => {
const [visible, setVisible] = useState(true);
const [visible, setVisible] = useState(true); // Initial visibility is true
const [fadeOut, setFadeOut] = useState(false); // Controls fade-out animation
const [isHovered, setIsHovered] = useState(false);
const timeoutRef = useRef(null);

Expand All @@ -32,44 +35,53 @@ const Toast = ({
const startHideTimeout = () => {
clearHideTimeout();
timeoutRef.current = setTimeout(() => {
setVisible(false); // This will trigger unmount if necessary
onClose?.(); // Pass the ID to remove the toast
setFadeOut(true); // Trigger fade-out before setting visible to false
onClose?.(); // Trigger onClose callback to remove toast
}, duration);
};

// Handle visibility change when hovered or not
useEffect(() => {
if (!isHovered) {
startHideTimeout(); // Start timeout when not hovered
} else {
clearHideTimeout(); // Clear timeout when hovered
}
const handleTimeout = () => {
if (!isHovered) {
setTimeout(startHideTimeout, delay); // Delay before auto-dismissing
} else {
clearHideTimeout(); // Clear timeout when hovered
}
};

handleTimeout();

return () => clearHideTimeout(); // Cleanup timeout on unmount
}, [isHovered, duration]);
}, [isHovered, delay, duration]);

// Always render dismiss button, regardless of toast visibility
const handleDismiss = () => {
setVisible(false);
clearHideTimeout();
onClose?.(); // Ensure it triggers onClose from parent
};
useEffect(() => {
if (fadeOut) {
// Wait for the exit animation to complete before removing the toast
timeoutRef.current = setTimeout(() => {
setVisible(false); // Remove from the DOM after animation
}, 500); // Match the duration of your fade-out transition
}

return () => clearTimeout(timeoutRef.current); // Cleanup the fade-out timeout
}, [fadeOut]);

if (!visible) return null; // Hide toast when not visible
if (!visible) return null; // If not visible, do not render the toast

return (
<div
className={`${styles.toast} ${fadeOut ? styles.exit : ""}`} // Add the exit class when fadeOut is true
style={{
background: skinVars.colors.background,
padding: "24px",
borderRadius: "8px",
border: `2px solid ${skinVars.colors.border}`,
zIndex: 1000,
width: 480,
position: "relative", // Ensures dismiss button is on top
width: "480px",
...style,
}}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
onMouseEnter={() => setIsHovered(true)} // Trigger hover state
onMouseLeave={() => setIsHovered(false)} // Reset hover state
>
<Inline space={16}>
<div
Expand All @@ -96,11 +108,14 @@ const Toast = ({
View progress
</ButtonLink>
</Stack>
{/* Dismiss button should always be on top */}
<div style={{ position: "absolute", top: 8, right: 8 }}>
<IconButton
Icon={IconCloseRegular}
onPress={handleDismiss} // Handle dismiss in the component itself
onPress={() => {
setFadeOut(true); // Trigger fade-out animation on close
clearHideTimeout(); // Clear the timeout when manually closed
onClose?.(); // Trigger onClose callback to remove toast
}}
/>
</div>
</Inline>
Expand Down
23 changes: 23 additions & 0 deletions src/pages/advent-calendar-2024/components/toast.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* toast.module.css */

/* Keyframes for the toast entry animation */
@keyframes slideIn {
0% {
opacity: 0;
transform: translateY(400px); /* Start below */
}
100% {
opacity: 1; /* Fade in */
transform: translateY(0); /* Move to final position */
}
}



/* Base toast styles */
.toast {
opacity: 0;
transform: translateY(400px); /* Initial off-screen position */
animation: slideIn 0.5s ease-out forwards; /* Entry animation */
}

0 comments on commit e45e742

Please sign in to comment.