Revert "Update README.md with installation instructions and Docker usage; add docker-compose.yml for service orchestration"
This reverts commit c8c2a800bb.
This commit is contained in:
@@ -1,193 +0,0 @@
|
||||
/**
|
||||
* API Client for backend communication
|
||||
*/
|
||||
|
||||
import { formatDateISO } from '../utils/dateUtils.js';
|
||||
import { showNotification } from '../ui/notifications.js';
|
||||
|
||||
/**
|
||||
* Fetch entries from the backend
|
||||
* @param {string|null} fromDate - Start date (YYYY-MM-DD)
|
||||
* @param {string|null} toDate - End date (YYYY-MM-DD)
|
||||
* @returns {Promise<Array>} - Array of entries
|
||||
*/
|
||||
export async function fetchEntries(fromDate = null, toDate = null) {
|
||||
try {
|
||||
let url = '/api/entries';
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (fromDate) params.append('from', fromDate);
|
||||
if (toDate) params.append('to', toDate);
|
||||
|
||||
if (params.toString()) {
|
||||
url += '?' + params.toString();
|
||||
}
|
||||
|
||||
const response = await fetch(url);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch entries');
|
||||
}
|
||||
|
||||
const entries = await response.json();
|
||||
return entries;
|
||||
} catch (error) {
|
||||
console.error('Error fetching entries:', error);
|
||||
showNotification('Fehler beim Laden der Einträge', 'error');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new entry
|
||||
* @param {string} date - Date in DD.MM.YYYY format
|
||||
* @param {string} startTime - Start time HH:MM
|
||||
* @param {string} endTime - End time HH:MM
|
||||
* @param {number|null} pauseMinutes - Pause in minutes
|
||||
* @param {string} location - Location (office/home)
|
||||
* @returns {Promise<Object|null>} - Created entry or null
|
||||
*/
|
||||
export async function createEntry(date, startTime, endTime, pauseMinutes, location) {
|
||||
try {
|
||||
const body = {
|
||||
date: formatDateISO(date),
|
||||
startTime,
|
||||
endTime,
|
||||
location: location || 'office'
|
||||
};
|
||||
|
||||
// Only include pauseMinutes if explicitly provided (not empty)
|
||||
if (pauseMinutes !== null && pauseMinutes !== undefined && pauseMinutes !== '') {
|
||||
body.pauseMinutes = parseInt(pauseMinutes);
|
||||
}
|
||||
|
||||
const response = await fetch('/api/entries', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.error || 'Failed to create entry');
|
||||
}
|
||||
|
||||
const entry = await response.json();
|
||||
return entry;
|
||||
} catch (error) {
|
||||
console.error('Error creating entry:', error);
|
||||
showNotification(error.message || 'Fehler beim Erstellen des Eintrags', 'error');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing entry
|
||||
* @param {number} id - Entry ID
|
||||
* @param {string} date - Date in DD.MM.YYYY format
|
||||
* @param {string} startTime - Start time HH:MM
|
||||
* @param {string} endTime - End time HH:MM
|
||||
* @param {number|null} pauseMinutes - Pause in minutes
|
||||
* @param {string} location - Location (office/home)
|
||||
* @returns {Promise<Object|null>} - Updated entry or null
|
||||
*/
|
||||
export async function updateEntry(id, date, startTime, endTime, pauseMinutes, location) {
|
||||
try {
|
||||
const body = {
|
||||
date: formatDateISO(date),
|
||||
startTime,
|
||||
endTime,
|
||||
location: location || 'office'
|
||||
};
|
||||
|
||||
// Only include pauseMinutes if explicitly provided (not empty)
|
||||
if (pauseMinutes !== null && pauseMinutes !== undefined && pauseMinutes !== '') {
|
||||
body.pauseMinutes = parseInt(pauseMinutes);
|
||||
}
|
||||
|
||||
const response = await fetch(`/api/entries/${id}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.error || 'Failed to update entry');
|
||||
}
|
||||
|
||||
const entry = await response.json();
|
||||
return entry;
|
||||
} catch (error) {
|
||||
console.error('Error updating entry:', error);
|
||||
showNotification(error.message || 'Fehler beim Aktualisieren des Eintrags', 'error');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an entry
|
||||
* @param {number} id - Entry ID
|
||||
* @returns {Promise<boolean>} - True if successful
|
||||
*/
|
||||
export async function deleteEntry(id) {
|
||||
try {
|
||||
const response = await fetch(`/api/entries/${id}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to delete entry');
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error deleting entry:', error);
|
||||
showNotification('Fehler beim Löschen des Eintrags', 'error');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export entries as CSV
|
||||
* @param {string|null} fromDate - Start date (YYYY-MM-DD)
|
||||
* @param {string|null} toDate - End date (YYYY-MM-DD)
|
||||
*/
|
||||
export async function exportEntries(fromDate = null, toDate = null) {
|
||||
try {
|
||||
let url = '/api/export';
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (fromDate) params.append('from', fromDate);
|
||||
if (toDate) params.append('to', toDate);
|
||||
|
||||
if (params.toString()) {
|
||||
url += '?' + params.toString();
|
||||
}
|
||||
|
||||
const response = await fetch(url);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to export entries');
|
||||
}
|
||||
|
||||
const blob = await response.blob();
|
||||
const downloadUrl = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = downloadUrl;
|
||||
a.download = 'zeiterfassung.csv';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
window.URL.revokeObjectURL(downloadUrl);
|
||||
|
||||
showNotification('Export erfolgreich', 'success');
|
||||
} catch (error) {
|
||||
console.error('Error exporting entries:', error);
|
||||
showNotification('Fehler beim Exportieren', 'error');
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/**
|
||||
* Toast notification system
|
||||
*/
|
||||
|
||||
/**
|
||||
* Show toast notification
|
||||
* @param {string} message - Message to display
|
||||
* @param {string} type - Type of notification (success, error, info)
|
||||
*/
|
||||
export function showNotification(message, type = 'info') {
|
||||
const container = document.getElementById('toastContainer');
|
||||
|
||||
// Create toast element
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
|
||||
// Icon based on type
|
||||
const icons = {
|
||||
success: '✓',
|
||||
error: '✕',
|
||||
info: 'ℹ'
|
||||
};
|
||||
|
||||
toast.innerHTML = `
|
||||
<span class="toast-icon">${icons[type] || 'ℹ'}</span>
|
||||
<span>${message}</span>
|
||||
`;
|
||||
|
||||
container.appendChild(toast);
|
||||
|
||||
// Auto-remove after 3 seconds
|
||||
setTimeout(() => {
|
||||
toast.classList.add('hiding');
|
||||
setTimeout(() => {
|
||||
container.removeChild(toast);
|
||||
}, 300);
|
||||
}, 3000);
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/**
|
||||
* Date utility functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Format date from YYYY-MM-DD to DD.MM.YYYY
|
||||
* @param {string} dateStr - Date in YYYY-MM-DD format
|
||||
* @returns {string} - Date in DD.MM.YYYY format
|
||||
*/
|
||||
export function formatDateDisplay(dateStr) {
|
||||
const [year, month, day] = dateStr.split('-');
|
||||
return `${day}.${month}.${year}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format date from DD.MM.YYYY to YYYY-MM-DD
|
||||
* @param {string} dateStr - Date in DD.MM.YYYY format
|
||||
* @returns {string} - Date in YYYY-MM-DD format
|
||||
*/
|
||||
export function formatDateISO(dateStr) {
|
||||
const [day, month, year] = dateStr.split('.');
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get today's date in YYYY-MM-DD format
|
||||
* @returns {string} - Today's date
|
||||
*/
|
||||
export function getTodayISO() {
|
||||
const today = new Date();
|
||||
const year = today.getFullYear();
|
||||
const month = String(today.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(today.getDate()).padStart(2, '0');
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get day of week name in German
|
||||
* @param {Date} date - Date object
|
||||
* @returns {string} - German day name (Mo, Di, Mi, etc.)
|
||||
*/
|
||||
export function getDayOfWeek(date) {
|
||||
const days = ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'];
|
||||
return days[date.getDay()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get month name in German
|
||||
* @param {number} monthIndex - Month index (0-11)
|
||||
* @returns {string} - German month name
|
||||
*/
|
||||
export function getMonthName(monthIndex) {
|
||||
const months = [
|
||||
'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni',
|
||||
'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'
|
||||
];
|
||||
return months[monthIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if date is weekend or holiday
|
||||
* @param {Date} date - Date object
|
||||
* @returns {boolean} - True if weekend or holiday
|
||||
*/
|
||||
export function isWeekendOrHoliday(date) {
|
||||
const dayOfWeek = date.getDay();
|
||||
return dayOfWeek === 0 || dayOfWeek === 6; // Sunday or Saturday
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/**
|
||||
* Time utility functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Round time down to nearest 15 minutes
|
||||
* @param {Date} date - Date object
|
||||
* @returns {Date} - Rounded date
|
||||
*/
|
||||
export function roundDownTo15Min(date) {
|
||||
const minutes = date.getMinutes();
|
||||
const roundedMinutes = Math.floor(minutes / 15) * 15;
|
||||
date.setMinutes(roundedMinutes);
|
||||
date.setSeconds(0);
|
||||
date.setMilliseconds(0);
|
||||
return date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Round time up to nearest 15 minutes
|
||||
* @param {Date} date - Date object
|
||||
* @returns {Date} - Rounded date
|
||||
*/
|
||||
export function roundUpTo15Min(date) {
|
||||
const minutes = date.getMinutes();
|
||||
const roundedMinutes = Math.ceil(minutes / 15) * 15;
|
||||
date.setMinutes(roundedMinutes);
|
||||
date.setSeconds(0);
|
||||
date.setMilliseconds(0);
|
||||
return date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format time as HH:MM
|
||||
* @param {Date} date - Date object
|
||||
* @returns {string} - Time in HH:MM format
|
||||
*/
|
||||
export function formatTime(date) {
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
return `${hours}:${minutes}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format seconds to HH:MM:SS
|
||||
* @param {number} seconds - Duration in seconds
|
||||
* @returns {string} - Formatted duration
|
||||
*/
|
||||
export function formatDuration(seconds) {
|
||||
const hrs = Math.floor(seconds / 3600);
|
||||
const mins = Math.floor((seconds % 3600) / 60);
|
||||
const secs = seconds % 60;
|
||||
return `${String(hrs).padStart(2, '0')}:${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
|
||||
}
|
||||
Reference in New Issue
Block a user