feat(web): Base UI toast region + global mutation feedback wiring (#47)
Add a module-scope Base UI toast manager bridged to the QueryClient so every mutation can give consistent feedback. A MutationCache (extracted into a makeQueryClient() factory for test reuse) emits a catch-all, type-aware error toast (unless meta.suppressErrorToast) and an opt-in success toast (meta.successMessage), reading mutation.meta + i18n.t outside React. meta is type-checked via a react-query Register augmentation. ToastRegion is mounted app-wide in main.tsx. Adds a toast i18n namespace (en/sv parity) and a validated story. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import {
|
||||
MutationCache,
|
||||
QueryClient,
|
||||
type MutationMeta,
|
||||
} from "@tanstack/react-query";
|
||||
|
||||
import i18n from "../i18n";
|
||||
import { toastManager } from "../toast/toast-manager";
|
||||
import { HttpError, InUseError } from "./queries";
|
||||
|
||||
function mutationErrorMessage(
|
||||
error: unknown,
|
||||
meta: MutationMeta | undefined,
|
||||
): string {
|
||||
if (meta?.errorMessage) return i18n.t(meta.errorMessage);
|
||||
if (error instanceof InUseError) {
|
||||
return i18n.t("actions.inUse", { count: error.count });
|
||||
}
|
||||
if (error instanceof HttpError && error.status === 503) {
|
||||
return i18n.t("search.unavailable");
|
||||
}
|
||||
return i18n.t("toast.error");
|
||||
}
|
||||
|
||||
/** Builds the app's QueryClient, including the MutationCache that bridges every
|
||||
* mutation to the toast region (catch-all error toast + opt-in success toast).
|
||||
* Shared by main.tsx and tests so the toast wiring stays consistent. */
|
||||
export function makeQueryClient(): QueryClient {
|
||||
return new QueryClient({
|
||||
defaultOptions: { queries: { retry: false, refetchOnWindowFocus: false } },
|
||||
mutationCache: new MutationCache({
|
||||
onError: (error, _vars, _ctx, mutation) => {
|
||||
if (mutation.meta?.suppressErrorToast) return;
|
||||
toastManager.add({
|
||||
type: "error",
|
||||
description: mutationErrorMessage(error, mutation.meta),
|
||||
});
|
||||
},
|
||||
onSuccess: (_data, _vars, _ctx, mutation) => {
|
||||
if (mutation.meta?.successMessage) {
|
||||
toastManager.add({
|
||||
type: "success",
|
||||
description: i18n.t(mutation.meta.successMessage),
|
||||
});
|
||||
}
|
||||
},
|
||||
}),
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user