Dateien nach "frontend/src" hochladen

This commit is contained in:
2026-05-26 14:49:06 +02:00
parent 75b5944d12
commit 0222778aab

View File

@@ -92,11 +92,15 @@ export default function CalendarWidget() {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [selected, setSelected] = useState(null); // date object const [selected, setSelected] = useState(null); // date object
const [errors, setErrors] = useState([]);
// Load all feeds // Load all feeds
const loadFeeds = async (feedList) => { const loadFeeds = async (feedList) => {
if (!feedList.length) { setEvents([]); return; } if (!feedList.length) { setEvents([]); return; }
setLoading(true); setLoading(true);
setErrors([]);
const all = []; const all = [];
const errs = [];
for (const f of feedList) { for (const f of feedList) {
try { try {
const res = await fetch(`/api/calendar/fetch?url=${encodeURIComponent(f.url)}`, { const res = await fetch(`/api/calendar/fetch?url=${encodeURIComponent(f.url)}`, {
@@ -106,14 +110,18 @@ export default function CalendarWidget() {
const text = await res.text(); const text = await res.text();
const evs = parseIcal(text).map(e => ({ ...e, color: f.color, feedName: f.name })); const evs = parseIcal(text).map(e => ({ ...e, color: f.color, feedName: f.name }));
all.push(...evs); all.push(...evs);
} else {
const d = await res.json().catch(()=>({error:'Unbekannter Fehler'}));
errs.push(`${f.name}: ${d.error}`);
} }
} catch {} } catch(e) { errs.push(`${f.name}: ${e.message}`); }
} }
setEvents(all); setEvents(all);
setErrors(errs);
setLoading(false); setLoading(false);
}; };
useEffect(() => { if (isOpen) loadFeeds(feeds); }, [isOpen]); useEffect(() => { if (isOpen && feeds.length > 0) loadFeeds(feeds); }, [isOpen]);
// Calendar grid // Calendar grid
const days = useMemo(() => { const days = useMemo(() => {
@@ -135,15 +143,37 @@ export default function CalendarWidget() {
return ( return (
<div style={{ ...S.card, marginBottom:10 }}> <div style={{ ...S.card, marginBottom:10 }}>
{/* Header */} {/* Header */}
<button onClick={()=>setIsOpen(v=>!v)} style={{ width:'100%', background:'transparent', border:'none', <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center' }}>
<button onClick={()=>setIsOpen(v=>!v)} style={{ flex:1, background:'transparent', border:'none',
display:'flex', justifyContent:'space-between', alignItems:'center', cursor:'pointer', padding:0 }}> display:'flex', justifyContent:'space-between', alignItems:'center', cursor:'pointer', padding:0 }}>
<div style={S.head}>KALENDER{loading?' …':''}</div> <div style={S.head}>KALENDER</div>
<span style={{ color:'rgba(255,255,255,0.4)', fontSize:11, display:'inline-block', <span style={{ color:'rgba(255,255,255,0.4)', fontSize:11, display:'inline-block',
transform:isOpen?'rotate(90deg)':'rotate(0)', transition:'transform 0.2s' }}></span> transform:isOpen?'rotate(90deg)':'rotate(0)', transition:'transform 0.2s' }}></span>
</button> </button>
{isOpen && feeds.length > 0 && (
<button onClick={()=>loadFeeds(feeds)} disabled={loading}
style={{ background:'transparent', border:'none', color:'rgba(255,255,255,0.4)',
cursor:'pointer', fontSize:13, padding:'0 0 0 8px', marginLeft:8 }}
title="Neu laden">
{loading ? '⏳' : '↻'}
</button>
)}
</div>
{isOpen && ( {isOpen && (
<div style={{ marginTop:12 }}> <div style={{ marginTop:12 }}>
{/* Fehler */}
{errors.length > 0 && (
<div style={{ marginBottom:10 }}>
{errors.map((e,i) => (
<div key={i} style={{ color:'#ff6b9d', fontFamily:'monospace', fontSize:10,
background:'rgba(255,107,157,0.08)', borderRadius:6, padding:'4px 8px', marginBottom:3 }}>
{e}
</div>
))}
</div>
)}
{/* Monat Nav */} {/* Monat Nav */}
<div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:10 }}> <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:10 }}>
<button onClick={prevMonth} style={{ background:'transparent', border:'none', color:'rgba(255,255,255,0.5)', <button onClick={prevMonth} style={{ background:'transparent', border:'none', color:'rgba(255,255,255,0.5)',