import React, { useState, useEffect } from 'react'; import { FaPlus, FaTrash, FaCheck, FaEdit, FaShoppingCart, FaClock } from 'react-icons/fa'; import shoppingService from './services/ShoppingService'; import './App.sass'; const App = () => { const [items, setItems] = useState([]); const [loading, setLoading] = useState(true); const [initialLoad, setInitialLoad] = useState(true); const [error, setError] = useState(null); const [newItem, setNewItem] = useState({ name: '', amount: '1' }); const [editingItem, setEditingItem] = useState(null); const [showAddForm, setShowAddForm] = useState(false); const [deferredPrompt, setDeferredPrompt] = useState(null); const [showInstallPrompt, setShowInstallPrompt] = useState(false); // Load shopping items on component mount useEffect(() => { loadItems(); // Set up auto-refresh every 5 seconds const interval = setInterval(() => { loadItems(); }, 5000); // PWA install prompt handling const handleBeforeInstallPrompt = (e) => { e.preventDefault(); setDeferredPrompt(e); setShowInstallPrompt(true); }; window.addEventListener('beforeinstallprompt', handleBeforeInstallPrompt); // Cleanup interval and event listener on component unmount return () => { clearInterval(interval); window.removeEventListener('beforeinstallprompt', handleBeforeInstallPrompt); }; }, []); const loadItems = async () => { try { if (initialLoad) { setLoading(true); } const data = await shoppingService.getItems(); setItems(data); setError(null); } catch (err) { setError('Failed to load shopping items'); console.error('Error loading items:', err); } finally { if (initialLoad) { setLoading(false); setInitialLoad(false); } } }; const handleAddItem = async (e) => { e.preventDefault(); if (!newItem.name.trim()) return; try { const createdItem = await shoppingService.createItem({ name: newItem.name.trim(), amount: newItem.amount.trim() || '1' }); setItems([createdItem, ...items]); setNewItem({ name: '', amount: '1' }); setShowAddForm(false); } catch (err) { setError('Failed to add item'); console.error('Error adding item:', err); } }; const handleToggleItem = async (id) => { try { const updatedItem = await shoppingService.toggleItem(id); setItems(items.map(item => item.id === id ? updatedItem : item )); } catch (err) { setError('Failed to update item'); console.error('Error toggling item:', err); } }; const handleDeleteItem = async (id) => { try { await shoppingService.deleteItem(id); setItems(items.filter(item => item.id !== id)); } catch (err) { setError('Failed to delete item'); console.error('Error deleting item:', err); } }; const handleUpdateItem = async (id, updatedData) => { try { const updatedItem = await shoppingService.updateItem(id, updatedData); setItems(items.map(item => item.id === id ? updatedItem : item )); setEditingItem(null); } catch (err) { setError('Failed to update item'); console.error('Error updating item:', err); } }; const handleDeleteChecked = async () => { try { await shoppingService.deleteCheckedItems(); setItems(items.filter(item => !item.checked)); } catch (err) { setError('Failed to delete checked items'); console.error('Error deleting checked items:', err); } }; const handleInstallApp = async () => { if (deferredPrompt) { deferredPrompt.prompt(); const { outcome } = await deferredPrompt.userChoice; if (outcome === 'accepted') { setDeferredPrompt(null); setShowInstallPrompt(false); } } }; const formatDate = (dateString) => { const date = new Date(dateString); return date.toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' }); }; const getTimeUntilDeletion = (checkedAt) => { if (!checkedAt) return null; const twoHoursLater = new Date(new Date(checkedAt).getTime() + 2 * 60 * 60 * 1000); const now = new Date(); const timeDiff = twoHoursLater - now; if (timeDiff <= 0) return 'Wird gelöscht...'; const minutes = Math.floor(timeDiff / (1000 * 60)); const hours = Math.floor(minutes / 60); const remainingMinutes = minutes % 60; if (hours > 0) { return `${hours}h ${remainingMinutes}m`; } return `${minutes}m`; }; const uncheckedItems = items.filter(item => !item.checked); const checkedItems = items.filter(item => item.checked); if (loading && initialLoad) { return (

Einkaufsliste wird geladen...

); } return (

Einkaufsliste

{checkedItems.length > 0 && ( )}
{error && (
{error}
)} {showInstallPrompt && (

Diese App auf dem Homescreen installieren?

)} {showAddForm && (

Neuer Artikel

setNewItem({ ...newItem, name: e.target.value })} autoFocus /> setNewItem({ ...newItem, amount: e.target.value })} />
)}
{/* Unchecked Items */}

Zu kaufen ({uncheckedItems.length})

{uncheckedItems.length === 0 ? (

Keine Artikel auf der Einkaufsliste

) : ( uncheckedItems.map(item => ( )) )}
{/* Checked Items */} {checkedItems.length > 0 && (

Erledigt ({checkedItems.length})

{checkedItems.map(item => ( ))}
)}
); }; // Shopping Item Component const ShoppingItem = ({ item, onToggle, onDelete, onUpdate, editingItem, setEditingItem, formatDate, getTimeUntilDeletion }) => { const [editData, setEditData] = useState({ name: item.name, amount: item.amount }); const handleEdit = () => { setEditingItem(item.id); setEditData({ name: item.name, amount: item.amount }); }; const handleSave = () => { onUpdate(item.id, editData); }; const handleCancel = () => { setEditingItem(null); setEditData({ name: item.name, amount: item.amount }); }; const isEditing = editingItem === item.id; return (
{isEditing ? (
setEditData({ ...editData, name: e.target.value })} onKeyDown={(e) => { if (e.key === 'Enter') handleSave(); if (e.key === 'Escape') handleCancel(); }} autoFocus /> setEditData({ ...editData, amount: e.target.value })} onKeyDown={(e) => { if (e.key === 'Enter') handleSave(); if (e.key === 'Escape') handleCancel(); }} />
) : ( <>
{item.name} {item.amount}
{formatDate(item.date)} {item.checked && item.checkedAt && getTimeUntilDeletion && ( {getTimeUntilDeletion(item.checkedAt)} )}
)}
{!isEditing && ( <> )}
); }; export default App;