Merge backend + frontend #1
@@ -24,6 +24,10 @@ import { AuthContextProvider } from "./AuthContext";
 | 
				
			|||||||
// React router
 | 
					// React router
 | 
				
			||||||
import Router from "./Router";
 | 
					import Router from "./Router";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Toasts
 | 
				
			||||||
 | 
					import Toasts from "./components/Toasts";
 | 
				
			||||||
 | 
					import { ToastContextProvider } from "./ToastContext";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const queryClient = new QueryClient();
 | 
					const queryClient = new QueryClient();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const App = () => {
 | 
					const App = () => {
 | 
				
			||||||
@@ -35,9 +39,12 @@ const App = () => {
 | 
				
			|||||||
            <title>Todo</title>
 | 
					            <title>Todo</title>
 | 
				
			||||||
          </Helmet>
 | 
					          </Helmet>
 | 
				
			||||||
          <ThemeProvider>
 | 
					          <ThemeProvider>
 | 
				
			||||||
            <Container maxWidth="md">
 | 
					            <ToastContextProvider>
 | 
				
			||||||
              <Router />
 | 
					              <Container maxWidth="md">
 | 
				
			||||||
            </Container>
 | 
					                <Toasts />
 | 
				
			||||||
 | 
					                <Router />
 | 
				
			||||||
 | 
					              </Container>
 | 
				
			||||||
 | 
					            </ToastContextProvider>
 | 
				
			||||||
          </ThemeProvider>
 | 
					          </ThemeProvider>
 | 
				
			||||||
        </HelmetProvider>
 | 
					        </HelmetProvider>
 | 
				
			||||||
      </AuthContextProvider>
 | 
					      </AuthContextProvider>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										49
									
								
								frontend/src/ToastContext.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								frontend/src/ToastContext.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					import { AlertColor } from "@mui/material/Alert";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import React, { createContext, useState } from "react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface IToast {
 | 
				
			||||||
 | 
					  category?: AlertColor;
 | 
				
			||||||
 | 
					  key: number;
 | 
				
			||||||
 | 
					  message: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IToastContext {
 | 
				
			||||||
 | 
					  addToast: (message: string, category: AlertColor | undefined) => void;
 | 
				
			||||||
 | 
					  setToasts: React.Dispatch<React.SetStateAction<IToast[]>>;
 | 
				
			||||||
 | 
					  toasts: IToast[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const ToastContext = createContext<IToastContext>({
 | 
				
			||||||
 | 
					  addToast: () => {},
 | 
				
			||||||
 | 
					  setToasts: () => {},
 | 
				
			||||||
 | 
					  toasts: [],
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IProps {
 | 
				
			||||||
 | 
					  children?: React.ReactNode;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const ToastContextProvider = ({ children }: IProps) => {
 | 
				
			||||||
 | 
					  const [toasts, setToasts] = useState<IToast[]>([]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const addToast = (
 | 
				
			||||||
 | 
					    message: string,
 | 
				
			||||||
 | 
					    category: AlertColor | undefined = undefined,
 | 
				
			||||||
 | 
					  ) => {
 | 
				
			||||||
 | 
					    setToasts((prev) => [
 | 
				
			||||||
 | 
					      ...prev,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        category,
 | 
				
			||||||
 | 
					        key: new Date().getTime(),
 | 
				
			||||||
 | 
					        message,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <ToastContext.Provider value={{ addToast, setToasts, toasts }}>
 | 
				
			||||||
 | 
					      {children}
 | 
				
			||||||
 | 
					    </ToastContext.Provider>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -8,7 +8,7 @@ interface IProps {
 | 
				
			|||||||
const Title = ({ title }: IProps) => (
 | 
					const Title = ({ title }: IProps) => (
 | 
				
			||||||
  <>
 | 
					  <>
 | 
				
			||||||
    <Helmet>
 | 
					    <Helmet>
 | 
				
			||||||
      <title>Tozo | {title}</title>
 | 
					      <title>Todo | {title}</title>
 | 
				
			||||||
    </Helmet>
 | 
					    </Helmet>
 | 
				
			||||||
    <Typography component="h1" variant="h5">
 | 
					    <Typography component="h1" variant="h5">
 | 
				
			||||||
      {title}
 | 
					      {title}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										47
									
								
								frontend/src/components/Toasts.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								frontend/src/components/Toasts.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					import Alert from "@mui/material/Alert";
 | 
				
			||||||
 | 
					import Snackbar from "@mui/material/Snackbar";
 | 
				
			||||||
 | 
					import React, { useContext, useEffect, useState } from "react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ToastContext, IToast } from "src/ToastContext";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Toasts = () => {
 | 
				
			||||||
 | 
					  const { toasts, setToasts } = useContext(ToastContext);
 | 
				
			||||||
 | 
					  const [open, setOpen] = useState(false);
 | 
				
			||||||
 | 
					  const [currentToast, setCurrentToast] = useState<IToast | undefined>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (!open && toasts.length) {
 | 
				
			||||||
 | 
					      setCurrentToast(toasts[0]);
 | 
				
			||||||
 | 
					      setToasts((prev) => prev.slice(1));
 | 
				
			||||||
 | 
					      setOpen(true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, [open, setCurrentToast, setOpen, setToasts, toasts]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const onClose = (event?: React.SyntheticEvent | Event, reason?: string) => {
 | 
				
			||||||
 | 
					    if (reason !== "clickaway") {
 | 
				
			||||||
 | 
					      setOpen(false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Snackbar
 | 
				
			||||||
 | 
					      anchorOrigin={{
 | 
				
			||||||
 | 
					        horizontal: "center",
 | 
				
			||||||
 | 
					        vertical: "top",
 | 
				
			||||||
 | 
					      }}
 | 
				
			||||||
 | 
					      autoHideDuration={6000}
 | 
				
			||||||
 | 
					      key={currentToast?.key}
 | 
				
			||||||
 | 
					      onClose={onClose}
 | 
				
			||||||
 | 
					      open={open}
 | 
				
			||||||
 | 
					      TransitionProps={{
 | 
				
			||||||
 | 
					        onExited: () => setCurrentToast(undefined),
 | 
				
			||||||
 | 
					      }}
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <Alert onClose={onClose} severity={currentToast?.category}>
 | 
				
			||||||
 | 
					        {currentToast?.message}
 | 
				
			||||||
 | 
					      </Alert>
 | 
				
			||||||
 | 
					    </Snackbar>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Toasts;
 | 
				
			||||||
		Reference in New Issue
	
	Block a user