Skip to content

Commit

Permalink
Fix page crash caused by BillingAlert component (#5220)
Browse files Browse the repository at this point in the history
Fixes: DASH-356
  • Loading branch information
MananTank committed Oct 29, 2024
1 parent c8b5780 commit 71a21e1
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 101 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"use client";

import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { TrackedLinkTW } from "@/components/ui/tracked-link";
Expand All @@ -12,14 +11,15 @@ import {
useAccountUsage,
} from "@3rdweb-sdk/react/hooks/useApi";
import { useLoggedInUser } from "@3rdweb-sdk/react/hooks/useLoggedInUser";
import { useDisclosure } from "@chakra-ui/react";
import * as Sentry from "@sentry/nextjs";
import { OnboardingModal } from "components/onboarding/Modal";
import { format } from "date-fns";
import { useTrack } from "hooks/analytics/useTrack";
import { useLocalStorage } from "hooks/useLocalStorage";
import { ExternalLinkIcon, XIcon } from "lucide-react";
import { usePathname } from "next/navigation";
import { useCallback, useMemo, useState } from "react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { ErrorBoundary, type FallbackProps } from "react-error-boundary";
import { LazyOnboardingBilling } from "../../../../onboarding/LazyOnboardingBilling";
import { ManageBillingButton } from "../ManageButton";
import { RecurringPaymentFailureAlert } from "./RecurringPaymentFailureAlert";
Expand Down Expand Up @@ -301,7 +301,9 @@ export function BillingAlertsUI(props: {
}

return (
<div className={cn("flex flex-col gap-4", props.className)}>{alerts}</div>
<ErrorBoundary FallbackComponent={BillingAlertsErrorBoundary}>
<div className={cn("flex flex-col gap-4", props.className)}>{alerts}</div>
</ErrorBoundary>
);
}

Expand Down Expand Up @@ -331,16 +333,11 @@ const AddPaymentNotification: React.FC<AddPaymentNotificationProps> = ({
// TODO: We should find a way to move this deeper into the
// TODO: ManageBillingButton component and set an optional field to override
const [paymentMethodSaving, setPaymentMethodSaving] = useState(false);

const {
onOpen: onPaymentMethodOpen,
onClose: onPaymentMethodClose,
isOpen: isPaymentMethodOpen,
} = useDisclosure();
const [isPaymentMethodOpen, setIsPaymentMethodOpen] = useState(false);

const handlePaymentAdded = () => {
setPaymentMethodSaving(true);
onPaymentMethodClose();
setIsPaymentMethodOpen(false);
};

const isBilling = ctaHref === "/dashboard/settings/billing";
Expand All @@ -353,21 +350,21 @@ const AddPaymentNotification: React.FC<AddPaymentNotificationProps> = ({
<OnboardingModal isOpen={isPaymentMethodOpen}>
<LazyOnboardingBilling
onSave={handlePaymentAdded}
onCancel={onPaymentMethodClose}
onCancel={() => setIsPaymentMethodOpen(false)}
/>
</OnboardingModal>

<AlertTitle>{title}</AlertTitle>
<AlertDescription>{description}</AlertDescription>

{showCTAs && (
<div className="mt-4 flex gap-2">
<div className="mt-4 flex flex-col gap-3 md:flex-row">
{isBilling ? (
<ManageBillingButton
account={dashboardAccount}
loading={paymentMethodSaving}
loadingText="Verifying payment method"
onClick={onPaymentMethodOpen}
onClick={() => setIsPaymentMethodOpen(true)}
/>
) : (
<Button variant="outline" asChild>
Expand Down Expand Up @@ -412,3 +409,17 @@ const AddPaymentNotification: React.FC<AddPaymentNotificationProps> = ({
</Alert>
);
};

function BillingAlertsErrorBoundary(errorProps: FallbackProps) {
// eslint-disable-next-line no-restricted-syntax
useEffect(() => {
Sentry.withScope((scope) => {
scope.setTag("component-crashed", "true");
scope.setTag("component-crashed-boundary", "BillingAlertsErrorBoundary");
scope.setLevel("fatal");
Sentry.captureException(errorProps.error);
});
}, [errorProps.error]);

return null;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { ChakraProviderSetup } from "@/components/ChakraProviderSetup";
import type { Meta, StoryObj } from "@storybook/react";
import { ThirdwebProvider } from "thirdweb/react";
import { AccountStatus } from "../../../../../@3rdweb-sdk/react/hooks/useApi";
Expand Down Expand Up @@ -43,92 +42,88 @@ function tomorrow(d: Date) {

function Story() {
return (
<div className="py-4">
<ChakraProviderSetup>
<ThirdwebProvider>
<div className="container flex max-w-[1100px] flex-col gap-10 py-10">
<BadgeContainer label="#usage">
<BillingAlertsUI
dashboardAccount={createDashboardAccountStub("foo")}
usageData={createBillableServiceUsageDataStub()}
/>
</BadgeContainer>
<ThirdwebProvider>
<div className="container flex max-w-[1100px] flex-col gap-10 py-10">
<BadgeContainer label="#usage">
<BillingAlertsUI
dashboardAccount={createDashboardAccountStub("foo")}
usageData={createBillableServiceUsageDataStub()}
/>
</BadgeContainer>

<BadgeContainer label="#paymentVerification">
<BillingAlertsUI
dashboardAccount={createDashboardAccountStub("foo", {
status: AccountStatus.PaymentVerification,
stripePaymentActionUrl: "https://example.com",
})}
usageData={createBillableServiceUsageDataStub({
limits: {
embeddedWallets: 100,
storage: 100,
},
})}
/>
<BadgeContainer label="#paymentVerification">
<BillingAlertsUI
dashboardAccount={createDashboardAccountStub("foo", {
status: AccountStatus.PaymentVerification,
stripePaymentActionUrl: "https://example.com",
})}
usageData={createBillableServiceUsageDataStub({
limits: {
embeddedWallets: 100,
storage: 100,
},
})}
/>
</BadgeContainer>

<BadgeContainer label="#serviceCutoff">
<BillingAlertsUI
dashboardAccount={createDashboardAccountStub("foo", {
recurringPaymentFailures: [
{
subscriptionId: "s1",
subscriptionDescription: "s1 desc",
paymentFailureCode: "400",
serviceCutoffDate: yesterday(new Date()).toISOString(),
},
],
})}
usageData={createBillableServiceUsageDataStub({
limits: {
embeddedWallets: 100,
storage: 100,
},
})}
/>
</BadgeContainer>
<BadgeContainer label="#serviceCutoff">
<BillingAlertsUI
dashboardAccount={createDashboardAccountStub("foo", {
recurringPaymentFailures: [
{
subscriptionId: "s1",
subscriptionDescription: "s1 desc",
paymentFailureCode: "400",
serviceCutoffDate: yesterday(new Date()).toISOString(),
},
],
})}
usageData={createBillableServiceUsageDataStub({
limits: {
embeddedWallets: 100,
storage: 100,
},
})}
/>
</BadgeContainer>

<BadgeContainer label="#recurringPayment">
<BillingAlertsUI
dashboardAccount={createDashboardAccountStub("foo", {
recurringPaymentFailures: [
{
subscriptionId: "s1",
subscriptionDescription: "s1 desc",
paymentFailureCode: "400",
serviceCutoffDate: tomorrow(new Date()).toISOString(),
},
],
})}
usageData={createBillableServiceUsageDataStub({
limits: {
embeddedWallets: 100,
storage: 100,
},
})}
/>
</BadgeContainer>
<BadgeContainer label="#recurringPayment">
<BillingAlertsUI
dashboardAccount={createDashboardAccountStub("foo", {
recurringPaymentFailures: [
{
subscriptionId: "s1",
subscriptionDescription: "s1 desc",
paymentFailureCode: "400",
serviceCutoffDate: tomorrow(new Date()).toISOString(),
},
],
})}
usageData={createBillableServiceUsageDataStub({
limits: {
embeddedWallets: 100,
storage: 100,
},
})}
/>
</BadgeContainer>

<BadgeContainer label="usage + serviceCutoff">
<BillingAlertsUI
dashboardAccount={createDashboardAccountStub("foo", {
recurringPaymentFailures: [
{
subscriptionId: "s1",
subscriptionDescription: "s1 desc",
paymentFailureCode: "400",
serviceCutoffDate: yesterday(new Date()).toISOString(),
},
],
})}
usageData={createBillableServiceUsageDataStub()}
/>
</BadgeContainer>
</BadgeContainer>
</div>
</ThirdwebProvider>
</ChakraProviderSetup>
</div>
<BadgeContainer label="usage + serviceCutoff">
<BillingAlertsUI
dashboardAccount={createDashboardAccountStub("foo", {
recurringPaymentFailures: [
{
subscriptionId: "s1",
subscriptionDescription: "s1 desc",
paymentFailureCode: "400",
serviceCutoffDate: yesterday(new Date()).toISOString(),
},
],
})}
usageData={createBillableServiceUsageDataStub()}
/>
</BadgeContainer>
</div>
</ThirdwebProvider>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { OnboardingModal } from "components/onboarding/Modal";
import { getRecurringPaymentFailureResponse } from "lib/billing";
import { ExternalLinkIcon, XIcon } from "lucide-react";
import { useState } from "react";
import { Text } from "tw-components";
import { LazyOnboardingBilling } from "../../../../onboarding/LazyOnboardingBilling";
import { ManageBillingButton } from "../ManageButton";

Expand Down Expand Up @@ -70,14 +69,14 @@ export const RecurringPaymentFailureAlert: React.FC<
<ul className="list-disc pl-3.5">
{affectedServices.map((service) => (
<li key={service}>
<Text>{service}</Text>
<span>{service}</span>
</li>
))}
</ul>
</div>
)}

<div className="flex gap-2">
<div className="flex flex-col gap-3 md:flex-row">
<ManageBillingButton
account={dashboardAccount}
loading={paymentMethodSaving}
Expand Down

0 comments on commit 71a21e1

Please sign in to comment.