Conversation
WalkthroughAdds a new PulseToast component and integrates it into HomeScreen to auto-show a bottom-right toast on mount, with an 8-second auto-dismiss and manual close. HomeScreen manages a local flag to render the toast and hides it via onClose. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant HS as HomeScreen
participant PT as PulseToast
participant T as Timer
User->>HS: Navigate to HomeScreen (mount)
HS->>HS: set showBetaToast = true
HS->>PT: Render <PulseToast onClose=... />
activate PT
PT->>PT: isVisible = true (animate in)
PT->>T: start 8s timer
T-->>PT: timeout
PT->>PT: animate out (300ms)
PT-->>HS: onClose()
HS->>HS: set showBetaToast = false (unmount PT)
opt Manual close
User->>PT: Click close button
PT->>PT: animate out (300ms)
PT-->>HS: onClose()
HS->>HS: set showBetaToast = false
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🧪 Early access (Sonnet 4.5): enabledWe are currently testing the Sonnet 4.5 model, which is expected to improve code review quality. However, this model may lead to increased noise levels in the review comments. Please disable the early access features if the noise level causes any inconvenience. Note:
Comment |
Deploying x with
|
| Latest commit: |
e3e3ad7
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://ca42f99f.x-e62.pages.dev |
| Branch Preview URL: | https://feat-pro-3749-pulse-beta-tag.x-e62.pages.dev |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
src/apps/pulse/components/Toast/PulseToast.tsx (3)
19-30: Consider using useCallback for handleClose to avoid the eslint-disable.The
exhaustive-depsrule is disabled becausehandleCloseis not included in the dependency array. While this works for a mount-only effect, it creates a stale closure risk ifonClosewere to change (though unlikely in this case).A cleaner pattern would be:
+import { useCallback, useEffect, useRef, useState } from 'react'; const PulseToast = ({ onClose }: PulseToastProps) => { const [isVisible, setIsVisible] = useState(false); - const handleClose = () => { + const handleClose = useCallback(() => { setIsVisible(false); setTimeout(() => { onClose(); }, 300); - }; + }, [onClose]); useEffect(() => { setIsVisible(true); const timer = setTimeout(() => { handleClose(); }, 8000); return () => { clearTimeout(timer); }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [handleClose]);This eliminates the need for the disable comment and ensures
handleCloseproperly tracks its dependencies.
32-36: Consider respecting prefers-reduced-motion for accessibility.The toast animates regardless of the user's motion preferences. Users who have enabled
prefers-reduced-motionin their system settings may experience discomfort.React-spring provides
useReducedMotion()hook (per learnings). You can use it to disable animations:-import { animated, useSpring } from '@react-spring/web'; +import { animated, useReducedMotion, useSpring } from '@react-spring/web'; const PulseToast = ({ onClose }: PulseToastProps) => { const [isVisible, setIsVisible] = useState(false); + const prefersReducedMotion = useReducedMotion(); // ... handleClose and useEffect ... const toastAnimation = useSpring({ opacity: isVisible ? 1 : 0, - transform: isVisible ? 'translateY(0px)' : 'translateY(20px)', + transform: isVisible && !prefersReducedMotion ? 'translateY(0px)' : 'translateY(20px)', - config: { tension: 200, friction: 20 }, + config: prefersReducedMotion ? { duration: 0 } : { tension: 200, friction: 20 }, });This respects user accessibility preferences while maintaining the visual polish for others.
38-63: Consider adding Escape key handler for better UX.Users typically expect to dismiss toasts using the Escape key, especially when they auto-appear.
Add a keyboard event listener:
useEffect(() => { setIsVisible(true); + const handleEscape = (e: KeyboardEvent) => { + if (e.key === 'Escape') { + handleClose(); + } + }; + + document.addEventListener('keydown', handleEscape); + const timer = setTimeout(() => { handleClose(); }, 8000); return () => { + document.removeEventListener('keydown', handleEscape); clearTimeout(timer); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []);This provides an additional accessible way to dismiss the toast.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/apps/pulse/components/App/HomeScreen.tsx(4 hunks)src/apps/pulse/components/Toast/PulseToast.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/apps/pulse/components/Toast/PulseToast.tsx (1)
src/components/LandingPage/Header/index.jsx (1)
isVisible(9-9)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: unit-tests
- GitHub Check: lint
- GitHub Check: build
🔇 Additional comments (8)
src/apps/pulse/components/Toast/PulseToast.tsx (4)
1-3: LGTM!Imports are appropriate and follow best practices. Using
@react-spring/webpackage-specific entrypoint enables better tree-shaking.
5-7: LGTM!Type definition is clear and appropriate for the component's API.
9-10: LGTM!Component declaration and initial state setup are correct. Starting with
isVisible = falseenables the entrance animation.
32-36: LGTM!Animation configuration is appropriate. The fade-in with slide-up effect provides good visual feedback, and the spring config values are reasonable.
src/apps/pulse/components/App/HomeScreen.tsx (4)
29-29: LGTM!Import path and default import are correct.
59-59: LGTM!State initialization is correct. Starting with
falseand setting totruein the effect ensures the toast animates in properly.
85-88: LGTM!The mount effect correctly shows the toast on entry. The comment "on every entry to Pulse" is accurate assuming the component remounts on navigation (typical for React SPAs).
416-416: LGTM!Conditional rendering and integration with
PulseToastare correct. TheonClosecallback properly manages the toast visibility state.
| return ( | ||
| <animated.div | ||
| style={toastAnimation} | ||
| className="flex fixed bottom-4 right-4 max-w-80 bg-[#8A77FF] text-medium_grey p-4 rounded-lg shadow-lg z-[500] border border-white/[.5]" | ||
| > | ||
| <div className="flex flex-col"> | ||
| <div className="flex justify-between"> | ||
| <p className="text-sm font-medium text-white mb-2"> | ||
| Welcome to Pulse (beta) | ||
| </p> | ||
| <button | ||
| type="button" | ||
| className="absolute top-2 right-2" | ||
| onClick={handleClose} | ||
| aria-label="Close" | ||
| > | ||
| <MdClose color="white" /> | ||
| </button> | ||
| </div> | ||
| <p className="text-xs font-normal text-white"> | ||
| You’re trying out the beta version of Pulse: expect improvements | ||
| ahead. Thank you for being part of the journey! | ||
| </p> | ||
| </div> | ||
| </animated.div> | ||
| ); |
There was a problem hiding this comment.
Add ARIA role for screen reader announcement.
The toast appears automatically without user action, but lacks an ARIA role to announce its presence to screen readers. This impacts accessibility for users relying on assistive technology.
Add role="status" or role="alert" to the toast container:
<animated.div
style={toastAnimation}
className="flex fixed bottom-4 right-4 max-w-80 bg-[#8A77FF] text-medium_grey p-4 rounded-lg shadow-lg z-[500] border border-white/[.5]"
+ role="status"
+ aria-live="polite"
>Use role="status" with aria-live="polite" for informational messages (preferred for beta announcements), or role="alert" with aria-live="assertive" for urgent messages.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| return ( | |
| <animated.div | |
| style={toastAnimation} | |
| className="flex fixed bottom-4 right-4 max-w-80 bg-[#8A77FF] text-medium_grey p-4 rounded-lg shadow-lg z-[500] border border-white/[.5]" | |
| > | |
| <div className="flex flex-col"> | |
| <div className="flex justify-between"> | |
| <p className="text-sm font-medium text-white mb-2"> | |
| Welcome to Pulse (beta) | |
| </p> | |
| <button | |
| type="button" | |
| className="absolute top-2 right-2" | |
| onClick={handleClose} | |
| aria-label="Close" | |
| > | |
| <MdClose color="white" /> | |
| </button> | |
| </div> | |
| <p className="text-xs font-normal text-white"> | |
| You’re trying out the beta version of Pulse: expect improvements | |
| ahead. Thank you for being part of the journey! | |
| </p> | |
| </div> | |
| </animated.div> | |
| ); | |
| return ( | |
| <animated.div | |
| style={toastAnimation} | |
| className="flex fixed bottom-4 right-4 max-w-80 bg-[#8A77FF] text-medium_grey p-4 rounded-lg shadow-lg z-[500] border border-white/[.5]" | |
| role="status" | |
| aria-live="polite" | |
| > | |
| <div className="flex flex-col"> | |
| <div className="flex justify-between"> | |
| <p className="text-sm font-medium text-white mb-2"> | |
| Welcome to Pulse (beta) | |
| </p> | |
| <button | |
| type="button" | |
| className="absolute top-2 right-2" | |
| onClick={handleClose} | |
| aria-label="Close" | |
| > | |
| <MdClose color="white" /> | |
| </button> | |
| </div> | |
| <p className="text-xs font-normal text-white"> | |
| You’re trying out the beta version of Pulse: expect improvements | |
| ahead. Thank you for being part of the journey! | |
| </p> | |
| </div> | |
| </animated.div> | |
| ); |
🤖 Prompt for AI Agents
In src/apps/pulse/components/Toast/PulseToast.tsx around lines 38 to 63, the
toast lacks ARIA attributes so screen readers won’t announce it; add
accessibility attributes to the top-level animated.div by setting role="status"
and aria-live="polite" (optionally aria-atomic="true") to ensure the
informational beta message is announced politely to assistive technologies.
Description
How Has This Been Tested?
Screenshots (if appropriate):
Types of changes
Summary by CodeRabbit