diff --git a/.gitignore b/.gitignore
index 1fffb8e724..cf77178438 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,3 +43,6 @@ bun.lockb
/playwright/.cache/
/playwright/.auth/
/playwright/results
+
+# Sentry Config File
+.env.sentry-build-plugin
diff --git a/next.config.js b/next.config.js
index 4a038a3d69..1d55f0130f 100644
--- a/next.config.js
+++ b/next.config.js
@@ -139,4 +139,51 @@ const nextConfig = {
},
}
-module.exports = nextConfig
+// Injected content via Sentry wizard below
+
+const { withSentryConfig } = require("@sentry/nextjs");
+
+module.exports = withSentryConfig(
+ nextConfig,
+ {
+ // For all available options, see:
+ // https://github.com/getsentry/sentry-webpack-plugin#options
+
+ org: "zgen",
+ project: "guildxyz",
+
+ // Only print logs for uploading source maps in CI
+ silent: !process.env.CI,
+
+ // For all available options, see:
+ // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
+
+ // Upload a larger set of source maps for prettier stack traces (increases build time)
+ widenClientFileUpload: true,
+
+ // Automatically annotate React components to show their full name in breadcrumbs and session replay
+ reactComponentAnnotation: {
+ enabled: true,
+ },
+
+ // Route browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers.
+ // This can increase your server load as well as your hosting bill.
+ // Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client-
+ // side errors will fail.
+ tunnelRoute: "/monitoring",
+
+ // Hides source maps from generated client bundles
+ hideSourceMaps: true,
+
+ // Automatically tree-shake Sentry logger statements to reduce bundle size
+ disableLogger: true,
+
+ // Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.)
+ // See the following for more information:
+ // https://docs.sentry.io/product/crons/
+ // https://vercel.com/docs/cron-jobs
+ automaticVercelMonitors: true,
+
+ sourcemaps: { deleteSourcemapsAfterUpload: true },
+ }
+);
diff --git a/package.json b/package.json
index 9b2c388d12..b2dc1402ac 100644
--- a/package.json
+++ b/package.json
@@ -30,6 +30,8 @@
"@radix-ui/react-toggle": "^1.1.0",
"@radix-ui/react-toggle-group": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.4",
+ "@reflet/http": "^1.0.0",
+ "@sentry/nextjs": "^8",
"@t3-oss/env-nextjs": "^0.11.1",
"@tailwindcss/typography": "^0.5.15",
"@tanstack/react-query": "^5.62.2",
@@ -48,6 +50,7 @@
"react": "19.0.0-rc-66855b96-20241106",
"react-canvas-confetti": "^2.0.7",
"react-dom": "19.0.0-rc-66855b96-20241106",
+ "react-error-boundary": "^4.1.2",
"react-hook-form": "^7.53.2",
"react-markdown": "^9.0.1",
"rehype-external-links": "^3.0.0",
diff --git a/sentry.client.config.ts b/sentry.client.config.ts
new file mode 100644
index 0000000000..7cdfa2bb87
--- /dev/null
+++ b/sentry.client.config.ts
@@ -0,0 +1,28 @@
+// This file configures the initialization of Sentry on the client.
+// The config you add here will be used whenever a users loads a page in their browser.
+// https://docs.sentry.io/platforms/javascript/guides/nextjs/
+
+import * as Sentry from "@sentry/nextjs";
+
+Sentry.init({
+ dsn: "https://eba4a78ff99c793accdeb809346d12de@o4508437633171456.ingest.de.sentry.io/4508437781151824",
+
+ // Add optional integrations for additional features
+ integrations: [
+ Sentry.replayIntegration(),
+ ],
+
+ // Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control.
+ tracesSampleRate: 1,
+
+ // Define how likely Replay events are sampled.
+ // This sets the sample rate to be 10%. You may want this to be 100% while
+ // in development and sample at a lower rate in production
+ replaysSessionSampleRate: 0.1,
+
+ // Define how likely Replay events are sampled when an error occurs.
+ replaysOnErrorSampleRate: 1.0,
+
+ // Setting this option to true will print useful information to the console while you're setting up Sentry.
+ debug: false,
+});
diff --git a/sentry.edge.config.ts b/sentry.edge.config.ts
new file mode 100644
index 0000000000..a2176bb4d2
--- /dev/null
+++ b/sentry.edge.config.ts
@@ -0,0 +1,16 @@
+// This file configures the initialization of Sentry for edge features (middleware, edge routes, and so on).
+// The config you add here will be used whenever one of the edge features is loaded.
+// Note that this config is unrelated to the Vercel Edge Runtime and is also required when running locally.
+// https://docs.sentry.io/platforms/javascript/guides/nextjs/
+
+import * as Sentry from "@sentry/nextjs";
+
+Sentry.init({
+ dsn: "https://eba4a78ff99c793accdeb809346d12de@o4508437633171456.ingest.de.sentry.io/4508437781151824",
+
+ // Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control.
+ tracesSampleRate: 1,
+
+ // Setting this option to true will print useful information to the console while you're setting up Sentry.
+ debug: false,
+});
diff --git a/sentry.server.config.ts b/sentry.server.config.ts
new file mode 100644
index 0000000000..c44636be62
--- /dev/null
+++ b/sentry.server.config.ts
@@ -0,0 +1,15 @@
+// This file configures the initialization of Sentry on the server.
+// The config you add here will be used whenever the server handles a request.
+// https://docs.sentry.io/platforms/javascript/guides/nextjs/
+
+import * as Sentry from "@sentry/nextjs";
+
+Sentry.init({
+ dsn: "https://eba4a78ff99c793accdeb809346d12de@o4508437633171456.ingest.de.sentry.io/4508437781151824",
+
+ // Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control.
+ tracesSampleRate: 1,
+
+ // Setting this option to true will print useful information to the console while you're setting up Sentry.
+ debug: false,
+});
diff --git a/src/app/(dashboard)/[guildUrlName]/[pageUrlName]/page.tsx b/src/app/(dashboard)/[guildUrlName]/[pageUrlName]/page.tsx
index e11b50a273..9b6a1aa843 100644
--- a/src/app/(dashboard)/[guildUrlName]/[pageUrlName]/page.tsx
+++ b/src/app/(dashboard)/[guildUrlName]/[pageUrlName]/page.tsx
@@ -1,16 +1,19 @@
"use client";
+import { GenericError } from "@/components/GenericError";
import { RequirementDisplayComponent } from "@/components/requirements/RequirementDisplayComponent";
import { Button } from "@/components/ui/Button";
import { Card } from "@/components/ui/Card";
import { ScrollArea } from "@/components/ui/ScrollArea";
import { Skeleton } from "@/components/ui/Skeleton";
+import { CustomError, FetchError } from "@/lib/error";
import { rewardBatchOptions, roleBatchOptions } from "@/lib/options";
import type { Schemas } from "@guildxyz/types";
import { Lock } from "@phosphor-icons/react/dist/ssr";
import { useSuspenseQuery } from "@tanstack/react-query";
import { useParams } from "next/navigation";
import { Suspense } from "react";
+import { ErrorBoundary } from "react-error-boundary";
const GuildPage = () => {
const { pageUrlName, guildUrlName } = useParams<{
@@ -26,12 +29,15 @@ const GuildPage = () => {
return (