setLightboxFile(null)} />}
{/* Assign modal */}
{assignFileId && ReactDOM.createPortal(
setAssignFileId(null)}>
e.stopPropagation()}>
{t('files.assignTitle')}
{files.find(f => f.id === assignFileId)?.original_name || ''}
{t('files.noteLabel') || 'Note'}
f.id === assignFileId)?.description || ''}
onBlur={e => {
const val = e.target.value.trim()
const file = files.find(f => f.id === assignFileId)
if (file && val !== (file.description || '')) {
handleAssign(file.id, { description: val } as any)
}
}}
onKeyDown={e => { if (e.key === 'Enter') (e.target as HTMLInputElement).blur() }}
style={{
width: '100%', padding: '7px 10px', fontSize: 13, borderRadius: 8,
border: '1px solid var(--border-primary)', background: 'var(--bg-secondary)',
color: 'var(--text-primary)', fontFamily: 'inherit', outline: 'none',
}}
/>
{(() => {
const file = files.find(f => f.id === assignFileId)
if (!file) return null
const assignedPlaceIds = new Set
()
const dayGroups: { day: Day; dayPlaces: Place[] }[] = []
for (const day of days) {
const da = assignments[String(day.id)] || []
const dayPlaces = da.map(a => places.find(p => p.id === a.place?.id || p.id === a.place_id)).filter(Boolean) as Place[]
if (dayPlaces.length > 0) {
dayGroups.push({ day, dayPlaces })
dayPlaces.forEach(p => assignedPlaceIds.add(p.id))
}
}
const unassigned = places.filter(p => !assignedPlaceIds.has(p.id))
const placeBtn = (p: Place) => (
)
const placesSection = places.length > 0 && (
{t('files.assignPlace')}
{dayGroups.map(({ day, dayPlaces }) => (
{day.title || `${t('dayplan.dayN', { n: day.day_number })}${day.date ? ` · ${day.date}` : ''}`}
{dayPlaces.map(placeBtn)}
))}
{unassigned.length > 0 && (
{dayGroups.length > 0 &&
{t('files.unassigned')}
}
{unassigned.map(placeBtn)}
)}
)
const bookingsSection = reservations.length > 0 && (
{t('files.assignBooking')}
{reservations.map(r => (
))}
)
const hasBoth = placesSection && bookingsSection
return (
{placesSection}
{hasBoth &&
}
{hasBoth &&
}
{bookingsSection}
)
})()}
,
document.body
)}
{/* PDF preview modal */}
{previewFile && ReactDOM.createPortal(
,
document.body
)}
{/* Header */}
{showTrash ? (t('files.trash') || 'Trash') : t('files.title')}
{showTrash
? `${trashFiles.length} ${trashFiles.length === 1 ? 'file' : 'files'}`
: (files.length === 1 ? t('files.countSingular') : t('files.count', { count: files.length }))}
{showTrash ? (
/* Trash view */
{trashFiles.length > 0 && (
)}
{loadingTrash ? (
) : trashFiles.length === 0 ? (
{t('files.trashEmpty') || 'Trash is empty'}
) : (
{trashFiles.map(file => renderFileRow(file, true))}
)}
) : (
<>
{/* Upload zone */}
{uploading ? (
) : (
<>
{t('files.dropzone')}
{t('files.dropzoneHint')}
{(allowedFileTypes || 'jpg,jpeg,png,gif,webp,heic,pdf,doc,docx,xls,xlsx,txt,csv').toUpperCase().split(',').join(', ')} · Max 50 MB
>
)}
{/* Filter tabs */}
{[
{ id: 'all', label: t('files.filterAll') },
...(files.some(f => f.starred) ? [{ id: 'starred', icon: Star }] : []),
{ id: 'pdf', label: t('files.filterPdf') },
{ id: 'image', label: t('files.filterImages') },
{ id: 'doc', label: t('files.filterDocs') },
...(files.some(f => f.note_id) ? [{ id: 'collab', label: t('files.filterCollab') || 'Collab' }] : []),
].map(tab => (
))}
{filteredFiles.length === 1 ? t('files.countSingular') : t('files.count', { count: filteredFiles.length })}
{/* File list */}
{filteredFiles.length === 0 ? (
{t('files.empty')}
{t('files.emptyHint')}
) : (
{filteredFiles.map(file => renderFileRow(file))}
)}
>
)}