From 6b626eca95332e042c5934ea47c02ae96b84ca0d Mon Sep 17 00:00:00 2001 From: houseassassin Date: Wed, 20 May 2026 12:16:30 +0300 Subject: [PATCH] feat: auth store, API client, router setup --- src/App.tsx | 145 +++++-------------------- src/api/client.ts | 54 +++++++++ src/components/layout/PrivateRoute.tsx | 7 ++ src/lib/utils.ts | 3 + src/pages/Landing.tsx | 1 + src/pages/Login.tsx | 1 + src/pages/Profile.tsx | 1 + src/pages/Register.tsx | 1 + src/pages/dashboard/Dashboard.tsx | 1 + src/pages/dashboard/Devices.tsx | 1 + src/pages/dashboard/Keys.tsx | 1 + src/pages/dashboard/Payments.tsx | 1 + src/pages/dashboard/Servers.tsx | 1 + src/store/auth.ts | 32 ++++++ 14 files changed, 131 insertions(+), 119 deletions(-) create mode 100644 src/api/client.ts create mode 100644 src/components/layout/PrivateRoute.tsx create mode 100644 src/lib/utils.ts create mode 100644 src/pages/Landing.tsx create mode 100644 src/pages/Login.tsx create mode 100644 src/pages/Profile.tsx create mode 100644 src/pages/Register.tsx create mode 100644 src/pages/dashboard/Dashboard.tsx create mode 100644 src/pages/dashboard/Devices.tsx create mode 100644 src/pages/dashboard/Keys.tsx create mode 100644 src/pages/dashboard/Payments.tsx create mode 100644 src/pages/dashboard/Servers.tsx create mode 100644 src/store/auth.ts diff --git a/src/App.tsx b/src/App.tsx index a66b5ef..318c512 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,122 +1,29 @@ -import { useState } from 'react' -import reactLogo from './assets/react.svg' -import viteLogo from './assets/vite.svg' -import heroImg from './assets/hero.png' -import './App.css' - -function App() { - const [count, setCount] = useState(0) +import { BrowserRouter, Routes, Route } from "react-router-dom"; +import { PrivateRoute } from "./components/layout/PrivateRoute"; +import Landing from "./pages/Landing"; +import Login from "./pages/Login"; +import Register from "./pages/Register"; +import Dashboard from "./pages/dashboard/Dashboard"; +import Keys from "./pages/dashboard/Keys"; +import Devices from "./pages/dashboard/Devices"; +import Payments from "./pages/dashboard/Payments"; +import Servers from "./pages/dashboard/Servers"; +import Profile from "./pages/Profile"; +export default function App() { return ( - <> -
-
- - React logo - Vite logo -
-
-

Get started

-

- Edit src/App.tsx and save to test HMR -

-
- -
- -
- -
-
- -

Documentation

-

Your questions, answered

- -
-
- -

Connect with us

-

Join the Vite community

- -
-
- -
-
- - ) + + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + + ); } - -export default App diff --git a/src/api/client.ts b/src/api/client.ts new file mode 100644 index 0000000..273c277 --- /dev/null +++ b/src/api/client.ts @@ -0,0 +1,54 @@ +import { useAuthStore } from "../store/auth"; + +const BASE = "/api"; + +async function request( + url: string, + options: RequestInit = {}, + withAuth = true +): Promise { + const headers: Record = { + "Content-Type": "application/json", + ...(options.headers as Record), + }; + + if (withAuth) { + const token = useAuthStore.getState().accessToken; + if (token) headers["Authorization"] = `Bearer ${token}`; + } + + const res = await fetch(`${BASE}${url}`, { ...options, headers }); + return res.json(); +} + +export const api = { + register: (email: string, password: string, name?: string) => + request("/web/register", { + method: "POST", + body: JSON.stringify({ email, password, name }), + }, false), + + login: (email: string, password: string) => + request("/web/login", { + method: "POST", + body: JSON.stringify({ email, password }), + }, false), + + tgAuth: (data: Record) => + request("/web/tg_auth", { + method: "POST", + body: JSON.stringify(data), + }, false), + + refresh: (refresh_token: string) => + request("/web/refresh", { + method: "POST", + body: JSON.stringify({ refresh_token }), + }, false), + + action: (action: string, payload: Record = {}) => + request("/web/action", { + method: "POST", + body: JSON.stringify({ action, payload }), + }), +}; diff --git a/src/components/layout/PrivateRoute.tsx b/src/components/layout/PrivateRoute.tsx new file mode 100644 index 0000000..152e885 --- /dev/null +++ b/src/components/layout/PrivateRoute.tsx @@ -0,0 +1,7 @@ +import { Navigate } from "react-router-dom"; +import { useAuthStore } from "../../store/auth"; + +export function PrivateRoute({ children }: { children: React.ReactNode }) { + const isLoggedIn = useAuthStore((s) => s.isLoggedIn()); + return isLoggedIn ? <>{children} : ; +} diff --git a/src/lib/utils.ts b/src/lib/utils.ts new file mode 100644 index 0000000..72cdf88 --- /dev/null +++ b/src/lib/utils.ts @@ -0,0 +1,3 @@ +export function cn(...classes: (string | undefined | false | null)[]) { + return classes.filter(Boolean).join(" "); +} diff --git a/src/pages/Landing.tsx b/src/pages/Landing.tsx new file mode 100644 index 0000000..2304eaf --- /dev/null +++ b/src/pages/Landing.tsx @@ -0,0 +1 @@ +export default function Landing() { return
Landing
; } diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx new file mode 100644 index 0000000..e791fc2 --- /dev/null +++ b/src/pages/Login.tsx @@ -0,0 +1 @@ +export default function Login() { return
Login
; } diff --git a/src/pages/Profile.tsx b/src/pages/Profile.tsx new file mode 100644 index 0000000..39d846c --- /dev/null +++ b/src/pages/Profile.tsx @@ -0,0 +1 @@ +export default function Profile() { return
Profile
; } diff --git a/src/pages/Register.tsx b/src/pages/Register.tsx new file mode 100644 index 0000000..1c84e19 --- /dev/null +++ b/src/pages/Register.tsx @@ -0,0 +1 @@ +export default function Register() { return
Register
; } diff --git a/src/pages/dashboard/Dashboard.tsx b/src/pages/dashboard/Dashboard.tsx new file mode 100644 index 0000000..9ac672f --- /dev/null +++ b/src/pages/dashboard/Dashboard.tsx @@ -0,0 +1 @@ +export default function Dashboard() { return
Dashboard
; } diff --git a/src/pages/dashboard/Devices.tsx b/src/pages/dashboard/Devices.tsx new file mode 100644 index 0000000..15cfed3 --- /dev/null +++ b/src/pages/dashboard/Devices.tsx @@ -0,0 +1 @@ +export default function Devices() { return
Devices
; } diff --git a/src/pages/dashboard/Keys.tsx b/src/pages/dashboard/Keys.tsx new file mode 100644 index 0000000..42131e0 --- /dev/null +++ b/src/pages/dashboard/Keys.tsx @@ -0,0 +1 @@ +export default function Keys() { return
Keys
; } diff --git a/src/pages/dashboard/Payments.tsx b/src/pages/dashboard/Payments.tsx new file mode 100644 index 0000000..eaab442 --- /dev/null +++ b/src/pages/dashboard/Payments.tsx @@ -0,0 +1 @@ +export default function Payments() { return
Payments
; } diff --git a/src/pages/dashboard/Servers.tsx b/src/pages/dashboard/Servers.tsx new file mode 100644 index 0000000..64b0d1e --- /dev/null +++ b/src/pages/dashboard/Servers.tsx @@ -0,0 +1 @@ +export default function Servers() { return
Servers
; } diff --git a/src/store/auth.ts b/src/store/auth.ts new file mode 100644 index 0000000..875e27b --- /dev/null +++ b/src/store/auth.ts @@ -0,0 +1,32 @@ +import { create } from "zustand"; +import { persist } from "zustand/middleware"; + +interface AuthUser { + name: string; + email?: string; + tg_linked: boolean; +} + +interface AuthState { + accessToken: string | null; + refreshToken: string | null; + user: AuthUser | null; + setAuth: (access: string, refresh: string, user: AuthUser) => void; + logout: () => void; + isLoggedIn: () => boolean; +} + +export const useAuthStore = create()( + persist( + (set, get) => ({ + accessToken: null, + refreshToken: null, + user: null, + setAuth: (accessToken, refreshToken, user) => + set({ accessToken, refreshToken, user }), + logout: () => set({ accessToken: null, refreshToken: null, user: null }), + isLoggedIn: () => !!get().accessToken, + }), + { name: "aura-auth" } + ) +);