diff --git a/frontend/src/tools/dateien.jsx b/frontend/src/tools/dateien.jsx new file mode 100644 index 0000000..961ed35 --- /dev/null +++ b/frontend/src/tools/dateien.jsx @@ -0,0 +1,291 @@ +import { useState, useEffect, useRef } from 'react'; +import { api, S } from '../lib.js'; +import { useConfirm } from '../confirm.jsx'; +import { UploadIcon, DownloadIcon, TrashIcon, SearchIcon, XIcon, PlusIcon } from '../icons.jsx'; + +function fmtSize(bytes) { + if (bytes < 1024) return `${bytes} B`; + if (bytes < 1024*1024) return `${(bytes/1024).toFixed(1)} KB`; + return `${(bytes/(1024*1024)).toFixed(1)} MB`; +} + +function fmtDate(s) { + return new Date(s).toLocaleDateString('de-DE', { day:'2-digit', month:'2-digit', year:'numeric' }); +} + +const extIcon = name => { + const ext = name.split('.').pop().toLowerCase(); + if (['jpg','jpeg','png','gif','webp'].includes(ext)) return 'πΌ'; + if (['pdf'].includes(ext)) return 'π'; + if (['zip','rar','7z'].includes(ext)) return 'π¦'; + if (['mp4','mov','avi'].includes(ext)) return 'π¬'; + if (['mp3','wav'].includes(ext)) return 'π΅'; + if (['stl','3mf'].includes(ext)) return 'π¨'; + if (['txt','md'].includes(ext)) return 'π'; + if (['xlsx','csv'].includes(ext)) return 'π'; + if (['docx','doc'].includes(ext)) return 'π'; + return 'π'; +}; + +function ShareModal({ file, onClose, toast }) { + const [username, setUsername] = useState(''); + const [shares, setShares] = useState([]); + const [busy, setBusy] = useState(false); + + useEffect(() => { + api('/tools/dateien').then(d => { + // find current shares for this file + const allShares = d.own.find(f => f.id === file.id); + // get shares via separate query approach - just reload full list + }).catch(() => {}); + // Load shares from API + api(`/tools/dateien/${file.id}/shares`).then(setShares).catch(() => {}); + }, [file.id]); + + const share = async () => { + if (!username.trim()) return; + setBusy(true); + try { + await api(`/tools/dateien/${file.id}/share`, { body: { username: username.trim() } }); + toast(`Mit ${username} geteilt β`); + setUsername(''); + api(`/tools/dateien/${file.id}/shares`).then(setShares).catch(() => {}); + } catch(e) { toast(e.message, 'error'); } finally { setBusy(false); } + }; + + const unshare = async userId => { + try { + await api(`/tools/dateien/${file.id}/share/${userId}`, { method: 'DELETE' }); + setShares(p => p.filter(s => s.id !== userId)); + toast('Freigabe entfernt'); + } catch(e) { toast(e.message, 'error'); } + }; + + const isMobile = window.innerWidth < 768; + return ( +