Skip to content

Commit 71a21e1

Browse files
committed
Fix page crash caused by BillingAlert component (#5220)
Fixes: DASH-356
1 parent c8b5780 commit 71a21e1

File tree

3 files changed

+106
-101
lines changed

3 files changed

+106
-101
lines changed

apps/dashboard/src/components/settings/Account/Billing/alerts/Alert.tsx

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
"use client";
2-
32
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
43
import { Button } from "@/components/ui/button";
54
import { TrackedLinkTW } from "@/components/ui/tracked-link";
@@ -12,14 +11,15 @@ import {
1211
useAccountUsage,
1312
} from "@3rdweb-sdk/react/hooks/useApi";
1413
import { useLoggedInUser } from "@3rdweb-sdk/react/hooks/useLoggedInUser";
15-
import { useDisclosure } from "@chakra-ui/react";
14+
import * as Sentry from "@sentry/nextjs";
1615
import { OnboardingModal } from "components/onboarding/Modal";
1716
import { format } from "date-fns";
1817
import { useTrack } from "hooks/analytics/useTrack";
1918
import { useLocalStorage } from "hooks/useLocalStorage";
2019
import { ExternalLinkIcon, XIcon } from "lucide-react";
2120
import { usePathname } from "next/navigation";
22-
import { useCallback, useMemo, useState } from "react";
21+
import { useCallback, useEffect, useMemo, useState } from "react";
22+
import { ErrorBoundary, type FallbackProps } from "react-error-boundary";
2323
import { LazyOnboardingBilling } from "../../../../onboarding/LazyOnboardingBilling";
2424
import { ManageBillingButton } from "../ManageButton";
2525
import { RecurringPaymentFailureAlert } from "./RecurringPaymentFailureAlert";
@@ -301,7 +301,9 @@ export function BillingAlertsUI(props: {
301301
}
302302

303303
return (
304-
<div className={cn("flex flex-col gap-4", props.className)}>{alerts}</div>
304+
<ErrorBoundary FallbackComponent={BillingAlertsErrorBoundary}>
305+
<div className={cn("flex flex-col gap-4", props.className)}>{alerts}</div>
306+
</ErrorBoundary>
305307
);
306308
}
307309

@@ -331,16 +333,11 @@ const AddPaymentNotification: React.FC<AddPaymentNotificationProps> = ({
331333
// TODO: We should find a way to move this deeper into the
332334
// TODO: ManageBillingButton component and set an optional field to override
333335
const [paymentMethodSaving, setPaymentMethodSaving] = useState(false);
334-
335-
const {
336-
onOpen: onPaymentMethodOpen,
337-
onClose: onPaymentMethodClose,
338-
isOpen: isPaymentMethodOpen,
339-
} = useDisclosure();
336+
const [isPaymentMethodOpen, setIsPaymentMethodOpen] = useState(false);
340337

341338
const handlePaymentAdded = () => {
342339
setPaymentMethodSaving(true);
343-
onPaymentMethodClose();
340+
setIsPaymentMethodOpen(false);
344341
};
345342

346343
const isBilling = ctaHref === "/dashboard/settings/billing";
@@ -353,21 +350,21 @@ const AddPaymentNotification: React.FC<AddPaymentNotificationProps> = ({
353350
<OnboardingModal isOpen={isPaymentMethodOpen}>
354351
<LazyOnboardingBilling
355352
onSave={handlePaymentAdded}
356-
onCancel={onPaymentMethodClose}
353+
onCancel={() => setIsPaymentMethodOpen(false)}
357354
/>
358355
</OnboardingModal>
359356

360357
<AlertTitle>{title}</AlertTitle>
361358
<AlertDescription>{description}</AlertDescription>
362359

363360
{showCTAs && (
364-
<div className="mt-4 flex gap-2">
361+
<div className="mt-4 flex flex-col gap-3 md:flex-row">
365362
{isBilling ? (
366363
<ManageBillingButton
367364
account={dashboardAccount}
368365
loading={paymentMethodSaving}
369366
loadingText="Verifying payment method"
370-
onClick={onPaymentMethodOpen}
367+
onClick={() => setIsPaymentMethodOpen(true)}
371368
/>
372369
) : (
373370
<Button variant="outline" asChild>
@@ -412,3 +409,17 @@ const AddPaymentNotification: React.FC<AddPaymentNotificationProps> = ({
412409
</Alert>
413410
);
414411
};
412+
413+
function BillingAlertsErrorBoundary(errorProps: FallbackProps) {
414+
// eslint-disable-next-line no-restricted-syntax
415+
useEffect(() => {
416+
Sentry.withScope((scope) => {
417+
scope.setTag("component-crashed", "true");
418+
scope.setTag("component-crashed-boundary", "BillingAlertsErrorBoundary");
419+
scope.setLevel("fatal");
420+
Sentry.captureException(errorProps.error);
421+
});
422+
}, [errorProps.error]);
423+
424+
return null;
425+
}
Lines changed: 79 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { ChakraProviderSetup } from "@/components/ChakraProviderSetup";
21
import type { Meta, StoryObj } from "@storybook/react";
32
import { ThirdwebProvider } from "thirdweb/react";
43
import { AccountStatus } from "../../../../../@3rdweb-sdk/react/hooks/useApi";
@@ -43,92 +42,88 @@ function tomorrow(d: Date) {
4342

4443
function Story() {
4544
return (
46-
<div className="py-4">
47-
<ChakraProviderSetup>
48-
<ThirdwebProvider>
49-
<div className="container flex max-w-[1100px] flex-col gap-10 py-10">
50-
<BadgeContainer label="#usage">
51-
<BillingAlertsUI
52-
dashboardAccount={createDashboardAccountStub("foo")}
53-
usageData={createBillableServiceUsageDataStub()}
54-
/>
55-
</BadgeContainer>
45+
<ThirdwebProvider>
46+
<div className="container flex max-w-[1100px] flex-col gap-10 py-10">
47+
<BadgeContainer label="#usage">
48+
<BillingAlertsUI
49+
dashboardAccount={createDashboardAccountStub("foo")}
50+
usageData={createBillableServiceUsageDataStub()}
51+
/>
52+
</BadgeContainer>
5653

57-
<BadgeContainer label="#paymentVerification">
58-
<BillingAlertsUI
59-
dashboardAccount={createDashboardAccountStub("foo", {
60-
status: AccountStatus.PaymentVerification,
61-
stripePaymentActionUrl: "https://example.com",
62-
})}
63-
usageData={createBillableServiceUsageDataStub({
64-
limits: {
65-
embeddedWallets: 100,
66-
storage: 100,
67-
},
68-
})}
69-
/>
54+
<BadgeContainer label="#paymentVerification">
55+
<BillingAlertsUI
56+
dashboardAccount={createDashboardAccountStub("foo", {
57+
status: AccountStatus.PaymentVerification,
58+
stripePaymentActionUrl: "https://example.com",
59+
})}
60+
usageData={createBillableServiceUsageDataStub({
61+
limits: {
62+
embeddedWallets: 100,
63+
storage: 100,
64+
},
65+
})}
66+
/>
67+
</BadgeContainer>
7068

71-
<BadgeContainer label="#serviceCutoff">
72-
<BillingAlertsUI
73-
dashboardAccount={createDashboardAccountStub("foo", {
74-
recurringPaymentFailures: [
75-
{
76-
subscriptionId: "s1",
77-
subscriptionDescription: "s1 desc",
78-
paymentFailureCode: "400",
79-
serviceCutoffDate: yesterday(new Date()).toISOString(),
80-
},
81-
],
82-
})}
83-
usageData={createBillableServiceUsageDataStub({
84-
limits: {
85-
embeddedWallets: 100,
86-
storage: 100,
87-
},
88-
})}
89-
/>
90-
</BadgeContainer>
69+
<BadgeContainer label="#serviceCutoff">
70+
<BillingAlertsUI
71+
dashboardAccount={createDashboardAccountStub("foo", {
72+
recurringPaymentFailures: [
73+
{
74+
subscriptionId: "s1",
75+
subscriptionDescription: "s1 desc",
76+
paymentFailureCode: "400",
77+
serviceCutoffDate: yesterday(new Date()).toISOString(),
78+
},
79+
],
80+
})}
81+
usageData={createBillableServiceUsageDataStub({
82+
limits: {
83+
embeddedWallets: 100,
84+
storage: 100,
85+
},
86+
})}
87+
/>
88+
</BadgeContainer>
9189

92-
<BadgeContainer label="#recurringPayment">
93-
<BillingAlertsUI
94-
dashboardAccount={createDashboardAccountStub("foo", {
95-
recurringPaymentFailures: [
96-
{
97-
subscriptionId: "s1",
98-
subscriptionDescription: "s1 desc",
99-
paymentFailureCode: "400",
100-
serviceCutoffDate: tomorrow(new Date()).toISOString(),
101-
},
102-
],
103-
})}
104-
usageData={createBillableServiceUsageDataStub({
105-
limits: {
106-
embeddedWallets: 100,
107-
storage: 100,
108-
},
109-
})}
110-
/>
111-
</BadgeContainer>
90+
<BadgeContainer label="#recurringPayment">
91+
<BillingAlertsUI
92+
dashboardAccount={createDashboardAccountStub("foo", {
93+
recurringPaymentFailures: [
94+
{
95+
subscriptionId: "s1",
96+
subscriptionDescription: "s1 desc",
97+
paymentFailureCode: "400",
98+
serviceCutoffDate: tomorrow(new Date()).toISOString(),
99+
},
100+
],
101+
})}
102+
usageData={createBillableServiceUsageDataStub({
103+
limits: {
104+
embeddedWallets: 100,
105+
storage: 100,
106+
},
107+
})}
108+
/>
109+
</BadgeContainer>
112110

113-
<BadgeContainer label="usage + serviceCutoff">
114-
<BillingAlertsUI
115-
dashboardAccount={createDashboardAccountStub("foo", {
116-
recurringPaymentFailures: [
117-
{
118-
subscriptionId: "s1",
119-
subscriptionDescription: "s1 desc",
120-
paymentFailureCode: "400",
121-
serviceCutoffDate: yesterday(new Date()).toISOString(),
122-
},
123-
],
124-
})}
125-
usageData={createBillableServiceUsageDataStub()}
126-
/>
127-
</BadgeContainer>
128-
</BadgeContainer>
129-
</div>
130-
</ThirdwebProvider>
131-
</ChakraProviderSetup>
132-
</div>
111+
<BadgeContainer label="usage + serviceCutoff">
112+
<BillingAlertsUI
113+
dashboardAccount={createDashboardAccountStub("foo", {
114+
recurringPaymentFailures: [
115+
{
116+
subscriptionId: "s1",
117+
subscriptionDescription: "s1 desc",
118+
paymentFailureCode: "400",
119+
serviceCutoffDate: yesterday(new Date()).toISOString(),
120+
},
121+
],
122+
})}
123+
usageData={createBillableServiceUsageDataStub()}
124+
/>
125+
</BadgeContainer>
126+
</div>
127+
</ThirdwebProvider>
133128
);
134129
}

apps/dashboard/src/components/settings/Account/Billing/alerts/RecurringPaymentFailureAlert.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { OnboardingModal } from "components/onboarding/Modal";
66
import { getRecurringPaymentFailureResponse } from "lib/billing";
77
import { ExternalLinkIcon, XIcon } from "lucide-react";
88
import { useState } from "react";
9-
import { Text } from "tw-components";
109
import { LazyOnboardingBilling } from "../../../../onboarding/LazyOnboardingBilling";
1110
import { ManageBillingButton } from "../ManageButton";
1211

@@ -70,14 +69,14 @@ export const RecurringPaymentFailureAlert: React.FC<
7069
<ul className="list-disc pl-3.5">
7170
{affectedServices.map((service) => (
7271
<li key={service}>
73-
<Text>{service}</Text>
72+
<span>{service}</span>
7473
</li>
7574
))}
7675
</ul>
7776
</div>
7877
)}
7978

80-
<div className="flex gap-2">
79+
<div className="flex flex-col gap-3 md:flex-row">
8180
<ManageBillingButton
8281
account={dashboardAccount}
8382
loading={paymentMethodSaving}

0 commit comments

Comments
 (0)