06ea149d41
Führt Login mit vier Rollen (Admin, Teamleiter, Mitarbeiter, Beobachter) ein, über die Teammitglieder eigenen Urlaub inkl. Pflicht-Vertreter eintragen können. Die Auslastungsberechnung berücksichtigt Urlaub jetzt als reduzierte Kapazität. Neue Konten vergeben ihr Passwort selbst beim ersten Login. Migrationsskript für bestehende Mitarbeiter aus der Vorversion inklusive. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
93 lines
3.6 KiB
JavaScript
93 lines
3.6 KiB
JavaScript
let authToken = localStorage.getItem('authToken') || null;
|
|
|
|
export function setAuthToken(token) {
|
|
authToken = token;
|
|
if (token) localStorage.setItem('authToken', token);
|
|
else localStorage.removeItem('authToken');
|
|
}
|
|
|
|
async function request(method, url, body) {
|
|
const headers = {};
|
|
if (body) headers['Content-Type'] = 'application/json';
|
|
if (authToken) headers['Authorization'] = `Bearer ${authToken}`;
|
|
|
|
const res = await fetch(url, {
|
|
method,
|
|
headers,
|
|
body: body ? JSON.stringify(body) : undefined,
|
|
});
|
|
if (!res.ok) {
|
|
const text = await res.text().catch(() => '');
|
|
let error;
|
|
try {
|
|
error = JSON.parse(text).error;
|
|
} catch {
|
|
error = text;
|
|
}
|
|
throw new Error(error || `${method} ${url} fehlgeschlagen: ${res.status}`);
|
|
}
|
|
const text = await res.text();
|
|
return text ? JSON.parse(text) : null;
|
|
}
|
|
|
|
export const api = {
|
|
// auth
|
|
login: (email, password) => request('POST', '/api/auth/login', { email, password }),
|
|
logout: () => request('POST', '/api/auth/logout'),
|
|
me: () => request('GET', '/api/auth/me'),
|
|
|
|
// vacations
|
|
getVacations: () => request('GET', '/api/vacations'),
|
|
createVacation: (data) => request('POST', '/api/vacations', data),
|
|
updateVacation: (id, data) => request('PUT', `/api/vacations/${id}`, data),
|
|
deleteVacation: (id) => request('DELETE', `/api/vacations/${id}`),
|
|
|
|
// users
|
|
getUsers: () => request('GET', '/api/users'),
|
|
createUser: (data) => request('POST', '/api/users', data),
|
|
updateUser: (id, data) => request('PUT', `/api/users/${id}`, data),
|
|
deleteUser: (id) => request('DELETE', `/api/users/${id}`),
|
|
|
|
// employees
|
|
getEmployees: () => request('GET', '/api/employees'),
|
|
createEmployee: (data) => request('POST', '/api/employees', data),
|
|
updateEmployee: (id, data) => request('PUT', `/api/employees/${id}`, data),
|
|
deleteEmployee: (id) => request('DELETE', `/api/employees/${id}`),
|
|
|
|
// teams
|
|
getTeams: () => request('GET', '/api/teams'),
|
|
createTeam: (data) => request('POST', '/api/teams', data),
|
|
updateTeam: (id, data) => request('PUT', `/api/teams/${id}`, data),
|
|
deleteTeam: (id) => request('DELETE', `/api/teams/${id}`),
|
|
addTeamMember: (teamId, employeeId) =>
|
|
request('POST', `/api/teams/${teamId}/members`, { employee_id: employeeId }),
|
|
removeTeamMember: (teamId, employeeId) =>
|
|
request('DELETE', `/api/teams/${teamId}/members/${employeeId}`),
|
|
|
|
// projects & tasks
|
|
getProjects: () => request('GET', '/api/projects'),
|
|
createProject: (data) => request('POST', '/api/projects', data),
|
|
updateProject: (id, data) => request('PUT', `/api/projects/${id}`, data),
|
|
deleteProject: (id) => request('DELETE', `/api/projects/${id}`),
|
|
|
|
createTask: (data) => request('POST', '/api/tasks', data),
|
|
updateTask: (id, data) => request('PUT', `/api/tasks/${id}`, data),
|
|
deleteTask: (id) => request('DELETE', `/api/tasks/${id}`),
|
|
duplicateTask: (id, data) => request('POST', `/api/tasks/${id}/duplicate`, data),
|
|
addDependency: (taskId, dependsOnId) =>
|
|
request('POST', `/api/tasks/${taskId}/dependencies`, { depends_on_task_id: dependsOnId }),
|
|
removeDependency: (taskId, dependsOnId) =>
|
|
request('DELETE', `/api/tasks/${taskId}/dependencies/${dependsOnId}`),
|
|
|
|
// assignments
|
|
createAssignment: (data) => request('POST', '/api/assignments', data),
|
|
updateAssignment: (id, data) => request('PUT', `/api/assignments/${id}`, data),
|
|
deleteAssignment: (id) => request('DELETE', `/api/assignments/${id}`),
|
|
|
|
// utilization
|
|
getUtilization: (params = {}) => {
|
|
const qs = new URLSearchParams(params).toString();
|
|
return request('GET', `/api/utilization${qs ? `?${qs}` : ''}`);
|
|
},
|
|
};
|