feat: add authorization
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import { MantineProvider } from "@mantine/core";
|
||||
import { cleanup, render, screen } from "@testing-library/react";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { cleanup, render, screen, waitFor } from "@testing-library/react";
|
||||
import { MemoryRouter } from "react-router";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { AuthProvider } from "../../features/auth";
|
||||
import {
|
||||
AccountsPageEmpty,
|
||||
AccountsPageError,
|
||||
@@ -12,43 +14,46 @@ import { AppRoutes } from "./AppRoutes";
|
||||
|
||||
describe("AppRoutes", () => {
|
||||
afterEach(cleanup);
|
||||
function renderRoutes(path: string) {
|
||||
return render(
|
||||
<QueryClientProvider client={new QueryClient()}>
|
||||
<MemoryRouter initialEntries={[path]}>
|
||||
<MantineProvider theme={theme}>
|
||||
<AuthProvider>
|
||||
<AppRoutes />
|
||||
</AuthProvider>
|
||||
</MantineProvider>
|
||||
</MemoryRouter>
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
it.each([
|
||||
["/", "Счета"],
|
||||
["/", "Вход"],
|
||||
["/login", "Вход"],
|
||||
["/register", "Регистрация"],
|
||||
["/accounts", "Счета"],
|
||||
["/accounts/demo", "Счет"],
|
||||
["/settings", "Настройки"],
|
||||
["/accounts", "Вход"],
|
||||
["/accounts/demo", "Вход"],
|
||||
["/settings", "Вход"],
|
||||
["/unknown", "Страница не найдена"],
|
||||
])("renders %s with its page title", (path, title) => {
|
||||
render(
|
||||
<MemoryRouter initialEntries={[path]}>
|
||||
<MantineProvider theme={theme}>
|
||||
<AppRoutes />
|
||||
</MantineProvider>
|
||||
</MemoryRouter>,
|
||||
);
|
||||
])("renders %s with its page title", async (path, title) => {
|
||||
renderRoutes(path);
|
||||
|
||||
expect(
|
||||
screen.getByRole("heading", { level: 1, name: title }),
|
||||
).toBeInTheDocument();
|
||||
await waitFor(() =>
|
||||
expect(
|
||||
screen.getByRole("heading", { level: 1, name: title }),
|
||||
).toBeInTheDocument(),
|
||||
);
|
||||
});
|
||||
|
||||
it("renders only the empty state for accounts by default", () => {
|
||||
render(
|
||||
<MemoryRouter initialEntries={["/accounts"]}>
|
||||
<MantineProvider theme={theme}>
|
||||
<AppRoutes />
|
||||
</MantineProvider>
|
||||
</MemoryRouter>,
|
||||
);
|
||||
it("redirects anonymous users from accounts", async () => {
|
||||
renderRoutes("/accounts");
|
||||
|
||||
expect(
|
||||
screen.getByRole("heading", { level: 2, name: "Пока ничего нет" }),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.queryByText("Загрузка")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("Что-то пошло не так")).not.toBeInTheDocument();
|
||||
await waitFor(() =>
|
||||
expect(
|
||||
screen.getByRole("heading", { level: 1, name: "Вход" }),
|
||||
).toBeInTheDocument(),
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Navigate, Route, Routes } from "react-router";
|
||||
|
||||
import { Navigate, Route, Routes, useLocation } from "react-router";
|
||||
import { useAuth } from "../../features/auth";
|
||||
import { AccountPage } from "../../pages/account";
|
||||
import { AccountsPage } from "../../pages/accounts";
|
||||
import { LoginPage } from "../../pages/login";
|
||||
@@ -8,13 +8,54 @@ import { RegisterPage } from "../../pages/register";
|
||||
import { SettingsPage } from "../../pages/settings";
|
||||
import { AppShell } from "../../shared/ui/AppShell";
|
||||
|
||||
function Protected({ children }: { children: React.ReactNode }) {
|
||||
const { user, ready } = useAuth();
|
||||
const location = useLocation();
|
||||
if (!ready) return null;
|
||||
return user ? (
|
||||
children
|
||||
) : (
|
||||
<Navigate
|
||||
to="/login"
|
||||
state={{ returnTo: `${location.pathname}${location.search}` }}
|
||||
replace
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function Public({ children }: { children: React.ReactNode }) {
|
||||
const { user, ready } = useAuth();
|
||||
if (!ready) return null;
|
||||
return user ? <Navigate to="/accounts" replace /> : children;
|
||||
}
|
||||
|
||||
export function AppRoutes() {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/" element={<Navigate to="/accounts" replace />} />
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route path="/register" element={<RegisterPage />} />
|
||||
<Route element={<AppShell />}>
|
||||
<Route
|
||||
path="/login"
|
||||
element={
|
||||
<Public>
|
||||
<LoginPage />
|
||||
</Public>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/register"
|
||||
element={
|
||||
<Public>
|
||||
<RegisterPage />
|
||||
</Public>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<Protected>
|
||||
<AppShell />
|
||||
</Protected>
|
||||
}
|
||||
>
|
||||
<Route path="/accounts" element={<AccountsPage />} />
|
||||
<Route path="/accounts/:accountId" element={<AccountPage />} />
|
||||
<Route path="/settings" element={<SettingsPage />} />
|
||||
|
||||
Reference in New Issue
Block a user