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 (
- <>
-
-
-
-
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" }
+ )
+);
Connect with us
-Join the Vite community
---
-
-
- GitHub
-
-
- -
-
-
- Discord
-
-
- -
-
-
- X.com
-
-
- -
-
-
- Bluesky
-
-
-
-