import { useState, useEffect } from 'react' import { aclApi, type AclEntry, type ShareRecipient, type SharePermission, } from '../api/client' import { useOverlayDismiss } from '../hooks/useOverlayDismiss' interface Props { /** Was freigegeben wird – Ordner oder einzelne Datei. */ resource: { type: 'folder' | 'file' | 'calendar'; id: string; name: string } onClose: () => void } /** Freigabe an Personen und Gruppen innerhalb der Cloud. * * Bewusst getrennt vom öffentlichen Freigabelink: Der eine gibt einen * anonymen Zugang ins Internet, der andere benennt Personen, die sich * ohnehin anmelden. Ein Dialog für beides würde die Frage „wer kann das * sehen?" verwischen – und genau die muss beim Teilen eindeutig sein. */ export default function ShareWithDialog({ resource, onClose }: Props) { const overlay = useOverlayDismiss(onClose) const [entries, setEntries] = useState([]) const [recipients, setRecipients] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState('') const [subject, setSubject] = useState('') const [permission, setPermission] = useState('read') const [saving, setSaving] = useState(false) useEffect(() => { load() }, [resource.id]) async function load() { setLoading(true) try { const [list, people] = await Promise.all([ resource.type === 'folder' ? aclApi.listForFolder(resource.id) : resource.type === 'calendar' ? aclApi.listForCalendar(resource.id) : aclApi.listForFile(resource.id), aclApi.recipients(), ]) setEntries(list ?? []) setRecipients(people ?? []) } catch { setError('Could not load sharing settings') } finally { setLoading(false) } } async function grant() { const chosen = recipients.find(r => r.id === subject) if (!chosen) return setSaving(true) setError('') try { if (resource.type === 'calendar') { await aclApi.grantCalendar(resource.id, chosen.id, chosen.type, permission) } else if (resource.type === 'folder') { await aclApi.grantFolder(resource.id, chosen.id, chosen.type, permission) } else { await aclApi.grantFile(resource.id, chosen.id, chosen.type, permission) } setSubject('') await load() } catch (e) { setError(e instanceof Error ? e.message : 'Could not share') } finally { setSaving(false) } } async function revoke(entry: AclEntry) { try { await aclApi.revoke(entry.id) setEntries(list => list.filter(e => e.id !== entry.id)) } catch { setError('Could not remove access') } } // Wer schon Zugriff hat, gehört nicht noch einmal in die Auswahlliste. const alreadyShared = new Set(entries.map(e => e.subject_id)) const available = recipients.filter(r => !alreadyShared.has(r.id)) return (
{/* Kopf */}

Share with people

{resource.name}

{/* Hinzufügen */}
{resource.type === 'calendar' && (

The calendar shows up in their app too — web and CalDAV alike. With “can edit” they may add and change events; renaming or deleting the calendar stays with you.

)} {resource.type === 'folder' && (

Everything inside this folder is shared too, including anything added later. Files stay in your storage and count towards your quota.

)} {error && (

{error}

)}
{/* Wer hat Zugriff */}
Who has access
{loading ? (

Loading…

) : entries.length === 0 ? (

Only you. Nobody else can see this.

) : (
{entries.map(e => (
{e.subject_type === 'group' ? : }
{e.subject_name}
{e.subject_type === 'group' ? 'Group' : 'Person'} ·{' '} {e.permission === 'write' ? 'Can edit' : 'Can view'}
))}
)}
) } function PersonIcon() { return ( ) } function GroupIcon() { return ( ) }