school-timetracker/frontend/src/lib/stores.js
Patryk Hegenberg e719f4565f feat: add completed Web-Frontend in Svelte with some new Features
- Added import of Schedules
- Added export for schedule table
- Added import of logo
- Added password change to users
- improved ui/ux
2026-01-15 15:19:53 +01:00

71 lines
2.1 KiB
JavaScript

import { writable, get } from 'svelte/store';
function safeParse(jsonString) {
if (!jsonString || jsonString === 'undefined' || jsonString === 'null') return null;
try { return JSON.parse(jsonString); } catch (e) { return null; }
}
function decodeJwt(token) {
try {
const base64Url = token.split('.')[1];
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
const jsonPayload = decodeURIComponent(window.atob(base64).split('').map(c =>
'%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
).join(''));
return JSON.parse(jsonPayload);
} catch (e) { return null; }
}
const normalizeUser = (u) => {
if (!u) return null;
return { ...u, isAdmin: !!(u.isAdmin || u.is_admin) };
};
const storedToken = localStorage.getItem('token');
let initialUser = normalizeUser(safeParse(localStorage.getItem('user')));
let initialAuth = false;
if (storedToken) {
const decoded = decodeJwt(storedToken);
const currentTime = Date.now() / 1000;
if (decoded && decoded.exp && decoded.exp < currentTime) {
console.warn("Token im Storage ist abgelaufen. Auto-Logout.");
localStorage.removeItem('token');
localStorage.removeItem('user');
initialUser = null;
} else {
initialAuth = !!initialUser;
}
}
export const auth = writable({
token: initialAuth ? storedToken : null,
user: initialUser,
isAuthenticated: initialAuth
});
auth.subscribe(value => {
if (value.token && value.user) {
localStorage.setItem('token', value.token);
localStorage.setItem('user', JSON.stringify(value.user));
} else {
localStorage.removeItem('token');
localStorage.removeItem('user');
}
});
export const loading = writable(false);
export const toasts = writable([]);
export function addToast(message, type = 'info') {
const id = Date.now() + Math.random();
const newToast = { id, message, type };
toasts.update(all => [newToast, ...all]);
setTimeout(() => removeToast(id), 5000);
}
export function removeToast(id) {
toasts.update(all => all.filter(t => t.id !== id));
}