Skip to content

Commit 8118fa3

Browse files
batteryspecialQinkai Li
andauthored
Add API toast service for ARO and MCC (#599)
# Purpose Closes #570. # New Changes - A standardized notification service which responds based on the success or failure of an API call. The service is very flexible and can be called in a variety of situations. A toast will emerge from the top-left, and will last for five seconds. If you hover over it, the toast will not dissapear. - Uses `react-toastify`, so be sure to install that. - In ARO's main.tsx, I added two buttons that you can play around with to see how the toasts appear. Please remove them for future updates. - Added .DS_Store to .gitignore. # How to Use the Service ## Usage #### Import the Service ```TypeScript import toastService from '../services/Toast.service.ts'; ``` #### Call the Service The service should be used within logic that handles asynchronous operations, such as in a try...catch...finally block after an API call. On Success, call ```toastService.success()``` with a confirmation message. On Error, call ```toastService.error()``` with an informative error message. ### Example Implementation for a Form Place a single <ToastContainer /> at the application root and trigger toasts from the API service layer. ```TypeScript const handleFormSubmit = async (formData) => { try { await apiClient.saveData(formData); toastService.success("Data saved successfully!"); } catch (err: any) { const message = err.response?.data?.message || "An unexpected error occurred."; toastService.error(`Failed to save: ${message}`); } }; ``` ## Example in App.tsx Try running the following code added to App.tsx. The dots ```...``` represents the rest of the code. ```TypeScript ... import { ToastContainer } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; import './styles/toasts.css'; import toastService from './services/Toast.service.ts' ... function App() { ... const showSuccess = () => { toastService.success("This is a success message for testing!"); }; const showError = () => { toastService.error("This is an error message for testing."); }; return ( ... {/* --- TEST BUTTONS --- */} <div className="w-1/4 flex flex-row mt-[10%] ms-[34.5%]"> <h3>Toast Test Controls</h3> <button onClick={showSuccess} className="bg-lime-400 w-1/2 cursor-pointer">Success</button> <button onClick={showError} className="bg-red-400 btn w-1/2 cursor-pointer">Error</button> </div> <ToastContainer /> {/* --- END --- */} ... ) } ``` Clicking on the buttons should display the error messages respectively. # Testing Explain tests that you ran to verify code functionality. - [x] I have tested this PR by running the ARO website by adding buttons which call the toasts, and they worked as expected. - [x] I have tested this PR by running the MCC website by adding buttons which call the toasts, and they worked as expected. - [x] I have included a video of the tests performed below. https://github.com/user-attachments/assets/9fc79a4e-6791-4258-ae7b-3085ff06bf75 # Outstanding Changes Because this is meant to be a standardized service, I tried making the service with generality in mind. You can use this for any API call, from backend to frontend responses (although it was designed for frontend). --------- Co-authored-by: Qinkai Li <q95li@uwaterloo.ca>
1 parent 2056454 commit 8118fa3

File tree

8 files changed

+157
-4
lines changed

8 files changed

+157
-4
lines changed

gs/frontend/aro/package-lock.json

Lines changed: 44 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gs/frontend/aro/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"react-dom": "^19.1.1",
2121
"react-leaflet": "^5.0.0",
2222
"react-router-dom": "^7.9.2",
23+
"react-toastify": "^11.0.5",
2324
"tailwindcss": "^4.1.13"
2425
},
2526
"devDependencies": {

gs/frontend/aro/src/App.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { Route, Routes } from "react-router-dom";
2+
import { ToastContainer } from 'react-toastify';
3+
import 'react-toastify/dist/ReactToastify.css';
24
import Nav from "./components/Nav";
35
import Background from "./components/Background";
46
import NewRequestForm from "./components/new-request/new-request-form.tsx";
@@ -23,6 +25,7 @@ function App() {
2325
<Route path="/login" element={<Login />} /> */}
2426
{<Route path="/new-request" element={<NewRequestForm />} />}
2527
</Routes>
28+
<ToastContainer />
2629
</>
2730
);
2831
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { toast, type ToastOptions } from "react-toastify";
2+
3+
const baseToastConfig: ToastOptions = {
4+
position: "top-right",
5+
autoClose: 4900,
6+
hideProgressBar: false,
7+
closeOnClick: true,
8+
pauseOnHover: true,
9+
draggable: true,
10+
progress: undefined,
11+
theme: "dark",
12+
};
13+
14+
/**
15+
* Displays a success toast notification.
16+
* Uses Tailwind classes directly for styling.
17+
*/
18+
export const success = (message: string): void => {
19+
toast.success(message, {
20+
...baseToastConfig,
21+
className:
22+
"bg-black/75 border border-green-500 text-green-100 rounded-md shadow-md text-sm font-medium",
23+
progressClassName: "bg-green-500",
24+
});
25+
};
26+
27+
/**
28+
* Displays an error toast notification.
29+
* Uses Tailwind classes directly for styling.
30+
*/
31+
export const error = (message: string): void => {
32+
toast.error(message, {
33+
...baseToastConfig,
34+
className:
35+
"bg-black/75 border border-red-500 text-red-100 rounded-md shadow-md text-sm font-medium",
36+
progressClassName: "bg-red-500",
37+
});
38+
};
39+
40+
const toastService = {
41+
success,
42+
error,
43+
};
44+
45+
export default toastService;

gs/frontend/mcc/package-lock.json

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gs/frontend/mcc/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,14 @@
2222
"@radix-ui/react-separator": "^1.1.7",
2323
"@radix-ui/react-slot": "^1.2.3",
2424
"@tailwindcss/vite": "^4.1.13",
25+
"@tanstack/react-table": "^8.21.3",
2526
"class-variance-authority": "^0.7.1",
2627
"clsx": "^2.1.1",
2728
"lucide-react": "^0.544.0",
28-
"@tanstack/react-table": "^8.21.3",
2929
"react": "^19.1.1",
3030
"react-dom": "^19.1.1",
3131
"react-router-dom": "^7.8.2",
32+
"react-toastify": "^11.0.5",
3233
"tailwind-merge": "^3.3.1",
3334
"tailwindcss": "^4.1.13"
3435
},

gs/frontend/mcc/src/App.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { Routes, Route } from "react-router-dom";
2+
import { ToastContainer } from 'react-toastify';
3+
import 'react-toastify/dist/ReactToastify.css';
24
import Nav from "./components/Nav";
35
import Background from "./components/Background";
46
import Commands from "./pages/Command/Commands";
@@ -23,6 +25,7 @@ function App() {
2325
<Route path="/aro-requests" element={<LiveSession />} />
2426
<Route path="/login" element={<Login />} />
2527
</Routes>
28+
<ToastContainer />
2629
</>
2730
);
2831
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { toast, type ToastOptions } from "react-toastify";
2+
3+
const baseToastConfig: ToastOptions = {
4+
position: "top-right",
5+
autoClose: 4900,
6+
hideProgressBar: false,
7+
closeOnClick: true,
8+
pauseOnHover: true,
9+
draggable: true,
10+
progress: undefined,
11+
theme: "dark",
12+
};
13+
14+
/**
15+
* Displays a success toast notification.
16+
* Uses Tailwind classes directly for styling.
17+
*/
18+
export const success = (message: string): void => {
19+
toast.success(message, {
20+
...baseToastConfig,
21+
className:
22+
"bg-black/75 border border-green-500 text-green-100 rounded-md shadow-md text-sm font-medium",
23+
progressClassName: "bg-green-500",
24+
});
25+
};
26+
27+
/**
28+
* Displays an error toast notification.
29+
* Uses Tailwind classes directly for styling.
30+
*/
31+
export const error = (message: string): void => {
32+
toast.error(message, {
33+
...baseToastConfig,
34+
className:
35+
"bg-black/75 border border-red-500 text-red-100 rounded-md shadow-md text-sm font-medium",
36+
progressClassName: "bg-red-500",
37+
});
38+
};
39+
40+
const toastService = {
41+
success,
42+
error,
43+
};
44+
45+
export default toastService;

0 commit comments

Comments
 (0)