React + Vite + Tailwind dashboard with: - Login (JWT via snakkimo auth) - Dashboard with Datenbankverwaltung + Contentverwaltung tiles - Table overview with record counts (total, published, blocked) - Table record viewer with text/status filters and linked field navigation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
57 lines
1.6 KiB
JavaScript
57 lines
1.6 KiB
JavaScript
const BASE = (import.meta.env.VITE_API_BASE || 'https://hyggecraftery.com/api/snakkimo').replace(/\/$/, '');
|
|
|
|
export const AUTH_URL = `${BASE}/auth/login`;
|
|
export const API_URL = `${BASE}/api`;
|
|
|
|
function getToken() {
|
|
return localStorage.getItem('cmt_token');
|
|
}
|
|
|
|
export function logout() {
|
|
localStorage.removeItem('cmt_token');
|
|
localStorage.removeItem('cmt_user');
|
|
}
|
|
|
|
export async function login(email, password) {
|
|
const res = await fetch(AUTH_URL, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ email, password }),
|
|
});
|
|
if (!res.ok) {
|
|
const err = await res.json().catch(() => ({}));
|
|
throw new Error(err.error || 'Login fehlgeschlagen');
|
|
}
|
|
const data = await res.json();
|
|
localStorage.setItem('cmt_token', data.token);
|
|
localStorage.setItem('cmt_user', JSON.stringify(data.user));
|
|
return data;
|
|
}
|
|
|
|
export function getUser() {
|
|
try { return JSON.parse(localStorage.getItem('cmt_user')); } catch { return null; }
|
|
}
|
|
|
|
export async function apiFetch(path, options = {}) {
|
|
const token = getToken();
|
|
const res = await fetch(`${API_URL}${path}`, {
|
|
...options,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
...options.headers,
|
|
},
|
|
});
|
|
if (res.status === 401) { logout(); window.location.href = '/login'; return; }
|
|
if (!res.ok) {
|
|
const err = await res.json().catch(() => ({}));
|
|
throw new Error(err.error || `HTTP ${res.status}`);
|
|
}
|
|
if (res.status === 204) return null;
|
|
return res.json();
|
|
}
|
|
|
|
export async function fetchAll(endpoint) {
|
|
return apiFetch(`${endpoint}?limit=500&offset=0`);
|
|
}
|