Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions packages/keychain/src/components/purchase/CostBreakdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
Separator,
Thumbnail,
} from "@cartridge/ui";
import { TOKEN_ICONS } from "@/constants";
import { PricingDetails } from ".";
import { ExternalWalletType } from "@cartridge/controller";
import { FeesTooltip } from "./FeesTooltip";
Expand Down Expand Up @@ -135,13 +136,7 @@ const PaymentType = ({ unit }: { unit?: PaymentUnit }) => {
<CardContent className="flex items-center px-3 bg-background-200 gap-2 rounded-[4px] text-sm font-medium">
<Thumbnail
size="sm"
icon={
unit === "usdc" ? (
"https://static.cartridge.gg/tokens/usdc.svg"
) : (
<CreditIcon />
)
}
icon={unit === "usdc" ? TOKEN_ICONS.USDC : <CreditIcon />}
variant="light"
rounded
/>
Expand Down
18 changes: 12 additions & 6 deletions packages/keychain/src/components/purchase/FeesTooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export const FeesTooltip = ({
defaultOpen?: boolean;
isStripe: boolean;
}) => {
const clientFeePercentage = isStripe ? "8.9%" : "2.5%"; // Combined Stripe + Cartridge or just Cartridge

return (
<TooltipProvider>
<Tooltip defaultOpen={defaultOpen}>
Expand All @@ -26,13 +28,17 @@ export const FeesTooltip = ({
>
<div>Processing Fees:</div>
<Separator className="bg-background-125" />
{isStripe && (
<div className="flex flex-row justify-between text-foreground-300">
Stripe Processing Fee: <div>3.9%</div>
</div>
)}
<div className="flex flex-row justify-between text-foreground-300">
Cartridge Processing Fee: <div>{isStripe ? "5%" : "2.5%"}</div>
<span>Marketplace Fee:</span>
<span>0.00%</span>
</div>
<div className="flex flex-row justify-between text-foreground-300">
<span>Creator Royalties:</span>
<span>0.00%</span>
</div>
<div className="flex flex-row justify-between text-foreground-300">
<span>Client Fee:</span>
<span>{clientFeePercentage}</span>
</div>
</TooltipContent>
</Tooltip>
Expand Down
185 changes: 172 additions & 13 deletions packages/keychain/src/components/purchasenew/review/cost.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,89 @@
import type { Meta, StoryObj } from "@storybook/react";

import { CostBreakdown } from "./cost";
import { PurchaseProvider } from "@/context";
import { WalletType } from "@cartridge/ui";
import { PurchaseContext } from "@/context/purchase";
import { ItemType, type Item } from "@/context";
import type { PurchaseContextType } from "@/context";
import { TOKEN_ICONS } from "@/constants";

// Mock context with purchase items
const MockPurchaseProvider = ({
children,
purchaseItems = [],
layerswapFees,
}: {
children: React.ReactNode;
purchaseItems?: Item[];
layerswapFees?: string;
}) => {
const mockContext: PurchaseContextType = {
usdAmount: 100,
purchaseItems,
claimItems: [],
layerswapFees,
isFetchingFees: false,
selectedPlatform: "ethereum",
stripePromise: Promise.resolve(null),
isStripeLoading: false,
isDepositLoading: false,
isStarterpackLoading: false,
clearError: () => {},
clearSelectedWallet: () => {},
availableTokens: [],
convertedPrice: null,
swapQuote: null,
isFetchingConversion: false,
conversionError: null,
setUsdAmount: () => {},
setDepositAmount: () => {},
setStarterpackId: () => {},
setClaimItems: () => {},
setTransactionHash: () => {},
setSelectedToken: () => {},
onCreditCardPurchase: async () => {},
onBackendCryptoPurchase: async () => {},
onOnchainPurchase: async () => {},
onExternalConnect: async () => undefined,
waitForDeposit: async () => true,
fetchFees: async () => {},
};

return (
<PurchaseContext.Provider value={mockContext}>
{children}
</PurchaseContext.Provider>
);
};

// Extend the component args to include mock data
type StoryArgs = React.ComponentProps<typeof CostBreakdown> & {
mockPurchaseItems?: Item[];
mockLayerswapFees?: string;
};

const meta: Meta<typeof CostBreakdown> = {
const meta: Meta<StoryArgs> = {
component: CostBreakdown,
parameters: {
layout: "centered",
},
decorators: [
(Story) => (
<PurchaseProvider>
<div className="w-[400px]">
<Story />
</div>
</PurchaseProvider>
),
(Story, { args }) => {
return (
<MockPurchaseProvider
purchaseItems={args.mockPurchaseItems || []}
layerswapFees={args.mockLayerswapFees}
>
<div className="w-[400px]">
<Story />
</div>
</MockPurchaseProvider>
);
},
],
};

export default meta;

type Story = StoryObj<typeof meta>;
type Story = StoryObj<StoryArgs>;

export const WithoutFee: Story = {
args: {
Expand All @@ -32,6 +93,22 @@ export const WithoutFee: Story = {
totalInCents: 1000,
},
rails: "stripe",
mockPurchaseItems: [
{
title: "Adventurer #8",
subtitle: "Adventurers",
icon: TOKEN_ICONS.LORDS,
value: 5.0,
type: ItemType.NFT,
},
{
title: "Adventurer #12",
subtitle: "Adventurers",
icon: TOKEN_ICONS.LORDS,
value: 5.0,
type: ItemType.NFT,
},
],
},
};

Expand All @@ -43,7 +120,16 @@ export const WithCartridgeFee: Story = {
totalInCents: 1025,
},
rails: "crypto",
walletType: WalletType.Controller,
walletType: "metamask",
mockPurchaseItems: [
{
title: "1000 Credits",
subtitle: "Game Credits",
icon: TOKEN_ICONS.CREDITS,
value: 10.0,
type: ItemType.CREDIT,
},
],
},
};

Expand All @@ -55,5 +141,78 @@ export const WithStripeFee: Story = {
totalInCents: 1089,
},
rails: "stripe",
mockPurchaseItems: [
{
title: "Starter Pack #1",
subtitle: "Loot Survivor",
icon: TOKEN_ICONS.LORDS,
value: 8.0,
type: ItemType.NFT,
},
{
title: "500 Credits",
subtitle: "Game Credits",
icon: TOKEN_ICONS.CREDITS,
value: 2.0,
type: ItemType.CREDIT,
},
],
},
};

export const WithLayerswapFee: Story = {
args: {
costDetails: {
baseCostInCents: 2500,
processingFeeInCents: 62,
totalInCents: 2562,
},
rails: "crypto",
walletType: "metamask",
mockPurchaseItems: [
{
title: "Premium Pack",
subtitle: "Realms World",
icon: TOKEN_ICONS.LORDS,
value: 15.0,
type: ItemType.NFT,
},
{
title: "Building Materials",
subtitle: "Resources",
icon: TOKEN_ICONS.STRK,
value: 10.0,
type: ItemType.ERC20,
},
],
mockLayerswapFees: "2500000", // $2.50 in wei
},
};

export const WithTooltipOpen: Story = {
args: {
costDetails: {
baseCostInCents: 1500,
processingFeeInCents: 134,
totalInCents: 1634,
},
rails: "stripe",
openFeesTooltip: true,
mockPurchaseItems: [
{
title: "Epic Sword",
subtitle: "Weapons",
icon: TOKEN_ICONS.ETH,
value: 12.0,
type: ItemType.NFT,
},
{
title: "Magic Potion x3",
subtitle: "Consumables",
icon: TOKEN_ICONS.STRK,
value: 3.0,
type: ItemType.ERC20,
},
],
},
};
Loading
Loading