// Primus IQ — SharePoint Picker Modal const spFmtSize = (bytes) => { const b = bytes || 0; return b < 1024 ? `${b} B` : b < 1048576 ? `${(b / 1024).toFixed(1)} KB` : `${(b / 1048576).toFixed(1)} MB`; }; const SharePointPickerModal = ({ open, onClose, onConfirm }) => { const [tab, setTab] = React.useState('onedrive'); // 'onedrive' | 'sharepoint' const [siteQuery, setSiteQuery] = React.useState(''); const [sites, setSites] = React.useState([]); const [selectedSite, setSelectedSite] = React.useState(null); const [drives, setDrives] = React.useState([]); const [drive, setDrive] = React.useState(null); // active drive being browsed const [path, setPath] = React.useState([]); // breadcrumb: [{id, name}] const [items, setItems] = React.useState([]); const [selected, setSelected] = React.useState({}); // itemId -> {drive_id, item_id, name, size} const [loading, setLoading] = React.useState(false); const [error, setError] = React.useState(''); const fail = (ex) => { setError(ex && ex.message ? ex.message : 'Something went wrong'); setLoading(false); }; // ── OneDrive: open the user's drive directly ── const openOneDrive = async () => { setTab('onedrive'); setSelectedSite(null); setDrives([]); setSites([]); setSiteQuery(''); setError(''); setLoading(true); try { const d = await PrimusAPI.spOneDrive(); setDrive(d); setPath([{ id: null, name: d.name || 'OneDrive' }]); const its = await PrimusAPI.spListItems(d.id, null); setItems(its || []); setLoading(false); } catch (ex) { fail(ex); } }; // ── SharePoint: switch tab and auto-load accessible sites ── const switchToSharePoint = async () => { setTab('sharepoint'); setDrive(null); setSelectedSite(null); setDrives([]); setPath([]); setItems([]); setError(''); setSites([]); setLoading(true); try { const res = await PrimusAPI.spSearchSites(siteQuery); setSites(res || []); setLoading(false); } catch (ex) { fail(ex); } }; // ── SharePoint: refine site search ── const runSiteSearch = async () => { setLoading(true); setError(''); try { const res = await PrimusAPI.spSearchSites(siteQuery); setSites(res || []); setLoading(false); } catch (ex) { fail(ex); } }; // Auto-load OneDrive when modal opens. Reset selection + breadcrumb so a fresh open // never carries over the previously imported file's selection. React.useEffect(() => { if (open) { setSelected({}); setPath([]); openOneDrive(); } }, [open]); const pickSite = async (site) => { setSelectedSite(site); setDrive(null); setPath([]); setItems([]); setError(''); setLoading(true); try { const ds = await PrimusAPI.spListDrives(site.id); setDrives(ds || []); setLoading(false); } catch (ex) { fail(ex); } }; const pickDrive = async (d) => { setDrive(d); setPath([{ id: null, name: d.name }]); setError(''); setLoading(true); try { const its = await PrimusAPI.spListItems(d.id, null); setItems(its || []); setLoading(false); } catch (ex) { fail(ex); } }; const openFolder = async (folder) => { setError(''); setLoading(true); try { const its = await PrimusAPI.spListItems(drive.id, folder.id); setPath(prev => [...prev, { id: folder.id, name: folder.name }]); setItems(its || []); setLoading(false); } catch (ex) { fail(ex); } }; const goToCrumb = async (idx) => { const crumb = path[idx]; setError(''); setLoading(true); try { const its = await PrimusAPI.spListItems(drive.id, crumb.id); setPath(prev => prev.slice(0, idx + 1)); setItems(its || []); setLoading(false); } catch (ex) { fail(ex); } }; const toggleFile = (item) => { setSelected(prev => { const next = { ...prev }; if (next[item.id]) delete next[item.id]; else next[item.id] = { drive_id: drive.id, item_id: item.id, name: item.name, size: item.size }; return next; }); }; const selectedList = Object.values(selected); const confirm = () => { if (selectedList.length === 0) return; onConfirm(selectedList); }; if (!open) return null; const showBrowser = !!drive; const showSiteList = tab === 'sharepoint' && !selectedSite; const showDriveList = tab === 'sharepoint' && selectedSite && !drive; return (
e.stopPropagation()} style={{ width: 920, maxWidth: '94%', height: 620, maxHeight: '92%', background: 'var(--bg-card)', borderRadius: 18, boxShadow: '0 30px 80px rgba(26,22,20,0.30), 0 0 0 1px var(--line)', animation: 'rise 0.22s ease-out', display: 'flex', flexDirection: 'column', overflow: 'hidden', }}> {/* Header */}

Add from Microsoft 365

Browse your OneDrive or SharePoint and pick files to import.
{/* Source tabs */}
{/* Body */}
{/* Site search */} {showSiteList && (
setSiteQuery(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') runSiteSearch(); }} placeholder="Search SharePoint sites by name…" style={{ flex: 1, height: 38, padding: '0 12px', borderRadius: 9, border: '1px solid var(--line-2)', fontSize: 13, fontFamily: 'inherit', outline: 'none', color: 'var(--ink)', background: 'white', }} />
)} {/* Breadcrumbs when browsing */} {showBrowser && (
{selectedSite && ( <> / )} {path.map((c, i) => ( {i > 0 && /} ))}
)} {error && (
{error}
)} {/* List area */}
{loading &&
Loading…
} {/* Site results */} {!loading && showSiteList && sites.length === 0 &&
No accessible SharePoint sites found.
} {!loading && showSiteList && sites.map(s => (
pickSite(s)} style={spRow}>
{s.display_name}
{s.web_url &&
{s.web_url}
}
))} {/* Drive (library) list */} {!loading && showDriveList && drives.length === 0 &&
No document libraries on this site.
} {!loading && showDriveList && drives.map(d => (
pickDrive(d)} style={spRow}>
{d.name}
))} {/* File / folder browser */} {!loading && showBrowser && items.length === 0 &&
This folder is empty.
} {!loading && showBrowser && items.map(it => { const checked = !!selected[it.id]; if (it.is_folder) { return (
openFolder(it)} style={spRow}>
{it.name}
); } return (
toggleFile(it)} style={{ ...spRow, background: checked ? 'var(--maroon-06)' : 'transparent' }}>
{checked && }
{it.name}
{spFmtSize(it.size)}
); })}
{/* Footer */}
{selectedList.length > 0 ? `${selectedList.length} file${selectedList.length > 1 ? 's' : ''} selected` : 'No files selected'}
); }; const SpIcon = ({ kind }) => { const color = kind === 'site' ? 'var(--maroon)' : kind === 'library' ? 'var(--gold)' : kind === 'folder' ? 'var(--gold)' : 'var(--mute)'; const paths = { site: , library: , folder: , file: , }; return {paths[kind]}; }; const spTabStyle = (active) => ({ height: 34, padding: '0 16px', borderRadius: '9px 9px 0 0', cursor: 'pointer', fontFamily: 'inherit', fontSize: 13, fontWeight: 600, border: '1px solid var(--line)', borderBottom: active ? '1px solid var(--bg-card)' : '1px solid var(--line)', background: active ? 'var(--bg-card)' : 'var(--bg-soft)', color: active ? 'var(--maroon)' : 'var(--mute)', position: 'relative', top: 1, }); const spRow = { display: 'flex', alignItems: 'center', gap: 12, padding: '11px 14px', borderBottom: '1px solid var(--line)', cursor: 'pointer', }; const spName = { fontSize: 13, fontWeight: 600, color: 'var(--ink)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }; const spSub = { fontSize: 11, color: 'var(--mute)', marginTop: 2, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }; const spCrumbBtn = { background: 'none', border: 'none', cursor: 'pointer', fontFamily: 'inherit', fontSize: 13, color: 'var(--maroon)', padding: 0 }; const spEmpty = { padding: '48px 20px', textAlign: 'center', color: 'var(--mute)', fontSize: 13 }; Object.assign(window, { SharePointPickerModal, SpIcon, });