/* global React, L, MZ */ const { useState, useEffect, useRef } = React; function LoginModal({ onClose, onLoggedIn, onToast }) { const [mode, setMode] = useState('signin'); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [handle, setHandle] = useState(''); const [name, setName] = useState(''); const [rodo, setRodo] = useState(false); const [busy, setBusy] = useState(false); const [err, setErr] = useState(null); const submit = async (e) => { e.preventDefault(); setErr(null); setBusy(true); try { if (mode === 'signin') { await MZ.signIn({ email, password }); } else { if (!rodo) throw new Error('Musisz zaakceptować regulamin i politykę prywatności'); if (!/^[a-z0-9_]{3,20}$/.test(handle)) throw new Error('Nazwa: małe litery, cyfry, podkreślniki, 3–20 znaków'); if (password.length < 8) throw new Error('Hasło musi mieć min. 8 znaków'); await MZ.signUp({ email, password, handle, name }); onToast('Konto utworzone — jesteś zalogowany.'); } onLoggedIn(); } catch (e2) { setErr(e2.message || 'Błąd'); } setBusy(false); }; return (
e.stopPropagation()} onSubmit={submit}>

{mode==='signin' ? 'Zaloguj się' : 'Załóż konto'}

{mode === 'signup' && ( <>
setHandle(e.target.value.toLowerCase())} placeholder="np. kierowca_kasia" required />
MAŁE LITERY, CYFRY, PODKREŚLNIKI · 3–20 ZNAKÓW
setName(e.target.value)} placeholder="Wyświetlane publicznie" />
)}
setEmail(e.target.value)} placeholder="ty@example.pl" />
setPassword(e.target.value)} placeholder="min. 8 znaków" />
{mode === 'signup' && (
)} {err &&
{err}
}
); } function SubmitModal({ onClose, theme, onSubmitted, onToast }) { const [step, setStep] = useState(1); const [data, setData] = useState({ url: '', title: '', severity: 'collision', city: '', tags: '', description: '', duration: '', recorded_on: '', }); const [coords, setCoords] = useState({ lat: 52.23, lng: 21.01 }); const [rules, setRules] = useState(false); const [busy, setBusy] = useState(false); const [err, setErr] = useState(null); const mapRef = useRef(null); const instRef = useRef(null); const markerRef = useRef(null); const set = (k, v) => setData(d => ({ ...d, [k]: v })); useEffect(() => { if (step !== 2 || instRef.current) return; const m = L.map(mapRef.current).setView([coords.lat, coords.lng], 6); instRef.current = m; const t = TILES[theme==='dark'?'dark':'light']; L.tileLayer(t.url, { attribution: t.attr, subdomains: 'abcd' }).addTo(m); const icon = L.divIcon({ className:'', html:'
', iconSize:[14,14], iconAnchor:[7,7] }); markerRef.current = L.marker([coords.lat, coords.lng], { icon, draggable: true }).addTo(m); markerRef.current.on('dragend', () => { const p = markerRef.current.getLatLng(); setCoords({ lat: p.lat, lng: p.lng }); }); m.on('click', (e) => { markerRef.current.setLatLng(e.latlng); setCoords({ lat: e.latlng.lat, lng: e.latlng.lng }); }); return () => { m.remove(); instRef.current = null; }; }, [step]); const nextStep = () => { setErr(null); if (step === 1) { const yid = MZ.extractYouTubeId(data.url); if (!yid) { setErr('Niepoprawny link YouTube'); return; } if (data.title.trim().length < 5) { setErr('Tytuł musi mieć min. 5 znaków'); return; } } setStep(step + 1); }; const submit = async (e) => { e.preventDefault(); if (!rules) { setErr('Zaakceptuj zasady społeczności'); return; } setBusy(true); setErr(null); try { const yid = MZ.extractYouTubeId(data.url); const sevMap = { 'Kolizja':'collision', 'Prawie-kolizja':'near-miss', 'Zwierzęta':'wildlife', 'Pogoda':'weather', 'Inne':'other' }; const severity = sevMap[data.severity] || data.severity; const payload = { title: data.title.trim(), youtube_id: yid, severity, city: data.city.trim() || null, lat: coords.lat, lng: coords.lng, duration: data.duration.trim() || null, tags: data.tags.split(',').map(s => s.trim()).filter(Boolean), description: data.description.trim() || null, recorded_on: data.recorded_on || null, }; const result = await MZ.createVideo(payload); const msg = result.status === 'published' ? 'Nagranie opublikowane — dziękujemy!' : 'Nagranie wysłane do moderacji (do ~6h).'; onToast(msg); onSubmitted?.(result); onClose(); } catch (er) { setErr(er.message || 'Błąd'); } setBusy(false); }; return (
e.stopPropagation()} onSubmit={submit} style={{maxWidth: 640}}>

Dodaj nagranie KROK {step} Z 3

{step === 1 && ( <>
set('url', e.target.value)} placeholder="https://youtube.com/watch?v=..." required />
PUBLICZNE LUB NIEPUBLICZNE · NIE PRYWATNE
set('title', e.target.value)} placeholder="Krótki opis — co się stało, gdzie" required />
set('duration', e.target.value)} placeholder="np. 1:24" />
)} {step === 2 && ( <>
KLIKNIJ NA MAPIE LUB PRZECIĄGNIJ PINEZKĘ · {coords.lat.toFixed(4)}, {coords.lng.toFixed(4)}
set('city', e.target.value)} placeholder="np. A4, Wrocław" />
set('recorded_on', e.target.value)} />
)} {step === 3 && ( <>
set('tags', e.target.value)} placeholder="skrzyżowanie, rowerzysta, czerwone-światło" />