Skip to content

Commit

Permalink
feat: add Checkout component to Playground (#1428)
Browse files Browse the repository at this point in the history
  • Loading branch information
0xAlec authored Oct 23, 2024
1 parent 83a49dd commit 30c7ad4
Show file tree
Hide file tree
Showing 8 changed files with 309 additions and 26 deletions.
33 changes: 33 additions & 0 deletions playground/nextjs-app-router/components/AppProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { WalletPreference } from './form/wallet-type';
export enum OnchainKitComponent {
Fund = 'fund',
Identity = 'identity',
Checkout = 'checkout',
Swap = 'swap',
SwapDefault = 'swap-default',
Transaction = 'transaction',
Expand All @@ -32,6 +33,16 @@ export type Paymaster = {
enabled: boolean;
};

export type CheckoutOptions = {
chargeId?: string;
productId?: string;
};

export enum CheckoutTypes {
ChargeID = 'chargeId',
ProductID = 'productId',
}

export type ComponentTheme =
| 'base'
| 'cyberpunk'
Expand All @@ -55,6 +66,10 @@ type State = {
setTransactionType?: (transactionType: TransactionTypes) => void;
paymasters?: Record<number, Paymaster>; // paymasters is per network
setPaymaster?: (chainId: number, url: string, enabled: boolean) => void;
checkoutOptions?: CheckoutOptions;
setCheckoutOptions?: (checkoutOptions: CheckoutOptions) => void;
checkoutTypes?: CheckoutTypes;
setCheckoutTypes?: (checkoutTypes: CheckoutTypes) => void;
componentTheme?: ComponentTheme;
setComponentTheme: (theme: ComponentTheme) => void;
componentMode: ComponentMode;
Expand Down Expand Up @@ -83,6 +98,11 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => {
const [transactionType, setTransactionTypeState] = useState<TransactionTypes>(
TransactionTypes.Contracts,
);
const [checkoutOptions, setCheckoutOptionsState] =
useState<CheckoutOptions>();
const [checkoutTypes, setCheckoutTypesState] = useState<CheckoutTypes>(
CheckoutTypes.ProductID,
);
const [paymasters, setPaymastersState] =
useState<Record<number, Paymaster>>();
const [defaultMaxSlippage, setDefaultMaxSlippageState] = useState<number>(3);
Expand Down Expand Up @@ -171,6 +191,15 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => {
setDefaultMaxSlippageState(newDefaultMaxSlippage);
};

const setCheckoutOptions = (checkoutOptions: CheckoutOptions) => {
localStorage.setItem('productId', checkoutOptions.productId || '');
setCheckoutOptionsState(checkoutOptions);
};

const setCheckoutTypes = (checkoutTypes: CheckoutTypes) => {
setCheckoutTypesState(checkoutTypes);
};

const setPaymaster = (chainId: number, url: string, enabled: boolean) => {
const newObj = {
...paymasters,
Expand Down Expand Up @@ -211,6 +240,10 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => {
setComponentTheme,
componentMode,
setComponentMode,
checkoutOptions,
setCheckoutOptions,
checkoutTypes,
setCheckoutTypes,
paymasters,
setPaymaster,
transactionType,
Expand Down
31 changes: 13 additions & 18 deletions playground/nextjs-app-router/components/Demo.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
'use client';
import { AppContext, OnchainKitComponent } from '@/components/AppProvider';
import { Chain } from '@/components/form/chain';
import { ComponentMode } from '@/components/form/component-mode';
import { ComponentTheme } from '@/components/form/component-theme';
import { PaymasterUrl } from '@/components/form/paymaster';
import { SwapConfig } from '@/components/form/swap-config';
import { WalletType } from '@/components/form/wallet-type';
import { useContext, useEffect, useState } from 'react';
import DemoOptions from './DemoOptions';
import CheckoutDemo from './demo/Checkout';
import FundDemo from './demo/Fund';
import IdentityDemo from './demo/Identity';
import SwapDemo from './demo/Swap';
Expand All @@ -15,8 +11,6 @@ import TransactionDemo from './demo/Transaction';
import TransactionDefaultDemo from './demo/TransactionDefault';
import WalletDemo from './demo/Wallet';
import WalletDefaultDemo from './demo/WalletDefault';
import { ActiveComponent } from './form/active-component';
import { TransactionOptions } from './form/transaction-options';

function Demo() {
const { activeComponent } = useContext(AppContext);
Expand Down Expand Up @@ -59,6 +53,10 @@ function Demo() {
return <TransactionDemo />;
}

if (activeComponent === OnchainKitComponent.Checkout) {
return <CheckoutDemo />;
}

if (activeComponent === OnchainKitComponent.Swap) {
return <SwapDemo />;
}
Expand All @@ -85,7 +83,9 @@ function Demo() {
return (
<>
<div
className={`absolute top-0 right-0 bottom-0 left-0 z-20 flex w-full min-w-120 flex-col border-r bg-background p-6 transition-[height] sm:static sm:z-0 sm:w-1/4 ${sideBarVisible ? 'h-full min-h-screen' : 'h-[5rem] overflow-hidden'}`}
className={`absolute top-0 right-0 bottom-0 left-0 z-20 flex w-full min-w-120 flex-col border-r bg-background p-6 transition-[height] sm:static sm:z-0 sm:w-1/4 ${
sideBarVisible ? 'h-full min-h-screen' : 'h-[5rem] overflow-hidden'
}`}
>
<div className="mb-12 flex justify-between">
<div className="self-center font-semibold text-xl">
Expand All @@ -94,7 +94,9 @@ function Demo() {
<button
type="button"
onClick={toggleSidebar}
className={`${buttonStyles} px-1 transition-transform sm:hidden ${sideBarVisible ? '-rotate-90' : 'rotate-90'}`}
className={`${buttonStyles} px-1 transition-transform sm:hidden ${
sideBarVisible ? '-rotate-90' : 'rotate-90'
}`}
>
<span className="pl-2">&rang;</span>
</button>
Expand All @@ -103,14 +105,7 @@ function Demo() {
{isDarkMode ? 'Switch to Light Mode' : 'Switch to Dark Mode'}
</button>
<form className="mt-4 grid gap-8">
<ComponentMode />
<ComponentTheme />
<ActiveComponent />
<WalletType />
<Chain />
<TransactionOptions />
<PaymasterUrl />
<SwapConfig />
<DemoOptions component={activeComponent} />
</form>
<div className="bottom-6 left-6 text-sm sm:absolute">
<a
Expand Down
58 changes: 58 additions & 0 deletions playground/nextjs-app-router/components/DemoOptions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { ComponentMode } from '@/components/form/component-mode';
import { ComponentTheme } from '@/components/form/component-theme';
import { PaymasterUrl } from '@/components/form/paymaster';
import { OnchainKitComponent } from './AppProvider';
import { ActiveComponent } from './form/active-component';
import { Chain } from './form/chain';
import { CheckoutOptions } from './form/checkout-options';
import { SwapConfig } from './form/swap-config';
import { TransactionOptions } from './form/transaction-options';
import { WalletType } from './form/wallet-type';

export default function DemoOptions({
component,
}: {
component?: OnchainKitComponent;
}) {
const commonOptions = (
<>
<ComponentMode />
<ComponentTheme />
<ActiveComponent />
<WalletType />
</>
);

switch (component) {
case OnchainKitComponent.Checkout:
return (
<>
{commonOptions}
<Chain />
<PaymasterUrl />
<CheckoutOptions />
</>
);
case OnchainKitComponent.Swap || OnchainKitComponent.SwapDefault:
return (
<>
{commonOptions}
<Chain />
<PaymasterUrl />
<SwapConfig />
</>
);
case OnchainKitComponent.Transaction ||
OnchainKitComponent.TransactionDefault:
return (
<>
{commonOptions}
<Chain />
<PaymasterUrl />
<TransactionOptions />
</>
);
default:
return commonOptions;
}
}
3 changes: 2 additions & 1 deletion playground/nextjs-app-router/components/OnchainProviders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const config = createConfig({
[base.id]: http(),
[baseSepolia.id]: http(),
},
ssr: true,
connectors: [
coinbaseWallet({
appName: 'OnchainKit',
Expand All @@ -30,7 +31,7 @@ const queryClient = new QueryClient();

function OnchainProviders({ children }: { children: ReactNode }) {
return (
<WagmiProvider config={config} reconnectOnMount={false}>
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<OnchainKitProvider
apiKey={ENVIRONMENT_VARIABLES[ENVIRONMENT.API_KEY]}
Expand Down
95 changes: 95 additions & 0 deletions playground/nextjs-app-router/components/demo/Checkout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { useCapabilities } from '@/lib/hooks';
import {
Checkout,
CheckoutButton,
CheckoutStatus,
} from '@coinbase/onchainkit/checkout';
import type { LifecycleStatus } from '@coinbase/onchainkit/checkout';
import { useCallback, useMemo } from 'react';
import { useContext } from 'react';
import { AppContext, CheckoutTypes } from '../AppProvider';

export default function CheckoutDemo() {
const { checkoutTypes, checkoutOptions } = useContext(AppContext);
const capabilities = useCapabilities();

const chargeIDKey = useMemo(() => {
return `${checkoutOptions?.chargeId}`;
}, [checkoutOptions]);

const productIDKey = useMemo(() => {
return `${checkoutOptions?.productId}`;
}, [checkoutOptions]);

const handleOnStatus = useCallback((status: LifecycleStatus) => {
console.log('Playground.Checkout.onStatus:', status);
}, []);

const createCharge = useCallback(async () => {
return Promise.resolve(checkoutOptions?.chargeId || '');
}, [checkoutOptions]);

const chargeIDDisabled = !checkoutOptions?.chargeId;
const productIDDisabled = !checkoutOptions?.productId;

return (
<div className="mx-auto grid w-1/2 gap-8">
{checkoutTypes === CheckoutTypes.ProductID && (
<>
{checkoutOptions?.productId ? (
<Checkout
key={productIDKey}
productId={checkoutOptions?.productId}
onStatus={handleOnStatus}
isSponsored={capabilities?.paymasterService?.url != null}
>
<CheckoutButton
coinbaseBranded={true}
disabled={productIDDisabled}
/>
<CheckoutStatus />
</Checkout>
) : (
<>
<div className="relative flex h-full w-full flex-col items-center">
<div className="absolute top-0 left-0 z-10 flex h-full w-full flex-col justify-center rounded-xl bg-[#000000] bg-opacity-50 text-center">
<div className="mx-auto w-2/3 rounded-md bg-muted p-6 text-sm">
Enter a Product ID to continue
</div>
</div>
</div>
</>
)}
</>
)}
{checkoutTypes === CheckoutTypes.ChargeID && (
<>
{checkoutOptions?.chargeId ? (
<Checkout
key={chargeIDKey}
chargeHandler={createCharge}
onStatus={handleOnStatus}
isSponsored={capabilities?.paymasterService?.url != null}
>
<CheckoutButton
coinbaseBranded={true}
disabled={chargeIDDisabled}
/>
<CheckoutStatus />
</Checkout>
) : (
<>
<div className="relative flex h-full w-full flex-col items-center">
<div className="absolute top-0 left-0 z-10 flex h-full w-full flex-col justify-center rounded-xl bg-[#000000] bg-opacity-50 text-center">
<div className="mx-auto w-2/3 rounded-md bg-muted p-6 text-sm">
Enter a Charge ID to continue
</div>
</div>
</div>
</>
)}
</>
)}
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export function ActiveComponent() {
<SelectContent>
<SelectItem value={OnchainKitComponent.Fund}>Fund</SelectItem>
<SelectItem value={OnchainKitComponent.Identity}>Identity</SelectItem>
<SelectItem value={OnchainKitComponent.Checkout}>Checkout</SelectItem>
<SelectItem value={OnchainKitComponent.Transaction}>
Transaction
</SelectItem>
Expand Down
Loading

0 comments on commit 30c7ad4

Please sign in to comment.