75 lines
3.0 KiB
JavaScript
75 lines
3.0 KiB
JavaScript
/**
|
|
* 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 }
|
|
}
|