Skip to content

Commit 78cbc41

Browse files
committed
Migrate Billing related components to tailwind/shadcn - Part 1 (#4879)
## Problem solved Short description of the bug fixed or feature added <!-- start pr-codex --> --- ## PR-Codex overview This PR primarily refactors the onboarding and billing components, improving the UI structure and enhancing the modal functionalities. It replaces the `OnboardingTitle` with `TitleAndDescription`, streamlining the code and updating various components for better usability and consistency. ### Detailed summary - Replaced `<OnboardingTitle>` with `<TitleAndDescription>` in several components. - Updated `OnboardingModal` to remove redundant `onClose` props. - Refactored billing alert components to use new UI elements. - Enhanced the layout of forms and alerts for better UX. - Improved state management for modal visibility. - Added new utility functions for account and billing data stubs. - Updated import statements for consistency and clarity. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent 79c50cb commit 78cbc41

File tree

18 files changed

+540
-469
lines changed

18 files changed

+540
-469
lines changed

apps/dashboard/src/components/engine/create/CreateEnginePage.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,7 @@ export const CreateEnginePage = () => {
9393
/>
9494
)}
9595

96-
<OnboardingModal
97-
isOpen={isBillingModalOpen}
98-
onClose={() => setIsBillingModalOpen(false)}
99-
>
96+
<OnboardingModal isOpen={isBillingModalOpen}>
10097
<LazyOnboardingBilling
10198
onSave={async () => {
10299
if (!selectedTier) {

apps/dashboard/src/components/onboarding/ApplyForOpCreditsModal.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,7 @@ export const ApplyForOpCreditsModal: React.FC = () => {
216216
/>
217217
)}
218218
{/* // Add Payment Method Modal */}
219-
<OnboardingModal
220-
isOpen={paymentMethodModalState.isOpen}
221-
onClose={paymentMethodModalState.onClose}
222-
>
219+
<OnboardingModal isOpen={paymentMethodModalState.isOpen}>
223220
<LazyOnboardingBilling
224221
onSave={() => {
225222
setHasAddedPaymentMethod(true);

apps/dashboard/src/components/onboarding/Billing.tsx

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import { accountKeys } from "@3rdweb-sdk/react/cache-keys";
22
import { useUpdateAccount } from "@3rdweb-sdk/react/hooks/useApi";
33
import { useLoggedInUser } from "@3rdweb-sdk/react/hooks/useLoggedInUser";
4-
import { Flex, FocusLock } from "@chakra-ui/react";
54
import { Elements } from "@stripe/react-stripe-js";
65
import { loadStripe } from "@stripe/stripe-js";
76
import { useQueryClient } from "@tanstack/react-query";
87
import { useTrack } from "hooks/analytics/useTrack";
98
import { useTheme } from "next-themes";
109
import { OnboardingPaymentForm } from "./PaymentForm";
11-
import { OnboardingTitle } from "./Title";
10+
import { TitleAndDescription } from "./Title";
1211

1312
// only load stripe if the key is available
1413
const stripePromise = process.env.NEXT_PUBLIC_STRIPE_KEY
@@ -65,40 +64,37 @@ const OnboardingBilling: React.FC<OnboardingBillingProps> = ({
6564
};
6665

6766
return (
68-
<FocusLock>
69-
<Flex flexDir="column" gap={8}>
70-
<OnboardingTitle
71-
heading="Add a payment method"
72-
description="thirdweb is free to get started. Add a payment method to prevent service interruptions when you exceed limits."
67+
<div>
68+
<TitleAndDescription
69+
heading="Add a payment method"
70+
description="thirdweb is free to get started. Add a payment method to prevent service interruptions when you exceed limits."
71+
/>
72+
<div className="h-4" />
73+
<Elements
74+
stripe={stripePromise}
75+
options={{
76+
mode: "setup",
77+
paymentMethodCreation: "manual",
78+
currency: "usd",
79+
paymentMethodConfiguration:
80+
process.env.NEXT_PUBLIC_STRIPE_PAYMENT_METHOD_CFG_ID,
81+
appearance: {
82+
theme: theme === "dark" ? "night" : "stripe",
83+
...appearance,
84+
},
85+
}}
86+
>
87+
<OnboardingPaymentForm
88+
onSave={() => {
89+
queryClient.invalidateQueries({
90+
queryKey: accountKeys.me(user?.address as string),
91+
});
92+
onSave();
93+
}}
94+
onCancel={handleCancel}
7395
/>
74-
<Flex flexDir="column" gap={8}>
75-
<Elements
76-
stripe={stripePromise}
77-
options={{
78-
mode: "setup",
79-
paymentMethodCreation: "manual",
80-
currency: "usd",
81-
paymentMethodConfiguration:
82-
process.env.NEXT_PUBLIC_STRIPE_PAYMENT_METHOD_CFG_ID,
83-
appearance: {
84-
theme: theme === "dark" ? "night" : "stripe",
85-
...appearance,
86-
},
87-
}}
88-
>
89-
<OnboardingPaymentForm
90-
onSave={() => {
91-
queryClient.invalidateQueries({
92-
queryKey: accountKeys.me(user?.address as string),
93-
});
94-
onSave();
95-
}}
96-
onCancel={handleCancel}
97-
/>
98-
</Elements>
99-
</Flex>
100-
</Flex>
101-
</FocusLock>
96+
</Elements>
97+
</div>
10298
);
10399
};
104100

apps/dashboard/src/components/onboarding/ChoosePlan.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ import {
22
AccountPlan,
33
useUpdateAccountPlan,
44
} from "@3rdweb-sdk/react/hooks/useApi";
5-
import { SimpleGrid } from "@chakra-ui/react";
65
import { PricingCard } from "components/homepage/sections/PricingCard";
76
import { useTrack } from "hooks/analytics/useTrack";
8-
import { OnboardingTitle } from "./Title";
7+
import { TitleAndDescription } from "./Title";
98

109
interface OnboardingChoosePlanProps {
1110
onSave: () => void;
@@ -70,11 +69,11 @@ const OnboardingChoosePlan: React.FC<OnboardingChoosePlanProps> = ({
7069

7170
return (
7271
<>
73-
<OnboardingTitle
72+
<TitleAndDescription
7473
heading="Choose your plan"
7574
description="Get started for free with our Starter plan or subscribe to Growth plan to unlock higher rate limits and advanced features."
7675
/>
77-
<SimpleGrid columns={{ base: 1, md: 2 }} gap={8}>
76+
<div className="grid grid-cols-1 gap-8 md:grid-cols-2">
7877
<PricingCard
7978
size="sm"
8079
name={AccountPlan.Free}
@@ -110,7 +109,7 @@ const OnboardingChoosePlan: React.FC<OnboardingChoosePlanProps> = ({
110109
}}
111110
onDashboard
112111
/>
113-
</SimpleGrid>
112+
</div>
114113
</>
115114
);
116115
};

apps/dashboard/src/components/onboarding/ConfirmEmail.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { useForm } from "react-hook-form";
1717
import OtpInput from "react-otp-input";
1818
import { Button, Text } from "tw-components";
1919
import { shortenString } from "utils/usedapp-external";
20-
import { OnboardingTitle } from "./Title";
20+
import { TitleAndDescription } from "./Title";
2121

2222
interface OnboardingConfirmEmailProps {
2323
email: string;
@@ -158,7 +158,7 @@ const OnboardingConfirmEmail: React.FC<OnboardingConfirmEmailProps> = ({
158158

159159
return (
160160
<>
161-
<OnboardingTitle
161+
<TitleAndDescription
162162
heading={
163163
!linking
164164
? "You're almost done! Verify your email."

apps/dashboard/src/components/onboarding/General.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { AccountForm } from "components/settings/Account/AccountForm";
44
import { useState } from "react";
55
import { useActiveWallet, useDisconnect } from "thirdweb/react";
66
import { Button } from "tw-components";
7-
import { OnboardingTitle } from "./Title";
7+
import { TitleAndDescription } from "./Title";
88

99
type OnboardingGeneralProps = {
1010
account: Account;
@@ -34,7 +34,7 @@ const OnboardingGeneral: React.FC<OnboardingGeneralProps> = ({
3434

3535
return (
3636
<FocusLock>
37-
<OnboardingTitle
37+
<TitleAndDescription
3838
heading={
3939
!existing
4040
? "Create your thirdweb account"

apps/dashboard/src/components/onboarding/LinkWallet.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useLoggedInUser } from "@3rdweb-sdk/react/hooks/useLoggedInUser";
33
import { useTrack } from "hooks/analytics/useTrack";
44
import { Button, TrackedLink } from "tw-components";
55
import { shortenString } from "utils/usedapp-external";
6-
import { OnboardingTitle } from "./Title";
6+
import { TitleAndDescription } from "./Title";
77

88
interface OnboardingLinkWalletProps {
99
email: string;
@@ -64,7 +64,7 @@ const OnboardingLinkWallet: React.FC<OnboardingLinkWalletProps> = ({
6464

6565
return (
6666
<>
67-
<OnboardingTitle
67+
<TitleAndDescription
6868
heading="Linking Wallets"
6969
description={
7070
<>
Lines changed: 17 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,34 @@
1-
import {
2-
Flex,
3-
Modal,
4-
ModalBody,
5-
ModalContent,
6-
ModalOverlay,
7-
useBreakpointValue,
8-
} from "@chakra-ui/react";
1+
import { Dialog, DialogContent } from "@/components/ui/dialog";
2+
import { cn } from "@/lib/utils";
93
import { IconLogo } from "components/logo";
104
import type { ComponentWithChildren } from "types/component-with-children";
115

126
interface OnboardingModalProps {
137
isOpen: boolean;
14-
onClose: () => void;
158
wide?: boolean;
169
}
1710

1811
export const OnboardingModal: ComponentWithChildren<OnboardingModalProps> = ({
1912
children,
2013
isOpen,
21-
onClose,
22-
wide = false,
14+
wide,
2315
}) => {
24-
const isMobile = useBreakpointValue({ base: true, md: false });
25-
2616
return (
27-
<Modal
28-
size={isMobile ? "full" : wide ? "3xl" : "lg"}
29-
closeOnEsc={false}
30-
allowPinchZoom
31-
closeOnOverlayClick={false}
32-
isCentered={!isMobile}
33-
isOpen={isOpen}
34-
onClose={onClose}
35-
trapFocus={false}
36-
blockScrollOnMount={false}
37-
>
38-
<ModalOverlay />
39-
<ModalContent className="!bg-background rounded-lg border border-border">
40-
<ModalBody p={8} as={Flex} gap={4} flexDir="column">
41-
<div className="aspect-square w-[40px]">
17+
<Dialog open={isOpen}>
18+
<DialogContent
19+
dialogOverlayClassName="z-[10000]"
20+
className={cn("z-[10001] max-h-[90vh] overflow-auto", {
21+
"!max-w-[768px]": wide,
22+
})}
23+
dialogCloseClassName="hidden"
24+
>
25+
<div className="flex flex-col gap-4">
26+
<div className="w-[40px]">
4227
<IconLogo />
4328
</div>
44-
45-
<Flex flexDir="column" gap={8}>
46-
{children}
47-
</Flex>
48-
</ModalBody>
49-
</ModalContent>
50-
</Modal>
29+
<div className="flex flex-col gap-8">{children}</div>
30+
</div>
31+
</DialogContent>
32+
</Dialog>
5133
);
5234
};

apps/dashboard/src/components/onboarding/PaymentForm.tsx

Lines changed: 24 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1+
import { Spinner } from "@/components/ui/Spinner/Spinner";
2+
import { Alert, AlertTitle } from "@/components/ui/alert";
3+
import { Button } from "@/components/ui/button";
14
import { useCreatePaymentMethod } from "@3rdweb-sdk/react/hooks/useApi";
2-
import {
3-
Alert,
4-
AlertDescription,
5-
AlertIcon,
6-
Flex,
7-
Spinner,
8-
} from "@chakra-ui/react";
95
import {
106
PaymentElement,
117
useElements,
@@ -15,7 +11,6 @@ import { PaymentVerificationFailureAlert } from "components/settings/Account/Bil
1511
import { useErrorHandler } from "contexts/error-handler";
1612
import { useTrack } from "hooks/analytics/useTrack";
1713
import { type FormEvent, useState } from "react";
18-
import { Button, Text } from "tw-components";
1914

2015
interface OnboardingPaymentForm {
2116
onSave: () => void;
@@ -101,69 +96,44 @@ export const OnboardingPaymentForm: React.FC<OnboardingPaymentForm> = ({
10196

10297
return (
10398
<form id="payment-form" onSubmit={handleSubmit}>
104-
<Flex flexDir="column" gap={8}>
99+
<div className="flex flex-col gap-6">
105100
<PaymentElement
106101
onLoaderStart={() => setLoading(false)}
107102
options={{ terms: { card: "never" } }}
108103
/>
109104

110105
{loading ? (
111-
<div className="flex items-center justify-center pb-16">
112-
<Spinner size="sm" />
106+
<div className="flex min-h-[100px] items-center justify-center">
107+
<Spinner className="size-5" />
113108
</div>
114109
) : (
115-
<Flex flexDir="column" gap={4}>
110+
<div className="flex flex-col gap-6">
116111
{paymentFailureCode ? (
117112
<PaymentVerificationFailureAlert
118113
paymentFailureCode={paymentFailureCode}
119114
/>
120115
) : (
121-
<Alert
122-
status="info"
123-
borderRadius="md"
124-
as={Flex}
125-
alignItems="start"
126-
justifyContent="space-between"
127-
variant="left-accent"
128-
bg="inputBg"
129-
>
130-
<div className="flex flex-row">
131-
<AlertIcon boxSize={4} mt={1} ml={1} />
132-
<Flex flexDir="column" gap={1} pl={1}>
133-
<AlertDescription as={Text} fontSize="body.md">
134-
A temporary hold will be placed and immediately released
135-
on your payment method.
136-
</AlertDescription>
137-
</Flex>
138-
</div>
116+
<Alert variant="info">
117+
<AlertTitle className="text-sm">
118+
A temporary hold will be placed and immediately released on
119+
your payment method.
120+
</AlertTitle>
139121
</Alert>
140122
)}
141123

142-
<Button
143-
w="full"
144-
size="lg"
145-
fontSize="md"
146-
colorScheme="blue"
147-
type="submit"
148-
isDisabled={!stripe}
149-
isLoading={saving}
150-
>
151-
Add payment
152-
</Button>
153-
<Button
154-
size="lg"
155-
fontSize="sm"
156-
variant="link"
157-
mt="4"
158-
onClick={onCancel}
159-
isDisabled={saving}
160-
colorScheme="blue"
161-
>
162-
<Text color="blue.500">I&apos;ll do this later</Text>
163-
</Button>
164-
</Flex>
124+
<div className="flex justify-end gap-4">
125+
<Button variant="outline" onClick={onCancel} disabled={saving}>
126+
I'll do this later
127+
</Button>
128+
129+
<Button className="gap-2" type="submit" disabled={!stripe}>
130+
{loading && <Spinner className="size-4" />}
131+
Add payment
132+
</Button>
133+
</div>
134+
</div>
165135
)}
166-
</Flex>
136+
</div>
167137
</form>
168138
);
169139
};

0 commit comments

Comments
 (0)