feat(admin): scaffold Vite+React admin workspace
This commit is contained in:
20
apps/admin/src/App.test.tsx
Normal file
20
apps/admin/src/App.test.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import App from './App';
|
||||
|
||||
function renderApp() {
|
||||
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
||||
return render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<App />
|
||||
</QueryClientProvider>
|
||||
);
|
||||
}
|
||||
|
||||
describe('App', () => {
|
||||
it('renders the admin app name', () => {
|
||||
renderApp();
|
||||
expect(screen.getByText('SoleLog Admin')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
3
apps/admin/src/App.tsx
Normal file
3
apps/admin/src/App.tsx
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function App() {
|
||||
return <div>SoleLog Admin</div>;
|
||||
}
|
||||
37
apps/admin/src/lib/api.ts
Normal file
37
apps/admin/src/lib/api.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { getToken, setToken } from './auth-storage';
|
||||
|
||||
export const API_URL = import.meta.env.VITE_API_URL ?? 'http://localhost:3000';
|
||||
|
||||
export class ApiError extends Error {
|
||||
constructor(
|
||||
public status: number,
|
||||
message: string
|
||||
) {
|
||||
super(message);
|
||||
this.name = 'ApiError';
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiFetch<T>(path: string, init: RequestInit = {}): Promise<T> {
|
||||
const token = getToken();
|
||||
const headers = new Headers(init.headers);
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`);
|
||||
if (init.body && !headers.has('Content-Type')) headers.set('Content-Type', 'application/json');
|
||||
const res = await fetch(`${API_URL}${path}`, { ...init, headers });
|
||||
if (!res.ok) throw new ApiError(res.status, `Request failed: ${res.status}`);
|
||||
const text = await res.text();
|
||||
return (text ? JSON.parse(text) : undefined) as T;
|
||||
}
|
||||
|
||||
// Sign in: POST /api/auth/sign-in/email, capture the bearer token from the response header.
|
||||
export async function signIn(email: string, password: string): Promise<void> {
|
||||
const res = await fetch(`${API_URL}/api/auth/sign-in/email`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ email, password }),
|
||||
});
|
||||
if (!res.ok) throw new ApiError(res.status, 'Inloggen mislukt');
|
||||
const token = res.headers.get('set-auth-token');
|
||||
if (!token) throw new ApiError(500, 'Geen token ontvangen');
|
||||
setToken(token);
|
||||
}
|
||||
13
apps/admin/src/lib/auth-storage.ts
Normal file
13
apps/admin/src/lib/auth-storage.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
const TOKEN_KEY = 'solelog.token';
|
||||
|
||||
export function getToken(): string | null {
|
||||
return localStorage.getItem(TOKEN_KEY);
|
||||
}
|
||||
|
||||
export function setToken(token: string): void {
|
||||
localStorage.setItem(TOKEN_KEY, token);
|
||||
}
|
||||
|
||||
export function clearToken(): void {
|
||||
localStorage.removeItem(TOKEN_KEY);
|
||||
}
|
||||
15
apps/admin/src/main.tsx
Normal file
15
apps/admin/src/main.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import React from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import App from './App';
|
||||
import './styles.css';
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<React.StrictMode>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<App />
|
||||
</QueryClientProvider>
|
||||
</React.StrictMode>
|
||||
);
|
||||
0
apps/admin/src/styles.css
Normal file
0
apps/admin/src/styles.css
Normal file
1
apps/admin/src/test/setup.ts
Normal file
1
apps/admin/src/test/setup.ts
Normal file
@@ -0,0 +1 @@
|
||||
import '@testing-library/jest-dom';
|
||||
9
apps/admin/src/vite-env.d.ts
vendored
Normal file
9
apps/admin/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_API_URL?: string;
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
Reference in New Issue
Block a user