From 1a135e8274ea0c73381c239661aa2e7e60f07143 Mon Sep 17 00:00:00 2001 From: zkldi <20380519+zkldi@users.noreply.github.com> Date: Mon, 20 Feb 2023 01:53:32 +0000 Subject: [PATCH] fix: stupid crlfisms --- bot/README.md | 8 +- bot/tsconfig.json | 76 +-- client/src/app/App.tsx | 92 +-- client/src/app/pages/ErrorPage.tsx | 166 +++--- .../src/app/pages/dashboard/DashboardPage.tsx | 562 +++++++++--------- client/src/app/routes/AppRoutes.tsx | 190 +++--- client/src/app/routes/DashboardRoutes.tsx | 268 ++++----- client/src/components/layout/Layout.tsx | 90 +-- .../src/components/layout/footer/Footer.tsx | 204 +++---- .../src/components/layout/header/Header.tsx | 72 +-- .../components/layout/header/HeaderMenu.tsx | 342 +++++------ .../components/layout/header/HeaderMobile.tsx | 126 ++-- .../components/layout/header/SearchButton.tsx | 36 +- .../src/components/layout/header/Topbar.tsx | 68 +-- .../layout/header/UserNotificationButton.tsx | 70 +-- .../layout/header/UserProfileDropdown.tsx | 270 ++++----- .../layout/misc/MaterialThemeProvider.tsx | 60 +- .../layout/screens/LoadingScreen.tsx | 114 ++-- .../layout/screens/SplashScreen.tsx | 26 +- .../components/layout/subheader/SubHeader.tsx | 64 +- .../subheader/components/Breadcrumbs.tsx | 80 +-- client/src/context/SubheaderContext.tsx | 40 +- client/src/index.tsx | 24 +- 23 files changed, 1524 insertions(+), 1524 deletions(-) diff --git a/bot/README.md b/bot/README.md index 95bb62033..321b85a2f 100644 --- a/bot/README.md +++ b/bot/README.md @@ -1,5 +1,5 @@ -# Tachi Bot - -This is a discord bot that interacts with an instance of Tachi. - +# Tachi Bot + +This is a discord bot that interacts with an instance of Tachi. + It's currently not documented, so you'll have to read the source to figure things out. Sorry! \ No newline at end of file diff --git a/bot/tsconfig.json b/bot/tsconfig.json index 8a02f0d43..dfe4aa527 100644 --- a/bot/tsconfig.json +++ b/bot/tsconfig.json @@ -1,39 +1,39 @@ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "rootDir": "src", - "baseUrl": "src", - "outDir": "js", - "lib": [ - "DOM" // hack workaround. URLSearchParams must be imported, yet - // discordJS carelessly uses it without being imported - // as if it were a DOM type. - // Sad! - ], - "types": [ - "node", - ], - "paths": { - "tachi-common": [ - "../../common/src" - ], - "tachi-common/*": [ - "../../common/src/*" - ] - }, - "composite": true, - "tsBuildInfoFile": ".tsbuildinfo" - }, - "include": [ - "src/**/*" - ], - "exclude": [ - "node_modules", - "**/*.test.ts" - ], - "references": [ - { - "path": "../common" - } - ], +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "baseUrl": "src", + "outDir": "js", + "lib": [ + "DOM" // hack workaround. URLSearchParams must be imported, yet + // discordJS carelessly uses it without being imported + // as if it were a DOM type. + // Sad! + ], + "types": [ + "node", + ], + "paths": { + "tachi-common": [ + "../../common/src" + ], + "tachi-common/*": [ + "../../common/src/*" + ] + }, + "composite": true, + "tsBuildInfoFile": ".tsbuildinfo" + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "**/*.test.ts" + ], + "references": [ + { + "path": "../common" + } + ], } \ No newline at end of file diff --git a/client/src/app/App.tsx b/client/src/app/App.tsx index d706313e2..a214b97d6 100644 --- a/client/src/app/App.tsx +++ b/client/src/app/App.tsx @@ -1,46 +1,46 @@ -import { MaterialThemeProvider } from "components/layout/misc/MaterialThemeProvider"; -import { LoadingScreen } from "components/layout/screens/LoadingScreen"; -import { AllLUGPTStatsContextProvider } from "context/AllLUGPTStatsContext"; -import { BannedContextProvider } from "context/BannedContext"; -import { NotificationsContextProvider } from "context/NotificationsContext"; -import { SubheaderContextProvider } from "context/SubheaderContext"; -import { UserContextProvider } from "context/UserContext"; -import { UserSettingsContextProvider } from "context/UserSettingsContext"; -import React from "react"; -import { Toaster } from "react-hot-toast"; -import { QueryClient, QueryClientProvider } from "react-query"; -import { BrowserRouter } from "react-router-dom"; -import { Routes } from "./routes/AppRoutes"; - -const queryClient = new QueryClient({ - defaultOptions: { queries: { staleTime: 1000 * 60 * 5, retry: false } }, -}); - -export default function App({ basename }: { basename: string }) { - return ( - - - - - - - - - - - - - - - - - - - - - - - - - ); -} +import { MaterialThemeProvider } from "components/layout/misc/MaterialThemeProvider"; +import { LoadingScreen } from "components/layout/screens/LoadingScreen"; +import { AllLUGPTStatsContextProvider } from "context/AllLUGPTStatsContext"; +import { BannedContextProvider } from "context/BannedContext"; +import { NotificationsContextProvider } from "context/NotificationsContext"; +import { SubheaderContextProvider } from "context/SubheaderContext"; +import { UserContextProvider } from "context/UserContext"; +import { UserSettingsContextProvider } from "context/UserSettingsContext"; +import React from "react"; +import { Toaster } from "react-hot-toast"; +import { QueryClient, QueryClientProvider } from "react-query"; +import { BrowserRouter } from "react-router-dom"; +import { Routes } from "./routes/AppRoutes"; + +const queryClient = new QueryClient({ + defaultOptions: { queries: { staleTime: 1000 * 60 * 5, retry: false } }, +}); + +export default function App({ basename }: { basename: string }) { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/client/src/app/pages/ErrorPage.tsx b/client/src/app/pages/ErrorPage.tsx index 09203b2b2..f7a309326 100644 --- a/client/src/app/pages/ErrorPage.tsx +++ b/client/src/app/pages/ErrorPage.tsx @@ -1,83 +1,83 @@ -import { ToCDNURL } from "util/api"; -import { HistorySafeGoBack } from "util/misc"; -import useSetSubheader from "components/layout/header/useSetSubheader"; -import React from "react"; -import { useHistory } from "react-router-dom"; - -export function ErrorPage({ - statusCode, - customMessage, -}: { - statusCode: number; - customMessage?: string; -}) { - useSetSubheader(statusCode ? statusCode.toString() : "Completely Screwed."); - - let message; - - const history = useHistory(); - - if (!customMessage) { - switch (statusCode) { - case 400: - message = "The server refused this request."; - break; - case 401: - message = "Looks like you're not authorised. Try logging in."; - break; - case 403: - message = "Looks like you're not allowed to be here."; - break; - case 404: - message = "This page does not exist. If you think it should exist, let us know!"; - break; - case 429: - message = "You're being rate limited. If this was unexpected, please report this."; - break; - case 500: - message = "Looks like the server has failed. This has been reported!"; - break; - case undefined: - message = - "Looks like the server has completely crashed. Ah well. Try reloading, but there's no promises."; - break; - default: - message = "An unexpected error has occurred. This has been reported!"; - break; - } - } else { - message = customMessage; - } - - return ( -
-
-
-

- {statusCode || "Completely Screwed."} -

-

{message}

- HistorySafeGoBack(history)}> - Go Back. - -
-
-
- ); -} +import { ToCDNURL } from "util/api"; +import { HistorySafeGoBack } from "util/misc"; +import useSetSubheader from "components/layout/header/useSetSubheader"; +import React from "react"; +import { useHistory } from "react-router-dom"; + +export function ErrorPage({ + statusCode, + customMessage, +}: { + statusCode: number; + customMessage?: string; +}) { + useSetSubheader(statusCode ? statusCode.toString() : "Completely Screwed."); + + let message; + + const history = useHistory(); + + if (!customMessage) { + switch (statusCode) { + case 400: + message = "The server refused this request."; + break; + case 401: + message = "Looks like you're not authorised. Try logging in."; + break; + case 403: + message = "Looks like you're not allowed to be here."; + break; + case 404: + message = "This page does not exist. If you think it should exist, let us know!"; + break; + case 429: + message = "You're being rate limited. If this was unexpected, please report this."; + break; + case 500: + message = "Looks like the server has failed. This has been reported!"; + break; + case undefined: + message = + "Looks like the server has completely crashed. Ah well. Try reloading, but there's no promises."; + break; + default: + message = "An unexpected error has occurred. This has been reported!"; + break; + } + } else { + message = customMessage; + } + + return ( +
+
+
+

+ {statusCode || "Completely Screwed."} +

+

{message}

+ HistorySafeGoBack(history)}> + Go Back. + +
+
+
+ ); +} diff --git a/client/src/app/pages/dashboard/DashboardPage.tsx b/client/src/app/pages/dashboard/DashboardPage.tsx index 525a809f2..12a666218 100644 --- a/client/src/app/pages/dashboard/DashboardPage.tsx +++ b/client/src/app/pages/dashboard/DashboardPage.tsx @@ -1,281 +1,281 @@ -import { APIFetchV1 } from "util/api"; -import { ChangeOpacity } from "util/color-opacity"; -import { CreateGoalMap } from "util/data"; -import { RFA } from "util/misc"; -import { NumericSOV } from "util/sorts"; -import { heySplashes } from "util/splashes"; -import Activity from "components/activity/Activity"; -import DashboardActivity from "components/dashboard/DashboardActivity"; -import { DashboardHeader } from "components/dashboard/DashboardHeader"; -import useSetSubheader from "components/layout/header/useSetSubheader"; -import SessionCard from "components/sessions/SessionCard"; -import ApiError from "components/util/ApiError"; -import AsyncLoader from "components/util/AsyncLoader"; -import Divider from "components/util/Divider"; -import GoalLink from "components/util/GoalLink"; -import LinkButton from "components/util/LinkButton"; -import Loading from "components/util/Loading"; -import useApiQuery from "components/util/query/useApiQuery"; -import { UserContext } from "context/UserContext"; -import { UserSettingsContext } from "context/UserSettingsContext"; -import { ColourConfig, TachiConfig } from "lib/config"; -import React, { useContext, useMemo } from "react"; -import { Alert } from "react-bootstrap"; -import { Link, Route, Switch } from "react-router-dom"; -import { COLOUR_SET, GetGameConfig, UserDocument } from "tachi-common"; -import { UGSWithRankingData, UserRecentSummary } from "types/api-returns"; -import { GameStatContainer } from "./users/UserGamesPage"; - -export function DashboardPage() { - const { settings } = useContext(UserSettingsContext); - - useSetSubheader("Home", [settings]); - - const { user } = useContext(UserContext); - - if (!user) { - return ; - } - - return ; -} - -function DashboardLoggedIn({ user }: { user: UserDocument }) { - const splash = useMemo(() => RFA(heySplashes), [user]); - - return ( -
- - {splash}, {user.username}. - -
- -
- - - - - - - - - - - - - -
- ); -} - -function RecentInfo({ user }: { user: UserDocument }) { - const { data, error } = useApiQuery(`/users/${user.id}/recent-summary`); - - if (error) { - return ; - } - - if (!data) { - return ; - } - - const folderInfoMap = new Map(); - for (const folderInfo of data.recentFolderStats) { - folderInfoMap.set(folderInfo.folderID, folderInfo); - } - - const goalMap = CreateGoalMap(data.recentGoals); - - return ( - <> - {data.recentSessions.length !== 0 && ( - <> - -
-

Today's Summary

- You've gotten {data.recentPlaycount} new score - {data.recentPlaycount !== 1 ? "s" : ""} today! -
-
- -

New Sessions

- You've had {data.recentSessions.length} session - {data.recentSessions.length !== 1 ? "s" : ""} today! - - {data.recentSessions.sort(NumericSOV((x) => x.timeEnded, true)).map((e) => ( - <> - - - - ))} - - )} - {data.recentAchievedGoals.length !== 0 && ( - <> - -
-

- {RFA([ - "Sweet!", - "Nice!", - "Lookin' good!", - "Good Stuff!", - "owo", - "Cool!", - "Awesome!", - "Epic!", - ])} -

- You've achieved {data.recentAchievedGoals.length} new goal - {data.recentAchievedGoals.length !== 1 ? "s" : ""} today! -
- -
-
    - {data.recentAchievedGoals.map((e) => { - const goal = goalMap.get(e.goalID); - - if (!goal) { - return whoops, couldn't find this goal.; - } - - return ( -
  • - -
  • - ); - })} -
-
-
- - - )} - {/* {data.recentFolders.length !== 0 && ( - <> -

Here's some folders you checked out recently.

- -
- {data.recentFolders.map((e) => ( - - ))} -
- - - )} */} - - ); -} - -function UserGameStatsInfo({ user }: { user: UserDocument }) { - return ( -
- { - const res = await APIFetchV1( - `/users/${user.id}/game-stats` - ); - - if (!res.success) { - throw new Error(res.description); - } - - return res.body.sort((a, b) => { - if (a.game === b.game) { - const gameConfig = GetGameConfig(a.game); - - return ( - gameConfig.playtypes.indexOf(a.playtype) - - gameConfig.playtypes.indexOf(b.playtype) - ); - } - - const i1 = TachiConfig.games.indexOf(a.game); - const i2 = TachiConfig.games.indexOf(b.game); - - return i1 - i2; - }); - }} - > - {(ugs) => - ugs.map((e) => ( - - )) - } - -
- ); -} - -function DashboardNotLoggedIn() { - return ( -
-

Welcome to {TachiConfig.name}!

-

- Looks like you're not logged in. If you've got an account,{" "} - Login! -

- -

I'm New Around Here, What is this?

- - {TachiConfig.name} is a Rhythm Game Score Tracker. That means we... - - - - - - -
- Interested? You can register right now for free! -
- - Register! - -
- -
- Nosey? Here's what our users are up to. -
-
- -
-
-
- ); -} - -function FeatureContainer({ tagline, description }: { tagline: string; description: string }) { - return ( -
-
-

{tagline}

- {description} -
-
- ); -} +import { APIFetchV1 } from "util/api"; +import { ChangeOpacity } from "util/color-opacity"; +import { CreateGoalMap } from "util/data"; +import { RFA } from "util/misc"; +import { NumericSOV } from "util/sorts"; +import { heySplashes } from "util/splashes"; +import Activity from "components/activity/Activity"; +import DashboardActivity from "components/dashboard/DashboardActivity"; +import { DashboardHeader } from "components/dashboard/DashboardHeader"; +import useSetSubheader from "components/layout/header/useSetSubheader"; +import SessionCard from "components/sessions/SessionCard"; +import ApiError from "components/util/ApiError"; +import AsyncLoader from "components/util/AsyncLoader"; +import Divider from "components/util/Divider"; +import GoalLink from "components/util/GoalLink"; +import LinkButton from "components/util/LinkButton"; +import Loading from "components/util/Loading"; +import useApiQuery from "components/util/query/useApiQuery"; +import { UserContext } from "context/UserContext"; +import { UserSettingsContext } from "context/UserSettingsContext"; +import { ColourConfig, TachiConfig } from "lib/config"; +import React, { useContext, useMemo } from "react"; +import { Alert } from "react-bootstrap"; +import { Link, Route, Switch } from "react-router-dom"; +import { COLOUR_SET, GetGameConfig, UserDocument } from "tachi-common"; +import { UGSWithRankingData, UserRecentSummary } from "types/api-returns"; +import { GameStatContainer } from "./users/UserGamesPage"; + +export function DashboardPage() { + const { settings } = useContext(UserSettingsContext); + + useSetSubheader("Home", [settings]); + + const { user } = useContext(UserContext); + + if (!user) { + return ; + } + + return ; +} + +function DashboardLoggedIn({ user }: { user: UserDocument }) { + const splash = useMemo(() => RFA(heySplashes), [user]); + + return ( +
+ + {splash}, {user.username}. + +
+ +
+ + + + + + + + + + + + + +
+ ); +} + +function RecentInfo({ user }: { user: UserDocument }) { + const { data, error } = useApiQuery(`/users/${user.id}/recent-summary`); + + if (error) { + return ; + } + + if (!data) { + return ; + } + + const folderInfoMap = new Map(); + for (const folderInfo of data.recentFolderStats) { + folderInfoMap.set(folderInfo.folderID, folderInfo); + } + + const goalMap = CreateGoalMap(data.recentGoals); + + return ( + <> + {data.recentSessions.length !== 0 && ( + <> + +
+

Today's Summary

+ You've gotten {data.recentPlaycount} new score + {data.recentPlaycount !== 1 ? "s" : ""} today! +
+
+ +

New Sessions

+ You've had {data.recentSessions.length} session + {data.recentSessions.length !== 1 ? "s" : ""} today! + + {data.recentSessions.sort(NumericSOV((x) => x.timeEnded, true)).map((e) => ( + <> + + + + ))} + + )} + {data.recentAchievedGoals.length !== 0 && ( + <> + +
+

+ {RFA([ + "Sweet!", + "Nice!", + "Lookin' good!", + "Good Stuff!", + "owo", + "Cool!", + "Awesome!", + "Epic!", + ])} +

+ You've achieved {data.recentAchievedGoals.length} new goal + {data.recentAchievedGoals.length !== 1 ? "s" : ""} today! +
+ +
+
    + {data.recentAchievedGoals.map((e) => { + const goal = goalMap.get(e.goalID); + + if (!goal) { + return whoops, couldn't find this goal.; + } + + return ( +
  • + +
  • + ); + })} +
+
+
+ + + )} + {/* {data.recentFolders.length !== 0 && ( + <> +

Here's some folders you checked out recently.

+ +
+ {data.recentFolders.map((e) => ( + + ))} +
+ + + )} */} + + ); +} + +function UserGameStatsInfo({ user }: { user: UserDocument }) { + return ( +
+ { + const res = await APIFetchV1( + `/users/${user.id}/game-stats` + ); + + if (!res.success) { + throw new Error(res.description); + } + + return res.body.sort((a, b) => { + if (a.game === b.game) { + const gameConfig = GetGameConfig(a.game); + + return ( + gameConfig.playtypes.indexOf(a.playtype) - + gameConfig.playtypes.indexOf(b.playtype) + ); + } + + const i1 = TachiConfig.games.indexOf(a.game); + const i2 = TachiConfig.games.indexOf(b.game); + + return i1 - i2; + }); + }} + > + {(ugs) => + ugs.map((e) => ( + + )) + } + +
+ ); +} + +function DashboardNotLoggedIn() { + return ( +
+

Welcome to {TachiConfig.name}!

+

+ Looks like you're not logged in. If you've got an account,{" "} + Login! +

+ +

I'm New Around Here, What is this?

+ + {TachiConfig.name} is a Rhythm Game Score Tracker. That means we... + + + + + + +
+ Interested? You can register right now for free! +
+ + Register! + +
+ +
+ Nosey? Here's what our users are up to. +
+
+ +
+
+
+ ); +} + +function FeatureContainer({ tagline, description }: { tagline: string; description: string }) { + return ( +
+
+

{tagline}

+ {description} +
+
+ ); +} diff --git a/client/src/app/routes/AppRoutes.tsx b/client/src/app/routes/AppRoutes.tsx index a73aa00d3..442b1f92c 100644 --- a/client/src/app/routes/AppRoutes.tsx +++ b/client/src/app/routes/AppRoutes.tsx @@ -1,95 +1,95 @@ -import { HistorySafeGoBack } from "util/misc"; -import { ErrorPage } from "app/pages/ErrorPage"; -import ForgotPasswordPage from "app/pages/ForgotPasswordPage"; -import LoginPage from "app/pages/LoginPage"; -import OAuthRequestAuthPage from "app/pages/OAuthRequestAuthPage"; -import RegisterPage from "app/pages/RegisterPage"; -import ResetPasswordPage from "app/pages/ResetPasswordPage"; -import VerifyEmailPage from "app/pages/VerifyEmailPage"; -import CenterPage from "components/util/CenterPage"; -import ErrorBoundary from "components/util/ErrorBoundary"; -import MainPageTitleContainer from "components/util/MainPageTitleContainer"; -import { UserContext } from "context/UserContext"; -import { ClientConfig } from "lib/config"; -import React, { useContext } from "react"; -import { Redirect, Route, Switch, useHistory } from "react-router-dom"; -import ClientFileFlowRoutes from "./ClientFileFlowRoutes"; -import DashboardRoutes from "./DashboardRoutes"; -import OAuth2CallbackRoutes from "./OAuth2CallbackRoutes"; -import RedirectLegacyRoutes from "./RedirectLegacyRoutes"; - -/** - * Core Routes for Tachi-Client. - * These are things that involve redirecting to non-dashboard apps. - */ -export function Routes() { - const { user } = useContext(UserContext); - - const history = useHistory(); - - return ( - - - {/* redirects for legacy urls */} - - - - - - - - - - - - - - - - - - - - - - - - - {user ? : } - - - {user ? : } - - - {user ? : } - - - {user ? : } - - - {user ? ( - - ) : ( - - - HistorySafeGoBack(history)} - tabIndex={4} - className="btn btn-outline-danger" - > - Back - - - )} - - - - {!user && ClientConfig.MANDATE_LOGIN ? : } - - - - ); -} +import { HistorySafeGoBack } from "util/misc"; +import { ErrorPage } from "app/pages/ErrorPage"; +import ForgotPasswordPage from "app/pages/ForgotPasswordPage"; +import LoginPage from "app/pages/LoginPage"; +import OAuthRequestAuthPage from "app/pages/OAuthRequestAuthPage"; +import RegisterPage from "app/pages/RegisterPage"; +import ResetPasswordPage from "app/pages/ResetPasswordPage"; +import VerifyEmailPage from "app/pages/VerifyEmailPage"; +import CenterPage from "components/util/CenterPage"; +import ErrorBoundary from "components/util/ErrorBoundary"; +import MainPageTitleContainer from "components/util/MainPageTitleContainer"; +import { UserContext } from "context/UserContext"; +import { ClientConfig } from "lib/config"; +import React, { useContext } from "react"; +import { Redirect, Route, Switch, useHistory } from "react-router-dom"; +import ClientFileFlowRoutes from "./ClientFileFlowRoutes"; +import DashboardRoutes from "./DashboardRoutes"; +import OAuth2CallbackRoutes from "./OAuth2CallbackRoutes"; +import RedirectLegacyRoutes from "./RedirectLegacyRoutes"; + +/** + * Core Routes for Tachi-Client. + * These are things that involve redirecting to non-dashboard apps. + */ +export function Routes() { + const { user } = useContext(UserContext); + + const history = useHistory(); + + return ( + + + {/* redirects for legacy urls */} + + + + + + + + + + + + + + + + + + + + + + + + + {user ? : } + + + {user ? : } + + + {user ? : } + + + {user ? : } + + + {user ? ( + + ) : ( + + + HistorySafeGoBack(history)} + tabIndex={4} + className="btn btn-outline-danger" + > + Back + + + )} + + + + {!user && ClientConfig.MANDATE_LOGIN ? : } + + + + ); +} diff --git a/client/src/app/routes/DashboardRoutes.tsx b/client/src/app/routes/DashboardRoutes.tsx index b65fc6a59..b4d695788 100644 --- a/client/src/app/routes/DashboardRoutes.tsx +++ b/client/src/app/routes/DashboardRoutes.tsx @@ -1,134 +1,134 @@ -import { APIFetchV1, ToAPIURL } from "util/api"; -import SupportMePage from "app/pages/dashboard/misc/SupportMePage"; -import { ErrorPage } from "app/pages/ErrorPage"; -import PrivacyPolicyPage from "app/pages/PrivacyPolicyPage"; -import { Layout } from "components/layout/Layout"; -import EmailVerify from "components/layout/misc/EmailVerify"; -import DashboardErrorBoundary from "components/util/DashboardErrorBoundary"; -import { BannedContext } from "context/BannedContext"; -import { UserContext } from "context/UserContext"; -import React, { useContext, useEffect, useState } from "react"; -import { Redirect, Route, Switch } from "react-router-dom"; -import { BackgroundContext } from "context/BackgroundContext"; -import NotificationsPage from "app/pages/dashboard/users/NotificationsPage"; -import SearchPage from "app/pages/dashboard/search/SearchPage"; -import { DashboardPage } from "../pages/dashboard/DashboardPage"; -import CreditsPage from "../pages/dashboard/misc/CreditsPage"; -import GameRoutes from "./GameRoutes"; -import ImportRoutes from "./ImportRoutes"; -import UserRoutes from "./UserRoutes"; -import UtilRoutes from "./UtilRoutes"; -import { RedirectLegacyUserRoutes } from "./RedirectLegacyRoutes"; - -export default function DashboardRoutes() { - const { user } = useContext(UserContext); - const { banned } = useContext(BannedContext); - const { setBackground } = useContext(BackgroundContext); - - const [hasVerifiedEmail, setHasVerifiedEmail] = useState(null); - - useEffect(() => { - if (!user) { - return setHasVerifiedEmail(null); - } - - (async () => { - const hasVerified = await APIFetchV1(`/users/${user.id}/is-email-verified`); - - if (hasVerified.success) { - setHasVerifiedEmail(hasVerified.body); - } - })(); - }, [user]); - - useEffect(() => { - if (user) { - setBackground(ToAPIURL(`/users/${user.id}/banner`)); - } else { - setBackground(null); - } - - return () => { - setBackground(null); - }; - }, [user]); - - if (hasVerifiedEmail === false) { - return ( - - - - ); - } - - if (banned) { - return ; - } - - return ( - - - - {/* this is the easiest (read: least sucky) way of handling */} - {/* these routes */} - - - - - - - - - - - - - - - - - - - - - {/* this used to be called /dashboard/users/username, now it's called /u/username */} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -} +import { APIFetchV1, ToAPIURL } from "util/api"; +import SupportMePage from "app/pages/dashboard/misc/SupportMePage"; +import { ErrorPage } from "app/pages/ErrorPage"; +import PrivacyPolicyPage from "app/pages/PrivacyPolicyPage"; +import { Layout } from "components/layout/Layout"; +import EmailVerify from "components/layout/misc/EmailVerify"; +import DashboardErrorBoundary from "components/util/DashboardErrorBoundary"; +import { BannedContext } from "context/BannedContext"; +import { UserContext } from "context/UserContext"; +import React, { useContext, useEffect, useState } from "react"; +import { Redirect, Route, Switch } from "react-router-dom"; +import { BackgroundContext } from "context/BackgroundContext"; +import NotificationsPage from "app/pages/dashboard/users/NotificationsPage"; +import SearchPage from "app/pages/dashboard/search/SearchPage"; +import { DashboardPage } from "../pages/dashboard/DashboardPage"; +import CreditsPage from "../pages/dashboard/misc/CreditsPage"; +import GameRoutes from "./GameRoutes"; +import ImportRoutes from "./ImportRoutes"; +import UserRoutes from "./UserRoutes"; +import UtilRoutes from "./UtilRoutes"; +import { RedirectLegacyUserRoutes } from "./RedirectLegacyRoutes"; + +export default function DashboardRoutes() { + const { user } = useContext(UserContext); + const { banned } = useContext(BannedContext); + const { setBackground } = useContext(BackgroundContext); + + const [hasVerifiedEmail, setHasVerifiedEmail] = useState(null); + + useEffect(() => { + if (!user) { + return setHasVerifiedEmail(null); + } + + (async () => { + const hasVerified = await APIFetchV1(`/users/${user.id}/is-email-verified`); + + if (hasVerified.success) { + setHasVerifiedEmail(hasVerified.body); + } + })(); + }, [user]); + + useEffect(() => { + if (user) { + setBackground(ToAPIURL(`/users/${user.id}/banner`)); + } else { + setBackground(null); + } + + return () => { + setBackground(null); + }; + }, [user]); + + if (hasVerifiedEmail === false) { + return ( + + + + ); + } + + if (banned) { + return ; + } + + return ( + + + + {/* this is the easiest (read: least sucky) way of handling */} + {/* these routes */} + + + + + + + + + + + + + + + + + + + + + {/* this used to be called /dashboard/users/username, now it's called /u/username */} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/client/src/components/layout/Layout.tsx b/client/src/components/layout/Layout.tsx index 1716d4c90..95bac855b 100644 --- a/client/src/components/layout/Layout.tsx +++ b/client/src/components/layout/Layout.tsx @@ -1,45 +1,45 @@ -import BackgroundImage from "components/layout/misc/BackgroundImage"; -import { BackgroundContextProvider } from "context/BackgroundContext"; -import React, { useState } from "react"; -import { JustChildren } from "types/react"; -import { Footer } from "./footer/Footer"; -import { Header } from "./header/Header"; -import { HeaderMobile } from "./header/HeaderMobile"; -import { SubHeader } from "./subheader/SubHeader"; - -export function Layout({ children }: JustChildren) { - const [mobileShow, setMobileShow] = useState(false); - - return ( - <> - - -
-
-
-
- - - - -
- - -
{children}
-
-
- -
-
-
-
- - ); -} +import BackgroundImage from "components/layout/misc/BackgroundImage"; +import { BackgroundContextProvider } from "context/BackgroundContext"; +import React, { useState } from "react"; +import { JustChildren } from "types/react"; +import { Footer } from "./footer/Footer"; +import { Header } from "./header/Header"; +import { HeaderMobile } from "./header/HeaderMobile"; +import { SubHeader } from "./subheader/SubHeader"; + +export function Layout({ children }: JustChildren) { + const [mobileShow, setMobileShow] = useState(false); + + return ( + <> + + +
+
+
+
+ + + + +
+ + +
{children}
+
+
+ +
+
+
+
+ + ); +} diff --git a/client/src/components/layout/footer/Footer.tsx b/client/src/components/layout/footer/Footer.tsx index 64cb80ecc..220b30276 100644 --- a/client/src/components/layout/footer/Footer.tsx +++ b/client/src/components/layout/footer/Footer.tsx @@ -1,102 +1,102 @@ -import { APIFetchV1 } from "util/api"; -import Divider from "components/util/Divider"; -import ExternalLink from "components/util/ExternalLink"; -import { BannedContext } from "context/BannedContext"; -import React, { useContext, useEffect, useState } from "react"; -import { Link } from "react-router-dom"; -import { ServerStatus } from "types/api-returns"; - -export function Footer() { - const [serverVersion, setServerVersion] = useState("Loading..."); - const { setBanned } = useContext(BannedContext); - - useEffect(() => { - APIFetchV1("/status").then((r) => { - if (r.statusCode === 403) { - setBanned(true); - } - - if (!r.success) { - setServerVersion("Error Fetching data!"); - } else { - setServerVersion(r.body.version); - } - }); - }, []); - - return ( - <> - - - - - ); -} +import { APIFetchV1 } from "util/api"; +import Divider from "components/util/Divider"; +import ExternalLink from "components/util/ExternalLink"; +import { BannedContext } from "context/BannedContext"; +import React, { useContext, useEffect, useState } from "react"; +import { Link } from "react-router-dom"; +import { ServerStatus } from "types/api-returns"; + +export function Footer() { + const [serverVersion, setServerVersion] = useState("Loading..."); + const { setBanned } = useContext(BannedContext); + + useEffect(() => { + APIFetchV1("/status").then((r) => { + if (r.statusCode === 403) { + setBanned(true); + } + + if (!r.success) { + setServerVersion("Error Fetching data!"); + } else { + setServerVersion(r.body.version); + } + }); + }, []); + + return ( + <> + + + + + ); +} diff --git a/client/src/components/layout/header/Header.tsx b/client/src/components/layout/header/Header.tsx index bcee8fab2..ba60acc4f 100644 --- a/client/src/components/layout/header/Header.tsx +++ b/client/src/components/layout/header/Header.tsx @@ -1,36 +1,36 @@ -import { ToCDNURL } from "util/api"; -import React from "react"; -import { Link } from "react-router-dom"; -import { SetState } from "types/react"; -import { HeaderMenu } from "./HeaderMenu"; -import { Topbar } from "./Topbar"; - -export function Header({ - mobileShow, - setMobileShow, -}: { - mobileShow: boolean; - setMobileShow: SetState; -}) { - return ( -
-
-
-
- - Logo - -
- - -
- - -
-
- ); -} +import { ToCDNURL } from "util/api"; +import React from "react"; +import { Link } from "react-router-dom"; +import { SetState } from "types/react"; +import { HeaderMenu } from "./HeaderMenu"; +import { Topbar } from "./Topbar"; + +export function Header({ + mobileShow, + setMobileShow, +}: { + mobileShow: boolean; + setMobileShow: SetState; +}) { + return ( +
+
+
+
+ + Logo + +
+ + +
+ + +
+
+ ); +} diff --git a/client/src/components/layout/header/HeaderMenu.tsx b/client/src/components/layout/header/HeaderMenu.tsx index 8a35ef063..1fe30f154 100644 --- a/client/src/components/layout/header/HeaderMenu.tsx +++ b/client/src/components/layout/header/HeaderMenu.tsx @@ -1,171 +1,171 @@ -import { APIFetchV1, ToCDNURL } from "util/api"; -import Divider from "components/util/Divider"; -import Icon from "components/util/Icon"; -import Loading from "components/util/Loading"; -import useComponentVisible from "components/util/useComponentVisible"; -import { AllLUGPTStatsContext } from "context/AllLUGPTStatsContext"; -import { UserContext } from "context/UserContext"; -import { UserSettingsContext } from "context/UserSettingsContext"; -import { TachiConfig } from "lib/config"; -import React, { useContext, useEffect } from "react"; -import { Button } from "react-bootstrap"; -import toast from "react-hot-toast"; -import { useQuery } from "react-query"; -import { Link } from "react-router-dom"; -import { FormatGame, GetGameConfig, UserGameStats } from "tachi-common"; -import { SetState } from "types/react"; -import AllGames from "./AllGames"; -import ImportScoresLink from "./ImportScoresLink"; -import MenuDropdown from "./MenuDropdown"; -import MenuLink from "./MenuLink"; -import UtilsDropdown from "./UtilsDropdown"; - -export function HeaderMenu({ - mobileShow, - setMobileShow, -}: { - mobileShow: boolean; - setMobileShow: SetState; -}) { - const { user, setUser } = useContext(UserContext); - const { ugs, setUGS } = useContext(AllLUGPTStatsContext); - const { settings } = useContext(UserSettingsContext); - - const { isLoading, error } = useQuery([user?.id, "game_stats"], async () => { - if (!user) { - return null; - } - - const res = await APIFetchV1("/users/me/game-stats"); - - if (!res.success) { - throw res; - } - - return setUGS(res.body); - }); - - if (error) { - console.error(error); - } - - const { ref, isComponentVisible, setIsComponentVisible } = useComponentVisible(mobileShow); - - // how does this not cause a problem. What? - useEffect(() => { - setIsComponentVisible(mobileShow); - }, [mobileShow]); - - useEffect(() => { - setMobileShow(isComponentVisible); - }, [isComponentVisible]); - - if (isLoading) { - return ; - } - - const userProfileLinks = []; - - if (user && ugs && ugs.length !== 0) { - const ugsMap = new Map(); - for (const s of ugs) { - ugsMap.set(`${s.game}:${s.playtype}`, s); - } - - for (const game of TachiConfig.games) { - for (const playtype of GetGameConfig(game).playtypes) { - const e = ugsMap.get(`${game}:${playtype}`); - - if (!e) { - continue; - } - - userProfileLinks.push( - - ); - } - } - } - - return ( -
-
-
-
- - - - -
- -
-
-
    - {user && ugs && ugs.length !== 0 && ( - {userProfileLinks} - )} - - - - {user && } - - {settings?.preferences.developerMode && } -
-
- {user && ( -
-
- -
- -
- )} -
-
- ); -} +import { APIFetchV1, ToCDNURL } from "util/api"; +import Divider from "components/util/Divider"; +import Icon from "components/util/Icon"; +import Loading from "components/util/Loading"; +import useComponentVisible from "components/util/useComponentVisible"; +import { AllLUGPTStatsContext } from "context/AllLUGPTStatsContext"; +import { UserContext } from "context/UserContext"; +import { UserSettingsContext } from "context/UserSettingsContext"; +import { TachiConfig } from "lib/config"; +import React, { useContext, useEffect } from "react"; +import { Button } from "react-bootstrap"; +import toast from "react-hot-toast"; +import { useQuery } from "react-query"; +import { Link } from "react-router-dom"; +import { FormatGame, GetGameConfig, UserGameStats } from "tachi-common"; +import { SetState } from "types/react"; +import AllGames from "./AllGames"; +import ImportScoresLink from "./ImportScoresLink"; +import MenuDropdown from "./MenuDropdown"; +import MenuLink from "./MenuLink"; +import UtilsDropdown from "./UtilsDropdown"; + +export function HeaderMenu({ + mobileShow, + setMobileShow, +}: { + mobileShow: boolean; + setMobileShow: SetState; +}) { + const { user, setUser } = useContext(UserContext); + const { ugs, setUGS } = useContext(AllLUGPTStatsContext); + const { settings } = useContext(UserSettingsContext); + + const { isLoading, error } = useQuery([user?.id, "game_stats"], async () => { + if (!user) { + return null; + } + + const res = await APIFetchV1("/users/me/game-stats"); + + if (!res.success) { + throw res; + } + + return setUGS(res.body); + }); + + if (error) { + console.error(error); + } + + const { ref, isComponentVisible, setIsComponentVisible } = useComponentVisible(mobileShow); + + // how does this not cause a problem. What? + useEffect(() => { + setIsComponentVisible(mobileShow); + }, [mobileShow]); + + useEffect(() => { + setMobileShow(isComponentVisible); + }, [isComponentVisible]); + + if (isLoading) { + return ; + } + + const userProfileLinks = []; + + if (user && ugs && ugs.length !== 0) { + const ugsMap = new Map(); + for (const s of ugs) { + ugsMap.set(`${s.game}:${s.playtype}`, s); + } + + for (const game of TachiConfig.games) { + for (const playtype of GetGameConfig(game).playtypes) { + const e = ugsMap.get(`${game}:${playtype}`); + + if (!e) { + continue; + } + + userProfileLinks.push( + + ); + } + } + } + + return ( +
+
+
+
+ + + + +
+ +
+
+
    + {user && ugs && ugs.length !== 0 && ( + {userProfileLinks} + )} + + + + {user && } + + {settings?.preferences.developerMode && } +
+
+ {user && ( +
+
+ +
+ +
+ )} +
+
+ ); +} diff --git a/client/src/components/layout/header/HeaderMobile.tsx b/client/src/components/layout/header/HeaderMobile.tsx index b4dad5fb2..1b7d2eaa3 100644 --- a/client/src/components/layout/header/HeaderMobile.tsx +++ b/client/src/components/layout/header/HeaderMobile.tsx @@ -1,63 +1,63 @@ -import { ToAPIURL } from "util/api"; -import { UserContext } from "context/UserContext"; -import React, { useContext } from "react"; -import { Link } from "react-router-dom"; -import { SetState } from "types/react"; -import { UserNotificationButton } from "./UserNotificationButton"; -import { SearchButton } from "./SearchButton"; - -export function HeaderMobile({ - mobileShow, - setMobileShow, -}: { - mobileShow: boolean; - setMobileShow: SetState; -}) { - const { user } = useContext(UserContext); - - return ( - <> -
-
- -
- -
- - - {user ? ( - <> - - - - ) : ( - <> - )} -
-
- - ); -} +import { ToAPIURL } from "util/api"; +import { UserContext } from "context/UserContext"; +import React, { useContext } from "react"; +import { Link } from "react-router-dom"; +import { SetState } from "types/react"; +import { UserNotificationButton } from "./UserNotificationButton"; +import { SearchButton } from "./SearchButton"; + +export function HeaderMobile({ + mobileShow, + setMobileShow, +}: { + mobileShow: boolean; + setMobileShow: SetState; +}) { + const { user } = useContext(UserContext); + + return ( + <> +
+
+ +
+ +
+ + + {user ? ( + <> + + + + ) : ( + <> + )} +
+
+ + ); +} diff --git a/client/src/components/layout/header/SearchButton.tsx b/client/src/components/layout/header/SearchButton.tsx index 81783f5ac..fb5a38c2c 100644 --- a/client/src/components/layout/header/SearchButton.tsx +++ b/client/src/components/layout/header/SearchButton.tsx @@ -1,18 +1,18 @@ -import Icon from "components/util/Icon"; -import useApiQuery from "components/util/query/useApiQuery"; -import { NotificationsContext } from "context/NotificationsContext"; -import React, { useContext, useMemo } from "react"; -import { Link } from "react-router-dom"; -import { NotificationDocument, UserDocument } from "tachi-common"; - -export function SearchButton() { - return ( -
- -
- -
- -
- ); -} +import Icon from "components/util/Icon"; +import useApiQuery from "components/util/query/useApiQuery"; +import { NotificationsContext } from "context/NotificationsContext"; +import React, { useContext, useMemo } from "react"; +import { Link } from "react-router-dom"; +import { NotificationDocument, UserDocument } from "tachi-common"; + +export function SearchButton() { + return ( +
+ +
+ +
+ +
+ ); +} diff --git a/client/src/components/layout/header/Topbar.tsx b/client/src/components/layout/header/Topbar.tsx index 2b0704d07..185f9d471 100644 --- a/client/src/components/layout/header/Topbar.tsx +++ b/client/src/components/layout/header/Topbar.tsx @@ -1,34 +1,34 @@ -import { UserProfileDropdown } from "components/layout/header/UserProfileDropdown"; -import LinkButton from "components/util/LinkButton"; -import { UserContext } from "context/UserContext"; -import React, { useContext } from "react"; -import { UserNotificationButton } from "./UserNotificationButton"; -import { SearchButton } from "./SearchButton"; - -export function Topbar() { - const { user } = useContext(UserContext); - - return ( -
- - - {user ? ( - <> - - - - ) : ( - <> -
- - Log In - -
-
- Create Account -
- - )} -
- ); -} +import { UserProfileDropdown } from "components/layout/header/UserProfileDropdown"; +import LinkButton from "components/util/LinkButton"; +import { UserContext } from "context/UserContext"; +import React, { useContext } from "react"; +import { UserNotificationButton } from "./UserNotificationButton"; +import { SearchButton } from "./SearchButton"; + +export function Topbar() { + const { user } = useContext(UserContext); + + return ( +
+ + + {user ? ( + <> + + + + ) : ( + <> +
+ + Log In + +
+
+ Create Account +
+ + )} +
+ ); +} diff --git a/client/src/components/layout/header/UserNotificationButton.tsx b/client/src/components/layout/header/UserNotificationButton.tsx index 6ffa0f333..3d24a80b6 100644 --- a/client/src/components/layout/header/UserNotificationButton.tsx +++ b/client/src/components/layout/header/UserNotificationButton.tsx @@ -1,35 +1,35 @@ -import Icon from "components/util/Icon"; -import useApiQuery from "components/util/query/useApiQuery"; -import { NotificationsContext } from "context/NotificationsContext"; -import React, { useContext, useMemo } from "react"; -import { Link } from "react-router-dom"; -import { NotificationDocument, UserDocument } from "tachi-common"; - -export function UserNotificationButton({ user }: { user: UserDocument }) { - const { notifications } = useContext(NotificationsContext); - - const unread = useMemo(() => { - if (!notifications) { - return 0; - } - - return notifications.filter((e) => e.read === false).length; - }, [notifications]); - - return ( -
- -
- {unread > 0 ? ( - - ) : ( - - )} -
- -
- ); -} +import Icon from "components/util/Icon"; +import useApiQuery from "components/util/query/useApiQuery"; +import { NotificationsContext } from "context/NotificationsContext"; +import React, { useContext, useMemo } from "react"; +import { Link } from "react-router-dom"; +import { NotificationDocument, UserDocument } from "tachi-common"; + +export function UserNotificationButton({ user }: { user: UserDocument }) { + const { notifications } = useContext(NotificationsContext); + + const unread = useMemo(() => { + if (!notifications) { + return 0; + } + + return notifications.filter((e) => e.read === false).length; + }, [notifications]); + + return ( +
+ +
+ {unread > 0 ? ( + + ) : ( + + )} +
+ +
+ ); +} diff --git a/client/src/components/layout/header/UserProfileDropdown.tsx b/client/src/components/layout/header/UserProfileDropdown.tsx index 2da7cde4e..b68a8fd5c 100644 --- a/client/src/components/layout/header/UserProfileDropdown.tsx +++ b/client/src/components/layout/header/UserProfileDropdown.tsx @@ -1,135 +1,135 @@ -import { APIFetchV1, ToAPIURL } from "util/api"; -import { RFA } from "util/misc"; -import { heySplashes } from "util/splashes"; -import Divider from "components/util/Divider"; -import DropdownToggleOverride from "components/util/DropdownToggleOverride"; -import Icon from "components/util/Icon"; -import { UserContext } from "context/UserContext"; -import React, { useContext, useState } from "react"; -import { Button } from "react-bootstrap"; -import Dropdown from "react-bootstrap/Dropdown"; -import toast from "react-hot-toast"; -import { Link } from "react-router-dom"; -import { UserDocument } from "tachi-common"; - -export function UserProfileDropdown({ user }: { user: UserDocument }) { - const { setUser } = useContext(UserContext); - const [heySplash] = useState(RFA(heySplashes)); - - return ( - - -
- - {heySplash}, - {" "} - - {user.username} - - - Pic - -
-
- -
- -
-
- -
-
-
My Profile
-
View your profile!
-
-
- - -
-
- -
-
-
Notifications
-
View your notifications!
-
-
- - -
-
- -
-
-
- Profile Settings -
-
- Manage your profile picture, status, and more! -
-
-
- - -
-
- -
-
-
- My Integrations -
-
- Manage your API Keys and integrations with other services. -
-
-
- - - - -
- -
-
-
-
- ); -} +import { APIFetchV1, ToAPIURL } from "util/api"; +import { RFA } from "util/misc"; +import { heySplashes } from "util/splashes"; +import Divider from "components/util/Divider"; +import DropdownToggleOverride from "components/util/DropdownToggleOverride"; +import Icon from "components/util/Icon"; +import { UserContext } from "context/UserContext"; +import React, { useContext, useState } from "react"; +import { Button } from "react-bootstrap"; +import Dropdown from "react-bootstrap/Dropdown"; +import toast from "react-hot-toast"; +import { Link } from "react-router-dom"; +import { UserDocument } from "tachi-common"; + +export function UserProfileDropdown({ user }: { user: UserDocument }) { + const { setUser } = useContext(UserContext); + const [heySplash] = useState(RFA(heySplashes)); + + return ( + + +
+ + {heySplash}, + {" "} + + {user.username} + + + Pic + +
+
+ +
+ +
+
+ +
+
+
My Profile
+
View your profile!
+
+
+ + +
+
+ +
+
+
Notifications
+
View your notifications!
+
+
+ + +
+
+ +
+
+
+ Profile Settings +
+
+ Manage your profile picture, status, and more! +
+
+
+ + +
+
+ +
+
+
+ My Integrations +
+
+ Manage your API Keys and integrations with other services. +
+
+
+ + + + +
+ +
+
+
+
+ ); +} diff --git a/client/src/components/layout/misc/MaterialThemeProvider.tsx b/client/src/components/layout/misc/MaterialThemeProvider.tsx index 66afed61e..0a01486fc 100644 --- a/client/src/components/layout/misc/MaterialThemeProvider.tsx +++ b/client/src/components/layout/misc/MaterialThemeProvider.tsx @@ -1,30 +1,30 @@ -import { ThemeProvider, createTheme } from "@mui/material/styles"; - -import { ColourConfig } from "lib/config"; -import React from "react"; -import { JustChildren } from "types/react"; - -const theme = createTheme({ - typography: { - fontFamily: "Poppins", - }, - palette: { - secondary: { - main: ColourConfig.primary, - }, - primary: { - main: ColourConfig.primary, - }, - }, - components: { - MuiButtonBase: { - defaultProps: { - disableRipple: true, - }, - }, - }, -}); - -export function MaterialThemeProvider({ children }: JustChildren) { - return {children}; -} +import { ThemeProvider, createTheme } from "@mui/material/styles"; + +import { ColourConfig } from "lib/config"; +import React from "react"; +import { JustChildren } from "types/react"; + +const theme = createTheme({ + typography: { + fontFamily: "Poppins", + }, + palette: { + secondary: { + main: ColourConfig.primary, + }, + primary: { + main: ColourConfig.primary, + }, + }, + components: { + MuiButtonBase: { + defaultProps: { + disableRipple: true, + }, + }, + }, +}); + +export function MaterialThemeProvider({ children }: JustChildren) { + return {children}; +} diff --git a/client/src/components/layout/screens/LoadingScreen.tsx b/client/src/components/layout/screens/LoadingScreen.tsx index 3fad2d442..a0a30d220 100644 --- a/client/src/components/layout/screens/LoadingScreen.tsx +++ b/client/src/components/layout/screens/LoadingScreen.tsx @@ -1,57 +1,57 @@ -import { APIFetchV1 } from "util/api"; -import { UserContext } from "context/UserContext"; -import { TachiConfig } from "lib/config"; -import React, { useContext, useEffect, useState } from "react"; -import { UserDocument } from "tachi-common"; -import { JustChildren } from "types/react"; -import { SplashScreen } from "./SplashScreen"; - -export function LoadingScreen({ children }: JustChildren) { - const [loading, setLoading] = useState(true); - // if we've been waiting around for too long, maybe we're down. - const [broke, setBroke] = useState(""); - - const { setUser } = useContext(UserContext); - - useEffect(() => { - if (!localStorage.getItem("isLoggedIn")) { - setLoading(false); - return; - } - - const timeout = setTimeout( - () => - setBroke( - `It's taking a long time for ${TachiConfig.name} to load. We might be under strain, or completely down, sorry!` - ), - 4_000 - ); - - Promise.all([ - APIFetchV1("/users/me").then((rj) => { - if (rj.success) { - setUser(rj.body); - } else { - localStorage.removeItem("isLoggedIn"); - } - }), - ]) - .then(() => { - setLoading(false); - clearTimeout(timeout); - }) - .catch((err) => { - console.error(err); - setBroke( - `${TachiConfig.name} is currently down, sadly. Check back in a while, or we might be doing a quick server restart. Sorry!` - ); - clearTimeout(timeout); - }); - }, []); - - if (loading) { - return ; - } - - return <>{children}; -} +import { APIFetchV1 } from "util/api"; +import { UserContext } from "context/UserContext"; +import { TachiConfig } from "lib/config"; +import React, { useContext, useEffect, useState } from "react"; +import { UserDocument } from "tachi-common"; +import { JustChildren } from "types/react"; +import { SplashScreen } from "./SplashScreen"; + +export function LoadingScreen({ children }: JustChildren) { + const [loading, setLoading] = useState(true); + // if we've been waiting around for too long, maybe we're down. + const [broke, setBroke] = useState(""); + + const { setUser } = useContext(UserContext); + + useEffect(() => { + if (!localStorage.getItem("isLoggedIn")) { + setLoading(false); + return; + } + + const timeout = setTimeout( + () => + setBroke( + `It's taking a long time for ${TachiConfig.name} to load. We might be under strain, or completely down, sorry!` + ), + 4_000 + ); + + Promise.all([ + APIFetchV1("/users/me").then((rj) => { + if (rj.success) { + setUser(rj.body); + } else { + localStorage.removeItem("isLoggedIn"); + } + }), + ]) + .then(() => { + setLoading(false); + clearTimeout(timeout); + }) + .catch((err) => { + console.error(err); + setBroke( + `${TachiConfig.name} is currently down, sadly. Check back in a while, or we might be doing a quick server restart. Sorry!` + ); + clearTimeout(timeout); + }); + }, []); + + if (loading) { + return ; + } + + return <>{children}; +} diff --git a/client/src/components/layout/screens/SplashScreen.tsx b/client/src/components/layout/screens/SplashScreen.tsx index 606ebef28..534aedf21 100644 --- a/client/src/components/layout/screens/SplashScreen.tsx +++ b/client/src/components/layout/screens/SplashScreen.tsx @@ -1,13 +1,13 @@ -import { CircularProgress } from "@mui/material"; -import React from "react"; -import SplashImage from "../misc/SplashImage"; - -export function SplashScreen({ broke }: { broke: string }) { - return ( -
- - {!broke && } - {broke &&

{broke}

} -
- ); -} +import { CircularProgress } from "@mui/material"; +import React from "react"; +import SplashImage from "../misc/SplashImage"; + +export function SplashScreen({ broke }: { broke: string }) { + return ( +
+ + {!broke && } + {broke &&

{broke}

} +
+ ); +} diff --git a/client/src/components/layout/subheader/SubHeader.tsx b/client/src/components/layout/subheader/SubHeader.tsx index 7675d403f..be4008544 100644 --- a/client/src/components/layout/subheader/SubHeader.tsx +++ b/client/src/components/layout/subheader/SubHeader.tsx @@ -1,32 +1,32 @@ -import Divider from "components/util/Divider"; -import React, { useContext } from "react"; -import { SubheaderContext } from "../../../context/SubheaderContext"; -import { Breadcrumbs } from "./components/Breadcrumbs"; - -export function SubHeader() { - const subheader = useContext(SubheaderContext); - - return ( - <> -
-
-
-

{subheader.title}

-
-
-
-

- {subheader.title} -

- - -
-
-
-
-
- -
- - ); -} +import Divider from "components/util/Divider"; +import React, { useContext } from "react"; +import { SubheaderContext } from "../../../context/SubheaderContext"; +import { Breadcrumbs } from "./components/Breadcrumbs"; + +export function SubHeader() { + const subheader = useContext(SubheaderContext); + + return ( + <> +
+
+
+

{subheader.title}

+
+
+
+

+ {subheader.title} +

+ + +
+
+
+
+
+ +
+ + ); +} diff --git a/client/src/components/layout/subheader/components/Breadcrumbs.tsx b/client/src/components/layout/subheader/components/Breadcrumbs.tsx index 4d02e551c..88869a138 100644 --- a/client/src/components/layout/subheader/components/Breadcrumbs.tsx +++ b/client/src/components/layout/subheader/components/Breadcrumbs.tsx @@ -1,40 +1,40 @@ -import React, { Fragment } from "react"; -import { Link } from "react-router-dom"; -import { GetGameConfig } from "tachi-common"; - -export function Breadcrumbs({ items }: { items: string[] }) { - const url = location.pathname; - - // we also need to remove the first param, as it is an empty string - const parts = url.split("/").slice(1); - - return ( -
- - - - {items.map((name, index) => { - // Skip playtype in the breadcrumbs if the game only has one playtype. - // @hack - // this only works if the game has one playtype called "Single". - // Some games (like pop'n) have one playtype, but it's called - // 9B. They'll just have to cope. - if (items[index - 2] === "Games" && name === "Single") { - return; - } - - return ( - - - - {name} - - - ); - })} -
- ); -} +import React, { Fragment } from "react"; +import { Link } from "react-router-dom"; +import { GetGameConfig } from "tachi-common"; + +export function Breadcrumbs({ items }: { items: string[] }) { + const url = location.pathname; + + // we also need to remove the first param, as it is an empty string + const parts = url.split("/").slice(1); + + return ( +
+ + + + {items.map((name, index) => { + // Skip playtype in the breadcrumbs if the game only has one playtype. + // @hack + // this only works if the game has one playtype called "Single". + // Some games (like pop'n) have one playtype, but it's called + // 9B. They'll just have to cope. + if (items[index - 2] === "Games" && name === "Single") { + return; + } + + return ( + + + + {name} + + + ); + })} +
+ ); +} diff --git a/client/src/context/SubheaderContext.tsx b/client/src/context/SubheaderContext.tsx index 3c77e755e..eed233a3e 100644 --- a/client/src/context/SubheaderContext.tsx +++ b/client/src/context/SubheaderContext.tsx @@ -1,20 +1,20 @@ -import { NO_OP } from "util/misc"; -import React, { createContext, useState } from "react"; -import { JustChildren, SetState } from "types/react"; - -export const SubheaderContext = createContext({ - title: "", - setTitle: NO_OP as SetState, - breadcrumbs: [] as string[], - setBreadcrumbs: NO_OP as SetState, -}); - -export function SubheaderContextProvider({ children }: JustChildren) { - const [title, setTitle] = useState(""); - const [breadcrumbs, setBreadcrumbs] = useState([]); - return ( - - {children} - - ); -} +import { NO_OP } from "util/misc"; +import React, { createContext, useState } from "react"; +import { JustChildren, SetState } from "types/react"; + +export const SubheaderContext = createContext({ + title: "", + setTitle: NO_OP as SetState, + breadcrumbs: [] as string[], + setBreadcrumbs: NO_OP as SetState, +}); + +export function SubheaderContextProvider({ children }: JustChildren) { + const [title, setTitle] = useState(""); + const [breadcrumbs, setBreadcrumbs] = useState([]); + return ( + + {children} + + ); +} diff --git a/client/src/index.tsx b/client/src/index.tsx index bc07eaa5d..3ba31e21c 100644 --- a/client/src/index.tsx +++ b/client/src/index.tsx @@ -1,12 +1,12 @@ -import "@fortawesome/fontawesome-free/css/all.min.css"; -import React from "react"; -import ReactDOM from "react-dom"; -import "./_style/stub.scss"; -import "./_assets/flaticon/flaticon.css"; -import "./_assets/flaticon2/flaticon.css"; -import "./_assets/keenthemes-icons/font/ki.css"; -import App from "app/App"; - -const { PUBLIC_URL } = process.env; - -ReactDOM.render(, document.getElementById("root")); +import "@fortawesome/fontawesome-free/css/all.min.css"; +import React from "react"; +import ReactDOM from "react-dom"; +import "./_style/stub.scss"; +import "./_assets/flaticon/flaticon.css"; +import "./_assets/flaticon2/flaticon.css"; +import "./_assets/keenthemes-icons/font/ki.css"; +import App from "app/App"; + +const { PUBLIC_URL } = process.env; + +ReactDOM.render(, document.getElementById("root"));