🔧 fix(authGuard): add missing newline at the end of the file
🆕 feat(headerComponent): add logout functionality and redirect to login page on sign out 🔧 fix(constants): add missing URL to the list of excluded error retries 🔧 fix(authContext): add refreshToken state and update login and logout functions to handle refresh token 🆕 feat(api): add interceptor to handle access token expiration and refresh 🔧 fix(api): add missing request interceptor to add access token to every request 🔧 fix(API/index.ts): import missing LoginAuthType and LoginType from types/api/index to resolve compilation error ✨ feat(API/index.ts): add onLogin function to handle user login and authentication ✨ feat(API/index.ts): add renewAccessToken function to handle token renewal 🔧 fix(loginPage/index.tsx): import missing onLogin function from controllers/API to resolve compilation error ✨ feat(loginPage/index.tsx): add signIn function to handle user sign in and authentication 🔧 fix(routes.tsx): import ProtectedRoute component from components/authGuard to resolve compilation error ✨ feat(routes.tsx): add protected routes for HomePage, FlowPage, AdminPage, and DeleteAccountPage to enforce authentication 🔧 fix(api/index.ts): add missing grant_type, scope, client_id, and client_secret properties to LoginType to match API requirements ✨ feat(api/index.ts): add LoginAuthType to represent the authentication response from the server 🔧 fix(contexts/auth.ts): add refreshToken property to AuthContextType to store the refresh token
This commit is contained in:
parent
c30cb3e002
commit
c0f586ad89
11 changed files with 240 additions and 42 deletions
14
src/frontend/src/components/authGuard/index.tsx
Normal file
14
src/frontend/src/components/authGuard/index.tsx
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { useContext } from "react";
|
||||||
|
import { Navigate } from "react-router-dom";
|
||||||
|
import { AuthContext } from "../../contexts/authContext";
|
||||||
|
|
||||||
|
export const ProtectedRoute = ({ children }) => {
|
||||||
|
|
||||||
|
const { isAuthenticated } = useContext(AuthContext);
|
||||||
|
|
||||||
|
if (!isAuthenticated) {
|
||||||
|
return <Navigate to="/login" replace />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return children;
|
||||||
|
};
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { useContext, useEffect, useState } from "react";
|
import { useContext, useEffect, useState } from "react";
|
||||||
import { FaDiscord, FaGithub, FaTwitter } from "react-icons/fa";
|
import { FaDiscord, FaGithub, FaTwitter } from "react-icons/fa";
|
||||||
import { Link, useLocation } from "react-router-dom";
|
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||||
import AlertDropdown from "../../alerts/alertDropDown";
|
import AlertDropdown from "../../alerts/alertDropDown";
|
||||||
import { USER_PROJECTS_HEADER } from "../../constants/constants";
|
import { USER_PROJECTS_HEADER } from "../../constants/constants";
|
||||||
import { alertContext } from "../../contexts/alertContext";
|
import { alertContext } from "../../contexts/alertContext";
|
||||||
|
|
@ -11,12 +11,15 @@ import IconComponent from "../genericIconComponent";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
import { Separator } from "../ui/separator";
|
import { Separator } from "../ui/separator";
|
||||||
import MenuBar from "./components/menuBar";
|
import MenuBar from "./components/menuBar";
|
||||||
|
import { AuthContext } from "../../contexts/authContext";
|
||||||
|
|
||||||
export default function Header() {
|
export default function Header() {
|
||||||
const { flows, tabId } = useContext(TabsContext);
|
const { flows, tabId } = useContext(TabsContext);
|
||||||
const { dark, setDark } = useContext(darkContext);
|
const { dark, setDark } = useContext(darkContext);
|
||||||
const { notificationCenter } = useContext(alertContext);
|
const { notificationCenter } = useContext(alertContext);
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const { logout } = useContext(AuthContext);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [stars, setStars] = useState(null);
|
const [stars, setStars] = useState(null);
|
||||||
|
|
||||||
|
|
@ -34,7 +37,13 @@ export default function Header() {
|
||||||
<Link to="/">
|
<Link to="/">
|
||||||
<span className="ml-4 text-2xl">⛓️</span>
|
<span className="ml-4 text-2xl">⛓️</span>
|
||||||
</Link>
|
</Link>
|
||||||
<Button variant="outline" className="">
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
logout();
|
||||||
|
navigate("/login");
|
||||||
|
|
||||||
|
}}
|
||||||
|
variant="outline" className="">
|
||||||
Sign out
|
Sign out
|
||||||
</Button>
|
</Button>
|
||||||
{flows.findIndex((f) => tabId === f.id) !== -1 && tabId !== "" && (
|
{flows.findIndex((f) => tabId === f.id) !== -1 && tabId !== "" && (
|
||||||
|
|
|
||||||
|
|
@ -507,6 +507,7 @@ export const URL_EXCLUDED_FROM_ERROR_RETRIES = [
|
||||||
"/api/v1/validate/code",
|
"/api/v1/validate/code",
|
||||||
"/api/v1/custom_component",
|
"/api/v1/custom_component",
|
||||||
"/api/v1/validate/prompt",
|
"/api/v1/validate/prompt",
|
||||||
|
"http://localhost:7860/login"
|
||||||
];
|
];
|
||||||
export const CONTROL_INPUT_STATE = {
|
export const CONTROL_INPUT_STATE = {
|
||||||
password: "",
|
password: "",
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
import { createContext, useEffect, useState } from "react";
|
import { createContext, useEffect, useState } from "react";
|
||||||
import { AuthContextType, userData } from "../types/contexts/auth";
|
import { AuthContextType, userData } from "../types/contexts/auth";
|
||||||
|
import { LoginType } from "../types/api";
|
||||||
|
import { api } from "../controllers/API/api";
|
||||||
|
|
||||||
const initialValue: AuthContextType = {
|
const initialValue: AuthContextType = {
|
||||||
isAuthenticated: false,
|
isAuthenticated: false,
|
||||||
accessToken: null,
|
accessToken: null,
|
||||||
|
refreshToken: null,
|
||||||
login: () => {},
|
login: () => {},
|
||||||
logout: () => {},
|
logout: () => {},
|
||||||
refreshAccessToken: () => Promise.resolve(),
|
refreshAccessToken: () => Promise.resolve(),
|
||||||
|
|
@ -11,10 +14,12 @@ const initialValue: AuthContextType = {
|
||||||
setUserData: () => {},
|
setUserData: () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
const AuthContext = createContext<AuthContextType>(initialValue);
|
export const AuthContext = createContext<AuthContextType>(initialValue);
|
||||||
|
|
||||||
export function AuthProvider({ children }): React.ReactElement {
|
export function AuthProvider({ children }): React.ReactElement {
|
||||||
const [accessToken, setAccessToken] = useState<string | null>(null);
|
const [accessToken, setAccessToken] = useState<string | null>(null);
|
||||||
|
const [refreshToken, setRefreshToken] = useState<string | null>(null);
|
||||||
|
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
|
||||||
const [userData, setUserData] = useState<userData>(null);
|
const [userData, setUserData] = useState<userData>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -27,18 +32,23 @@ export function AuthProvider({ children }): React.ReactElement {
|
||||||
function login(newAccessToken: string, refreshToken: string) {
|
function login(newAccessToken: string, refreshToken: string) {
|
||||||
localStorage.setItem("access_token", newAccessToken);
|
localStorage.setItem("access_token", newAccessToken);
|
||||||
setAccessToken(newAccessToken);
|
setAccessToken(newAccessToken);
|
||||||
// Store refreshToken if needed
|
|
||||||
|
localStorage.setItem("refresh_token", refreshToken);
|
||||||
|
setRefreshToken(refreshToken);
|
||||||
|
|
||||||
|
setIsAuthenticated(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function logout() {
|
function logout() {
|
||||||
localStorage.removeItem("access_token");
|
localStorage.removeItem("access_token");
|
||||||
// Clear refreshToken if used
|
localStorage.removeItem("refresh_token");
|
||||||
setAccessToken(null);
|
setAccessToken(null);
|
||||||
|
setRefreshToken(null);
|
||||||
|
setIsAuthenticated(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function refreshAccessToken(refreshToken: string) {
|
async function refreshAccessToken(refreshToken: string) {
|
||||||
try {
|
try {
|
||||||
// Call your API to refresh the access token using the refresh token
|
|
||||||
const response = await fetch("/api/refresh-token", {
|
const response = await fetch("/api/refresh-token", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
|
|
@ -57,6 +67,7 @@ export function AuthProvider({ children }): React.ReactElement {
|
||||||
logout();
|
logout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// !! to convert string to boolean
|
// !! to convert string to boolean
|
||||||
|
|
@ -64,6 +75,7 @@ export function AuthProvider({ children }): React.ReactElement {
|
||||||
value={{
|
value={{
|
||||||
isAuthenticated: !!accessToken,
|
isAuthenticated: !!accessToken,
|
||||||
accessToken,
|
accessToken,
|
||||||
|
refreshToken,
|
||||||
login,
|
login,
|
||||||
logout,
|
logout,
|
||||||
refreshAccessToken,
|
refreshAccessToken,
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import { LocationProvider } from "./locationContext";
|
||||||
import { TabsProvider } from "./tabsContext";
|
import { TabsProvider } from "./tabsContext";
|
||||||
import { TypesProvider } from "./typesContext";
|
import { TypesProvider } from "./typesContext";
|
||||||
import { UndoRedoProvider } from "./undoRedoContext";
|
import { UndoRedoProvider } from "./undoRedoContext";
|
||||||
|
import { AuthProvider } from "./authContext";
|
||||||
|
|
||||||
export default function ContextWrapper({ children }: { children: ReactNode }) {
|
export default function ContextWrapper({ children }: { children: ReactNode }) {
|
||||||
//element to wrap all context
|
//element to wrap all context
|
||||||
|
|
@ -18,6 +19,7 @@ export default function ContextWrapper({ children }: { children: ReactNode }) {
|
||||||
<DarkProvider>
|
<DarkProvider>
|
||||||
<TypesProvider>
|
<TypesProvider>
|
||||||
<LocationProvider>
|
<LocationProvider>
|
||||||
|
<AuthProvider>
|
||||||
<AlertProvider>
|
<AlertProvider>
|
||||||
<SSEProvider>
|
<SSEProvider>
|
||||||
<TabsProvider>
|
<TabsProvider>
|
||||||
|
|
@ -25,6 +27,7 @@ export default function ContextWrapper({ children }: { children: ReactNode }) {
|
||||||
</TabsProvider>
|
</TabsProvider>
|
||||||
</SSEProvider>
|
</SSEProvider>
|
||||||
</AlertProvider>
|
</AlertProvider>
|
||||||
|
</AuthProvider>
|
||||||
</LocationProvider>
|
</LocationProvider>
|
||||||
</TypesProvider>
|
</TypesProvider>
|
||||||
</DarkProvider>
|
</DarkProvider>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
import axios, { AxiosError, AxiosInstance } from "axios";
|
import axios, { AxiosError, AxiosInstance } from "axios";
|
||||||
import { useContext, useEffect, useRef } from "react";
|
import { useContext, useEffect, useRef } from "react";
|
||||||
import { alertContext } from "../../contexts/alertContext";
|
import { alertContext } from "../../contexts/alertContext";
|
||||||
|
import { AuthContext } from "../../contexts/authContext";
|
||||||
|
import { URL_EXCLUDED_FROM_ERROR_RETRIES } from "../../constants/constants";
|
||||||
|
import { renewAccessToken } from ".";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
// Create a new Axios instance
|
// Create a new Axios instance
|
||||||
const api: AxiosInstance = axios.create({
|
const api: AxiosInstance = axios.create({
|
||||||
|
|
@ -10,44 +14,80 @@ const api: AxiosInstance = axios.create({
|
||||||
function ApiInterceptor() {
|
function ApiInterceptor() {
|
||||||
const retryCounts = useRef([]);
|
const retryCounts = useRef([]);
|
||||||
const { setErrorData } = useContext(alertContext);
|
const { setErrorData } = useContext(alertContext);
|
||||||
|
const { accessToken, refreshAccessToken, login, logout } = useContext(AuthContext);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const interceptor = api.interceptors.response.use(
|
const interceptor = api.interceptors.response.use(
|
||||||
(response) => response,
|
(response) => response,
|
||||||
async (error: AxiosError) => {
|
async (error: AxiosError) => {
|
||||||
// if (URL_EXCLUDED_FROM_ERROR_RETRIES.includes(error.config?.url)) {
|
if (URL_EXCLUDED_FROM_ERROR_RETRIES.includes(error.config?.url)) {
|
||||||
// return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
// }
|
}
|
||||||
// let retryCount = 0;
|
|
||||||
// while (retryCount < 4) {
|
if(error.response?.status === 401){
|
||||||
// await sleep(5000); // Sleep for 5 seconds
|
const refreshToken = localStorage.getItem("refresh_token");
|
||||||
// retryCount++;
|
if (refreshToken) {
|
||||||
// try {
|
const res = await renewAccessToken(refreshToken);
|
||||||
// const response = await axios.request(error.config);
|
login(res.access_token, res.refresh_token)
|
||||||
// return response;
|
try {
|
||||||
// } catch (error) {
|
const response = await axios.request(error.config);
|
||||||
// if (retryCount === 3) {
|
return response;
|
||||||
// setErrorData({
|
} catch (error) {
|
||||||
// title: "There was an error on web connection, please: ",
|
if(error.response?.status === 401){
|
||||||
// list: [
|
logout();
|
||||||
// "Refresh the page",
|
navigate("/login");
|
||||||
// "Use a new flow tab",
|
}
|
||||||
// "Check if the backend is up",
|
}
|
||||||
// "Endpoint: " + error.config?.url,
|
}
|
||||||
// ],
|
}
|
||||||
// });
|
|
||||||
// return Promise.reject(error);
|
else{
|
||||||
// }
|
let retryCount = 0;
|
||||||
// }
|
while (retryCount < 4) {
|
||||||
// }
|
await sleep(5000); // Sleep for 5 seconds
|
||||||
|
retryCount++;
|
||||||
|
try {
|
||||||
|
const response = await axios.request(error.config);
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
if (retryCount === 3) {
|
||||||
|
setErrorData({
|
||||||
|
title: "There was an error on web connection, please: ",
|
||||||
|
list: [
|
||||||
|
"Refresh the page",
|
||||||
|
"Use a new flow tab",
|
||||||
|
"Check if the backend is up",
|
||||||
|
"Endpoint: " + error.config?.url,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Request interceptor to add access token to every request
|
||||||
|
const requestInterceptor = api.interceptors.request.use(
|
||||||
|
(config) => {
|
||||||
|
if (accessToken) {
|
||||||
|
config.headers["Authorization"] = `Bearer ${accessToken}`;
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
// Clean up the interceptor when the component unmounts
|
// Clean up the interceptors when the component unmounts
|
||||||
api.interceptors.response.eject(interceptor);
|
api.interceptors.response.eject(interceptor);
|
||||||
|
api.interceptors.request.eject(requestInterceptor);
|
||||||
};
|
};
|
||||||
}, [retryCounts]);
|
}, [accessToken, setErrorData]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { AxiosResponse } from "axios";
|
import { AxiosResponse } from "axios";
|
||||||
import { ReactFlowJsonObject } from "reactflow";
|
import { ReactFlowJsonObject } from "reactflow";
|
||||||
import { api } from "../../controllers/API/api";
|
import { api } from "../../controllers/API/api";
|
||||||
import { APIObjectType, sendAllProps } from "../../types/api/index";
|
import { APIObjectType, LoginAuthType, LoginType, sendAllProps } from "../../types/api/index";
|
||||||
import { FlowStyleType, FlowType } from "../../types/flow";
|
import { FlowStyleType, FlowType } from "../../types/flow";
|
||||||
import {
|
import {
|
||||||
APIClassType,
|
APIClassType,
|
||||||
|
|
@ -346,3 +346,43 @@ export async function postCustomComponent(
|
||||||
): Promise<AxiosResponse<APIClassType>> {
|
): Promise<AxiosResponse<APIClassType>> {
|
||||||
return await api.post(`/api/v1/custom_component`, { code });
|
return await api.post(`/api/v1/custom_component`, { code });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function onLogin(
|
||||||
|
user: LoginType
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const response = await api.post(
|
||||||
|
"http://localhost:7860/login",
|
||||||
|
new URLSearchParams({
|
||||||
|
username: user.username,
|
||||||
|
password: user.password,
|
||||||
|
}).toString(),
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.status === 200) {
|
||||||
|
const data = response.data;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function renewAccessToken(
|
||||||
|
token: string
|
||||||
|
): Promise<LoginAuthType> {
|
||||||
|
try {
|
||||||
|
return await api.post(`http://localhost:7860/refresh?token=${token}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import * as Form from "@radix-ui/react-form";
|
import * as Form from "@radix-ui/react-form";
|
||||||
import { useState } from "react";
|
import { useContext, useState } from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
import IconComponent from "../../components/genericIconComponent";
|
import IconComponent from "../../components/genericIconComponent";
|
||||||
import InputComponent from "../../components/inputComponent";
|
import InputComponent from "../../components/inputComponent";
|
||||||
import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button";
|
||||||
|
|
@ -10,18 +10,43 @@ import {
|
||||||
inputHandlerEventType,
|
inputHandlerEventType,
|
||||||
loginInputStateType,
|
loginInputStateType,
|
||||||
} from "../../types/components";
|
} from "../../types/components";
|
||||||
|
import { onLogin } from "../../controllers/API";
|
||||||
|
import { LoginType } from "../../types/api";
|
||||||
|
import { AuthContext } from "../../contexts/authContext";
|
||||||
|
|
||||||
export default function LoginPage(): JSX.Element {
|
export default function LoginPage(): JSX.Element {
|
||||||
const [inputState, setInputState] =
|
const [inputState, setInputState] =
|
||||||
useState<loginInputStateType>(CONTROL_LOGIN_STATE);
|
useState<loginInputStateType>(CONTROL_LOGIN_STATE);
|
||||||
|
|
||||||
const { password, username } = inputState;
|
const { password, username } = inputState;
|
||||||
|
const { login } = useContext(AuthContext);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
function handleInput({
|
function handleInput({
|
||||||
target: { name, value },
|
target: { name, value },
|
||||||
}: inputHandlerEventType): void {
|
}: inputHandlerEventType): void {
|
||||||
setInputState((prev) => ({ ...prev, [name]: value }));
|
setInputState((prev) => ({ ...prev, [name]: value }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function signIn(){
|
||||||
|
|
||||||
|
const user: LoginType = {
|
||||||
|
username: username,
|
||||||
|
password: password
|
||||||
|
};
|
||||||
|
|
||||||
|
try{
|
||||||
|
onLogin(
|
||||||
|
user
|
||||||
|
).then((user) => {
|
||||||
|
login(user.access_token, user.refresh_token);
|
||||||
|
navigate("/");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch(error){
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form.Root
|
<Form.Root
|
||||||
onSubmit={(event) => {
|
onSubmit={(event) => {
|
||||||
|
|
@ -107,7 +132,9 @@ export default function LoginPage(): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<Form.Submit asChild>
|
<Form.Submit asChild>
|
||||||
<Button className="mr-3 mt-6 w-full">Sign in</Button>
|
<Button
|
||||||
|
onClick={()=>signIn()}
|
||||||
|
className="mr-3 mt-6 w-full">Sign in</Button>
|
||||||
</Form.Submit>
|
</Form.Submit>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { Route, Routes } from "react-router-dom";
|
import { Route, Routes } from "react-router-dom";
|
||||||
|
import { ProtectedRoute } from "./components/authGuard";
|
||||||
import AdminPage from "./pages/AdminPage";
|
import AdminPage from "./pages/AdminPage";
|
||||||
import LoginAdminPage from "./pages/AdminPage/LoginPage";
|
import LoginAdminPage from "./pages/AdminPage/LoginPage";
|
||||||
import CommunityPage from "./pages/CommunityPage";
|
import CommunityPage from "./pages/CommunityPage";
|
||||||
|
|
@ -11,21 +12,56 @@ import SignUp from "./pages/signUpPage";
|
||||||
const Router = () => {
|
const Router = () => {
|
||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<HomePage />} />
|
<Route
|
||||||
|
path="/"
|
||||||
|
element={
|
||||||
|
<ProtectedRoute>
|
||||||
|
<HomePage />
|
||||||
|
</ProtectedRoute>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Route path="/community" element={<CommunityPage />} />
|
<Route path="/community" element={<CommunityPage />} />
|
||||||
<Route path="/flow/:id/">
|
<Route path="/flow/:id/">
|
||||||
<Route path="" element={<FlowPage />} />
|
<Route
|
||||||
|
path=""
|
||||||
|
element={
|
||||||
|
<ProtectedRoute>
|
||||||
|
<FlowPage />
|
||||||
|
</ProtectedRoute>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="*" element={<HomePage />} />
|
<Route
|
||||||
|
path="*"
|
||||||
|
element={
|
||||||
|
<ProtectedRoute>
|
||||||
|
<HomePage />
|
||||||
|
</ProtectedRoute>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
<Route path="/login" element={<LoginPage />} />
|
<Route path="/login" element={<LoginPage />} />
|
||||||
<Route path="/signup" element={<SignUp />} />
|
<Route path="/signup" element={<SignUp />} />
|
||||||
<Route path="/login/admin" element={<LoginAdminPage />} />
|
<Route path="/login/admin" element={<LoginAdminPage />} />
|
||||||
|
|
||||||
<Route path="/admin" element={<AdminPage />} />
|
<Route
|
||||||
|
path="/admin"
|
||||||
|
element={
|
||||||
|
<ProtectedRoute>
|
||||||
|
<AdminPage />
|
||||||
|
</ProtectedRoute>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
<Route path="/account">
|
<Route path="/account">
|
||||||
<Route path="delete" element={<DeleteAccountPage />}></Route>
|
<Route
|
||||||
|
path="delete"
|
||||||
|
element={
|
||||||
|
<ProtectedRoute>
|
||||||
|
<DeleteAccountPage />
|
||||||
|
</ProtectedRoute>
|
||||||
|
}
|
||||||
|
></Route>
|
||||||
</Route>
|
</Route>
|
||||||
</Routes>
|
</Routes>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -62,3 +62,18 @@ export type UploadFileTypeAPI = {
|
||||||
file_path: string;
|
file_path: string;
|
||||||
flowId: string;
|
flowId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type LoginType = {
|
||||||
|
grant_type?: string;
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
scrope?: string;
|
||||||
|
client_id?: string;
|
||||||
|
client_secret?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LoginAuthType = {
|
||||||
|
access_token: string;
|
||||||
|
refresh_token: string;
|
||||||
|
token_type?: string;
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
export type AuthContextType = {
|
export type AuthContextType = {
|
||||||
isAuthenticated: boolean;
|
isAuthenticated: boolean;
|
||||||
accessToken: string | null;
|
accessToken: string | null;
|
||||||
|
refreshToken: string | null;
|
||||||
login: (accessToken: string, refreshToken: string) => void;
|
login: (accessToken: string, refreshToken: string) => void;
|
||||||
logout: () => void;
|
logout: () => void;
|
||||||
refreshAccessToken: (refreshToken: string) => Promise<void>;
|
refreshAccessToken: (refreshToken: string) => Promise<void>;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue