ThatAIguyA world of ideas

THE CONSCIOUSNESS ATLAS
Read. Experiment. Follow the evidence.

ConsciousnessLearn · Explore · Joseph Anady

Janady13/missionmatch / frontend/src/screens/OrgSettingsPanels.tsx

Source identity, revision, and recovered contents.

GitHub sourceSource text recovered

Source identity

FieldRecorded value
Source typeGitHub source
Original recordJanady13/missionmatch / frontend/src/screens/OrgSettingsPanels.tsx
DateNot specified in source
RepositoryJanady13/missionmatch
Revision720d47fae476b0d38477ae4401697d372b1ea2bc
Branchfeature/opportunity-to-outcome
Path or archive memberfrontend/src/screens/OrgSettingsPanels.tsx
Original SHA-256926d56758e63b75c314c17d484968b60370fefc05f0ea945251b7a21687c2337
Git blob SHA937d1fef41747f882f623cd256ab75df5a0828c3
Reading-copy SHA-2569cbb97403254434149ba4614be0f01297eb744a88bfa543b130b6367b295d585

Original source ↗

Recovered source transcript

Credential-bearing and unrelated personal details were removed from this reading copy. The source identity and original checksum remain recorded.

import { useState } from 'react' import { AlertTriangle, CheckCircle2, Mail, Send, Trash2, Users2 } from 'lucide-react' import { Link } from 'react-router-dom' import { Panel, Badge } from '../components/ui' import { Empty, Labeled, Note, Select, SettingRow, Toggle, btnGhost, btnPrimary, fieldCls } from '../components/form' import { useOrgSettings, useSaveSettings, useSetMailPassword, useClearMailPassword, useTestMail, } from '../lib/settingsQueries' import { SENSITIVITY_CHOICES, VISIBILITY_CHOICES, SCOPE_CHOICES, type OrgSettings, } from '../lib/settings' // THE ORGANIZATION SETTINGS PANELS. // // Owner only. Every panel is mounted behind a capability check in Settings.tsx, because the server refuses // these for anyone else and offering a control that fails is worse than not offering it. // // THE SETTINGS SAVE ON CHANGE, not behind a Save button. There is no draft to lose and no ambiguity about // whether what is on screen is what is in effect. Mail is the one exception, because its fields are typed // rather than chosen and a half typed host would be saved on every keystroke. // Choices carry a hint the settings vocabulary defines, which the shared Select does not render, so the // selected hint is shown beneath the row instead. That keeps the explanation attached to the ANSWER rather // than hidden inside a list somebody has to open to read. function hintFor<T extends string>(choices: { value: T; hint: string }[], value: T): string { return choices.find((c) => c.value === value)?.hint ?? '' } export function WhoSeesWhatPanel() { const q = useOrgSettings() const save = useSaveSettings() const s = q.data?.settings if (!s) return null const set = (patch: Partial<OrgSettings>) => save.mutate(patch) return ( <Panel title="Who sees what" hint="pay data, contact details, and each other's work"> <p className="pb-1 text-[11px] leading-relaxed text-faint"> These narrow what people see on records they can already open. They never grant more than a person&apos;s role allows, and the server decides, so nothing here can be worked around in a browser. </p> {/* The two rows govern DIFFERENT things and the labels now say which. Rates cover the bill rate, the pay rate and their difference, because anybody holding both can subtract them. The margin setting covers the wrap and everything computed from it, which is the firm's own cost structure and appears nowhere else. Before the wrap existed these were the same disclosure wearing two names. */} <SettingRow label="Bill and pay rates, and the spread" hint={hintFor(SENSITIVITY_CHOICES, s.rate_visibility)} > <Select value={s.rate_visibility} choices={SENSITIVITY_CHOICES} onChange={(v) => set({ rate_visibility: v })} /> </SettingRow> <SettingRow label="Your wrap rate, cost and margin" hint={hintFor(SENSITIVITY_CHOICES, s.margin_visibility)} > <Select value={s.margin_visibility} choices={SENSITIVITY_CHOICES} onChange={(v) => set({ margin_visibility: v })} /> </SettingRow> <SettingRow label="Candidate contact details" hint={hintFor(SENSITIVITY_CHOICES, s.contact_visibility)}> <Select value={s.contact_visibility} choices={SENSITIVITY_CHOICES} onChange={(v) => set({ contact_visibility: v })} /> </SettingRow> <SettingRow label="Seeing who is working a record" hint={hintFor(VISIBILITY_CHOICES, s.work_visibility)}> <Select value={s.work_visibility} choices={VISIBILITY_CHOICES} onChange={(v) => set({ work_visibility: v })} /> </SettingRow> <SettingRow label="Show recent visits" hint="a note that a colleague opened this record recently, which is how two people avoid calling the same candidate on the same day" > <Toggle label="Show recent visits" value={s.show_activity_presence} onChange={(v) => set({ show_activity_presence: v })} /> </SettingRow> <SettingRow label="Ask people to claim before working" hint="a warning, never a block, because a desk has to be able to move on a deadline day" > <Toggle label="Ask people to claim before working" value={s.claim_required} onChange={(v) => set({ claim_required: v })} /> </SettingRow> <p className="pt-2 text-[11px] leading-relaxed text-faint"> Managers and the owner see their team&apos;s activity at every setting. A manager who cannot see a collision is the one person who could have fixed it. </p> </Panel> ) } export function RecordScopePanel() { const q = useOrgSettings() const save = useSaveSettings() const s = q.data?.settings if (!s) return null const narrowed = s.staff_record_scope !== 'organization' return ( <Panel title="Which records people can see" hint="the whole bench, their team's, or their own"> <p className="pb-1 text-[11px] leading-relaxed text-faint"> This decides which records exist for a person at all, in every list, search and report. It is stronger than the settings above, which only hide fields on records somebody can already open. </p> <SettingRow label="Recruiters, members and viewers" hint={hintFor(SCOPE_CHOICES, s.staff_record_scope)}> <Select value={s.staff_record_scope} choices={SCOPE_CHOICES} onChange={(v) => save.mutate({ staff_record_scope: v })} /> </SettingRow> <SettingRow label="Managers" hint={hintFor(SCOPE_CHOICES, s.manager_record_scope)}> {/* A manager cannot be narrowed to their own records. They could not run a desk, and the server rejects it, so the option is absent rather than offered and refused. */} <Select value={s.manager_record_scope} choices={SCOPE_CHOICES.filter((c) => c.value !== 'own')} onChange={(v) => save.mutate({ manager_record_scope: v as 'team' | 'organization' })} /> </SettingRow> <SettingRow label="Records nobody owns" hint="an unowned candidate nobody can see is a candidate nobody will ever work" > <Toggle label="Records nobody owns" value={s.unowned_records_visible} onChange={(v) => save.mutate({ unowned_records_visible: v })} /> </SettingRow> {narrowed && ( <div className="mt-2"> <Note tone="warn"> Scope is narrowed, so people will see fewer records than the bench holds and searches will say so rather than looking empty. Put people on teams under{' '} <Link to="/admin" className="underline"> accounts and access </Link> , or team scope resolves to each person alone. </Note> </div> )} <p className="pt-2 text-[11px] leading-relaxed text-faint"> The owner and administrators always see everything. Somebody has to, and it is the people accountable for the account. </p> </Panel> ) } // MailPanel has a real sequence to it: configure, store a password, prove it works, then switch delivery on. // The server enforces that order, so the panel shows where you are in it rather than presenting four // controls and letting somebody discover the order by failing. export function MailPanel() { const q = useOrgSettings() const save = useSaveSettings() const setPw = useSetMailPassword() const clearPw = useClearMailPassword() const test = useTestMail() const [pw, setPwValue] = useState('') const [draft, setDraft] = useState<Partial<OrgSettings>>({}) const s = q.data?.settings if (!s) return null const canStoreSecret = q.data?.secret_storage_available ?? false const v = <K extends keyof OrgSettings>(k: K): OrgSettings[K] => k in draft ? (draft[k] as OrgSettings[K]) : s[k] const verified = !!s.smtp_verified_at const dirty = Object.keys(draft).length > 0 return ( <Panel title="Sending email" hint="invitations and candidate messages leave from your own address"> <p className="pb-3 text-[11px] leading-relaxed text-faint"> Messages go through your own mail server, so they arrive from your address and pass your own SPF and DKIM rather than a shared sender nobody recognises. Until this is set up, inviting a teammate returns a link for you to send by hand. </p> {!canStoreSecret && ( <div className="mb-3"> <Note tone="warn"> This server cannot store a password yet, so nothing here will save. The organization secret key is not configured. </Note> </div> )} <div className="grid gap-2.5 sm:grid-cols-2"> <Labeled label="Mail server"> <input value={String(v('smtp_host') ?? '')} maxLength={255} placeholder="smtp.yourcompany.com" onChange={(e) => setDraft({ ...draft, smtp_host: e.target.value })} className={fieldCls} /> </Labeled> <Labeled label="Port"> <input type="number" value={Number(v('smtp_port') ?? 587)} onChange={(e) => setDraft({ ...draft, smtp_port: Number(e.target.value) })} className={fieldCls} /> </Labeled> <Labeled label="Sign in name"> <input value={String(v('smtp_username') ?? '')} maxLength={255} onChange={(e) => setDraft({ ...draft, smtp_username: e.target.value })} className={fieldCls} /> </Labeled> <Labeled label="Security"> <select value={String(v('smtp_security'))} onChange={(e) => setDraft({ ...draft, smtp_security: e.target.value as OrgSettings['smtp_security'] })} className={fieldCls} > <option value="starttls" className="bg-navy-900"> STARTTLS, usually port 587 </option> <option value="implicit_tls" className="bg-navy-900"> TLS from the start, usually port 465 </option> </select> </Labeled> <Labeled label="Send from"> <input value={String(v('email_from_address') ?? '')} maxLength={255} placeholder="talent@yourcompany.com" onChange={(e) => setDraft({ ...draft, email_from_address: e.target.value })} className={fieldCls} /> </Labeled> <Labeled label="Sender name"> <input value={String(v('email_from_name') ?? '')} maxLength={120} placeholder="Acme Recruiting" onChange={(e) => setDraft({ ...draft, email_from_name: e.target.value })} className={fieldCls} /> </Labeled> <Labeled label="Replies go to" hint="leave this empty and replies go to the sending address"> <input value={String(v('email_reply_to') ?? '')} maxLength={255} onChange={(e) => setDraft({ ...draft, email_reply_to: e.target.value })} className={fieldCls} /> </Labeled> </div> {dirty && ( <div className="mt-3 space-y-2"> {/* Changing the connection clears the proof that it worked and switches delivery off. Saying so BEFORE the click is the difference between a deliberate step and a surprise. */} {verified && ( <Note tone="warn">Saving these switches sending off until you test the connection again.</Note> )} <div className="flex gap-2"> <button type="button" disabled={save.isPending || !canStoreSecret} onClick={() => save.mutate(draft, { onSuccess: () => setDraft({}) })} className={btnPrimary} > {save.isPending ? 'Saving' : 'Save mail settings'} </button> <button type="button" onClick={() => setDraft({})} className={btnGhost}> Discard </button> </div> </div> )} {save.isError && ( <div className="mt-2"> <Note tone="risk">{(save.error as Error).message}</Note> </div> )} <div className="mt-4 border-t border-line/40 pt-3"> <Labeled label="Mail password" hint="stored encrypted and never shown again, to anybody, including you"> <div className="flex gap-2"> <input type="password" value={pw} maxLength={255} disabled={!canStoreSecret} onChange={(e) => setPwValue(e.target.value)} placeholder={s.smtp_password_set ? 'a password is [credential removed], type to replace it' : 'not set'} className={fieldCls} /> <button type="button" disabled={!pw || setPw.isPending || !canStoreSecret} onClick={() => setPw.mutate(pw, { onSuccess: () => setPwValue('') })} className={btnGhost} > Save </button> {s.smtp_password_set && ( <button type="button" onClick={() => clearPw.mutate()} className={btnGhost}> <Trash2 size={13} /> Remove </button> )} </div> </Labeled> </div> <div className="mt-4 flex flex-wrap items-center gap-3 border-t border-line/40 pt-3"> <button type="button" onClick={() => test.mutate()} disabled={test.isPending || !s.smtp_host || !s.smtp_password_set} className={btnGhost} > <Send size={13} /> {test.isPending ? 'Sending' : 'Send a test to yourself'} </button> {verified ? ( <Badge color="var(--color-ok)" subtle> <CheckCircle2 size={11} /> Verified </Badge> ) : ( <Badge color="var(--color-warn)" subtle> <AlertTriangle size={11} /> Not verified </Badge> )} <div className="ml-auto flex items-center gap-2"> <span className="text-sm font-semibold text-ink">Send invitations and messages</span> <Toggle label="Send invitations and messages" value={s.email_delivery_enabled} disabled={!verified} onChange={(val) => save.mutate({ email_delivery_enabled: val })} /> </div> </div> <div className="mt-2 space-y-2"> {test.isSuccess && ( <Note tone="ok"> <Mail size={11} className="mr-1 inline" /> Sent to {test.data?.to}. If it does not arrive within a few minutes, check the spam folder before changing anything here. </Note> )} {test.isError && <Note tone="risk">{(test.error as Error).message}</Note>} {s.smtp_last_error && !test.isSuccess && !test.isError && ( <Note tone="risk">The last attempt failed: {s.smtp_last_error}</Note> )} {!verified && s.smtp_host && ( <p className="text-[11px] leading-relaxed text-faint"> Sending stays off until a test message actually leaves. That way a typo surfaces here rather than as invitations quietly going nowhere. </p> )} </div> </Panel> ) } // THE WRAP RATE, which is the setting that decides whether this product can report a margin at all. // // Until a firm enters one, every money figure in the product is a SPREAD, bill minus pay, and the screens say // so. That is not a limitation to apologise for, it is the honest position: without knowing what employing // somebody costs, the difference between two rates is all that can be computed, and calling it profit would // be a guess dressed as a number. export function WrapRatePanel() { const q = useOrgSettings() const save = useSaveSettings() const [draft, setDraft] = useState<string | null>(null) const s = q.data?.settings if (!s) return null const stored = s.default_burden_pct ?? '' const shown = draft ?? stored const dirty = draft !== null && draft !== stored // Entered as a fraction and echoed as a percentage, because a firm says "our wrap is thirty five percent" // and stores 0.35. Showing both removes the one ambiguity that would otherwise be entered wrong. const asPercent = (() => { const n = Number(shown) if (!shown || Number.isNaN(n)) return '' return `${(n * 100).toFixed(2).replace(/\.?0+$/, '')} percent` })() return ( <Panel title="Your wrap rate" hint="what employing somebody costs on top of their pay"> <p className="pb-2 text-[11px] leading-relaxed text-faint"> Payroll taxes, workers compensation, unemployment insurance, health cover, paid leave, retirement, general and administrative, and overhead. Enter it as a fraction, so a 35 percent wrap is 0.35. </p> <div className="flex flex-wrap items-end gap-2"> <Labeled label="Standard wrap" hint={asPercent}> <input value={shown} maxLength={12} inputMode="decimal" placeholder="0.35" onChange={(e) => setDraft(e.target.value)} className={`${fieldCls} max-w-[10rem]`} /> </Labeled> {dirty && ( <button type="button" disabled={save.isPending} onClick={() => save.mutate( // An emptied box CLEARS the wrap, sent as an explicit null. Omitting the field would mean // leave it alone, and an owner who deleted the number would watch nothing happen. { default_burden_pct: shown.trim() === '' ? null : shown.trim() }, { onSuccess: () => setDraft(null) }, ) } className={btnPrimary} > {save.isPending ? 'Saving' : 'Save the wrap'} </button> )} {dirty && ( <button type="button" className={btnGhost} onClick={() => setDraft(null)}> Discard </button> )} </div> {save.isError && ( <div className="mt-2"> <Note tone="risk">{(save.error as Error).message}</Note> </div> )} <div className="mt-3"> {stored === '' ? ( <Note tone="warn"> No wrap is set, so the product reports SPREADS and no margins. A spread is bill minus pay before any employment cost, and on typical numbers it is close to three times the money actually kept. Nothing here is guessed on your behalf. </Note> ) : ( <Note tone="muted"> Margins are reported using this wrap unless a placement carries its own. It is one figure for the whole firm, which is right for most lines; a client contract or a labour category with a different wrap is set on the record itself. </Note> )} </div> </Panel> ) } // THE AUTOMATED DECISION RULE, which is the one setting on this screen with a legal deadline attached. export function AedtNoticePanel() { const q = useOrgSettings() const save = useSaveSettings() const s = q.data?.settings if (!s) return null return ( <Panel title="Automated decision notices" hint="telling candidates before a tool assesses them"> <p className="pb-2 text-[11px] leading-relaxed text-faint"> This product scores people with an automated employment decision tool. New York City requires the person to be told at least ten business days beforehand and to be told what is assessed. The EU treats hiring as high risk from August 2026. Illinois and Colorado have their own rules. The common shape is the same everywhere: tell them first, and be able to prove you did. </p> <SettingRow label="Refuse to score anybody with no notice on file" hint="a recruiter is told exactly what is missing and can record it in a click on the candidate record" > <Toggle label="Refuse to score anybody with no notice on file" value={s.aedt_notice_required} onChange={(v) => save.mutate({ aedt_notice_required: v })} /> </SettingRow> {!s.aedt_notice_required && ( <div className="mt-2"> <Note tone="warn"> This is off, so people can be scored with no notice recorded. It ships off on purpose: switching it on before your notices are in place would refuse your whole bench. Recording a notice works either way, on every candidate record. </Note> </div> )} <p className="pt-2 text-[11px] leading-relaxed text-faint"> missionMATCH never sends the notice for you. Delivering it is yours; what this holds is the evidence that you did, per candidate, with the date and what they were told. </p> </Panel> ) } export function InviteDefaultsPanel() { const q = useOrgSettings() const save = useSaveSettings() const s = q.data?.settings if (!s) return null const HOURS = [ { value: '24', label: '1 day' }, { value: '72', label: '3 days' }, { value: '168', label: '7 days' }, { value: '336', label: '14 days' }, ] const CLAIM_HOURS = [ { value: '8', label: '8 hours' }, { value: '24', label: '1 day' }, { value: '72', label: '3 days' }, { value: '168', label: '7 days' }, ] const ROLES = [ { value: 'viewer', label: 'Viewer' }, { value: 'member', label: 'Member' }, { value: 'recruiter', label: 'Recruiter' }, { value: 'manager', label: 'Manager' }, { value: 'admin', label: 'Administrator' }, ] return ( <Panel title="Defaults" hint="the small settings that only matter on the day they are wrong"> <SettingRow label="Invitation link lifetime" hint="an unused invitation stops working after this"> <Select value={String(s.invite_expiry_hours)} choices={HOURS} onChange={(v) => save.mutate({ invite_expiry_hours: Number(v) })} /> </SettingRow> <SettingRow label="Suggested role for a new person" hint="a starting point only, because nobody can invite somebody at or above their own level" > <Select value={s.default_invite_role} choices={ROLES} onChange={(v) => save.mutate({ default_invite_role: v })} /> </SettingRow> <SettingRow label="How long a claim lasts" hint="a claim nobody releases would hold a candidate forever, so it lapses on its own" > <Select value={String(s.claim_expiry_hours)} choices={CLAIM_HOURS} onChange={(v) => save.mutate({ claim_expiry_hours: Number(v) })} /> </SettingRow> <p className="flex items-center gap-1.5 pt-2 text-[11px] text-faint"> <Users2 size={12} /> Teams are managed under accounts and access, because who is on a desk is what decides team scope. </p> </Panel> ) } // SettingsLoadFailure is what an owner sees when the settings cannot be read at all. It is separate from the // panels because a failed read must not render four panels of defaults that look like real settings. export function SettingsLoadFailure() { const q = useOrgSettings() if (!q.isError) return null return ( <Panel title="Organization settings"> <Empty title="The organization settings could not be read" reason={(q.error as Error)?.message || 'The server did not answer. Nothing has been changed.'} action={ <button type="button" onClick={() => void q.refetch()} className={btnGhost}> Try again </button> } /> </Panel> ) }

Search equations, builds, manuscript text, and recovered sources.