# Notification Toast System Documentation
## Overview
The Adopt-a-Street frontend now includes a comprehensive notification toast system that integrates with Socket.IO for real-time updates. The system uses `react-toastify` with custom styling that matches the Bootstrap theme.
## Features
- **Real-time notifications** via Socket.IO integration
- **Four toast types**: success, error, info, warning
- **Auto-dismiss** after 5 seconds (configurable)
- **Dismissible** by clicking or using the close button
- **Mobile responsive** with optimized positioning
- **Duplicate prevention** using toast IDs
- **Custom styling** matching Bootstrap theme
- **Accessibility** compliant with ARIA attributes
## Components
### NotificationProvider
Located at: `frontend/src/context/NotificationProvider.js`
The `NotificationProvider` component automatically listens to Socket.IO events and displays appropriate toast notifications. It must be wrapped within both `AuthProvider` and `SocketProvider`.
### Custom Styles
Located at: `frontend/src/styles/toastStyles.css`
Custom CSS that overrides react-toastify defaults to match the Bootstrap theme, including:
- Bootstrap color scheme (success green, error red, warning yellow, info blue)
- Responsive mobile layout
- Custom animations
- Dark mode support
## Setup
The notification system is already integrated into `App.js`:
```javascript
{/* Your routes */}
```
## Usage
### Method 1: Using the notify utility (Recommended)
```javascript
import { notify } from "../context/NotificationProvider";
// Success notification
notify.success("Operation completed successfully!");
// Error notification
notify.error("Something went wrong!");
// Info notification
notify.info("Here's some information");
// Warning notification
notify.warning("Please be careful!");
// With custom options
notify.success("Data saved!", {
autoClose: 3000,
position: "bottom-right",
});
// Dismiss specific toast
notify.dismiss("toast-id");
// Dismiss all toasts
notify.dismissAll();
```
### Method 2: Using toast directly
```javascript
import { toast } from "react-toastify";
// Basic usage
toast.success("Success message");
toast.error("Error message");
toast.info("Info message");
toast.warning("Warning message");
// Prevent duplicates with toast ID
toast.success("Message", {
toastId: "unique-id",
});
// Custom content
toast.success(
Title
Message
Details
);
```
### Method 3: Promise-based toasts
```javascript
const myPromise = fetch("/api/data");
toast.promise(myPromise, {
pending: "Loading...",
success: "Success!",
error: "Failed!",
});
```
### Method 4: Loading toasts
```javascript
const toastId = toast.loading("Processing...");
// Later, update the toast
toast.update(toastId, {
render: "Completed!",
type: "success",
isLoading: false,
autoClose: 5000,
});
```
## Socket.IO Events
The `NotificationProvider` automatically handles these Socket.IO events:
### Connection Events
- `connect` - Shows success toast when connected
- `disconnect` - Shows error/warning toast when disconnected
- `reconnect` - Shows success toast when reconnected
- `reconnect_error` - Shows error toast if reconnection fails
### Event Updates (`eventUpdate`)
- `new_event` - New event created
- `participants_updated` - Event participants changed
- `event_updated` - Event details updated
- `event_deleted` - Event cancelled
### Task Updates (`taskUpdate`)
- `new_task` - New task available
- `task_completed` - Task completed by another user
- `task_updated` - Task details updated
- `task_deleted` - Task removed
### Street Updates (`streetUpdate`)
- `street_adopted` - Street adopted by a user
- `street_unadopted` - Street available for adoption
### Achievements
- `achievementUnlocked` - User unlocked an achievement
- `badgeUnlocked` - User earned a badge
### Social Updates
- `newPost` - New post created
- `newComment` - New comment on a post
### Generic Notification
- `notification` - Fallback for any custom notification with `type` and `message`
## Triggering Toasts from Components
### Example: Form Submission
```javascript
import React, { useState } from "react";
import { notify } from "../context/NotificationProvider";
import axios from "axios";
const MyComponent = () => {
const [loading, setLoading] = useState(false);
const handleSubmit = async (data) => {
try {
setLoading(true);
await axios.post("/api/endpoint", data);
notify.success("Data submitted successfully!");
} catch (error) {
notify.error(error.response?.data?.msg || "Failed to submit");
} finally {
setLoading(false);
}
};
return (
);
};
```
### Example: Real-time Updates
The `NotificationProvider` automatically handles Socket.IO events, but you can also trigger custom notifications:
```javascript
import { useContext } from "react";
import { SocketContext } from "../context/SocketContext";
import { notify } from "../context/NotificationProvider";
const MyComponent = () => {
const { emit } = useContext(SocketContext);
const sendNotification = () => {
// This will be handled by the NotificationProvider
emit("notification", {
type: "success",
message: "Custom notification message",
});
};
return ;
};
```
## Configuration Options
### ToastContainer Options
Configured in `App.js`:
```javascript
```
### Individual Toast Options
```javascript
toast.success("Message", {
position: "top-right",
autoClose: 5000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
toastId: "unique-id", // Prevent duplicates
onOpen: () => {}, // Callback on open
onClose: () => {}, // Callback on close
transition: Bounce, // Custom transition
className: "custom-class", // Custom CSS class
bodyClassName: "body", // Custom body class
progressClassName: "bar", // Custom progress bar class
closeButton: , // Custom close button
});
```
## Mobile Responsiveness
The toast system is fully responsive:
- **Desktop**: Positioned in top-right corner (configurable)
- **Mobile (≤480px)**: Full-width toasts at the top of the screen
- **Touch-friendly**: Large touch targets for dismissing
- **Smooth animations**: Optimized for mobile performance
## Accessibility
- ARIA attributes for screen readers
- Keyboard navigation support
- Focus management
- Semantic HTML structure
- Color contrast compliance
## Best Practices
1. **Prevent duplicate toasts**: Always use `toastId` for repeated actions
2. **Keep messages concise**: Aim for 1-2 sentences
3. **Use appropriate types**:
- `success` for completed actions
- `error` for failures
- `warning` for cautions
- `info` for neutral information
4. **Don't spam**: Limit notifications to important events
5. **Provide context**: Include relevant details (e.g., "Task 'Clean Street' completed")
6. **Auto-dismiss**: Use appropriate auto-close times (3-7 seconds)
7. **Persistent toasts**: Set `autoClose: false` for critical errors
## Styling Customization
To customize toast styles, edit `frontend/src/styles/toastStyles.css`:
```css
/* Change colors */
:root {
--toastify-color-success: #28a745;
--toastify-color-error: #dc3545;
--toastify-color-warning: #ffc107;
--toastify-color-info: #17a2b8;
}
/* Custom toast style */
.Toastify__toast--success {
border-left: 4px solid var(--toastify-color-success);
}
/* Custom animations */
@keyframes customAnimation {
/* your animation */
}
```
## Backend Integration
To trigger notifications from the backend, emit Socket.IO events:
```javascript
// In backend route
const io = req.app.get("io");
// Notify all connected users
io.emit("notification", {
type: "info",
message: "System maintenance in 5 minutes",
});
// Notify specific user
io.to(userSocketId).emit("achievementUnlocked", {
badge: {
name: "First Adoption",
description: "Adopted your first street!",
},
});
// Notify event participants
io.to(`event_${eventId}`).emit("eventUpdate", {
type: "participants_updated",
eventId,
participants: updatedParticipants,
});
```
## Troubleshooting
### Toasts not appearing
1. Check that `ToastContainer` is in `App.js`
2. Verify `NotificationProvider` is wrapping your app
3. Check browser console for errors
4. Ensure Socket.IO is connected
### Duplicate toasts
1. Add `toastId` to prevent duplicates
2. Check if multiple components are triggering the same event
3. Use `toast.isActive(toastId)` to check before showing
### Styling issues
1. Verify `toastStyles.css` is imported in `App.js`
2. Check for CSS conflicts with Bootstrap
3. Inspect element to verify classes are applied
4. Clear browser cache
## Testing
Example test for components using notifications:
```javascript
import { render, screen, waitFor } from "@testing-library/react";
import { toast } from "react-toastify";
import MyComponent from "./MyComponent";
jest.mock("react-toastify", () => ({
toast: {
success: jest.fn(),
error: jest.fn(),
},
}));
test("shows success toast on submit", async () => {
render();
// Trigger action
fireEvent.click(screen.getByText("Submit"));
await waitFor(() => {
expect(toast.success).toHaveBeenCalledWith("Success message");
});
});
```
## Resources
- [react-toastify Documentation](https://fkhadra.github.io/react-toastify/)
- [Socket.IO Documentation](https://socket.io/docs/)
- [Bootstrap Colors](https://getbootstrap.com/docs/5.0/utilities/colors/)
## Support
For issues or questions:
1. Check this documentation
2. Review `notificationExamples.js` for usage examples
3. Check browser console for errors
4. Review Socket.IO connection status