diff --git a/apps/dashboard/src/components/settings/Account/Billing/ApplyCouponCard.stories.tsx b/apps/dashboard/src/components/settings/Account/Billing/ApplyCouponCard.stories.tsx
index 9bf79a07d61..4b5fdb9dd3d 100644
--- a/apps/dashboard/src/components/settings/Account/Billing/ApplyCouponCard.stories.tsx
+++ b/apps/dashboard/src/components/settings/Account/Billing/ApplyCouponCard.stories.tsx
@@ -59,6 +59,19 @@ function Story() {
submit={statusStub(200)}
onCouponApplied={undefined}
prefillPromoCode="XYZ"
+ isPaymentSetup={true}
+ onAddPayment={() => {}}
+ />
+
+
+
+ {
+ console.log("show payment modal");
+ }}
/>
@@ -66,6 +79,8 @@ function Story() {
{}}
/>
@@ -73,6 +88,8 @@ function Story() {
{}}
/>
@@ -80,6 +97,8 @@ function Story() {
{}}
/>
@@ -87,6 +106,8 @@ function Story() {
{}}
/>
@@ -94,6 +115,8 @@ function Story() {
{}}
/>
@@ -101,6 +124,8 @@ function Story() {
{}}
/>
diff --git a/apps/dashboard/src/components/settings/Account/Billing/CouponCard.tsx b/apps/dashboard/src/components/settings/Account/Billing/CouponCard.tsx
index a1f718171b9..44fb4f82a74 100644
--- a/apps/dashboard/src/components/settings/Account/Billing/CouponCard.tsx
+++ b/apps/dashboard/src/components/settings/Account/Billing/CouponCard.tsx
@@ -37,6 +37,8 @@ export type ActiveCouponResponse = {
function ApplyCouponCard(props: {
teamId: string | undefined;
onCouponApplied: (data: ActiveCouponResponse) => void;
+ isPaymentSetup: boolean;
+ onAddPayment: () => void;
}) {
const searchParams = useSearchParams();
const couponCode = searchParams?.get("coupon");
@@ -45,6 +47,8 @@ function ApplyCouponCard(props: {
onCouponApplied={props.onCouponApplied}
prefillPromoCode={couponCode || undefined}
scrollIntoView={!!couponCode}
+ isPaymentSetup={props.isPaymentSetup}
+ onAddPayment={props.onAddPayment}
submit={async (promoCode: string) => {
const res = await fetch("/api/server-proxy/api/v1/coupons/redeem", {
method: "POST",
@@ -86,6 +90,8 @@ export function ApplyCouponCardUI(props: {
onCouponApplied: ((data: ActiveCouponResponse) => void) | undefined;
prefillPromoCode?: string;
scrollIntoView?: boolean;
+ isPaymentSetup: boolean;
+ onAddPayment: () => void;
}) {
const containerRef = useRef(null);
const form = useForm>({
@@ -113,6 +119,11 @@ export function ApplyCouponCardUI(props: {
});
async function onSubmit(values: z.infer) {
+ if (!props.isPaymentSetup) {
+ props.onAddPayment();
+ return;
+ }
+
try {
const res = await applyCoupon.mutateAsync(values.promoCode);
switch (res.status) {
@@ -161,7 +172,11 @@ export function ApplyCouponCardUI(props: {
description:
"Enter your coupon code to apply discounts or free trials on thirdweb products",
}}
- bottomText=""
+ bottomText={
+ props.isPaymentSetup
+ ? ""
+ : "A valid payment method must be added to apply a coupon"
+ }
saveButton={{
variant: "default",
disabled: false,
@@ -238,7 +253,11 @@ export function CouponDetailsCardUI(props: {
);
}
-export function CouponSection(props: { teamId: string | undefined }) {
+export function CouponSection(props: {
+ teamId: string | undefined;
+ isPaymentSetup: boolean;
+ onAddPayment: () => void;
+}) {
const loggedInUser = useLoggedInUser();
const [optimisticCouponData, setOptimisticCouponData] = useState<
| {
@@ -325,6 +344,8 @@ export function CouponSection(props: { teamId: string | undefined }) {
setOptimisticCouponData(undefined);
});
}}
+ isPaymentSetup={props.isPaymentSetup}
+ onAddPayment={props.onAddPayment}
/>
);
diff --git a/apps/dashboard/src/components/settings/Account/Billing/index.tsx b/apps/dashboard/src/components/settings/Account/Billing/index.tsx
index e9012561520..a0f0240d2fb 100644
--- a/apps/dashboard/src/components/settings/Account/Billing/index.tsx
+++ b/apps/dashboard/src/components/settings/Account/Billing/index.tsx
@@ -5,7 +5,7 @@ import {
AccountStatus,
useUpdateAccountPlan,
} from "@3rdweb-sdk/react/hooks/useApi";
-import { Flex, Icon, useDisclosure } from "@chakra-ui/react";
+import { Flex, Icon } from "@chakra-ui/react";
import { StepsCard } from "components/dashboard/StepsCard";
import { OnboardingModal } from "components/onboarding/Modal";
import { AccountForm } from "components/settings/Account/AccountForm";
@@ -32,11 +32,7 @@ export const Billing: React.FC = ({ account, teamId }) => {
const updatePlanMutation = useUpdateAccountPlan(
account?.plan === AccountPlan.Free,
);
- const {
- isOpen: isPaymentMethodOpen,
- onOpen: onPaymentMethodOpen,
- onClose: onPaymentMethodClose,
- } = useDisclosure();
+ const [isPaymentModalOpen, setIsPaymentModalOpen] = useState(false);
const [paymentMethodSaving, setPaymentMethodSaving] = useState(false);
const [selectedPlan, setSelectedPlan] = useState();
const trackEvent = useTrack();
@@ -114,7 +110,7 @@ export const Billing: React.FC = ({ account, teamId }) => {
if (!validPayment) {
setSelectedPlan(plan);
- onPaymentMethodOpen();
+ setIsPaymentModalOpen(true);
return;
}
// downgrade from Growth to Free
@@ -127,7 +123,7 @@ export const Billing: React.FC = ({ account, teamId }) => {
const handlePaymentAdded = () => {
setPaymentMethodSaving(true);
- onPaymentMethodClose();
+ setIsPaymentModalOpen(false);
};
const handleDowngradeAlertClose = () => {
@@ -186,12 +182,12 @@ export const Billing: React.FC = ({ account, teamId }) => {
account={account}
loading={paymentMethodSaving}
loadingText="Verifying payment method"
- onClick={onPaymentMethodOpen}
+ onClick={() => setIsPaymentModalOpen(true)}
/>
),
},
];
- }, [account, onPaymentMethodOpen, paymentMethodSaving, stepsCompleted]);
+ }, [account, paymentMethodSaving, stepsCompleted]);
// FIXME: this entire flow needs to be re-worked
// eslint-disable-next-line no-restricted-syntax
@@ -245,16 +241,16 @@ export const Billing: React.FC = ({ account, teamId }) => {
return (
+
+ setIsPaymentModalOpen(false)}
+ />
+
+
{showSteps ? (
<>
-
-
-
-
>
) : (
<>
@@ -303,7 +299,13 @@ export const Billing: React.FC = ({ account, teamId }) => {
/>
)}
-
+ {
+ setIsPaymentModalOpen(true);
+ }}
+ isPaymentSetup={validPayment}
+ />
);
};