Dateien nach "frontend/src" hochladen
This commit is contained in:
@@ -92,11 +92,15 @@ export default function CalendarWidget() {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [selected, setSelected] = useState(null); // date object
|
||||
|
||||
const [errors, setErrors] = useState([]);
|
||||
|
||||
// Load all feeds
|
||||
const loadFeeds = async (feedList) => {
|
||||
if (!feedList.length) { setEvents([]); return; }
|
||||
setLoading(true);
|
||||
setErrors([]);
|
||||
const all = [];
|
||||
const errs = [];
|
||||
for (const f of feedList) {
|
||||
try {
|
||||
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 evs = parseIcal(text).map(e => ({ ...e, color: f.color, feedName: f.name }));
|
||||
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);
|
||||
setErrors(errs);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => { if (isOpen) loadFeeds(feeds); }, [isOpen]);
|
||||
useEffect(() => { if (isOpen && feeds.length > 0) loadFeeds(feeds); }, [isOpen]);
|
||||
|
||||
// Calendar grid
|
||||
const days = useMemo(() => {
|
||||
@@ -135,15 +143,37 @@ export default function CalendarWidget() {
|
||||
return (
|
||||
<div style={{ ...S.card, marginBottom:10 }}>
|
||||
{/* 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 }}>
|
||||
<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',
|
||||
transform:isOpen?'rotate(90deg)':'rotate(0)', transition:'transform 0.2s' }}>▶</span>
|
||||
</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 && (
|
||||
<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 */}
|
||||
<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)',
|
||||
|
||||
Reference in New Issue
Block a user