a

Aplikacja

I am raw html block.
Click edit button to change this html

import React, { useState, useMemo, useCallback, useEffect } from 'react'; // Pominięto importy Firebase, aby zachować czystą wersję demo // --- Konfiguracja i Narzędzia --- const formatDate = (dateString) => { if (!dateString) return 'N/A'; try { const date = new Date(dateString); if (isNaN(date)) return dateString; // Wymuszenie daty na dzień, miesiąc, rok, aby uniknąć błędów formatowania return new Date(date.getTime() + date.getTimezoneOffset() * 60000).toLocaleDateString('pl-PL', { day: '2-digit', month: '2-digit', year: 'numeric' }); } catch (e) { return dateString; } }; const formatPrice = (price) => `${price.toFixed(2)} PLN`; const ADMIN_USER_ID = 'admin-user-biegun'; // Stały ID Admina const PARENT_USER_ID = 'default-user-1'; // Stały ID Rodzica do danych mockowych // --- DANE MOCKOWE (symulacja 20 uczestników z bazy) --- const MOCK_GROUPS = [ { id: 'g1', nazwa: 'Beeski', color: 'bg-yellow-200' }, { id: 'g2', nazwa: 'ProKids', color: 'bg-green-200' }, { id: 'g3', nazwa: 'SemiPRO', color: 'bg-blue-200' }, { id: 'g4', nazwa: 'Hero', color: 'bg-red-200' }, { id: 'g5', nazwa: 'PRO', color: 'bg-indigo-200' }, { id: 'g6', nazwa: 'Nieprzypisane', color: 'bg-gray-200' }, ]; const mockChildrenGenerator = () => { const names = [ { imie: 'Ignacy', nazwisko: 'Stepanik', ur: 2021, parentId: PARENT_USER_ID }, // Rodzic główny (1/2 dzieci) { imie: 'Franciszek', nazwisko: 'Stepanik', ur: 2023, parentId: PARENT_USER_ID }, // Rodzic główny (2/2 dzieci) { imie: 'Anna', nazwisko: 'Kowalska', ur: 2020, parentId: 'user-2' }, { imie: 'Michał', nazwisko: 'Zalega', ur: 2018, parentId: 'user-3' }, { imie: 'Kasia', nazwisko: 'Wesoła', ur: 2019, parentId: 'user-4' }, { imie: 'Piotr', nazwisko: 'Nowak', ur: 2022, parentId: 'user-5' }, { imie: 'Julia', nazwisko: 'Maj', ur: 2021, parentId: 'user-6' }, { imie: 'Krzysztof', nazwisko: 'Lis', ur: 2020, parentId: 'user-7' }, { imie: 'Ola', nazwisko: 'Wróbel', ur: 2019, parentId: 'user-8' }, { imie: 'Bartek', nazwisko: 'Kruk', ur: 2018, parentId: 'user-9' }, { imie: 'Weronika', nazwisko: 'Górska', ur: 2022, parentId: 'user-10' }, { imie: 'Filip', nazwisko: 'Jankowski', ur: 2023, parentId: 'user-11' }, { imie: 'Maja', nazwisko: 'Kowalczyk', ur: 2021, parentId: 'user-12' }, { imie: 'Adam', nazwisko: 'Wójtowicz', ur: 2020, parentId: 'user-13' }, { imie: 'Ewa', nazwisko: 'Zając', ur: 2019, parentId: 'user-14' }, { imie: 'Hubert', nazwisko: 'Duda', ur: 2018, parentId: 'user-15' }, { imie: 'Lena', nazwisko: 'Kaczmarek', ur: 2022, parentId: 'user-16' }, { imie: 'Oskar', nazwisko: 'Mazur', ur: 2023, parentId: 'user-17' }, { imie: 'Natalia', nazwisko: 'Szymańska', ur: 2021, parentId: 'user-18' }, { imie: 'Robert', nazwisko: 'Wysocki', ur: 2020, parentId: 'user-19' }, ]; return names.map((data, index) => { const parentEmail = `${data.imie.toLowerCase()}.${data.nazwisko.toLowerCase()}@example.com`; const parentPhone = `5${index + 1}0-${index + 1}00-${index + 1}00`; const groups = MOCK_GROUPS.map(g => g.nazwa).filter(n => n !== 'Nieprzypisane'); const grupa = index % 5 === 0 && index > 4 ? 'Nieprzypisane' : groups[index % groups.length]; return { id: `dziecko${index + 1}`, ...data, rokUrodzenia: data.ur, grupa: grupa, parentEmail, parentPhone, }; }); }; const MOCK_CHILDREN = mockChildrenGenerator(); const MOCK_PARENT_DATA = { [PARENT_USER_ID]: { imie: 'Kamil', nazwisko: 'Stepanik', email: 'kamil.stepanik@example.com', telefon: '500-100-200', }, // Dodajemy dane dla pozostałych rodziców, uproszczone 'user-2': { imie: 'Jan', nazwisko: 'Kowalski', email: 'jan.kowalski@example.com', telefon: '600-200-300' }, 'user-3': { imie: 'Marta', nazwisko: 'Zalega', email: 'marta.zalega@example.com', telefon: '700-300-400' }, // ... i tak dalej dla reszty }; const MOCK_TRIPS = [ { id: 'wyjazd1', nazwa: 'Obóz Narciarski Tatry 2026', opis: 'Tygodniowy wyjazd szkoleniowy w Zakopanem. Pełne szkolenie PZN. Zakwaterowanie w pensjonacie Giewont.', dataWyjazdu: '2026-01-10', godzinaWyjazdu: '07:00', miejsceWyjazdu: 'Kraków, parking przy Tauron Arena', dataPowrotu: '2026-01-17', godzinaPowrotu: '18:00', miejscePowrotu: 'Kraków, parking przy Tauron Arena', platnosci: [ { id: 'p1', tytul: 'Zaliczka', kwota: 500, termin: '2024-11-15', status: 'Oczekuje' }, // ZALEGŁA { id: 'p2', tytul: 'II Rata', kwota: 1500, termin: '2025-12-15', status: 'Oczekuje' }, { id: 'p3', tytul: 'Karnet (opcjonalny)', kwota: 400, termin: '2025-12-30', status: 'Oczekuje' }, ], grupy: ['Beeski', 'ProKids', 'SemiPRO', 'PRO'], pdfUrl: 'mock/umowa_tatry.pdf' }, { id: 'wyjazd2', nazwa: 'Zimowy Trening Biegowy (Weekend)', opis: 'Szybki wypad do Szklarskiej Poręby. Hotel Sudety.', dataWyjazdu: '2026-02-28', godzinaWyjazdu: '16:00', miejsceWyjazdu: 'Katowice, Dworzec Główny PKP', dataPowrotu: '2026-03-01', godzinaPowrotu: '20:00', miejscePowrotu: 'Katowice, Dworzec Główny PKP', platnosci: [{ id: 'p4', tytul: 'Całość', kwota: 999, termin: '2026-01-30', status: 'Oczekuje' }], grupy: ['Hero', 'PRO'], pdfUrl: 'mock/umowa_szklarska.pdf' }, ]; // Domyślne statusy wyjazdów (ustawiamy więcej dzieci na wyjazdy) const INITIAL_TRIP_STATUSES = {}; MOCK_CHILDREN.forEach((child, index) => { if (index % 3 !== 0) { // Co trzecie dziecko nie jedzie if (child.grupa === 'Beeski' || child.grupa === 'ProKids' || child.grupa === 'SemiPRO' || child.grupa === 'PRO') { INITIAL_TRIP_STATUSES['wyjazd1'] = { ...INITIAL_TRIP_STATUSES['wyjazd1'], [child.id]: { status: 'Jedzie' } }; } if (child.grupa === 'Hero' || child.grupa === 'PRO') { INITIAL_TRIP_STATUSES['wyjazd2'] = { ...INITIAL_TRIP_STATUSES['wyjazd2'], [child.id]: { status: 'Jedzie' } }; } } }); // Ustaw Ignacego jako "Jedzie" INITIAL_TRIP_STATUSES['wyjazd1'][MOCK_CHILDREN[0].id] = { status: 'Jedzie' }; // --- NARZĘDZIA ADMINA --- // ADMIN: Komponent Edycji Wyjazdu const AdminEditTripModal = ({ trip, onClose, tripsData, setTripsData, updateAllData }) => { const [editedTrip, setEditedTrip] = useState(trip); const [newPayment, setNewPayment] = useState({ tytul: '', kwota: 0, termin: '' }); const availableGroups = MOCK_GROUPS.map(g => g.nazwa).filter(n => n !== 'Nieprzypisane'); const handleChange = (e) => { const { name, value } = e.target; setEditedTrip(prev => ({ ...prev, [name]: value })); }; const handleGroupToggle = (groupName) => { setEditedTrip(prev => ({ ...prev, grupy: prev.grupy.includes(groupName) ? prev.grupy.filter(g => g !== groupName) : [...prev.grupy, groupName] })); }; const handleNewPaymentChange = (e) => { setNewPayment({ ...newPayment, [e.target.name]: e.target.value }); }; const addPaymentToTrip = () => { if (newPayment.tytul && newPayment.kwota > 0 && newPayment.termin) { setEditedTrip(prev => ({ ...prev, platnosci: [...prev.platnosci, { ...newPayment, id: `p${prev.platnosci.length + 1}`, kwota: parseFloat(newPayment.kwota), status: 'Oczekuje' }] })); setNewPayment({ tytul: '', kwota: 0, termin: '' }); } }; const removePayment = (paymentId) => { setEditedTrip(prev => ({ ...prev, platnosci: prev.platnosci.filter(p => p.id !== paymentId) })); }; const handlePdfUpload = (e) => { if (e.target.files.length > 0) { alert(`Plik PDF ${e.target.files[0].name} załadowany! (Symulacja zapisu URL)`); setEditedTrip(prev => ({...prev, pdfUrl: `mock-url-${e.target.files[0].name}`})); } }; const handleSave = () => { // Aktualizacja listy wyjazdów const updatedTrips = tripsData.map(t => t.id === editedTrip.id ? editedTrip : t); setTripsData(updatedTrips); // Wymuszenie aktualizacji całego stanu aplikacji updateAllData({ newTrips: updatedTrips }); alert(`Wyjazd "${editedTrip.nazwa}" został zaktualizowany!`); onClose(); }; return (

Edycja Wyjazdu: {trip.nazwa}

{/* Podstawowe Info */}

Informacje Ogólne