diff --git a/frontend/src/library/toast/Toast.tsx b/frontend/src/library/toast/Toast.tsx
new file mode 100644
index 0000000..90e69cc
--- /dev/null
+++ b/frontend/src/library/toast/Toast.tsx
@@ -0,0 +1,138 @@
+import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
+import { ToastContext } from './toast-context';
+import './toast.css';
+
+function useTimeout(callback: () => void, duration: number) {
+ const savedCallback = useRef(callback);
+
+ useEffect(() => {
+ savedCallback.current = callback;
+ }, [callback]);
+
+ useEffect(() => {
+ const functionId = setTimeout(() => savedCallback.current(), duration);
+
+ return () => {
+ clearTimeout(functionId);
+ };
+ }, [duration]);
+}
+type toastProperties = {
+ message: string;
+ close: () => void;
+ duration: number;
+ position: string;
+ color: string;
+};
+
+export function Toast({
+ message,
+ close,
+ duration,
+ position,
+ color,
+}: toastProperties) {
+ useTimeout(() => {
+ close();
+ }, duration);
+ return (
+
+
{message}
+
+
+ );
+}
+
+type ToastProviderProperties = {
+ children: React.ReactElement;
+};
+type ToastType = {
+ message: string;
+ id: number;
+ duration: number;
+ position: string;
+ color: string;
+};
+
+export function ToastProvider({ children }: ToastProviderProperties) {
+ const [toasts, setToasts] = useState([]);
+ const [position, setPosition] = useState('top-left');
+ type Options = {
+ message?: string;
+ duration?: number;
+ position?: string;
+ color?: 'info' | 'warning' | 'error' | 'success';
+ };
+ const openToast = useCallback(
+ ({
+ message = '',
+ duration = 5000,
+ position = 'top-center',
+ color = 'info',
+ }: Options = {}) => {
+ const newToast = {
+ message: message,
+ id: Date.now(),
+ duration: duration,
+ position: position,
+ color: color,
+ };
+ setToasts((prevToast) => [...prevToast, newToast]);
+ setPosition(position);
+ },
+ []
+ );
+
+ const closeToast = useCallback((id: number) => {
+ setTimeout(() => {
+ setToasts((prevToasts) =>
+ prevToasts.filter((toast) => toast.id !== id)
+ );
+ }, 300);
+
+ setToasts((toasts) => {
+ return toasts.map((toast) => {
+ if (toast.id === id) {
+ if (toast.position == 'top-left')
+ toast.position = 'fade-out-left';
+ else if (toast.position == 'top-right')
+ toast.position = 'fade-out-right';
+ else if (toast.position == 'top-center')
+ toast.position = 'fade-out-center';
+ }
+ return toast;
+ });
+ });
+ }, []);
+ const contextValue = useMemo(
+ () => ({
+ open: openToast,
+ close: closeToast,
+ }),
+ [openToast, closeToast]
+ );
+ return (
+
+ {children}
+
+ {toasts &&
+ toasts.map((toast) => {
+ return (
+ {
+ closeToast(toast.id);
+ }}
+ duration={toast.duration}
+ position={toast.position}
+ color={toast.color}
+ />
+ );
+ })}
+
+
+ );
+}
diff --git a/frontend/src/library/toast/toast-context.ts b/frontend/src/library/toast/toast-context.ts
new file mode 100644
index 0000000..625bc97
--- /dev/null
+++ b/frontend/src/library/toast/toast-context.ts
@@ -0,0 +1,20 @@
+import { createContext, useContext } from 'react';
+
+type Options = {
+ message?: string;
+ duration?: number;
+ position?: string;
+ color?: 'info' | 'warning' | 'error' | 'success';
+};
+
+type ToastContextValue = {
+ open: (options?: Options) => void;
+ close: (id: number) => void;
+};
+
+export const ToastContext = createContext({
+ open: () => {},
+ close: () => {},
+});
+
+export const useToast = () => useContext(ToastContext);
diff --git a/frontend/src/library/toast/toast.css b/frontend/src/library/toast/toast.css
new file mode 100644
index 0000000..42cf727
--- /dev/null
+++ b/frontend/src/library/toast/toast.css
@@ -0,0 +1,181 @@
+.toasts {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+
+.toast {
+ color: black;
+ border-radius: 5px;
+ padding: 10px 10px;
+ width: 300px;
+ position: relative;
+ display: flex;
+}
+
+.top-right {
+ position: fixed;
+ top: 10px;
+ right: 10px;
+}
+
+.top-left {
+ position: fixed;
+ top: 10px;
+ left: 10px;
+}
+.top-center {
+ position: fixed;
+ top: 10px;
+ left: 38%;
+}
+
+.top-center-animation {
+ animation-name: slideinCenter;
+ animation-duration: 0.35s;
+}
+
+.top-right-animation {
+ animation-name: slideinRight;
+ animation-duration: 0.35s;
+}
+
+.top-left-animation {
+ animation-name: slideinLeft;
+ animation-duration: 0.35s;
+}
+
+@keyframes slideinRight {
+ 0% {
+ transform: translateX(100%);
+ }
+ 60% {
+ transform: translateX(-15%);
+ }
+ 80% {
+ transform: translateX(5%);
+ }
+ 80% {
+ transform: translateX(0);
+ }
+}
+@keyframes slideinCenter {
+ 0% {
+ transform: translateY(-100%);
+ }
+ 60% {
+ transform: translateY(15%);
+ }
+ 80% {
+ transform: translateY(-5%);
+ }
+ 80% {
+ transform: translateY(0);
+ }
+}
+
+@keyframes slideinLeft {
+ 0% {
+ transform: translateX(-100%);
+ }
+ 60% {
+ transform: translateX(15%);
+ }
+ 80% {
+ transform: translateX(-5%);
+ }
+ 80% {
+ transform: translateX(0);
+ }
+}
+
+.fade-out-left-animation {
+ animation-name: fade-out-left;
+ animation-duration: 0.35s;
+}
+
+.fade-out-right-animation {
+ animation-name: fade-out-right;
+ animation-duration: 0.35s;
+}
+
+.fade-out-center-animation {
+ animation-name: fade-out-center;
+ animation-duration: 0.35s;
+}
+
+@keyframes fade-out-left {
+ 0% {
+ transform: translateX(0%);
+ }
+
+ 60% {
+ transform: translateX(-100%);
+ }
+
+ 80% {
+ transform: translateX(-195%);
+ }
+
+ 100% {
+ transform: translateX(-200%);
+ }
+}
+@keyframes fade-out-right {
+ 0% {
+ transform: translateX(0%);
+ }
+
+ 60% {
+ transform: translateX(100%);
+ }
+
+ 80% {
+ transform: translateX(195%);
+ }
+
+ 100% {
+ transform: translateX(200%);
+ }
+}
+
+@keyframes fade-out-center {
+ 0% {
+ transform: translateY(-100%);
+ }
+ 30% {
+ transform: translateY(-300%);
+ }
+ 80% {
+ transform: translateY(-700%);
+ }
+ 100% {
+ transform: translateY(-1000%);
+ }
+}
+
+.info {
+ background-color: cyan;
+}
+
+.success {
+ background-color: #5cb85c;
+}
+
+.error {
+ background-color: #d9534f;
+}
+.warning {
+ background-color: #f0ad4e;
+}
+
+.close-button {
+ position: absolute;
+ right: 0px;
+ top: 0px;
+ padding: 0px 5px;
+ background: none;
+ cursor: pointer;
+ border: transparent;
+ color: black;
+}
diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx
index 12afe2b..a3323d8 100644
--- a/frontend/src/main.tsx
+++ b/frontend/src/main.tsx
@@ -2,9 +2,12 @@ import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import './index.css';
+import { ToastProvider } from './library/toast/Toast.tsx';
ReactDOM.createRoot(document.getElementById('root')!).render(
-
+
+
+
);