Skip to content

feat: Add toast notification system for bounty actions (Closes #825)#1254

Open
sepulchralvoid666 wants to merge 2 commits into
SolFoundry:mainfrom
sepulchralvoid666:feat/bounty-825-toast-notifications
Open

feat: Add toast notification system for bounty actions (Closes #825)#1254
sepulchralvoid666 wants to merge 2 commits into
SolFoundry:mainfrom
sepulchralvoid666:feat/bounty-825-toast-notifications

Conversation

@sepulchralvoid666
Copy link
Copy Markdown

@sepulchralvoid666 sepulchralvoid666 commented May 12, 2026

What this does

Adds a toast notification system for bounty status changes, errors, and success messages across the site.

New Component: Toast.tsx

  • ToastProvider + useToast hook — React context-based, works anywhere in the component tree
  • 4 variants: success (emerald), error (red), warning (yellow), info (blue)
  • Auto-dismiss after 5 seconds (configurable per toast)
  • Slide-in animation from top-right via Framer Motion
  • Stacking — multiple toasts render in a column with AnimatePresence
  • Accessible — each toast has role="alert" and dismiss button has aria-label
  • Manual close — X button on each toast

Integration Points

  • SubmissionForm: Success toast on bounty submission, error toast on failure
  • BountyCreateWizard: Success toast on bounty creation and publish, error toast on failures
  • main.tsx: ToastProvider wraps the entire app

How to test

  1. Submit a bounty PR — verify success toast appears top-right and auto-dismisses
  2. Trigger a submission error — verify error toast appears
  3. Create a new bounty — verify toast on creation and publish steps
  4. Trigger multiple toasts simultaneously — verify they stack
  5. Click X on a toast — verify it dismisses

Closes #825

Wallet: 2JHa4QQWNV7AGSGsVeX1cwjZtFcmTTomb1TrJmQthoh3

Summary by CodeRabbit

  • New Features
    • Introduced toast notification system for real-time user feedback throughout the app
    • Bounty creation workflow now displays contextual success and error messages
    • Submission process now shows real-time notifications on completion or failure
    • Notifications automatically dismiss after a few seconds for an unobtrusive user experience

Review Change Stack

- New Toast.tsx: context-based toast system with success/error/warning/info variants
- Auto-dismiss after 5 seconds, manual close button, slide-in animation from top-right
- Multiple toasts stack properly with AnimatePresence
- Accessible with role="alert" on each toast
- ToastProvider wired into main.tsx wrapping App
- SubmissionForm: toast on bounty submission success/failure
- BountyCreateWizard: toast on bounty creation and publish success/failure

Closes SolFoundry#825

**Wallet:** 2JHa4QQWNV7AGSGsVeX1cwjZtFcmTTomb1TrJmQthoh3
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 12, 2026

📝 Walkthrough

Walkthrough

This PR implements a complete toast notification system for the app. It creates a React context-based Toast component with auto-dismiss and animations, integrates it into the app root, and wires toast success/error notifications into the bounty creation wizard and submission form flows.

Changes

Toast Notification System

Layer / File(s) Summary
Toast system foundation
frontend/src/components/ui/Toast.tsx
Defines toast types (success, error, warning, info) and context shape; implements useToast hook that throws if called outside provider; ToastProvider manages active toasts with unique IDs via counter, handles addToast/removeToast, and auto-dismisses via setTimeout after 5000ms default; ToastContainer renders toasts in fixed top-right stack with AnimatePresence; ToastItem uses framer-motion for animation, applies variant styling and icons, displays title and optional message, and includes dismiss button.
App root provider integration
frontend/src/main.tsx
Imports ToastProvider and wraps the App component with it in the render tree, positioned between AuthProvider and QueryClientProvider/BrowserRouter.
Bounty creation wizard toast integration
frontend/src/components/bounty/BountyCreateWizard.tsx
Imports and initializes useToast hook; updates handleStep2Next to emit success toast after bounty creation and escrow deposit info retrieval, and error toast on failure while still setting error state; updates handlePublish to emit success toast after escrow verification and error toast on failure while updating success/error state.
Submission form toast integration
frontend/src/components/bounty/SubmissionForm.tsx
Imports and initializes useToast hook; rewrites handleSubmit to preserve validation gates and state management but add success toast on createSubmission completion (and call onSuccess), and error toast on validation or API failure with centralized error message handling.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • SolFoundry/solfoundry#708: Implements and integrates the same toast notification system using useToast hook and ToastProvider.
  • SolFoundry/solfoundry#327: Implements and integrates the same toast notification system with ToastProvider and useToast wiring.

Suggested labels

approved, paid

Poem

🐰 A toast to your toasts—they pop and they glow,
Success and errors now steal the show!
From top-right they slide, animations so slick,
Auto-dismiss keeps the UI so slick—
Bounty and forms now notify with delight! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely describes the main change: adding a toast notification system for bounty actions, with a reference to the closed issue.
Linked Issues check ✅ Passed All requirements from issue #825 are met: Toast variants (success/error/warning/info) implemented, auto-dismiss at 5 seconds with manual close, slide-in animation from top-right, stacking via AnimatePresence, and accessibility (role="alert") included.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the toast notification system and integrating it into relevant components; no unrelated or out-of-scope modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Warning

⚠️ This pull request might be slop. It has been flagged by CodeRabbit slop detection and should be reviewed carefully.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src/components/bounty/BountyCreateWizard.tsx`:
- Around line 442-445: verifyEscrowDeposit is awaited but its return value is
ignored, so even non-verified escrow responses will mark the bounty published;
update the success flow in the async block that calls verifyEscrowDeposit({
bounty_id: state.bounty_id, tx_signature: state.tx_signature }) to capture its
result, check the result.verified boolean, and only call setSuccess(true) and
addToast(...) when verified is true; if verified is false (or response indicates
failure) then do not set success, instead call addToast with an error variant
and an explanatory message (and optionally set an error state) so the UI
reflects the failed verification.

In `@frontend/src/components/ui/Toast.tsx`:
- Around line 37-41: The auto-dismiss timers started for toasts are never
cleared, so update the implementation to track timeouts in a ref (replace or
supplement counter useRef with a timersRef Map or Record keyed by toast id),
store each timeout id when scheduling, and call clearTimeout for that id inside
removeToast (and remove it from timersRef) so manual dismissal cancels the
timer; also add a cleanup in the provider's useEffect/unmount to iterate
timersRef and clearTimeout all remaining timers. Ensure you update places that
schedule timers to write into timersRef and that removeToast and the unmount
cleanup both clear and delete entries.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 99b14938-11b1-46c2-9d21-376c6cc5abf6

📥 Commits

Reviewing files that changed from the base of the PR and between 0bb39b1 and 2be1056.

📒 Files selected for processing (4)
  • frontend/src/components/bounty/BountyCreateWizard.tsx
  • frontend/src/components/bounty/SubmissionForm.tsx
  • frontend/src/components/ui/Toast.tsx
  • frontend/src/main.tsx

Comment on lines +442 to +445
await verifyEscrowDeposit({ bounty_id: state.bounty_id, tx_signature: state.tx_signature });
setSuccess(true);
addToast({ variant: 'success', title: 'Bounty published!', message: 'Your bounty is now live and visible to contributors.' });
} catch (e: unknown) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle non-verified escrow responses before showing publish success.

At Line 442, verifyEscrowDeposit is awaited but its result is ignored. If it resolves with verified: false, the code still sets success state/toast.

Suggested fix
-  await verifyEscrowDeposit({ bounty_id: state.bounty_id, tx_signature: state.tx_signature });
+  const result = await verifyEscrowDeposit({ bounty_id: state.bounty_id, tx_signature: state.tx_signature });
+  if (!result.verified) {
+    throw new Error(result.error ?? 'Failed to publish bounty. Escrow deposit is not verified.');
+  }
   setSuccess(true);
   addToast({ variant: 'success', title: 'Bounty published!', message: 'Your bounty is now live and visible to contributors.' });
📝 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.

Suggested change
await verifyEscrowDeposit({ bounty_id: state.bounty_id, tx_signature: state.tx_signature });
setSuccess(true);
addToast({ variant: 'success', title: 'Bounty published!', message: 'Your bounty is now live and visible to contributors.' });
} catch (e: unknown) {
const result = await verifyEscrowDeposit({ bounty_id: state.bounty_id, tx_signature: state.tx_signature });
if (!result.verified) {
throw new Error(result.error ?? 'Failed to publish bounty. Escrow deposit is not verified.');
}
setSuccess(true);
addToast({ variant: 'success', title: 'Bounty published!', message: 'Your bounty is now live and visible to contributors.' });
} catch (e: unknown) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/bounty/BountyCreateWizard.tsx` around lines 442 -
445, verifyEscrowDeposit is awaited but its return value is ignored, so even
non-verified escrow responses will mark the bounty published; update the success
flow in the async block that calls verifyEscrowDeposit({ bounty_id:
state.bounty_id, tx_signature: state.tx_signature }) to capture its result,
check the result.verified boolean, and only call setSuccess(true) and
addToast(...) when verified is true; if verified is false (or response indicates
failure) then do not set success, instead call addToast with an error variant
and an explanatory message (and optionally set an error state) so the UI
reflects the failed verification.

Comment thread frontend/src/components/ui/Toast.tsx Outdated
Comment on lines +37 to +41
const counter = useRef(0);

const removeToast = useCallback((id: string) => {
setToasts((prev) => prev.filter((t) => t.id !== id));
}, []);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clear auto-dismiss timers on remove/unmount.

Line 50 schedules timers, but they aren’t cleared when a toast is manually dismissed or when the provider unmounts.

Suggested fix
-import React, { createContext, useContext, useState, useCallback, useRef } from 'react';
+import React, { createContext, useContext, useState, useCallback, useRef, useEffect } from 'react';

 export function ToastProvider({ children }: { children: React.ReactNode }) {
   const [toasts, setToasts] = useState<Toast[]>([]);
   const counter = useRef(0);
+  const timers = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());

   const removeToast = useCallback((id: string) => {
+    const timer = timers.current.get(id);
+    if (timer) {
+      clearTimeout(timer);
+      timers.current.delete(id);
+    }
     setToasts((prev) => prev.filter((t) => t.id !== id));
   }, []);

+  useEffect(() => {
+    return () => {
+      timers.current.forEach((t) => clearTimeout(t));
+      timers.current.clear();
+    };
+  }, []);
+
   const addToast = useCallback(
     (toast: Omit<Toast, 'id'>) => {
       const id = `toast-${++counter.current}`;
       const duration = toast.duration ?? 5000;
       setToasts((prev) => [...prev, { ...toast, id }]);

       if (duration > 0) {
-        setTimeout(() => removeToast(id), duration);
+        const t = setTimeout(() => removeToast(id), duration);
+        timers.current.set(id, t);
       }
     },
     [removeToast],
   );

Also applies to: 43-51

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/ui/Toast.tsx` around lines 37 - 41, The auto-dismiss
timers started for toasts are never cleared, so update the implementation to
track timeouts in a ref (replace or supplement counter useRef with a timersRef
Map or Record keyed by toast id), store each timeout id when scheduling, and
call clearTimeout for that id inside removeToast (and remove it from timersRef)
so manual dismissal cancels the timer; also add a cleanup in the provider's
useEffect/unmount to iterate timersRef and clearTimeout all remaining timers.
Ensure you update places that schedule timers to write into timersRef and that
removeToast and the unmount cleanup both clear and delete entries.

…check

- Toast.tsx: Track auto-dismiss timers in ref Map, clear on manual dismiss and unmount
- BountyCreateWizard.tsx: Check verifyEscrowDeposit result before showing success toast
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🏭 Bounty T1: Toast Notification System

1 participant