// From the core, not the `./api` barrel: these two are pure (no request), and a test that mocks the // barrel wholesale to stub its requests must not take the error path's own plumbing with it. import { alreadyReported, HttpError } from "./api/core"; import { notify } from "./notifications"; /** * Surface a failed write action as an error toast instead of the click silently doing nothing. * Prefers the server's own reason over the caller's already-translated generic fallback — but only * when the server sent a STRUCTURED detail (`{code, reason}`), which `req` has already run through * `localizeDetail`. A plain-string `detail` is whatever English the route hand-wrote, and * `reportFailure` deliberately leaves 403/404/429 to the caller, so exactly those statuses used to * put the route's English sentence into an otherwise Hungarian UI — "No user with that email.", * "Not subscribed to this channel" — where the caller's own translated fallback was right there * (deep-review round 5). Domain-agnostic: used by the Plex watched-toggles and the saved-view ops, * and delegated to by `notifyYouTubeActionError` for its non-403 case. */ export function notifyActionError( err: unknown, fallbackMessage: string, level: "error" | "warning" = "error", ): void { // Already on screen (`req` opened the error dialog, or the tab is being signed out): a toast on // top reported one fault twice. Playlists filtered this by status by hand; the watched toggles, // the saved views and a playlist delete did not. if (alreadyReported(err)) return; const localized = err instanceof HttpError && err.detailData != null ? err.detail : null; notify({ level, message: localized || fallbackMessage }); }