Skip to content
32 changes: 32 additions & 0 deletions ui/src/Components/notification/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { NOTIFICATION_TEXT_COLOR } from "../../Constant/constant";
import { useNotificationContext } from "../../Context/NotificationContext";

const NotificationContainer = () => {
const { notificationQueue } = useNotificationContext();

return (
<div
data-testid="notificationcontainer"
className="flex justify-center items-center flex-col-reverse fixed top-4 w-max gap-2 transition-[height] duration-300 ease-[cubic-bezier(0.165, 0.84, 0.44, 1)]"
//this piece of code will increase or decrease the height of the wrapper accr to the no. of notifications present
style={{ height: `${notificationQueue.length * 2.5}rem` }}
>
{notificationQueue.map((notification, index) => (
<div
key={index}
data-testid="notificationchild"
className="flex justify-start items-center min-w-full w-max bg-white font-['Helvetica', 'sans-serif'] font-medium text-base capitalize rounded px-2.5 py-1.5"
style={{
backgroundColor: `${
NOTIFICATION_TEXT_COLOR[notification.type.toUpperCase()]
}`,
}}
>
<h3 role={"alert"}>{notification.message}</h3>
</div>
))}
</div>
);
};

export default NotificationContainer;
16 changes: 12 additions & 4 deletions ui/src/Constant/constant.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
export const FOOTER = {
"COPYRIGHT": "Copyright 2022-2023",
"RDS_WEBSITE": "RDS Website",
"DISCORD_SERVER":"Discord server"
}
COPYRIGHT: "Copyright 2022-2023",
RDS_WEBSITE: "RDS Website",
DISCORD_SERVER: "Discord server",
};

export const NOTIFICATION_TEXT_COLOR = {
SUCCESS: "rgb(95, 214, 95)",
WARNING: "rgb(238, 241, 41)",
ERROR: "rgb(253, 81, 81)",
};

export const NOTIFICATION_TIMEOUT = 2000;
38 changes: 38 additions & 0 deletions ui/src/Context/NotificationContext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { createContext, useContext, useState } from "react";
import { NOTIFICATION_TIMEOUT } from "../Constant/constant";

export const NotificationContext = createContext({
createNotifcation() {},
notificationQueue: [],
});

export const useNotificationContext = () => useContext(NotificationContext);

const NotificationProvider = ({ children }) => {
const [notificationQueue, setNotificationQueue] = useState([]);

/**
*
* @param {type : string, message : string} notificationContent
*/
const createNotifcation = (notificationContent) => {
setNotificationQueue((prev) => [...prev, notificationContent]);

setTimeout(() => {
setNotificationQueue((prev) => {
let [, ...data] = prev;
return data;
});
}, NOTIFICATION_TIMEOUT);
};

return (
<NotificationContext.Provider
value={{ createNotifcation, notificationQueue }}
>
{children}
</NotificationContext.Provider>
);
};

export default NotificationProvider;
17 changes: 10 additions & 7 deletions ui/src/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import NotificationProvider from "./Context/NotificationContext";

const root = ReactDOM.createRoot(document.getElementById('root'));
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
<NotificationProvider>
<App />
</NotificationProvider>
</React.StrictMode>
);

Expand Down
82 changes: 82 additions & 0 deletions ui/src/test/Notification.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { render, screen, waitFor } from "@testing-library/react";
import "@testing-library/jest-dom";

import NotificationContainer from "../Components/notification";
import {
NOTIFICATION_TIMEOUT,
NOTIFICATION_TEXT_COLOR,
} from "../Constant/constant";
import { NotificationContext } from "../Context/NotificationContext";
import React from "react";

const customRender = (ui, { value, ...options }) =>
render(
<NotificationContext.Provider value={value}>
{ui}
</NotificationContext.Provider>,
options
);

let notificationContent = { message: "Hello World", type: "success" };

let mockNotificationContext = {};

beforeEach(() => {
mockNotificationContext = {
notificationQueue: [],
createNotifcation(data) {
this.notificationQueue = [data, ...this.notificationQueue];

setTimeout(() => {
let [, ...data] = this.notificationQueue;
this.notificationQueue = data;
}, NOTIFICATION_TIMEOUT);
},
};
});

afterEach(() => {
mockNotificationContext = {};
});

describe("Notification Component", () => {
it("should check if the notification wrapper renders", async () => {
render(<NotificationContainer />);
expect(screen.getByTestId("notificationcontainer")).toBeInTheDocument();
});

it("should check the function cycle of the notification component", async () => {
mockNotificationContext.createNotifcation(notificationContent);
customRender(<NotificationContainer />, { value: mockNotificationContext });

let notificationChild = await waitFor(() =>
screen.getByTestId("notificationchild")
);

expect(notificationChild).toHaveTextContent(notificationContent.message);
});

it("should check if the color rendered is the same one as passed", async () => {
mockNotificationContext.createNotifcation(notificationContent);
customRender(<NotificationContainer />, { value: mockNotificationContext });

let notificationChild = await waitFor(() =>
screen.getByTestId("notificationchild")
);
expect(notificationChild.style.backgroundColor).toEqual(
NOTIFICATION_TEXT_COLOR[notificationContent.type.toUpperCase()]
);
});
it("should check if the heading rendered as h3", async () => {
mockNotificationContext.createNotifcation(notificationContent);
customRender(<NotificationContainer />, { value: mockNotificationContext });

let notificationChild = await waitFor(() =>
screen.getByTestId("notificationchild")
);
expect(screen.getByRole("alert").nodeName).toEqual('H3')
expect(screen.getByRole("alert")).toHaveTextContent(
notificationContent.message
);
});
});