Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ NEXT_PUBLIC_SOCKET_URL=https://dnb-backend-api.onrender.com
DNB_API_URL=https://dnb-backend-api.onrender.com
NEXT_PUBLIC_API_URL=https://dnb-backend-api.onrender.com
NEXT_PUBLIC_STELLAR_NETWORK=testnet

# Sentry error monitoring. Safe to leave unset locally - the app and CI
# build both run fine without it, Sentry is simply disabled.
NEXT_PUBLIC_SENTRY_DSN=
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,9 @@ jobs:
env:
NEXT_PUBLIC_API_URL: https://api.example.com
NEXT_PUBLIC_STELLAR_NETWORK: testnet
# Optional: only present on the upstream repo, not on fork PRs.
# When absent, next.config.mjs disables the source-map upload step
# so the build still succeeds.
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
36 changes: 36 additions & 0 deletions app/dashboard/courses/error.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"use client";

import { useEffect, useState } from "react";
import * as Sentry from "@sentry/nextjs";

export default function CoursesError({ error, reset }) {
const [eventId, setEventId] = useState(null);

useEffect(() => {
const id = Sentry.captureException(error);
setEventId(id);
}, [error]);

return (
<div className="flex-1 w-full flex flex-col items-center justify-center px-6 py-16 text-center">
<div className="max-w-md">
<h2 className="text-xl font-bold text-[#252F40] mb-3">
Couldn&apos;t load this course
</h2>
<p className="text-sm text-gray-500 mb-8">
We ran into a problem fetching your course content. Please retry.
</p>
<button
type="button"
onClick={() => reset()}
className="px-5 py-2.5 rounded-lg bg-[#34AD5D] text-white text-sm font-medium hover:bg-[#2c9350] transition-colors"
>
Retry
</button>
{eventId && (
<p className="mt-6 text-xs text-gray-400">Report ID: {eventId}</p>
)}
</div>
</div>
);
}
39 changes: 39 additions & 0 deletions app/dashboard/error.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"use client";

import { useEffect, useState } from "react";
import * as Sentry from "@sentry/nextjs";

// Renders inside app/dashboard/layout.jsx's <SidebarInset>, so the sidebar
// and nav header stay usable while just this segment shows the fallback.
export default function DashboardError({ error, reset }) {
const [eventId, setEventId] = useState(null);

useEffect(() => {
const id = Sentry.captureException(error);
setEventId(id);
}, [error]);

return (
<div className="flex-1 w-full flex flex-col items-center justify-center px-6 py-16 text-center">
<div className="max-w-md">
<h2 className="text-xl font-bold text-[#252F40] mb-3">
This page ran into a problem
</h2>
<p className="text-sm text-gray-500 mb-8">
Something went wrong loading your dashboard. Try again, or use the
sidebar to head somewhere else.
</p>
<button
type="button"
onClick={() => reset()}
className="px-5 py-2.5 rounded-lg bg-[#34AD5D] text-white text-sm font-medium hover:bg-[#2c9350] transition-colors"
>
Try again
</button>
{eventId && (
<p className="mt-6 text-xs text-gray-400">Report ID: {eventId}</p>
)}
</div>
</div>
);
}
36 changes: 36 additions & 0 deletions app/dashboard/library/error.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"use client";

import { useEffect, useState } from "react";
import * as Sentry from "@sentry/nextjs";

export default function LibraryError({ error, reset }) {
const [eventId, setEventId] = useState(null);

useEffect(() => {
const id = Sentry.captureException(error);
setEventId(id);
}, [error]);

return (
<div className="flex-1 w-full flex flex-col items-center justify-center px-6 py-16 text-center">
<div className="max-w-md">
<h2 className="text-xl font-bold text-[#252F40] mb-3">
Couldn&apos;t load your library
</h2>
<p className="text-sm text-gray-500 mb-8">
We ran into a problem fetching this content. Please retry.
</p>
<button
type="button"
onClick={() => reset()}
className="px-5 py-2.5 rounded-lg bg-[#34AD5D] text-white text-sm font-medium hover:bg-[#2c9350] transition-colors"
>
Retry
</button>
{eventId && (
<p className="mt-6 text-xs text-gray-400">Report ID: {eventId}</p>
)}
</div>
</div>
);
}
48 changes: 48 additions & 0 deletions app/error.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"use client";

import { useEffect, useState } from "react";
import * as Sentry from "@sentry/nextjs";

// Kept dependency-light on purpose (no toasts, providers, or design-system
// imports) so this boundary can't itself throw while trying to render a
// recovery UI for an unrelated error.
export default function Error({ error, reset }) {
const [eventId, setEventId] = useState(null);

useEffect(() => {
const id = Sentry.captureException(error);
setEventId(id);
}, [error]);

return (
<div className="min-h-[60vh] w-full flex flex-col items-center justify-center px-6 py-16 text-center">
<div className="max-w-md">
<h1 className="text-2xl font-bold text-[#252F40] mb-3">
Something went wrong
</h1>
<p className="text-sm text-gray-500 mb-8">
An unexpected error occurred while loading this page. You can try
again, or head back to the homepage.
</p>
<div className="flex items-center justify-center gap-3">
<button
type="button"
onClick={() => reset()}
className="px-5 py-2.5 rounded-lg bg-[#34AD5D] text-white text-sm font-medium hover:bg-[#2c9350] transition-colors"
>
Try again
</button>
<a
href="/"
className="px-5 py-2.5 rounded-lg border border-gray-200 text-[#252F40] text-sm font-medium hover:bg-gray-50 transition-colors"
>
Go home
</a>
</div>
{eventId && (
<p className="mt-6 text-xs text-gray-400">Report ID: {eventId}</p>
)}
</div>
</div>
);
}
69 changes: 69 additions & 0 deletions app/global-error.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"use client";

import { useEffect, useState } from "react";
import * as Sentry from "@sentry/nextjs";

// This only activates in production builds (test with `npm run build && npm
// start`). No app providers, fonts, or global stylesheet are guaranteed to
// be available here, so this stays fully self-contained with inline styles
// and renders its own <html>/<body>.
export default function GlobalError({ error, reset }) {
const [eventId, setEventId] = useState(null);

useEffect(() => {
const id = Sentry.captureException(error);
setEventId(id);
}, [error]);

return (
<html lang="en">
<body
style={{
margin: 0,
minHeight: "100vh",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
padding: "24px",
textAlign: "center",
fontFamily:
"-apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, sans-serif",
backgroundColor: "#ffffff",
color: "#252F40",
}}
>
<div style={{ maxWidth: 420 }}>
<h1 style={{ fontSize: 24, fontWeight: 700, marginBottom: 12 }}>
Deen Bridge
</h1>
<p style={{ fontSize: 15, color: "#6b7280", marginBottom: 28 }}>
Something went wrong and this page couldn&apos;t load. Please
reload to try again.
</p>
<button
type="button"
onClick={() => reset()}
style={{
padding: "10px 20px",
borderRadius: 8,
border: "none",
backgroundColor: "#34AD5D",
color: "#ffffff",
fontSize: 14,
fontWeight: 500,
cursor: "pointer",
}}
>
Reload
</button>
{eventId && (
<p style={{ marginTop: 20, fontSize: 12, color: "#9ca3af" }}>
Report ID: {eventId}
</p>
)}
</div>
</body>
</html>
);
}
48 changes: 0 additions & 48 deletions components/DebugAuthLogs.jsx

This file was deleted.

1 change: 0 additions & 1 deletion hooks/useAuth.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ export const useAuth = () => {
let freshUser = res.data.user || res.data;
// Normalize user object to always have _id
if (freshUser.id && !freshUser._id) freshUser._id = freshUser.id;
console.log("User data refreshed:", freshUser);
// Update user state and cookies
setUser(freshUser);
Cookies.set("userInfo", JSON.stringify(freshUser), { expires: 1 });
Expand Down
8 changes: 8 additions & 0 deletions hooks/useStellarDonation.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use client";
import { useState, useCallback } from "react";
import { Networks } from "@creit.tech/stellar-wallets-kit";
import * as Sentry from "@sentry/nextjs";
import { useStellar } from "@/components/stellar/StellarProvider";
import { toast } from "sonner";
import axiosInstance from "@/lib/config/axios.config";
Expand Down Expand Up @@ -98,6 +99,13 @@ export const useStellarDonation = () => {
} catch (error) {
const message = error.response?.data?.message || error.message;

// Terminal failure the user already sees via toast below - still
// worth capturing so we notice patterns (wallet issues, backend
// errors) even though it's "handled".
Sentry.captureException(error, {
tags: { feature: "stellar-payment" },
});
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// Handle specific Stellar errors
if (message.includes("insufficient") || message.includes("underfunded")) {
toast.error("Insufficient USDC balance");
Expand Down
8 changes: 8 additions & 0 deletions hooks/useStellarPayment.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use client";
import { useState, useCallback } from "react";
import * as Sentry from "@sentry/nextjs";
import { useStellar } from "@/components/stellar/StellarProvider";
import { toast } from "sonner";
import axiosInstance from "@/lib/config/axios.config";
Expand Down Expand Up @@ -93,6 +94,13 @@ export const useStellarPayment = () => {
} catch (error) {
const message = error.response?.data?.message || error.message;

// Terminal failure the user already sees via toast below - still
// worth capturing so we notice patterns (wallet issues, backend
// errors) even though it's "handled".
Sentry.captureException(error, {
tags: { feature: "stellar-payment" },
});

// Handle specific Stellar errors
if (message.includes("insufficient") || message.includes("underfunded")) {
toast.error("Insufficient USDC balance");
Expand Down
32 changes: 32 additions & 0 deletions instrumentation-client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// 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";
import {
sentryBeforeSend,
sentryBeforeSendTransaction,
IGNORED_ERRORS,
} from "./sentry.shared.config";

Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,

// Never send cookies, headers, or IP addresses by default. Scrubbing in
// beforeSend below is a defense-in-depth backstop, not the primary control.
sendDefaultPii: false,

environment: process.env.NODE_ENV,

// Adjust this value in production, or use tracesSampler for greater control.
tracesSampleRate: 0.1,

// Known noisy, non-actionable errors (e.g. closing the Stellar wallet
// connect modal) should never create an event.
ignoreErrors: IGNORED_ERRORS,

beforeSend: sentryBeforeSend,
beforeSendTransaction: sentryBeforeSendTransaction,
});

export const onRouterTransitionStart = Sentry.captureRouterTransitionStart;
14 changes: 14 additions & 0 deletions instrumentation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export async function register() {
if (process.env.NEXT_RUNTIME === "nodejs") {
await import("./sentry.server.config");
}

if (process.env.NEXT_RUNTIME === "edge") {
await import("./sentry.edge.config");
}
}

export const onRequestError = async (...args) => {
const Sentry = await import("@sentry/nextjs");
Sentry.captureRequestError(...args);
};
Loading