Redirect on token expiry
This commit is contained in:
parent
9de454d491
commit
4e84dc842a
@ -12,10 +12,16 @@ import {
|
||||
Scripts,
|
||||
ScrollRestoration,
|
||||
isRouteErrorResponse,
|
||||
redirect,
|
||||
useNavigate,
|
||||
useRouteError,
|
||||
} from "@remix-run/react";
|
||||
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import {
|
||||
QueryCache,
|
||||
QueryClient,
|
||||
QueryClientProvider,
|
||||
} from "@tanstack/react-query";
|
||||
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
||||
|
||||
import {
|
||||
|
@ -1,7 +1,10 @@
|
||||
import { client } from "@/util/api";
|
||||
import { useAuth } from "@/util/auth";
|
||||
import { Center, Container, List, Loader, Stack, Text } from "@mantine/core";
|
||||
import { useParams } from "@remix-run/react";
|
||||
import { useNavigate, useParams } from "@remix-run/react";
|
||||
import { IconAlertTriangle } from "@tabler/icons-react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function Flight() {
|
||||
const params = useParams();
|
||||
@ -10,8 +13,21 @@ export default function Flight() {
|
||||
queryKey: [params.id],
|
||||
queryFn: async () =>
|
||||
await client.get(`/flights/${params.id}`).then((res) => res.data),
|
||||
retry: (failureCount, error) => {
|
||||
return !error || error.response?.status !== 401;
|
||||
},
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
const { clearUser } = useAuth();
|
||||
|
||||
useEffect(() => {
|
||||
if (flight.isError && flight.error.response.status === 401) {
|
||||
clearUser();
|
||||
navigate("/login");
|
||||
}
|
||||
}, [flight]);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Stack h="calc(100vh - 95px)">
|
||||
|
@ -5,7 +5,6 @@ import {
|
||||
Fieldset,
|
||||
Group,
|
||||
NumberInput,
|
||||
ScrollArea,
|
||||
ScrollAreaAutosize,
|
||||
Stack,
|
||||
TextInput,
|
||||
@ -86,6 +85,9 @@ export default function NewFlight() {
|
||||
console.log(res);
|
||||
return res.data;
|
||||
},
|
||||
retry: (failureCount, error) => {
|
||||
return !error || error.response?.status !== 401;
|
||||
},
|
||||
onError: (error) => {
|
||||
console.log(error);
|
||||
},
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { client } from "@/util/api";
|
||||
import { useAuth } from "@/util/auth";
|
||||
import { FlightConciseSchema } from "@/util/types";
|
||||
import {
|
||||
NavLink,
|
||||
@ -8,22 +9,38 @@ import {
|
||||
Stack,
|
||||
Loader,
|
||||
Center,
|
||||
Container,
|
||||
} from "@mantine/core";
|
||||
import { Link, useLocation, useNavigate } from "@remix-run/react";
|
||||
import { IconPlus } from "@tabler/icons-react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export function FlightsList() {
|
||||
const flights = useQuery({
|
||||
queryKey: ["flights-list"],
|
||||
queryFn: () => client.get(`/flights`).then((res) => res.data),
|
||||
});
|
||||
// const flights = useQuery({
|
||||
// queryKey: ["flights-list"],
|
||||
// queryFn: () => client.get(`/flights`).then((res) => res.data),
|
||||
// });
|
||||
|
||||
const location = useLocation();
|
||||
const page = location.pathname.split("/")[3];
|
||||
|
||||
const flights = useQuery({
|
||||
queryKey: ["flights-list"],
|
||||
queryFn: async () => await client.get(`/flights`).then((res) => res.data),
|
||||
retry: (failureCount, error) => {
|
||||
return !error || error.response?.status !== 401;
|
||||
},
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
const { clearUser } = useAuth();
|
||||
|
||||
useEffect(() => {
|
||||
if (flights.isError && flights.error.response.status === 401) {
|
||||
clearUser();
|
||||
navigate("/login");
|
||||
}
|
||||
}, [flights]);
|
||||
|
||||
return (
|
||||
<Stack p="0" m="0" gap="0">
|
||||
|
@ -1,12 +1,33 @@
|
||||
import { client } from "@/util/api";
|
||||
import { useAuth } from "@/util/auth";
|
||||
import { Container, Title } from "@mantine/core";
|
||||
import { Container, Text, Title } from "@mantine/core";
|
||||
import { useNavigate } from "@remix-run/react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function Me() {
|
||||
const { user } = useAuth();
|
||||
const user = useQuery({
|
||||
queryKey: ["user"],
|
||||
queryFn: async () => await client.get(`users/me`).then((res) => res.data),
|
||||
retry: (failureCount, error) => {
|
||||
return !error || error.response?.status !== 401;
|
||||
},
|
||||
});
|
||||
|
||||
const { clearUser } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
if (user.isError && user.error.response?.status === 401) {
|
||||
clearUser();
|
||||
navigate("/login");
|
||||
}
|
||||
}, [user]);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Title order={2}>{user}</Title>
|
||||
<Title order={2}>{user.data.username}</Title>
|
||||
<Text>Level {user.data.level}</Text>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import {
|
||||
Title,
|
||||
} from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function Login() {
|
||||
const form = useForm({
|
||||
@ -23,6 +24,10 @@ export default function Login() {
|
||||
|
||||
const { signin } = useAuth();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "Log In - Tailfin";
|
||||
});
|
||||
|
||||
return (
|
||||
<Container h="75%">
|
||||
<Stack gap="md" h="100%" justify="center" align="stretch">
|
||||
@ -50,7 +55,9 @@ export default function Login() {
|
||||
mt="md"
|
||||
/>
|
||||
<Group justify="center" mt="xl">
|
||||
<Button type="submit">Log In</Button>
|
||||
<Button type="submit" fullWidth>
|
||||
Log In
|
||||
</Button>
|
||||
</Group>
|
||||
</form>
|
||||
</Fieldset>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { useNavigate } from "@remix-run/react";
|
||||
import axios from "axios";
|
||||
import { useAuth } from "./auth";
|
||||
|
||||
export const client = axios.create({
|
||||
baseURL: "http://localhost:8081",
|
||||
@ -15,27 +15,21 @@ client.interceptors.request.use(
|
||||
return config;
|
||||
},
|
||||
async (error) => {
|
||||
const originalRequest = error.config;
|
||||
const navigate = useNavigate();
|
||||
if (error.response.status == 401 && !originalRequest._retry) {
|
||||
originalRequest._retry = true;
|
||||
const refreshToken = localStorage.getItem("refresh-token");
|
||||
if (refreshToken) {
|
||||
const { clearUser } = useAuth();
|
||||
console.log(error.response);
|
||||
if (error.response && error.response.status === 401) {
|
||||
try {
|
||||
const { data } = await client.post("/auth/refresh", {
|
||||
refresh: refreshToken,
|
||||
});
|
||||
localStorage.setItem("token", data.refreshToken);
|
||||
client.defaults.headers.common[
|
||||
"Authorization"
|
||||
] = `Bearer ${data.refreshToken}`;
|
||||
return client(originalRequest);
|
||||
} catch (_error) {
|
||||
localStorage.removeItem("token");
|
||||
localStorage.removeItem("refresh-token");
|
||||
console.log("Oh no!!!");
|
||||
navigate("/login");
|
||||
}
|
||||
const refreshToken = localStorage.getItem("refresh-token");
|
||||
const response = await client.post("/auth/refresh", { refreshToken });
|
||||
const newAccessToken = response.data.access_token;
|
||||
|
||||
localStorage.setItem("token", newAccessToken);
|
||||
error.config.headers.Authorization = `Bearer ${newAccessToken}`;
|
||||
return client(error.config);
|
||||
} catch (err) {
|
||||
console.log("ERRORRRRRRRRRRRRRR");
|
||||
clearUser();
|
||||
window.location.href = "/login";
|
||||
}
|
||||
}
|
||||
return Promise.reject(error);
|
||||
|
@ -13,6 +13,7 @@ interface AuthContextValues {
|
||||
password: string;
|
||||
}) => void;
|
||||
signout: () => void;
|
||||
clearUser: () => void;
|
||||
}
|
||||
|
||||
const AuthContext = createContext<AuthContextValues | null>(null);
|
||||
@ -86,6 +87,10 @@ function useProvideAuth() {
|
||||
return await client.post("/auth/logout").then(() => handleUser(null));
|
||||
};
|
||||
|
||||
const clearUser = () => {
|
||||
handleUser(null);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
client
|
||||
.get("/users/me")
|
||||
@ -99,5 +104,6 @@ function useProvideAuth() {
|
||||
loading,
|
||||
signin,
|
||||
signout,
|
||||
clearUser,
|
||||
};
|
||||
}
|
||||
|
12
web/package-lock.json
generated
12
web/package-lock.json
generated
@ -10,6 +10,7 @@
|
||||
"@mantine/dropzone": "^7.4.0",
|
||||
"@mantine/form": "^7.4.0",
|
||||
"@mantine/hooks": "^7.4.0",
|
||||
"@mantine/modals": "^7.4.0",
|
||||
"@mantine/notifications": "^7.4.0",
|
||||
"@remix-run/css-bundle": "^2.4.1",
|
||||
"@remix-run/node": "^2.4.1",
|
||||
@ -1493,6 +1494,17 @@
|
||||
"react": "^18.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@mantine/modals": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@mantine/modals/-/modals-7.4.0.tgz",
|
||||
"integrity": "sha512-uXZuN5vCx0Wdu0gOmoDaGD8/GVpx7qCeyAAFCH94WPHl/aK3fzKSk4K63deWY5Ml9a5ktic/i5pYil3MUBEj5w==",
|
||||
"peerDependencies": {
|
||||
"@mantine/core": "7.4.0",
|
||||
"@mantine/hooks": "7.4.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@mantine/notifications": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@mantine/notifications/-/notifications-7.4.0.tgz",
|
||||
|
@ -16,6 +16,7 @@
|
||||
"@mantine/dropzone": "^7.4.0",
|
||||
"@mantine/form": "^7.4.0",
|
||||
"@mantine/hooks": "^7.4.0",
|
||||
"@mantine/modals": "^7.4.0",
|
||||
"@mantine/notifications": "^7.4.0",
|
||||
"@remix-run/css-bundle": "^2.4.1",
|
||||
"@remix-run/node": "^2.4.1",
|
||||
|
Loading…
x
Reference in New Issue
Block a user