Merge backend + frontend #1
							
								
								
									
										73
									
								
								frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										73
									
								
								frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -15,6 +15,7 @@
 | 
				
			|||||||
        "@mui/lab": "^5.0.0-alpha.91",
 | 
					        "@mui/lab": "^5.0.0-alpha.91",
 | 
				
			||||||
        "@mui/material": "^5.9.1",
 | 
					        "@mui/material": "^5.9.1",
 | 
				
			||||||
        "@mui/x-date-pickers": "^5.0.0-beta.2",
 | 
					        "@mui/x-date-pickers": "^5.0.0-beta.2",
 | 
				
			||||||
 | 
					        "@tanstack/react-query": "^4.33.0",
 | 
				
			||||||
        "@testing-library/jest-dom": "^5.16.4",
 | 
					        "@testing-library/jest-dom": "^5.16.4",
 | 
				
			||||||
        "@testing-library/react": "^13.3.0",
 | 
					        "@testing-library/react": "^13.3.0",
 | 
				
			||||||
        "@testing-library/user-event": "^13.5.0",
 | 
					        "@testing-library/user-event": "^13.5.0",
 | 
				
			||||||
@@ -22,6 +23,7 @@
 | 
				
			|||||||
        "@types/node": "^16.11.45",
 | 
					        "@types/node": "^16.11.45",
 | 
				
			||||||
        "@types/react": "^18.0.15",
 | 
					        "@types/react": "^18.0.15",
 | 
				
			||||||
        "@types/react-dom": "^18.0.6",
 | 
					        "@types/react-dom": "^18.0.6",
 | 
				
			||||||
 | 
					        "axios": "^1.5.0",
 | 
				
			||||||
        "date-fns": "^2.29.1",
 | 
					        "date-fns": "^2.29.1",
 | 
				
			||||||
        "formik": "^2.2.9",
 | 
					        "formik": "^2.2.9",
 | 
				
			||||||
        "react": "^18.2.0",
 | 
					        "react": "^18.2.0",
 | 
				
			||||||
@@ -3953,6 +3955,41 @@
 | 
				
			|||||||
        "url": "https://github.com/sponsors/gregberge"
 | 
					        "url": "https://github.com/sponsors/gregberge"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@tanstack/query-core": {
 | 
				
			||||||
 | 
					      "version": "4.33.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.33.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-qYu73ptvnzRh6se2nyBIDHGBQvPY1XXl3yR769B7B6mIDD7s+EZhdlWHQ67JI6UOTFRaI7wupnTnwJ3gE0Mr/g==",
 | 
				
			||||||
 | 
					      "funding": {
 | 
				
			||||||
 | 
					        "type": "github",
 | 
				
			||||||
 | 
					        "url": "https://github.com/sponsors/tannerlinsley"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@tanstack/react-query": {
 | 
				
			||||||
 | 
					      "version": "4.33.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.33.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-97nGbmDK0/m0B86BdiXzx3EW9RcDYKpnyL2+WwyuLHEgpfThYAnXFaMMmnTDuAO4bQJXEhflumIEUfKmP7ESGA==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@tanstack/query-core": "4.33.0",
 | 
				
			||||||
 | 
					        "use-sync-external-store": "^1.2.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "funding": {
 | 
				
			||||||
 | 
					        "type": "github",
 | 
				
			||||||
 | 
					        "url": "https://github.com/sponsors/tannerlinsley"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
 | 
				
			||||||
 | 
					        "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0",
 | 
				
			||||||
 | 
					        "react-native": "*"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependenciesMeta": {
 | 
				
			||||||
 | 
					        "react-dom": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "react-native": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/@testing-library/dom": {
 | 
					    "node_modules/@testing-library/dom": {
 | 
				
			||||||
      "version": "9.3.1",
 | 
					      "version": "9.3.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.1.tgz",
 | 
				
			||||||
@@ -5379,6 +5416,29 @@
 | 
				
			|||||||
        "node": ">=4"
 | 
					        "node": ">=4"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/axios": {
 | 
				
			||||||
 | 
					      "version": "1.5.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "follow-redirects": "^1.15.0",
 | 
				
			||||||
 | 
					        "form-data": "^4.0.0",
 | 
				
			||||||
 | 
					        "proxy-from-env": "^1.1.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/axios/node_modules/form-data": {
 | 
				
			||||||
 | 
					      "version": "4.0.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "asynckit": "^0.4.0",
 | 
				
			||||||
 | 
					        "combined-stream": "^1.0.8",
 | 
				
			||||||
 | 
					        "mime-types": "^2.1.12"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">= 6"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/axobject-query": {
 | 
					    "node_modules/axobject-query": {
 | 
				
			||||||
      "version": "3.2.1",
 | 
					      "version": "3.2.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz",
 | 
				
			||||||
@@ -13438,6 +13498,11 @@
 | 
				
			|||||||
        "node": ">= 0.10"
 | 
					        "node": ">= 0.10"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/proxy-from-env": {
 | 
				
			||||||
 | 
					      "version": "1.1.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/psl": {
 | 
					    "node_modules/psl": {
 | 
				
			||||||
      "version": "1.9.0",
 | 
					      "version": "1.9.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
 | 
				
			||||||
@@ -15914,6 +15979,14 @@
 | 
				
			|||||||
        "requires-port": "^1.0.0"
 | 
					        "requires-port": "^1.0.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/use-sync-external-store": {
 | 
				
			||||||
 | 
					      "version": "1.2.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/util-deprecate": {
 | 
					    "node_modules/util-deprecate": {
 | 
				
			||||||
      "version": "1.0.2",
 | 
					      "version": "1.0.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@
 | 
				
			|||||||
    "@mui/lab": "^5.0.0-alpha.91",
 | 
					    "@mui/lab": "^5.0.0-alpha.91",
 | 
				
			||||||
    "@mui/material": "^5.9.1",
 | 
					    "@mui/material": "^5.9.1",
 | 
				
			||||||
    "@mui/x-date-pickers": "^5.0.0-beta.2",
 | 
					    "@mui/x-date-pickers": "^5.0.0-beta.2",
 | 
				
			||||||
 | 
					    "@tanstack/react-query": "^4.33.0",
 | 
				
			||||||
    "@testing-library/jest-dom": "^5.16.4",
 | 
					    "@testing-library/jest-dom": "^5.16.4",
 | 
				
			||||||
    "@testing-library/react": "^13.3.0",
 | 
					    "@testing-library/react": "^13.3.0",
 | 
				
			||||||
    "@testing-library/user-event": "^13.5.0",
 | 
					    "@testing-library/user-event": "^13.5.0",
 | 
				
			||||||
@@ -17,6 +18,7 @@
 | 
				
			|||||||
    "@types/node": "^16.11.45",
 | 
					    "@types/node": "^16.11.45",
 | 
				
			||||||
    "@types/react": "^18.0.15",
 | 
					    "@types/react": "^18.0.15",
 | 
				
			||||||
    "@types/react-dom": "^18.0.6",
 | 
					    "@types/react-dom": "^18.0.6",
 | 
				
			||||||
 | 
					    "axios": "^1.5.0",
 | 
				
			||||||
    "date-fns": "^2.29.1",
 | 
					    "date-fns": "^2.29.1",
 | 
				
			||||||
    "formik": "^2.2.9",
 | 
					    "formik": "^2.2.9",
 | 
				
			||||||
    "react": "^18.2.0",
 | 
					    "react": "^18.2.0",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,8 @@
 | 
				
			|||||||
import React from "react";
 | 
					import React from "react";
 | 
				
			||||||
import "./App.css";
 | 
					import "./App.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Roboto font and its weights
 | 
					// Roboto font and its weights
 | 
				
			||||||
import "@fontsource/roboto/300.css";
 | 
					import "@fontsource/roboto/300.css";
 | 
				
			||||||
import "@fontsource/roboto/400.css";
 | 
					import "@fontsource/roboto/400.css";
 | 
				
			||||||
@@ -22,21 +24,25 @@ import { AuthContextProvider } from "./AuthContext";
 | 
				
			|||||||
// React router
 | 
					// React router
 | 
				
			||||||
import Router from "./Router";
 | 
					import Router from "./Router";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function App() {
 | 
					const queryClient = new QueryClient();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const App = () => {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <AuthContextProvider>
 | 
					    <QueryClientProvider client={queryClient}>
 | 
				
			||||||
      <HelmetProvider>
 | 
					      <AuthContextProvider>
 | 
				
			||||||
        <Helmet>
 | 
					        <HelmetProvider>
 | 
				
			||||||
          <title>Todo</title>
 | 
					          <Helmet>
 | 
				
			||||||
        </Helmet>
 | 
					            <title>Todo</title>
 | 
				
			||||||
        <ThemeProvider>
 | 
					          </Helmet>
 | 
				
			||||||
          <Container maxWidth="md">
 | 
					          <ThemeProvider>
 | 
				
			||||||
            <Router />
 | 
					            <Container maxWidth="md">
 | 
				
			||||||
          </Container>
 | 
					              <Router />
 | 
				
			||||||
        </ThemeProvider>
 | 
					            </Container>
 | 
				
			||||||
      </HelmetProvider>
 | 
					          </ThemeProvider>
 | 
				
			||||||
    </AuthContextProvider>
 | 
					        </HelmetProvider>
 | 
				
			||||||
 | 
					      </AuthContextProvider>
 | 
				
			||||||
 | 
					    </QueryClientProvider>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default App;
 | 
					export default App;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										80
									
								
								frontend/src/query.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								frontend/src/query.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,80 @@
 | 
				
			|||||||
 | 
					import axios, { AxiosError } from "axios";
 | 
				
			||||||
 | 
					import { useContext } from "react";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  MutationFunction,
 | 
				
			||||||
 | 
					  QueryFunction,
 | 
				
			||||||
 | 
					  QueryFunctionContext,
 | 
				
			||||||
 | 
					  QueryKey,
 | 
				
			||||||
 | 
					  useMutation as useReactMutation,
 | 
				
			||||||
 | 
					  UseMutationOptions,
 | 
				
			||||||
 | 
					  UseMutationResult,
 | 
				
			||||||
 | 
					  useQuery as useReactQuery,
 | 
				
			||||||
 | 
					  UseQueryOptions,
 | 
				
			||||||
 | 
					  UseQueryResult,
 | 
				
			||||||
 | 
					} from "@tanstack/react-query";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { AuthContext } from "src/AuthContext";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const MAX_FAILURES = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function useQuery<
 | 
				
			||||||
 | 
					  TQueryFnData = unknown,
 | 
				
			||||||
 | 
					  TData = TQueryFnData,
 | 
				
			||||||
 | 
					  TQueryKey extends QueryKey = QueryKey,
 | 
				
			||||||
 | 
					>(
 | 
				
			||||||
 | 
					  queryKey: TQueryKey,
 | 
				
			||||||
 | 
					  queryFn: QueryFunction<TQueryFnData, TQueryKey>,
 | 
				
			||||||
 | 
					  options?: UseQueryOptions<TQueryFnData, AxiosError, TData, TQueryKey>,
 | 
				
			||||||
 | 
					): UseQueryResult<TData, AxiosError> {
 | 
				
			||||||
 | 
					  const { setAuthenticated } = useContext(AuthContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return useReactQuery<TQueryFnData, AxiosError, TData, TQueryKey>(
 | 
				
			||||||
 | 
					    queryKey,
 | 
				
			||||||
 | 
					    async (context: QueryFunctionContext<TQueryKey>) => {
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        return await queryFn(context);
 | 
				
			||||||
 | 
					      } catch (error) {
 | 
				
			||||||
 | 
					        if (axios.isAxiosError(error) && error.response?.status === 401) {
 | 
				
			||||||
 | 
					          setAuthenticated(false);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        throw error;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      retry: (failureCount: number, error: AxiosError) =>
 | 
				
			||||||
 | 
					        failureCount < MAX_FAILURES &&
 | 
				
			||||||
 | 
					        (!error.response || error.response.status >= 500),
 | 
				
			||||||
 | 
					      ...options,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function useMutation<
 | 
				
			||||||
 | 
					  TData = unknown,
 | 
				
			||||||
 | 
					  TVariables = void,
 | 
				
			||||||
 | 
					  TContext = unknown,
 | 
				
			||||||
 | 
					>(
 | 
				
			||||||
 | 
					  mutationFn: MutationFunction<TData, TVariables>,
 | 
				
			||||||
 | 
					  options?: UseMutationOptions<TData, AxiosError, TVariables, TContext>,
 | 
				
			||||||
 | 
					): UseMutationResult<TData, AxiosError, TVariables, TContext> {
 | 
				
			||||||
 | 
					  const { setAuthenticated } = useContext(AuthContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return useReactMutation<TData, AxiosError, TVariables, TContext>(
 | 
				
			||||||
 | 
					    async (variables: TVariables) => {
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        return await mutationFn(variables);
 | 
				
			||||||
 | 
					      } catch (error) {
 | 
				
			||||||
 | 
					        if (axios.isAxiosError(error) && error.response?.status === 401) {
 | 
				
			||||||
 | 
					          setAuthenticated(false);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        throw error;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      retry: (failureCount: number, error: AxiosError) =>
 | 
				
			||||||
 | 
					        failureCount < MAX_FAILURES &&
 | 
				
			||||||
 | 
					        (!error.response || error.response.status >= 500),
 | 
				
			||||||
 | 
					      ...options,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user