/** * The delivered copy: what a candidate becomes once it is on screen, plus the * two diagnoses the settings page prints about past deliveries. * * @module @dsh-plugin/session-notify/client/core/copy */ /** * Build the copy table for one translate function. * @param t - the translate function every string here goes through. * @returns `copyFor` (candidate โ†’ notice), `deliveryFacts` and `replayValue` * (the two status values the settings page shows). */ export function createCopy(t) { /** Build the delivered copy for one candidate. */ const copyFor = (candidate) => { const title = candidate.title === '' ? t('body.untitled') : candidate.title if (candidate.kind === 'completion') { // The heading already says what happened ("conversation finished"), so the // description is the conversation itself โ€” naming it twice would only make // the card longer. return { kind: 'completion', title: t('notification.completion'), body: title } } // A plan review arrives as a question with its own discriminator, so it is // answered before the question branch below โ€” a plan review says what it is, // rather than repeating the plan text the user has not read yet. if (candidate.pendingKind === 'plan-review') { return { kind: 'question', title: t('notification.question'), body: t('body.planReview', { title }) } } if (candidate.kind === 'question') { const question = candidate.detail return { kind: 'question', title: t('notification.question'), body: question === '' ? t('body.question', { title }) : `${title} ยท ${question}`, } } const tool = candidate.detail return { kind: 'approval', title: t('notification.approval'), body: tool === '' ? t('body.approvalPlain', { title }) : t('body.approval', { title, tool }), } } /** * Split the newest delivery into the three facts the status list shows. * @param last - `store.lastDelivery`. * @param tr - the translate function the outcome label is rendered with. * @returns `{ at, outcome, title }`, or null when nothing was ever delivered. */ const deliveryFacts = (last, tr) => { if (last === null || last === undefined) return null const outcome = last.outcome.startsWith('system-refused') ? tr('config.diag.refused') : last.outcome === 'system' ? last.shown === true ? tr('config.diag.systemShown') : last.shown === false ? tr('config.diag.systemFailed') : tr('config.diag.systemUnconfirmed') : last.outcome === 'replay' ? tr('config.diag.replayDelivery') : tr('config.diag.popup') return { at: last.at, outcome, title: last.title ?? '' } } /** How many away-channel alerts are still waiting for the user to come back. */ const replayValue = (count, tr) => ( count === 0 ? tr('config.diag.replayNone') : tr('config.diag.replayValue', { count }) ) return { copyFor, deliveryFacts, replayValue } }