feat: harden support, localize knowledge and add operator availability [skip ci]

Source-only publication of reviewed commit 64e96a7f423673dc29ad56485be9fc79bce8af1c.

Passed in isolation: focused frontend/backend tests, race checks, TypeScript typecheck, lint, Go compilation, Flowgram build, and deterministic SDK build/tests.

Not accepted as a production release: Next.js export/native assembly remains blocked by environment memory limits; browser interaction and MySQL staging acceptance remain unverified. No production server, database/schema, runtime configuration, deployment, release tag, or workflow execution was performed.

Expected source tree: 0a4a7528e9.
This commit is contained in:
2026-10-16 15:21:42 +00:00
parent 299ea50fb5
commit 2f7a491666
176 changed files with 11869 additions and 2716 deletions

View File

@@ -0,0 +1,112 @@
import assert from "node:assert/strict"
import { readFile } from "node:fs/promises"
import test from "node:test"
import vm from "node:vm"
import ts from "typescript"
async function compile(path, imports) {
const source = await readFile(new URL(path, import.meta.url), "utf8")
const compiled = ts.transpileModule(source, { compilerOptions: { target: ts.ScriptTarget.ES2020, module: ts.ModuleKind.CommonJS, jsx: ts.JsxEmit.ReactJSX } })
const loaded = { exports: {} }
vm.runInNewContext(compiled.outputText, { exports: loaded.exports, module: loaded, Intl, Date, Set, AbortController, setTimeout, clearTimeout, require: name => { assert.ok(name in imports, `unexpected import ${name}`); return imports[name] } })
return loaded.exports
}
const helpers = await compile("../../lib/support-availability.ts", {})
const enums = await compile("../../lib/generated/enums.ts", {})
const mappings = await compile("../../lib/support-availability-i18n.ts", { "@/lib/generated/enums": enums })
const guard = await compile("../../lib/session-request-guard.ts", {})
const sessionA = { user: { id: 1 }, accessToken: "fixture-a" }
const sessionB = { user: { id: 2 }, accessToken: "fixture-b" }
const calendar = { teamId: 5, mode: "recurring", timezone: "UTC", effectiveTimezone: "UTC", deploymentTimezone: "UTC", weekly: [], exceptions: [] }
const operator = { userId: 1, serviceStatus: 1, effectiveServiceStatus: 1, returnServiceStatus: 0, reason: "busy", online: true, calendar }
function deferred() { let resolve; const promise = new Promise(r => { resolve = r }); return { promise, resolve } }
function find(node, predicate) {
if (!node || typeof node !== "object") return null
if (predicate(node)) return node
for (const value of Object.values(node.props ?? {})) {
for (const child of Array.isArray(value) ? value.flat(Infinity) : [value]) {
const found = find(child, predicate)
if (found) return found
}
}
return null
}
async function harness(kind, options = {}) {
let session = sessionA, stateIndex = 0
const effects = [], calls = [], saved = []
const apiResult = options.apiResult ?? Promise.resolve(operator)
const formValues = options.formValues ?? { serviceStatus: "1", start: "", end: "", startOccurrence: "", endOccurrence: "" }
const jsx = (type, props, key) => ({ type, props, key })
const controls = new Proxy({}, { get: (_target, name) => name })
const imports = {
"react/jsx-runtime": { jsx, jsxs: jsx, Fragment: "Fragment" },
react: { useRef: value => ({ current: value }), useState: value => { const current = stateIndex++; return [current === 0 && options.editing ? true : typeof value === "function" ? value() : value, () => {}] }, useEffect: fn => { effects.push(fn) }, useCallback: fn => fn },
"react-hook-form": { Controller: "Controller", useFieldArray: () => ({ fields: [] }), useForm: () => ({ control: {}, register: () => ({}), handleSubmit: fn => fn, watch: key => key ? formValues[key] : calendar, setError: () => {}, clearErrors: () => {}, reset: () => {}, formState: { errors: {}, isDirty: true } }) },
"lucide-react": controls, "next/link": { default: "Link" }, sonner: { toast: { success: () => {} } },
"@/components/auth-provider": { useAuth: () => ({ session }) },
"@/components/confirm-provider": { useConfirm: () => options.confirm ?? (async () => true) },
"@/components/option-combobox": controls, "@/components/project-dialog": controls,
"@/components/ui/badge": controls, "@/components/ui/button": controls, "@/components/ui/field": controls, "@/components/ui/input": controls, "@/components/ui/switch": controls,
"@/i18n/provider": { useI18n: () => key => key, useAppLocale: () => ({ locale: "en-US" }) },
"@/lib/auth": { readSession: () => session }, "@/lib/session-request-guard": guard,
"@/lib/generated/enums": enums, "@/lib/support-availability-i18n": mappings, "@/lib/support-availability": helpers,
"@/components/support-availability/operator-status": { notifyAvailabilityUpdated: () => {} },
"@/lib/api/support-availability": { updateMyAvailability: payload => { calls.push(payload); return apiResult }, updateAgentAvailability: (id, payload) => { calls.push({ id, payload }); return apiResult }, updateSupportCalendar: payload => { calls.push(payload); return options.apiResult ?? Promise.resolve(calendar) } },
}
const file = kind === "operator" ? "./operator-status.tsx" : "../../app/(dashboard)/dashboard/support-availability/_components/calendar-editor.tsx"
const loaded = await compile(file, imports)
const root = kind === "operator" ? loaded.OperatorStatusDialog({ value: operator, onClose() {}, onSaved: value => saved.push(value) }) : loaded.CalendarEditor({ initial: calendar, writable: options.writable ?? true, onDirtyChange() {}, onSaved: value => saved.push(value) })
// Execute only lifetime effects: calendar also registers browser navigation listeners.
const lifetime = effects.filter(fn => fn.toString().includes("mounted.current = true"))
assert.equal(lifetime.length, 1)
const setup = () => lifetime[0]()
const submit = find(root, node => node.type === "form").props.onSubmit
return { calls, saved, setup, submit: () => submit(kind === "operator" ? formValues : calendar), switchSession: () => { session = sessionB } }
}
test("operator save still completes after StrictMode setup-cleanup-setup", async () => {
const h = await harness("operator")
h.setup()(); h.setup()
await h.submit()
assert.equal(h.calls.length, 1)
assert.equal(h.saved.length, 1)
})
test("operator save is single-flight and a late prior-session result is ignored", async () => {
const pending = deferred()
const h = await harness("operator", { apiResult: pending.promise })
h.setup()
const first = h.submit(), second = h.submit()
h.switchSession(); pending.resolve(operator)
await Promise.all([first, second])
assert.equal(h.calls.length, 1)
assert.equal(h.saved.length, 0)
})
test("operator controls from a stale session cannot submit a mutation", async () => {
const h = await harness("operator")
h.setup(); h.switchSession(); await h.submit()
assert.equal(h.calls.length, 0)
})
test("read-only calendar or preview Enter cannot save even when form appears dirty", async () => {
for (const writable of [false, true]) {
const h = await harness("calendar", { writable })
h.setup(); await h.submit()
assert.equal(h.calls.length, 0)
}
})
test("calendar confirmation cannot cross session or unmount boundaries", async () => {
for (const action of ["session", "unmount"]) {
const approval = deferred()
const h = await harness("calendar", { editing: true, confirm: () => approval.promise })
const cleanup = h.setup()
const submit = h.submit()
if (action === "session") h.switchSession(); else cleanup()
approval.resolve(true); await submit
assert.equal(h.calls.length, 0)
}
})
test("calendar save completes after StrictMode restart and explicit confirmation", async () => {
const h = await harness("calendar", { editing: true })
h.setup()(); h.setup(); await h.submit()
assert.equal(h.calls.length, 1)
assert.equal(h.saved.length, 1)
})

View File

@@ -0,0 +1,132 @@
"use client"
import { Clock3Icon, Loader2Icon, RefreshCwIcon } from "lucide-react"
import { useEffect, useRef, useState } from "react"
import { Controller, useForm } from "react-hook-form"
import { toast } from "sonner"
import { useAuth } from "@/components/auth-provider"
import { useConfirm } from "@/components/confirm-provider"
import { OptionCombobox } from "@/components/option-combobox"
import { ProjectDialog } from "@/components/project-dialog"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Field, FieldError, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
import { useAppLocale, useI18n } from "@/i18n/provider"
import { fetchAvailabilityAgents, fetchMyAvailability, updateAgentAvailability, updateMyAvailability, type OperatorAvailability } from "@/lib/api/support-availability"
import { isSameSession } from "@/lib/session-request-guard"
import { readSession } from "@/lib/auth"
import { ServiceStatus } from "@/lib/generated/enums"
import { availabilityReasonLabel, availabilityStatusLabel, availabilityStatusOptions } from "@/lib/support-availability-i18n"
import { formatAvailabilityTime, localDateTimeCandidates, selectedLocalDateTimeISO, toLocalDateTime } from "@/lib/support-availability"
export const AVAILABILITY_UPDATED_EVENT = "support-availability-updated"
export function notifyAvailabilityUpdated() { window.dispatchEvent(new Event(AVAILABILITY_UPDATED_EVENT)) }
export function OperatorStatusControl(props: { userId?: number; compact?: boolean }) {
const { session } = useAuth()
return <OperatorStatusControlContent key={session?.user.id ?? "signed-out"} {...props} />
}
function OperatorStatusControlContent({ userId, compact = false }: { userId?: number; compact?: boolean }) {
const t = useI18n()
const { session } = useAuth()
const [value, setValue] = useState<OperatorAvailability | null>(null)
const [error, setError] = useState(false)
const [loading, setLoading] = useState(true)
const [open, setOpen] = useState(false)
const [refreshKey, setRefreshKey] = useState(0)
const accountId = session?.user.id
useEffect(() => {
let active = true
let inFlight = false
let controller: AbortController | null = null
async function load() {
if (inFlight || !accountId) return
inFlight = true
controller = new AbortController()
try {
const data = userId ? (await fetchAvailabilityAgents(undefined, controller.signal)).find(item => item.userId === userId) ?? null : await fetchMyAvailability(controller.signal)
if (active) { setValue(data); setError(false) }
} catch { if (active) { setError(true); setValue(null) } }
finally { inFlight = false; if (active) setLoading(false) }
}
void load()
const refresh = () => { if (document.visibilityState === "visible") void load() }
window.addEventListener(AVAILABILITY_UPDATED_EVENT, refresh)
window.addEventListener("focus", refresh)
const timer = window.setInterval(refresh, 30000)
return () => { active = false; controller?.abort(); window.clearInterval(timer); window.removeEventListener("focus", refresh); window.removeEventListener(AVAILABILITY_UPDATED_EVENT, refresh) }
}, [accountId, userId, refreshKey])
// Responses are scoped to the mounted authenticated header/dialog; never show a previous account.
if (!accountId || (value && !userId && value.userId !== accountId)) return null
if (!value && !error) return loading ? <span className="inline-flex h-8 w-8 items-center justify-center" role="status" aria-label={t("supportAvailability.loading")}><Loader2Icon className="size-4 animate-spin" /></span> : null
return <>
<Button variant="outline" size="sm" className="h-8 max-w-56 gap-1.5 rounded-md px-2" title={t("supportAvailability.myStatus")} aria-label={t("supportAvailability.myStatus")} onClick={() => error ? setRefreshKey(key => key + 1) : setOpen(true)}>
{error ? <RefreshCwIcon className="size-4 shrink-0" /> : <Clock3Icon className="size-4 shrink-0" />}
<span className={compact ? "hidden truncate md:inline" : "truncate"}>{error ? t("supportAvailability.retryStatus") : value ? availabilityStatusLabel(value.effectiveServiceStatus, t) : t("supportAvailability.myStatus")}</span>
</Button>
{open && value ? <OperatorStatusDialog key={`${accountId}:${userId ?? "me"}`} value={value} admin={Boolean(userId)} onClose={() => setOpen(false)} onSaved={next => { setValue(next); notifyAvailabilityUpdated() }} /> : null}
</>
}
type StatusForm = { serviceStatus: string; start: string; end: string; startOccurrence: string; endOccurrence: string }
export function OperatorStatusDialog({ value, admin = false, onClose, onSaved }: { value: OperatorAvailability; admin?: boolean; onClose: () => void; onSaved: (value: OperatorAvailability) => void }) {
const t = useI18n()
const { locale } = useAppLocale()
const confirm = useConfirm()
const { session } = useAuth()
const capturedSession = useRef(session)
const mounted = useRef(true)
useEffect(() => { mounted.current = true; return () => { mounted.current = false } }, [])
const browserTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone
const [saving, setSaving] = useState(false)
const [failure, setFailure] = useState("")
const savingRef = useRef(false)
const form = useForm<StatusForm>({ defaultValues: { serviceStatus: String(value.serviceStatus), start: toLocalDateTime(value.absenceStartAt), end: toLocalDateTime(value.absenceEndAt), startOccurrence: value.absenceStartAt ? new Date(value.absenceStartAt).toISOString() : "", endOccurrence: value.absenceEndAt ? new Date(value.absenceEndAt).toISOString() : "" } })
const { register, control, handleSubmit, watch, setError, formState: { errors, isDirty } } = form
const vacation = Number(watch("serviceStatus")) === ServiceStatus.Vacation
const startISO = selectedLocalDateTimeISO(watch("start"), watch("startOccurrence")), endISO = selectedLocalDateTimeISO(watch("end"), watch("endOccurrence"))
async function close() {
if (savingRef.current) return
if (isDirty && !(await confirm({ title: t("supportAvailability.discardTitle"), description: t("supportAvailability.discardDescription"), confirmText: t("supportAvailability.discard") }))) return
onClose()
}
async function save(fields: StatusForm) {
if (savingRef.current || !isSameSession(capturedSession.current, readSession())) return
const serviceStatus = Number(fields.serviceStatus) as ServiceStatus
if (serviceStatus === ServiceStatus.Vacation) {
const start = selectedLocalDateTimeISO(fields.start, fields.startOccurrence), end = selectedLocalDateTimeISO(fields.end, fields.endOccurrence)
if (!start || !end || Date.parse(start) >= Date.parse(end)) { setError("end", { message: t("supportAvailability.invalidVacation") }); return }
}
savingRef.current = true; setSaving(true); setFailure("")
try {
const payload = { serviceStatus, ...(serviceStatus === ServiceStatus.Vacation ? { absenceStartAt: selectedLocalDateTimeISO(fields.start, fields.startOccurrence)!, absenceEndAt: selectedLocalDateTimeISO(fields.end, fields.endOccurrence)! } : {}) }
const result = admin ? await updateAgentAvailability(value.userId, payload) : await updateMyAvailability(payload)
if (!mounted.current || !isSameSession(capturedSession.current, readSession())) return
onSaved(result); toast.success(t("supportAvailability.statusSaved")); onClose()
} catch (error) { if (mounted.current) setFailure(error instanceof Error ? error.message : t("supportAvailability.saveFailed")) }
finally { savingRef.current = false; if (mounted.current) setSaving(false) }
}
return <ProjectDialog open onOpenChange={next => { if (!next) void close() }} title={admin ? t("supportAvailability.operatorStatus", { name: value.displayName || String(value.userId) }) : t("supportAvailability.myStatus")} description={t("supportAvailability.presenceHelp")} size="md" footer={<><Button variant="outline" disabled={saving} onClick={() => void close()}>{t("supportAvailability.cancel")}</Button><Button type="submit" form="operator-availability-form" disabled={saving || !isDirty}>{saving ? <Loader2Icon className="size-4 animate-spin" /> : null}{t(saving ? "supportAvailability.saving" : "supportAvailability.saveStatus")}</Button></>}>
<div className="mb-4 space-y-2 rounded-md border p-3 text-sm">
<div className="flex flex-wrap gap-2"><Badge variant="outline">{t(value.online ? "supportAvailability.online" : "supportAvailability.offline")}</Badge><Badge variant="outline">{availabilityStatusLabel(value.effectiveServiceStatus, t)}</Badge></div>
<p>{availabilityReasonLabel(value.reason, t)}</p>
{value.nextOpeningAt ? <p className="text-muted-foreground">{t("supportAvailability.nextOpening", { time: formatAvailabilityTime(value.nextOpeningAt, value.calendar.effectiveTimezone, locale) })}</p> : null}
</div>
<form id="operator-availability-form" onSubmit={handleSubmit(save)} className="space-y-4">
<Field><FieldLabel>{t("supportAvailability.workingStatus")}</FieldLabel><Controller control={control} name="serviceStatus" render={({ field }) => <OptionCombobox options={availabilityStatusOptions(t)} value={field.value} onChange={field.onChange} ariaLabel={t("supportAvailability.workingStatus")} placeholder={t("supportAvailability.workingStatus")} disabled={saving} />} /></Field>
<p className="text-xs text-muted-foreground">{t("supportAvailability.statusHelp")}</p>
{vacation ? <>
<p className="text-sm text-muted-foreground">{t("supportAvailability.vacationTimezone", { timezone: browserTimezone })}</p>
<div className="grid gap-4 sm:grid-cols-2">
<Field><FieldLabel htmlFor="absence-start">{t("supportAvailability.vacationStart")}</FieldLabel><Input id="absence-start" type="datetime-local" disabled={saving} {...register("start")} /></Field>
<Field data-invalid={Boolean(errors.end)}><FieldLabel htmlFor="absence-end">{t("supportAvailability.vacationEnd")}</FieldLabel><Input id="absence-end" type="datetime-local" disabled={saving} {...register("end")} aria-invalid={Boolean(errors.end)} /><FieldError errors={[errors.end]} /></Field>
</div>
{(["start", "end"] as const).map(name => localDateTimeCandidates(watch(name)).length > 1 ? <Field key={name}><FieldLabel>{t("supportAvailability.dstOccurrence", { field: t(name === "start" ? "supportAvailability.vacationStart" : "supportAvailability.vacationEnd") })}</FieldLabel><Controller control={control} name={name === "start" ? "startOccurrence" : "endOccurrence"} render={({ field }) => <OptionCombobox value={selectedLocalDateTimeISO(watch(name), field.value) ?? ""} options={localDateTimeCandidates(watch(name)).map(value => ({ value, label: value }))} onChange={field.onChange} disabled={saving} ariaLabel={t("supportAvailability.chooseOccurrence")} placeholder={t("supportAvailability.chooseOccurrence")} />} /></Field> : null)}
{startISO && endISO ? <p className="break-words text-xs text-muted-foreground">{t("supportAvailability.vacationExact", { start: startISO, end: endISO })}</p> : null}
<p className="text-xs text-muted-foreground">{t("supportAvailability.vacationHelp", { status: availabilityStatusLabel(value.serviceStatus === ServiceStatus.Vacation ? value.returnServiceStatus ?? value.effectiveServiceStatus : value.effectiveServiceStatus, t) })}</p>
</> : value.serviceStatus === ServiceStatus.Vacation ? <p className="text-sm text-muted-foreground">{t("supportAvailability.cancelVacationHelp")}</p> : null}
{failure ? <p role="alert" className="text-sm text-destructive">{failure}</p> : null}
</form>
</ProjectDialog>
}

View File

@@ -0,0 +1,47 @@
"use client"
import { useEffect, useState } from "react"
import { RefreshCwIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { useAppLocale, useI18n } from "@/i18n/provider"
import { fetchPublicSupportStatus, type PublicSupportStatus } from "@/lib/api/support-availability"
import { formatAvailabilityTime } from "@/lib/support-availability"
// Public server aggregates only. This never reads employee identities or private absence data.
// A successful HTTP check is not a socket connection and is not itself human presence.
export function PublicSupportAvailability({ identityScope }: { identityScope: string }) {
return <PublicSupportAvailabilityContent key={identityScope} />
}
function PublicSupportAvailabilityContent() {
const t = useI18n()
const { locale } = useAppLocale()
const [status, setStatus] = useState<PublicSupportStatus | null>(null)
const [failed, setFailed] = useState(false)
const [retry, setRetry] = useState(0)
useEffect(() => {
let active = true
let inFlight = false
let controller: AbortController | null = null
async function check() {
if (inFlight) return
inFlight = true
controller = new AbortController()
try {
const result = await fetchPublicSupportStatus(controller.signal)
if (active) { setStatus(result); setFailed(false) }
} catch { if (active) { setStatus(null); setFailed(true) } }
finally { inFlight = false }
}
void check()
const refresh = () => { if (document.visibilityState === "visible") void check() }
window.addEventListener("focus", refresh)
document.addEventListener("visibilitychange", refresh)
const timer = window.setInterval(refresh, 30000)
return () => { active = false; controller?.abort(); window.clearInterval(timer); window.removeEventListener("focus", refresh); document.removeEventListener("visibilitychange", refresh) }
}, [retry])
const reason = status?.available ? "available" : status && ["outside_hours", "temporarily_absent", "capacity"].includes(status.reason) ? status.reason : "unknown"
return <div className="mt-2 flex items-start justify-between gap-2 border-t border-border/50 pt-2 text-xs text-muted-foreground" aria-live="polite">
<div className="min-w-0 space-y-1"><p>{t(!status && !failed ? "supportAvailability.publicChecking" : `supportAvailability.public.${reason}`)}</p>{status?.nextOpeningAt ? <p>{t("supportAvailability.publicNextOpening", { time: formatAvailabilityTime(status.nextOpeningAt, status.timezone, locale) })}</p> : null}</div>
{failed ? <Button type="button" variant="ghost" size="icon" className="size-6 shrink-0" aria-label={t("supportAvailability.retry")} onClick={() => setRetry(value => value + 1)}><RefreshCwIcon className="size-3" /></Button> : null}
</div>
}