diff --git a/frontend/src/routes/app/_hiddenLayout/add-product.tsx b/frontend/src/routes/app/_hiddenLayout/add-product.tsx index 018fb7e..17f1080 100644 --- a/frontend/src/routes/app/_hiddenLayout/add-product.tsx +++ b/frontend/src/routes/app/_hiddenLayout/add-product.tsx @@ -1,14 +1,10 @@ -import { createFileRoute, redirect } from "@tanstack/react-router"; -import { isAuthenticated } from "../../../utils/api/auth"; +import { createFileRoute } from "@tanstack/react-router"; +import { verifyLogin } from "../../../utils/api/auth"; import { AddProduct } from "../../../pages/AddProduct"; export const Route = createFileRoute("/app/_hiddenLayout/add-product")({ beforeLoad: async () => { - if (!(await isAuthenticated())) { - throw redirect({ - to: "/login", - }); - } + await verifyLogin(); }, component: RouteComponent, }); diff --git a/frontend/src/routes/app/_hiddenLayout/app-settings.tsx b/frontend/src/routes/app/_hiddenLayout/app-settings.tsx index 8a4d700..f38e759 100644 --- a/frontend/src/routes/app/_hiddenLayout/app-settings.tsx +++ b/frontend/src/routes/app/_hiddenLayout/app-settings.tsx @@ -1,14 +1,10 @@ -import { createFileRoute, redirect } from "@tanstack/react-router"; -import { isAuthenticated } from "../../../utils/api/auth"; +import { createFileRoute } from "@tanstack/react-router"; +import { verifyLogin } from "../../../utils/api/auth"; import { Settings } from "../../../pages/Settings"; export const Route = createFileRoute("/app/_hiddenLayout/app-settings")({ beforeLoad: async () => { - if (!(await isAuthenticated())) { - throw redirect({ - to: "/login", - }); - } + await verifyLogin(); }, component: RouteComponent, }); diff --git a/frontend/src/routes/app/_hiddenLayout/inventory.tsx b/frontend/src/routes/app/_hiddenLayout/inventory.tsx index 211d30d..e5bca7e 100644 --- a/frontend/src/routes/app/_hiddenLayout/inventory.tsx +++ b/frontend/src/routes/app/_hiddenLayout/inventory.tsx @@ -1,14 +1,10 @@ -import { createFileRoute, redirect } from "@tanstack/react-router"; -import { isAuthenticated } from "../../../utils/api/auth"; +import { createFileRoute } from "@tanstack/react-router"; +import { verifyLogin } from "../../../utils/api/auth"; import { InventoryPage } from "../../../pages/Inventory"; export const Route = createFileRoute("/app/_hiddenLayout/inventory")({ beforeLoad: async () => { - if (!(await isAuthenticated())) { - throw redirect({ - to: "/login", - }); - } + await verifyLogin(); }, component: RouteComponent, }); diff --git a/frontend/src/routes/app/_hiddenLayout/storages.tsx b/frontend/src/routes/app/_hiddenLayout/storages.tsx index 9359de5..622feb3 100644 --- a/frontend/src/routes/app/_hiddenLayout/storages.tsx +++ b/frontend/src/routes/app/_hiddenLayout/storages.tsx @@ -1,14 +1,10 @@ -import { createFileRoute, redirect } from "@tanstack/react-router"; -import { isAuthenticated } from "../../../utils/api/auth"; +import { createFileRoute } from "@tanstack/react-router"; +import { verifyLogin } from "../../../utils/api/auth"; import { Storages } from "../../../pages/Storages"; export const Route = createFileRoute("/app/_hiddenLayout/storages")({ beforeLoad: async () => { - if (!(await isAuthenticated())) { - throw redirect({ - to: "/login", - }); - } + await verifyLogin(); }, component: RouteComponent, }); diff --git a/frontend/src/routes/app/_hiddenLayout/view-product.tsx b/frontend/src/routes/app/_hiddenLayout/view-product.tsx index 23ae4e4..8dbad97 100644 --- a/frontend/src/routes/app/_hiddenLayout/view-product.tsx +++ b/frontend/src/routes/app/_hiddenLayout/view-product.tsx @@ -1,15 +1,11 @@ -import { createFileRoute, redirect } from "@tanstack/react-router"; +import { createFileRoute } from "@tanstack/react-router"; import { z } from "zod"; -import { isAuthenticated } from "../../../utils/api/auth"; +import { verifyLogin } from "../../../utils/api/auth"; import { ViewProduct } from "../../../pages/ViewProduct"; export const Route = createFileRoute("/app/_hiddenLayout/view-product")({ beforeLoad: async () => { - if (!(await isAuthenticated())) { - throw redirect({ - to: "/login", - }); - } + await verifyLogin(); }, validateSearch: z.object({ product: z.string(), diff --git a/frontend/src/routes/index.tsx b/frontend/src/routes/index.tsx index 59a1b30..84a7aa6 100644 --- a/frontend/src/routes/index.tsx +++ b/frontend/src/routes/index.tsx @@ -6,6 +6,7 @@ export const Route = createFileRoute("/")({ if (!(await isAuthenticated())) { throw redirect({ to: "/login", + search: { loggedOut: true }, }); } else { throw redirect({ diff --git a/frontend/src/routes/login.tsx b/frontend/src/routes/login.tsx index 9940f41..2a3e6dc 100644 --- a/frontend/src/routes/login.tsx +++ b/frontend/src/routes/login.tsx @@ -1,7 +1,11 @@ import { createFileRoute } from "@tanstack/react-router"; import { LoginCard } from "../components/LoginCard"; +import { checkLogin } from "../utils/api/auth.ts"; export const Route = createFileRoute("/login")({ + beforeLoad: async () => { + await checkLogin(); + }, component: RouteComponent, }); diff --git a/frontend/src/utils/api/auth.ts b/frontend/src/utils/api/auth.ts index 0f95a71..318dcf3 100644 --- a/frontend/src/utils/api/auth.ts +++ b/frontend/src/utils/api/auth.ts @@ -1,85 +1,98 @@ -import {API_BASE} from "../../config/api.config"; +import { API_BASE } from "../../config/api.config"; import Cookies from "js-cookie"; -import type {TFunction} from "i18next"; -import {fetchSettings} from "./settings"; -import type {ChangePasswordIntf} from "../../misc/interfaces"; -import {createApiError} from "./apiError"; +import type { TFunction } from "i18next"; +import { fetchSettings } from "./settings"; +import type { ChangePasswordIntf } from "../../misc/interfaces"; +import { createApiError } from "./apiError"; +import { redirect } from "@tanstack/react-router"; -export async function isAuthenticated() { - if (Cookies.get("token")) { - const result = await fetch(`${API_BASE}/users/verify-token`, { - method: "POST", - headers: { - Authorization: `Bearer ${Cookies.get("token") || ""}`, - "Content-Type": "application/json", - Accept: "application/json", - }, - }); - - if (result.status === 200) { - return true; - } - } - - Cookies.remove("token"); - return false; -} - -export async function signInUser( - username: string, - password: string, - t: TFunction, -) { - const result = await fetch(`${API_BASE}/users/login`, { - method: "POST", - headers: { - Authorization: `Bearer ${Cookies.get("token") || ""}`, - "Content-Type": "application/json", - Accept: "application/json", - }, - body: JSON.stringify({username, password}), +export const isAuthenticated = async () => { + if (Cookies.get("token")) { + const result = await fetch(`${API_BASE}/users/verify-token`, { + method: "POST", + headers: { + Authorization: `Bearer ${Cookies.get("token") || ""}`, + "Content-Type": "application/json", + Accept: "application/json", + }, }); - const response = await result.json(); - - if (result.status === 202) { - Cookies.set("token", response.data.token); - - const settings = await fetchSettings(); - Cookies.set("app-name", settings?.data[0].value); - Cookies.set("currency", settings?.data[1].value); - - return {ok: true as const}; + if (result.status === 200) { + return true; } + } - Cookies.remove("token"); - throw createApiError(response.code, t(response.code || "unknown-error")); -} + Cookies.remove("token"); + return false; +}; -export function signOutUser() { - Cookies.remove("token"); - return {ok: true as const}; -} +export const signInUser = async ( + username: string, + password: string, + t: TFunction, +) => { + const result = await fetch(`${API_BASE}/users/login`, { + method: "POST", + headers: { + Authorization: `Bearer ${Cookies.get("token") || ""}`, + "Content-Type": "application/json", + Accept: "application/json", + }, + body: JSON.stringify({ username, password }), + }); + + const response = await result.json(); + + if (result.status === 202) { + Cookies.set("token", response.data.token); + + const settings = await fetchSettings(); + Cookies.set("app-name", settings?.data[0].value); + Cookies.set("currency", settings?.data[1].value); + + return { ok: true as const }; + } + + Cookies.remove("token"); + throw createApiError(response.code, t(response.code || "unknown-error")); +}; export const mutatePassword = async (payload: ChangePasswordIntf) => { - const result = await fetch(`${API_BASE}/users/change-password`, { - method: "POST", - headers: { - Authorization: `Bearer ${Cookies.get("token") || ""}`, - "Content-Type": "application/json", - Accept: "application/json", - }, - body: JSON.stringify({ - currentPassword: payload.currentPassword, - newPassword: payload.newPassword, - }), - }); + const result = await fetch(`${API_BASE}/users/change-password`, { + method: "POST", + headers: { + Authorization: `Bearer ${Cookies.get("token") || ""}`, + "Content-Type": "application/json", + Accept: "application/json", + }, + body: JSON.stringify({ + currentPassword: payload.currentPassword, + newPassword: payload.newPassword, + }), + }); - const response = await result.json(); + const response = await result.json(); - if (response.code === "SU005") { - return {code: response.code}; - } + if (response.code === "SU005") { + return { code: response.code }; + } - throw createApiError(response.code, "Change password failed"); + throw createApiError(response.code, "Change password failed"); +}; + +export const verifyLogin = async () => { + if (!(await isAuthenticated())) { + throw redirect({ + to: "/login", + search: { loggedOut: true }, + }); + } +}; + +export const checkLogin = async () => { + if (await isAuthenticated()) { + throw redirect({ + to: "/app/inventory", + }); + } };