// Primus IQ — Profile Screen const ProfileTagList = ({ items, editing, onChange, placeholder }) => { const [input, setInput] = React.useState(''); const add = () => { const v = input.trim(); if (v && !items.includes(v)) onChange([...items, v]); setInput(''); }; if (!editing) return (
{items.length === 0 ? : items.map(item => ( {item} ))}
); return (
{items.map(item => ( {item} ))}
setInput(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') { e.preventDefault(); add(); } }} placeholder={placeholder} style={{ flex: 1, height: 34, padding: '0 12px', borderRadius: 8, border: '1px solid var(--line-2)', background: 'var(--bg-card)', fontSize: 13, fontFamily: 'inherit', color: 'var(--ink)' }} />
); }; const ProfileInfoCard = ({ title, children }) => (
{title}
{children}
); const ProfileInfoField = ({ label, children }) => (
{label}
{children}
); const ProfileTab = ({ active, onClick, children }) => ( ); const ScreenProfile = ({ currentUser, onBack }) => { const [profile, setProfile] = React.useState(null); const [editing, setEditing] = React.useState(false); const [saving, setSaving] = React.useState(false); const [fullName, setFullName] = React.useState(''); const [yoe, setYoe] = React.useState(''); const [primaryDomain, setPrimaryDomain] = React.useState(''); const [secondaryDomain, setSecondaryDomain] = React.useState(''); const [skills, setSkills] = React.useState([]); const [tools, setTools] = React.useState([]); const [methodologies, setMethodologies] = React.useState([]); const [industries, setIndustries] = React.useState([]); const [regions, setRegions] = React.useState([]); const [languages, setLanguages] = React.useState([]); React.useEffect(() => { PrimusAPI.getMe().then(data => { setProfile(data); setFullName(data.full_name || ''); setYoe(String(data.yoe ?? '')); setPrimaryDomain(data.primary_domain || ''); setSecondaryDomain(data.secondary_domain || ''); setSkills(data.skills || []); setTools(data.tools || []); setMethodologies(data.methodologies || []); setIndustries(data.industries || []); setRegions(data.regions || []); setLanguages(data.languages || []); }).catch(() => {}); }, []); const handleSave = async () => { setSaving(true); try { const updated = await PrimusAPI.updateMe({ full_name: fullName, yoe: parseInt(yoe) || 0, primary_domain: primaryDomain, secondary_domain: secondaryDomain, skills, tools, methodologies, industries, regions, languages, }); setProfile(updated); setEditing(false); } catch (ex) { console.error('Save profile failed:', ex); } finally { setSaving(false); } }; const cancelEdit = () => { if (!profile) return; setFullName(profile.full_name || ''); setYoe(String(profile.yoe ?? '')); setPrimaryDomain(profile.primary_domain || ''); setSecondaryDomain(profile.secondary_domain || ''); setSkills(profile.skills || []); setTools(profile.tools || []); setMethodologies(profile.methodologies || []); setIndustries(profile.industries || []); setRegions(profile.regions || []); setLanguages(profile.languages || []); setEditing(false); }; if (!profile) return (
Loading profile…
); const initials = profile.full_name ? profile.full_name.split(' ').filter(Boolean).map(w => w[0].toUpperCase()).slice(0, 2).join('') : '?'; const designation = profile.designation ? profile.designation.split(/[\s_]/).map(w => w[0].toUpperCase() + w.slice(1)).join(' ') : ''; const textInput = (value, setValue, placeholder = '') => ({ value, onChange: e => setValue(e.target.value), placeholder, style: { width: '100%', height: 36, padding: '0 12px', borderRadius: 8, border: '1px solid var(--line-2)', background: 'var(--bg-card)', fontSize: 13, fontFamily: 'inherit', color: 'var(--ink)', }, }); return (
{/* Header */}
{initials}
{editing ? :

{profile.full_name}

}
{designation} · {profile.primus_email} {profile.tier}
{editing ? ( <> ) : ( )}
{/* Info grid */}
{profile.emp_code || '—'} {editing ? setYoe(e.target.value)} style={{ width: 100, height: 34, padding: '0 10px', borderRadius: 8, border: '1px solid var(--line-2)', background: 'var(--bg-card)', fontSize: 13, fontFamily: 'inherit' }}/> : {profile.yoe ?? '—'} yrs } {profile.tier || '—'} {editing ? : {profile.primary_domain || '—'} } {editing ? : {profile.secondary_domain || '—'} }
); }; // ── Personalize Intelligence — its own module (opened from the sidebar) ────── const ScreenPersonalize = ({ onBack }) => { const [prefs, setPrefs] = React.useState(''); const [prefsSet, setPrefsSet] = React.useState(false); const [prefsLoading, setPrefsLoading] = React.useState(true); const [prefsSaving, setPrefsSaving] = React.useState(false); const [prefsMsg, setPrefsMsg] = React.useState(null); // Writing Style — five friendly fields the API composes into a SKILL.md the // report agent applies when drafting reports. const WS_FIELDS = [ ['tone', 'Tone', 'e.g. Crisp and executive; confident, not salesy.'], ['structure', 'Structure', 'e.g. Lead with an executive summary, then detail.'], ['formatting', 'Formatting', 'e.g. Bullets for findings; tables for data.'], ['vocabulary', 'Vocabulary', 'e.g. Plain English; spell out acronyms once.'], ['avoid', 'Avoid', 'e.g. Hedging, filler, generic background.'], ]; const [ws, setWs] = React.useState({ tone: '', structure: '', formatting: '', vocabulary: '', avoid: '' }); const [wsLoading, setWsLoading] = React.useState(true); const [wsSaving, setWsSaving] = React.useState(false); const [wsMsg, setWsMsg] = React.useState(null); const [tab, setTab] = React.useState('instructions'); React.useEffect(() => { PrimusAPI.getPreferences() .then(data => { setPrefs(data.content || ''); setPrefsSet(!!data.is_set); }) .catch(() => {}) .finally(() => setPrefsLoading(false)); }, []); React.useEffect(() => { PrimusAPI.getWritingStyle() .then(data => { if (data && data.fields) setWs(data.fields); }) .catch(() => {}) .finally(() => setWsLoading(false)); }, []); const handleSavePrefs = async () => { setPrefsSaving(true); setPrefsMsg(null); try { const updated = await PrimusAPI.updatePreferences(prefs); setPrefs(updated.content || ''); setPrefsSet(true); setPrefsMsg({ type: 'ok', text: 'Instructions saved.' }); setTimeout(() => setPrefsMsg(null), 2500); } catch (ex) { setPrefsMsg({ type: 'error', text: ex.message || 'Could not save your instructions.' }); } finally { setPrefsSaving(false); } }; const handleSaveWs = async () => { setWsSaving(true); setWsMsg(null); try { const updated = await PrimusAPI.updateWritingStyle(ws); if (updated && updated.fields) setWs(updated.fields); setWsMsg({ type: 'ok', text: 'Writing style saved.' }); setTimeout(() => setWsMsg(null), 2500); } catch (ex) { setWsMsg({ type: 'error', text: ex.message || 'Could not save your writing style.' }); } finally { setWsSaving(false); } }; return (

Personalize Intelligence

Tell Primus IQ how you want it to work.
{[['instructions', 'Custom Instructions'], ['style', 'Writing Style']].map(([key, label]) => ( ))}
{tab === 'instructions' && (
Custom instructions
{prefsMsg && ( {prefsMsg.type === 'ok' ? '✓ ' : '⚠ '}{prefsMsg.text} )}
{!prefsSet && !prefsLoading && (
This is a starter template — edit it to fit how you work, then Save.
)}