106 lines
2.5 KiB
JavaScript
106 lines
2.5 KiB
JavaScript
/* FluentGerman.ai — API client with auth */
|
|
|
|
const API_BASE = '/api';
|
|
|
|
function getToken() {
|
|
return localStorage.getItem('fg_token');
|
|
}
|
|
|
|
function setToken(token) {
|
|
localStorage.setItem('fg_token', token);
|
|
}
|
|
|
|
function clearToken() {
|
|
localStorage.removeItem('fg_token');
|
|
}
|
|
|
|
function getUser() {
|
|
const data = localStorage.getItem('fg_user');
|
|
return data ? JSON.parse(data) : null;
|
|
}
|
|
|
|
function setUser(user) {
|
|
localStorage.setItem('fg_user', JSON.stringify(user));
|
|
}
|
|
|
|
function clearUser() {
|
|
localStorage.removeItem('fg_user');
|
|
}
|
|
|
|
async function api(path, options = {}) {
|
|
const token = getToken();
|
|
const headers = { ...options.headers };
|
|
|
|
if (token) {
|
|
headers['Authorization'] = `Bearer ${token}`;
|
|
}
|
|
|
|
// Don't set Content-Type for FormData (browser sets it with boundary)
|
|
if (!(options.body instanceof FormData)) {
|
|
headers['Content-Type'] = headers['Content-Type'] || 'application/json';
|
|
}
|
|
|
|
const response = await fetch(`${API_BASE}${path}`, { ...options, headers });
|
|
|
|
if (response.status === 401) {
|
|
clearToken();
|
|
clearUser();
|
|
window.location.href = '/';
|
|
return;
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
async function apiJSON(path, options = {}) {
|
|
const response = await api(path, options);
|
|
if (!response || !response.ok) {
|
|
const error = await response?.json().catch(() => ({ detail: 'Request failed' }));
|
|
throw new Error(error.detail || 'Request failed');
|
|
}
|
|
return response.json();
|
|
}
|
|
|
|
function requireAuth() {
|
|
if (!getToken()) {
|
|
window.location.href = '/';
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function requireAdmin() {
|
|
const user = getUser();
|
|
if (!user?.is_admin) {
|
|
window.location.href = '/chat.html';
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function logout() {
|
|
clearToken();
|
|
clearUser();
|
|
window.location.href = '/';
|
|
}
|
|
|
|
/* Toast notifications */
|
|
function showToast(message, type = 'success') {
|
|
let container = document.querySelector('.toast-container');
|
|
if (!container) {
|
|
container = document.createElement('div');
|
|
container.className = 'toast-container';
|
|
document.body.appendChild(container);
|
|
}
|
|
|
|
const toast = document.createElement('div');
|
|
toast.className = `toast toast-${type}`;
|
|
toast.textContent = message;
|
|
container.appendChild(toast);
|
|
|
|
setTimeout(() => {
|
|
toast.style.opacity = '0';
|
|
setTimeout(() => toast.remove(), 300);
|
|
}, 3000);
|
|
}
|