diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 10b347f..f740b28 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -43,7 +43,7 @@ dependencies:
'@fontsource/roboto': 4.5.8
'@mattjennings/react-modal-stack': 1.0.4_react@18.2.0
'@mui/material': 5.11.13_xqeqsl5kvjjtyxwyi3jhw3yuli
- '@puyodead1/fosscord-ts': github.com/Puyodead1/fosscord.ts/d736433fa8e05d8b761eb352c813d93f7afb0baf
+ '@puyodead1/fosscord-ts': github.com/Puyodead1/fosscord.ts/eb44aa8023076f6e18f22354143fe1032062fa67
'@testing-library/jest-dom': 5.16.5
'@testing-library/react': 13.4.0_biqbaboplfbrettd7655fr4n2y
'@testing-library/user-event': 13.5.0
@@ -11233,8 +11233,8 @@ packages:
- debug
dev: false
- github.com/Puyodead1/fosscord.ts/d736433fa8e05d8b761eb352c813d93f7afb0baf:
- resolution: {tarball: https://codeload.github.com/Puyodead1/fosscord.ts/tar.gz/d736433fa8e05d8b761eb352c813d93f7afb0baf}
+ github.com/Puyodead1/fosscord.ts/eb44aa8023076f6e18f22354143fe1032062fa67:
+ resolution: {tarball: https://codeload.github.com/Puyodead1/fosscord.ts/tar.gz/eb44aa8023076f6e18f22354143fe1032062fa67}
name: '@puyodead1/fosscord-ts'
version: 0.0.1
prepare: true
diff --git a/src/App.tsx b/src/App.tsx
index 67ecd7c..31d6999 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,22 +1,64 @@
-import { Route, Routes } from "react-router-dom";
+import { observer } from "mobx-react-lite";
+import React from "react";
+import { Route, Routes, useNavigate } from "react-router-dom";
+import secureLocalStorage from "react-secure-storage";
+import { AuthenticationGuard } from "./components/AuthenticationGuard";
+import LoadingPage from "./pages/LoadingPage";
import LoginPage from "./pages/LoginPage";
import NotFoundPage from "./pages/NotFound";
import RegistrationPage from "./pages/RegistrationPage";
import RootPage from "./pages/RootPage";
-import RequireAuth from "./utils/RequireAuth";
+import { useAppStore } from "./stores/AppStore";
function App() {
+ const app = useAppStore();
+ const navigate = useNavigate();
+ const [isLoading, setLoading] = React.useState(true);
+
+ React.useEffect(() => {
+ const token = secureLocalStorage.getItem("token");
+ if (token) {
+ app.api.loginWithToken(token as string).then(() => {
+ setLoading(false);
+ });
+ } else {
+ // set timeout to prevent flashing
+ setTimeout(() => {
+ setLoading(false);
+ }, 1000);
+ }
+ }, []);
+
+ // handles token changes
+ React.useEffect(() => {
+ if (!app.api.token && !isLoading) {
+ console.log("TOKEN REMOVED");
+ // remove token
+ secureLocalStorage.removeItem("token");
+ // navigate to login page if token is removed
+ navigate("/login", { replace: true });
+ }
+
+ if (app.api.token) {
+ console.log("TOKEN ADDED");
+ // save token
+ secureLocalStorage.setItem("token", app.api.token);
+ // navigate to root page if token is added
+ navigate("/", { replace: true });
+ }
+ }, [app.api.token, isLoading]);
+
+ if (isLoading) {
+ return ;
+ }
+
return (
-
-
- }
+ element={}
/>
-
} />
} />
} />
@@ -24,4 +66,4 @@ function App() {
);
}
-export default App;
+export default observer(App);
diff --git a/src/assets/images/logo/Logo-Blue.svg b/src/assets/images/logo/Logo-Blue.svg
new file mode 100644
index 0000000..65efd86
--- /dev/null
+++ b/src/assets/images/logo/Logo-Blue.svg
@@ -0,0 +1,11 @@
+
diff --git a/src/assets/images/logo/Logo-White.svg b/src/assets/images/logo/Logo-White.svg
new file mode 100644
index 0000000..af3ba30
--- /dev/null
+++ b/src/assets/images/logo/Logo-White.svg
@@ -0,0 +1,11 @@
+
diff --git a/src/components/AuthenticationGuard.tsx b/src/components/AuthenticationGuard.tsx
new file mode 100644
index 0000000..8b0fd08
--- /dev/null
+++ b/src/components/AuthenticationGuard.tsx
@@ -0,0 +1,17 @@
+import { Navigate } from "react-router-dom";
+import { useAppStore } from "../stores/AppStore";
+
+interface Props {
+ component: React.FC;
+}
+
+export const AuthenticationGuard = ({ component }: Props) => {
+ const app = useAppStore();
+
+ if (!app.api.token) {
+ return ;
+ }
+
+ const Component = component;
+ return ;
+};
diff --git a/src/components/Container.tsx b/src/components/Container.tsx
index 19cb6eb..c21562c 100644
--- a/src/components/Container.tsx
+++ b/src/components/Container.tsx
@@ -3,4 +3,5 @@ import styled from "styled-components";
export default styled.div`
background-color: var(--tertiary);
color: var(--text);
+ overflow: hidden;
`;
diff --git a/src/contexts/Auth.tsx b/src/contexts/Auth.tsx
deleted file mode 100644
index 68ab6a6..0000000
--- a/src/contexts/Auth.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import React from "react";
-
-interface AuthContextType {
- user: any;
- login: () => void;
- logout: () => void;
-}
-
-export const AuthContext = React.createContext(null!);
-
-export function AuthProvider({ children }: { children: React.ReactNode }) {
- let [user, setUser] = React.useState(null);
-
- let login = () => {
- setUser("test");
- };
-
- let logout = () => {
- setUser(null);
- };
-
- let value = { user, login, logout };
-
- return {children};
-}
diff --git a/src/contexts/Theme.tsx b/src/contexts/Theme.tsx
index cd82f3a..085bec3 100644
--- a/src/contexts/Theme.tsx
+++ b/src/contexts/Theme.tsx
@@ -40,7 +40,7 @@ export type Theme = Overrides & {
export const ThemePresets: Record = {
light: {
brandPrimary: "#0185ff",
- brandSecondary: "#000115",
+ brandSecondary: "#ffffff",
primary: "#ede8e7",
primaryAlt: "",
secondary: "#ebe5e4",
@@ -67,7 +67,7 @@ export const ThemePresets: Record = {
},
dark: {
brandPrimary: "#0185ff",
- brandSecondary: "#000115",
+ brandSecondary: "#ffffff",
primary: "#232120",
primaryAlt: "#312e2d",
secondary: "#1b1918",
diff --git a/src/hooks/useAuth.ts b/src/hooks/useAuth.ts
deleted file mode 100644
index 645e158..0000000
--- a/src/hooks/useAuth.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import React from "react";
-import { AuthContext } from "../contexts/Auth";
-
-export default function useAuth() {
- return React.useContext(AuthContext);
-}
diff --git a/src/index.tsx b/src/index.tsx
index 5caf8d2..ca22518 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -2,11 +2,9 @@ import "@fontsource/roboto/300.css";
import "@fontsource/roboto/400.css";
import "@fontsource/roboto/500.css";
import "@fontsource/roboto/700.css";
-import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
-import { AuthProvider } from "./contexts/Auth";
import Theme from "./contexts/Theme";
import "./index.css";
@@ -14,12 +12,8 @@ const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
root.render(
-
-
-
-
-
-
-
-
+
+
+
+
);
diff --git a/src/pages/LoadingPage.tsx b/src/pages/LoadingPage.tsx
new file mode 100644
index 0000000..d806a4a
--- /dev/null
+++ b/src/pages/LoadingPage.tsx
@@ -0,0 +1,31 @@
+import { observer } from "mobx-react-lite";
+import PulseLoader from "react-spinners/PulseLoader";
+import styled from "styled-components";
+import { ReactComponent as SpacebarLogoBlue } from "../assets/images/logo/Logo-Blue.svg";
+import Container from "../components/Container";
+
+const Wrapper = styled.div`
+ justify-content: center;
+ align-items: center;
+ display: flex;
+ height: 100vh;
+ flex-direction: column;
+`;
+
+const SpacebarLogo = styled(SpacebarLogoBlue)`
+ height: 120px;
+ margin-bottom: 32px;
+`;
+
+function LoadingPage() {
+ return (
+
+
+
+
+
+
+ );
+}
+
+export default observer(LoadingPage);
diff --git a/src/pages/LoginPage.tsx b/src/pages/LoginPage.tsx
index 9108cdf..7da9c1f 100644
--- a/src/pages/LoginPage.tsx
+++ b/src/pages/LoginPage.tsx
@@ -153,26 +153,23 @@ function LoginPage() {
} = useForm();
const onSubmit = handleSubmit((data) => {
- app.api
- .login(data)
- .then(app.setToken)
- .catch((e) => {
- if (e instanceof MFAError) {
- console.log("MFA Required", e);
- } else if (e instanceof CaptchaError) {
- console.log("Captcha Required", e);
- } else if (e instanceof APIError) {
- console.log("APIError", e.message, e.code, e.fieldErrors);
- e.fieldErrors.forEach((fieldError) => {
- setError(fieldError.field as any, {
- type: "manual",
- message: fieldError.error,
- });
+ app.api.login(data).catch((e) => {
+ if (e instanceof MFAError) {
+ console.log("MFA Required", e);
+ } else if (e instanceof CaptchaError) {
+ console.log("Captcha Required", e);
+ } else if (e instanceof APIError) {
+ console.log("APIError", e.message, e.code, e.fieldErrors);
+ e.fieldErrors.forEach((fieldError) => {
+ setError(fieldError.field as any, {
+ type: "manual",
+ message: fieldError.error,
});
- } else {
- console.log("General Error", e);
- }
- });
+ });
+ } else {
+ console.log("General Error", e);
+ }
+ });
});
return (
diff --git a/src/pages/RootPage.tsx b/src/pages/RootPage.tsx
index 1765c3d..5f7adbe 100644
--- a/src/pages/RootPage.tsx
+++ b/src/pages/RootPage.tsx
@@ -1,7 +1,16 @@
+import { observer } from "mobx-react-lite";
import Container from "../components/Container";
+import { useAppStore } from "../stores/AppStore";
+import LoadingPage from "./LoadingPage";
function RootPage() {
+ const app = useAppStore();
+
+ if (!app.ready) {
+ return ;
+ }
+
return RootPage;
}
-export default RootPage;
+export default observer(RootPage);
diff --git a/src/stores/AppStore.ts b/src/stores/AppStore.ts
index f258e5b..b9aaf7a 100644
--- a/src/stores/AppStore.ts
+++ b/src/stores/AppStore.ts
@@ -1,6 +1,5 @@
import { Client } from "@puyodead1/fosscord-ts";
-import { makeAutoObservable, observable } from "mobx";
-import secureLocalStorage from "react-secure-storage";
+import { makeAutoObservable, observable, runInAction } from "mobx";
import ThemeStore from "./ThemeStore";
export default class AppStore {
@@ -20,12 +19,15 @@ export default class AppStore {
this.api.on("debug", console.debug);
this.api.on("warn", console.warn);
this.api.on("error", console.error);
+ this.api.on("ready", this.onReady.bind(this));
makeAutoObservable(this);
}
- public setToken(token: string) {
- secureLocalStorage.setItem("token", token);
+ onReady() {
+ runInAction(() => {
+ this.ready = true;
+ });
}
}
diff --git a/src/utils/RequireAuth.tsx b/src/utils/RequireAuth.tsx
deleted file mode 100644
index 1cd62c1..0000000
--- a/src/utils/RequireAuth.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Navigate, useLocation } from "react-router-dom";
-import useAuth from "../hooks/useAuth";
-
-function RequireAuth({ children }: { children: JSX.Element }) {
- let auth = useAuth();
- let location = useLocation();
-
- if (!auth.user) {
- return ;
- }
-
- return children;
-}
-
-export default RequireAuth;