mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2025-10-29 13:15:46 +00:00
refactor: split app context and user context
This commit is contained in:
42
site/src/context/app-context.tsx
Normal file
42
site/src/context/app-context.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import React, { createContext, useContext } from "react";
|
||||
import axios from "axios";
|
||||
import { AppContextSchemaType } from "../schemas/app-context-schema";
|
||||
|
||||
const AppContext = createContext<AppContextSchemaType | null>(null);
|
||||
|
||||
export const AppContextProvider = ({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
const {
|
||||
data: userContext,
|
||||
isLoading,
|
||||
error,
|
||||
} = useQuery({
|
||||
queryKey: ["appContext"],
|
||||
queryFn: async () => {
|
||||
const res = await axios.get("/api/app");
|
||||
return res.data;
|
||||
},
|
||||
});
|
||||
|
||||
if (error && !isLoading) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return (
|
||||
<AppContext.Provider value={userContext}>{children}</AppContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useAppContext = () => {
|
||||
const context = useContext(AppContext);
|
||||
|
||||
if (context === null) {
|
||||
throw new Error("useAppContext must be used within an AppContextProvider");
|
||||
}
|
||||
|
||||
return context;
|
||||
};
|
||||
@@ -17,7 +17,7 @@ export const UserContextProvider = ({
|
||||
} = useQuery({
|
||||
queryKey: ["userContext"],
|
||||
queryFn: async () => {
|
||||
const res = await axios.get("/api/status");
|
||||
const res = await axios.get("/api/user");
|
||||
return res.data;
|
||||
},
|
||||
});
|
||||
|
||||
@@ -16,6 +16,7 @@ import { NotFoundPage } from "./pages/not-found-page.tsx";
|
||||
import { UnauthorizedPage } from "./pages/unauthorized-page.tsx";
|
||||
import { InternalServerError } from "./pages/internal-server-error.tsx";
|
||||
import { TotpPage } from "./pages/totp-page.tsx";
|
||||
import { AppContextProvider } from "./context/app-context.tsx";
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
@@ -30,20 +31,22 @@ createRoot(document.getElementById("root")!).render(
|
||||
<MantineProvider forceColorScheme="dark">
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<Notifications />
|
||||
<UserContextProvider>
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={<App />} />
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route path="/totp" element={<TotpPage />} />
|
||||
<Route path="/logout" element={<LogoutPage />} />
|
||||
<Route path="/continue" element={<ContinuePage />} />
|
||||
<Route path="/unauthorized" element={<UnauthorizedPage />} />
|
||||
<Route path="/error" element={<InternalServerError />} />
|
||||
<Route path="*" element={<NotFoundPage />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</UserContextProvider>
|
||||
<AppContextProvider>
|
||||
<UserContextProvider>
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={<App />} />
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route path="/totp" element={<TotpPage />} />
|
||||
<Route path="/logout" element={<LogoutPage />} />
|
||||
<Route path="/continue" element={<ContinuePage />} />
|
||||
<Route path="/unauthorized" element={<UnauthorizedPage />} />
|
||||
<Route path="/error" element={<InternalServerError />} />
|
||||
<Route path="*" element={<NotFoundPage />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</UserContextProvider>
|
||||
</AppContextProvider>
|
||||
</QueryClientProvider>
|
||||
</MantineProvider>
|
||||
</StrictMode>,
|
||||
|
||||
@@ -5,13 +5,15 @@ import { useUserContext } from "../context/user-context";
|
||||
import { Layout } from "../components/layouts/layout";
|
||||
import { ReactNode } from "react";
|
||||
import { isQueryValid } from "../utils/utils";
|
||||
import { useAppContext } from "../context/app-context";
|
||||
|
||||
export const ContinuePage = () => {
|
||||
const queryString = window.location.search;
|
||||
const params = new URLSearchParams(queryString);
|
||||
const redirectUri = params.get("redirect_uri") ?? "";
|
||||
|
||||
const { isLoggedIn, disableContinue } = useUserContext();
|
||||
const { isLoggedIn } = useUserContext();
|
||||
const { disableContinue } = useAppContext();
|
||||
|
||||
if (!isLoggedIn) {
|
||||
return <Navigate to={`/login?redirect_uri=${redirectUri}`} />;
|
||||
|
||||
@@ -9,14 +9,15 @@ import { OAuthButtons } from "../components/auth/oauth-buttons";
|
||||
import { LoginFormValues } from "../schemas/login-schema";
|
||||
import { LoginForm } from "../components/auth/login-forn";
|
||||
import { isQueryValid } from "../utils/utils";
|
||||
import { useAppContext } from "../context/app-context";
|
||||
|
||||
export const LoginPage = () => {
|
||||
const queryString = window.location.search;
|
||||
const params = new URLSearchParams(queryString);
|
||||
const redirectUri = params.get("redirect_uri") ?? "";
|
||||
|
||||
const { isLoggedIn, configuredProviders, title, genericName } =
|
||||
useUserContext();
|
||||
const { isLoggedIn } = useUserContext();
|
||||
const { configuredProviders, title, genericName } = useAppContext();
|
||||
|
||||
const oauthProviders = configuredProviders.filter(
|
||||
(value) => value !== "username",
|
||||
|
||||
@@ -6,9 +6,11 @@ import { useUserContext } from "../context/user-context";
|
||||
import { Navigate } from "react-router";
|
||||
import { Layout } from "../components/layouts/layout";
|
||||
import { capitalize } from "../utils/utils";
|
||||
import { useAppContext } from "../context/app-context";
|
||||
|
||||
export const LogoutPage = () => {
|
||||
const { isLoggedIn, username, oauth, provider, genericName } = useUserContext();
|
||||
const { isLoggedIn, username, oauth, provider } = useUserContext();
|
||||
const { genericName } = useAppContext();
|
||||
|
||||
if (!isLoggedIn) {
|
||||
return <Navigate to="/login" />;
|
||||
@@ -45,8 +47,9 @@ export const LogoutPage = () => {
|
||||
</Text>
|
||||
<Text>
|
||||
You are currently logged in as <Code>{username}</Code>
|
||||
{oauth && ` using ${capitalize(provider === "generic" ? genericName : provider)} OAuth`}. Click the button
|
||||
below to log out.
|
||||
{oauth &&
|
||||
` using ${capitalize(provider === "generic" ? genericName : provider)} OAuth`}
|
||||
. Click the button below to log out.
|
||||
</Text>
|
||||
<Button
|
||||
fullWidth
|
||||
|
||||
@@ -6,13 +6,15 @@ import { TotpForm } from "../components/auth/totp-form";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import axios from "axios";
|
||||
import { notifications } from "@mantine/notifications";
|
||||
import { useAppContext } from "../context/app-context";
|
||||
|
||||
export const TotpPage = () => {
|
||||
const queryString = window.location.search;
|
||||
const params = new URLSearchParams(queryString);
|
||||
const redirectUri = params.get("redirect_uri") ?? "";
|
||||
|
||||
const { totpPending, isLoggedIn, title } = useUserContext();
|
||||
const { totpPending, isLoggedIn } = useUserContext();
|
||||
const { title } = useAppContext();
|
||||
|
||||
if (isLoggedIn) {
|
||||
return <Navigate to={`/logout`} />;
|
||||
|
||||
10
site/src/schemas/app-context-schema.ts
Normal file
10
site/src/schemas/app-context-schema.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const appContextSchema = z.object({
|
||||
configuredProviders: z.array(z.string()),
|
||||
disableContinue: z.boolean(),
|
||||
title: z.string(),
|
||||
genericName: z.string(),
|
||||
});
|
||||
|
||||
export type AppContextSchemaType = z.infer<typeof appContextSchema>;
|
||||
@@ -5,10 +5,6 @@ export const userContextSchema = z.object({
|
||||
username: z.string(),
|
||||
oauth: z.boolean(),
|
||||
provider: z.string(),
|
||||
configuredProviders: z.array(z.string()),
|
||||
disableContinue: z.boolean(),
|
||||
title: z.string(),
|
||||
genericName: z.string(),
|
||||
totpPending: z.boolean(),
|
||||
});
|
||||
|
||||
|
||||
@@ -4,4 +4,14 @@ import react from "@vitejs/plugin-react-swc";
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
server: {
|
||||
host: "0.0.0.0",
|
||||
proxy: {
|
||||
"/api": {
|
||||
target: "http://tinyauth-backend:3000/api",
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, ""),
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user