// Primus IQ — Library Screen
const LIB_FILES = [
{ name: 'Public Policy Whitepaper 2026.pdf', ext: 'pdf', size: '6.2 MB', modified: '12 May 2026', conf: 'public', practice: 'Public Policy Realization' },
{ name: 'GCC Fintech Sector Map.png', ext: 'png', size: '2.1 MB', modified: '10 May 2026', conf: 'internal', practice: 'Sector Potential Realization' },
{ name: 'Sector Outlook · KSA.pptx', ext: 'pptx', size: '14.8 MB', modified: '08 May 2026', conf: 'internal', practice: 'Sector Potential Realization' },
{ name: 'TCFD Compliance Matrix.xlsx', ext: 'xlsx', size: '3.4 MB', modified: '04 May 2026', conf: 'public', practice: 'Economic Potential Realization' },
{ name: 'Renewables Capex 2026.pdf', ext: 'pdf', size: '4.8 MB', modified: '30 Apr 2026', conf: 'public', practice: 'Economic Potential Realization' },
{ name: 'CFO interview transcript.docx', ext: 'docx', size: '180 KB', modified: '22 Apr 2026', conf: 'client', practice: 'Sector Potential Realization' },
{ name: 'Cost build · Phase 1.xlsx', ext: 'xlsx', size: '2.4 MB', modified: '18 Apr 2026', conf: 'client', practice: 'Transaction Realization' },
];
const adaptLibraryFile = (f) => {
const ext = (f.file_name || '').split('.').pop().toLowerCase() || 'doc';
const bytes = f.file_size || 0;
const size = bytes < 1024 ? `${bytes} B` : bytes < 1048576 ? `${(bytes / 1024).toFixed(1)} KB` : `${(bytes / 1048576).toFixed(1)} MB`;
return {
id: f.id,
name: f.file_name || f.name || '',
ext,
size: size || '',
modified: f.uploaded_at ? new Date(f.uploaded_at).toLocaleDateString('en-IN', { day: 'numeric', month: 'short', year: 'numeric' }) : '—',
conf: f.confidentiality || 'internal',
tags: f.tags || [],
practice: (f.tags && f.tags.length > 0) ? f.tags[0] : '',
status: f.status || 'uploading',
};
};
const ScreenLibrary = ({ openAddSources, libraryFiles, onDeleteFile, onDownloadFile, onEditFile }) => {
const [filter, setFilter] = React.useState('all');
const [q, setQ] = React.useState('');
// Instant client-side filter — the library list is already loaded, so no network round-trip.
const sourceFiles = (libraryFiles && libraryFiles.length > 0) ? libraryFiles.map(adaptLibraryFile) : [];
const ql = q.trim().toLowerCase();
const filtered = sourceFiles.filter(f =>
(filter === 'all'
|| (filter === 'images' && (f.ext === 'png' || f.ext === 'jpg'))
|| (filter === 'docs' && (f.ext === 'pdf' || f.ext === 'docx'))
|| (filter === 'sheets' && f.ext === 'xlsx')
|| (filter === 'decks' && f.ext === 'pptx')
) && (!ql || f.name.toLowerCase().includes(ql))
);
return (
Library
Firm-wide knowledge base — searchable across every chat.
{[
{ id: 'all', l: 'All', n: sourceFiles.length },
{ id: 'docs', l: 'Docs', n: sourceFiles.filter(f => f.ext === 'pdf' || f.ext === 'docx').length },
{ id: 'decks', l: 'Decks', n: sourceFiles.filter(f => f.ext === 'pptx').length },
{ id: 'sheets', l: 'Sheets', n: sourceFiles.filter(f => f.ext === 'xlsx').length },
{ id: 'images', l: 'Images', n: sourceFiles.filter(f => f.ext === 'png' || f.ext === 'jpg').length },
].map(t => (
))}
{sourceFiles.length === 0 && !q && (
No files in the library yet.{' '}
)}
{sourceFiles.length > 0 && (
{/* Column headers - sticky so they stay aligned with rows under the scrollbar */}
Name
Confidentiality
Status
Modified
{filtered.length === 0 && (
No files match your filter.
)}
{filtered.map((f, i) => (
onDownloadFile(f.id) : null}
onDelete={onDeleteFile ? () => onDeleteFile(f.id) : null}
onEdit={onEditFile ? () => onEditFile(f) : null}
/>
))}
)}
);
};
const LibraryFileRow = ({ f, isLast, onDownload, onDelete, onEdit }) => {
const [menuOpen, setMenuOpen] = React.useState(false);
const menuRef = React.useRef(null);
React.useEffect(() => {
if (!menuOpen) return;
const handler = (e) => { if (menuRef.current && !menuRef.current.contains(e.target)) setMenuOpen(false); };
document.addEventListener('mousedown', handler);
return () => document.removeEventListener('mousedown', handler);
}, [menuOpen]);
return (
e.currentTarget.style.background = 'var(--bg-soft)'}
onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
>
{CONF_LABELS[f.conf] || f.conf}
{
f.status === 'complete'
? 'File Saved'
: f.status === 'failed'
? 'Save Failed'
: f.status
}
{f.modified}
{menuOpen && (
{onDownload && (
)}
{onEdit && (
)}
{onDelete && (
)}
)}
);
};
Object.assign(window, {
LIB_FILES,
adaptLibraryFile,
ScreenLibrary,
LibraryFileRow,
});