toast.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import { toast } from "sonner";
  2. import { ApiClientError } from "@/lib/frontend/apiClient";
  3. function normalizeText(value) {
  4. if (typeof value !== "string") return null;
  5. const s = value.trim();
  6. return s ? s : null;
  7. }
  8. function buildToastOptions({ description, ...rest }) {
  9. const opts = { ...rest };
  10. const desc = normalizeText(description);
  11. if (desc) opts.description = desc;
  12. return opts;
  13. }
  14. export function notifySuccess({ title, description, ...options } = {}) {
  15. const t = normalizeText(title);
  16. if (!t) return null;
  17. return toast.success(t, buildToastOptions({ description, ...options }));
  18. }
  19. export function notifyError({ title, description, ...options } = {}) {
  20. const t = normalizeText(title);
  21. if (!t) return null;
  22. return toast.error(t, buildToastOptions({ description, ...options }));
  23. }
  24. export function notifyInfo({ title, description, ...options } = {}) {
  25. const t = normalizeText(title);
  26. if (!t) return null;
  27. return toast.info(t, buildToastOptions({ description, ...options }));
  28. }
  29. export function notifyWarning({ title, description, ...options } = {}) {
  30. const t = normalizeText(title);
  31. if (!t) return null;
  32. return toast.warning(t, buildToastOptions({ description, ...options }));
  33. }
  34. export function notifyLoading({ title, description, ...options } = {}) {
  35. const t = normalizeText(title);
  36. if (!t) return null;
  37. return toast.loading(t, buildToastOptions({ description, ...options }));
  38. }
  39. export function dismissToast(toastId) {
  40. return toast.dismiss(toastId);
  41. }
  42. export function mapApiErrorToToast(
  43. err,
  44. {
  45. overrides = null,
  46. fallbackTitle = "Fehler",
  47. fallbackDescription = "Bitte versuchen Sie es erneut.",
  48. } = {},
  49. ) {
  50. // Allow call sites (like Change Password) to override messages per error code.
  51. if (err instanceof ApiClientError) {
  52. const code = String(err.code || "");
  53. if (overrides && overrides[code]) {
  54. const o = overrides[code] || {};
  55. return {
  56. title: normalizeText(o.title) || fallbackTitle,
  57. description: normalizeText(o.description) || null,
  58. };
  59. }
  60. if (code === "CLIENT_NETWORK_ERROR") {
  61. return {
  62. title: "Netzwerkfehler",
  63. description:
  64. "Bitte prüfen Sie Ihre Verbindung und versuchen Sie es erneut.",
  65. };
  66. }
  67. if (code === "AUTH_UNAUTHENTICATED") {
  68. return {
  69. title: "Sitzung abgelaufen",
  70. description: "Bitte melden Sie sich erneut an.",
  71. };
  72. }
  73. if (code.startsWith("VALIDATION_")) {
  74. return {
  75. title: "Ungültige Eingabe",
  76. description:
  77. "Bitte prüfen Sie Ihre Eingaben und versuchen Sie es erneut.",
  78. };
  79. }
  80. }
  81. return {
  82. title: normalizeText(fallbackTitle) || "Fehler",
  83. description: normalizeText(fallbackDescription) || null,
  84. };
  85. }
  86. export function notifyApiError(
  87. err,
  88. {
  89. overrides = null,
  90. fallbackTitle = "Fehler",
  91. fallbackDescription = "Bitte versuchen Sie es erneut.",
  92. ...toastOptions
  93. } = {},
  94. ) {
  95. const mapped = mapApiErrorToToast(err, {
  96. overrides,
  97. fallbackTitle,
  98. fallbackDescription,
  99. });
  100. return toast.error(
  101. mapped.title,
  102. buildToastOptions({ description: mapped.description, ...toastOptions }),
  103. );
  104. }