Skip to content

Commit

Permalink
chore: add onramp message and disable apple pay on desktop (#1785)
Browse files Browse the repository at this point in the history
Co-authored-by: Alissa Crane <alissa.crane@coinbase.com>
  • Loading branch information
abcrane123 and alissacrane-cb authored Dec 20, 2024
1 parent e579527 commit bfe044d
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 20 deletions.
6 changes: 3 additions & 3 deletions src/buy/components/BuyDropdown.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ describe('BuyDropdown', () => {
(openPopup as Mock).mockReturnValue('popup');
render(<BuyDropdown />);

const onrampButton = screen.getByTestId('ock-applePayOnrampItem');
const onrampButton = screen.getByTestId('ock-coinbasePayOnrampItem');

act(() => {
fireEvent.click(onrampButton);
Expand Down Expand Up @@ -106,12 +106,12 @@ describe('BuyDropdown', () => {
render(<BuyDropdown />);

// Find and click the first BuyOnrampItem button
const buyButton = screen.getByTestId('ock-applePayOnrampItem');
const buyButton = screen.getByTestId('ock-coinbasePayOnrampItem');
fireEvent.click(buyButton);

expect(openPopup).toHaveBeenCalledWith(
expect.objectContaining({
url: 'https://pay.coinbase.com/buy/one-click?appId=mock-project-id&addresses={"0xMockAddress":["base"]}&assets=["DEGEN"]&presetCryptoAmount=0.5&defaultPaymentMethod=APPLE_PAY',
url: 'https://pay.coinbase.com/buy/one-click?appId=mock-project-id&addresses={"0xMockAddress":["base"]}&assets=["DEGEN"]&presetCryptoAmount=0.5&defaultPaymentMethod=CRYPTO_ACCOUNT',
}),
);
});
Expand Down
7 changes: 7 additions & 0 deletions src/buy/components/BuyDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { ONRAMP_BUY_URL } from '../../fund/constants';
import { getFundingPopupSize } from '../../fund/utils/getFundingPopupSize';
import { background, border, cn, color, text } from '../../styles/theme';
import { ONRAMP_PAYMENT_METHODS } from '../constants';
import { isApplePaySupported } from '../utils/isApplePaySupported';
import { BuyOnrampItem } from './BuyOnrampItem';
import { useBuyContext } from './BuyProvider';
import { BuyTokenItem } from './BuyTokenItem';
Expand Down Expand Up @@ -74,6 +75,8 @@ export function BuyDropdown() {
};
}, [setIsDropdownOpen]);

const isApplePayEnabled = isApplePaySupported();

return (
<div
className={cn(
Expand All @@ -90,13 +93,17 @@ export function BuyDropdown() {
{showFromToken && <BuyTokenItem swapUnit={from} />}

{ONRAMP_PAYMENT_METHODS.map((method) => {
if (method.id === 'APPLE_PAY' && !isApplePayEnabled) {
return null;
}
return (
<BuyOnrampItem
key={method.id}
name={method.name}
description={method.description}
onClick={handleOnrampClick(method.id)}
icon={method.icon}
amountUSDC={to?.amountUSD}
/>
);
})}
Expand Down
15 changes: 8 additions & 7 deletions src/buy/components/BuyOnrampItem.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ describe('BuyOnrampItem', () => {
description="Fast and secure payments."
onClick={mockOnClick}
icon="applePay"
amountUSDC="5"
/>,
);

Expand All @@ -47,6 +48,7 @@ describe('BuyOnrampItem', () => {
description="Use your card to pay."
onClick={mockOnClick}
icon="creditCard"
amountUSDC="5"
/>,
);

Expand All @@ -60,6 +62,7 @@ describe('BuyOnrampItem', () => {
description="Pay using your Coinbase account."
onClick={mockOnClick}
icon="coinbasePay"
amountUSDC="5"
/>,
);

Expand All @@ -77,6 +80,7 @@ describe('BuyOnrampItem', () => {
description="Fast and secure payments."
onClick={mockOnClick}
icon="applePay"
amountUSDC="5"
/>,
);

Expand All @@ -85,21 +89,18 @@ describe('BuyOnrampItem', () => {
expect(button).toHaveAttribute('type', 'button');
});

it('should show overlay on mouse enter', () => {
const { getByTestId, getByText, queryByText } = render(
it('should disables and shows message if amount is less than 5', () => {
const { getByText, queryByText } = render(
<BuyOnrampItem
name="Apple Pay"
description="Fast and secure payments."
onClick={mockOnClick}
icon="applePay"
amountUSDC=".4"
/>,
);

fireEvent.mouseEnter(getByTestId('ockBuyApplePayInfo'));

expect(getByText('Only on mobile and Safari')).toBeInTheDocument();

fireEvent.mouseLeave(getByTestId('ockBuyApplePayInfo'));
expect(getByText('Minimum purchase amount is $5')).toBeInTheDocument();

expect(queryByText('Only on mobile and Safari')).toBeNull();
});
Expand Down
29 changes: 19 additions & 10 deletions src/buy/components/BuyOnrampItem.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Tooltip } from '@/ui-react/internal/components/Tooltip';
import { useCallback } from 'react';
import { useCallback, useMemo } from 'react';
import { appleSvg } from '../../internal/svg/appleSvg';
import { cardSvg } from '../../internal/svg/cardSvg';
import { coinbaseLogoSvg } from '../../internal/svg/coinbaseLogoSvg';
import { cn, color, text } from '../../styles/theme';
import { cn, color, pressable, text } from '../../styles/theme';
import { useBuyContext } from './BuyProvider';

type OnrampItemReact = {
Expand All @@ -12,6 +11,7 @@ type OnrampItemReact = {
onClick: () => void;
svg?: React.ReactNode;
icon: string;
amountUSDC?: string;
};

const ONRAMP_ICON_MAP: Record<string, React.ReactNode> = {
Expand All @@ -25,6 +25,7 @@ export function BuyOnrampItem({
description,
onClick,
icon,
amountUSDC,
}: OnrampItemReact) {
const { setIsDropdownOpen } = useBuyContext();

Expand All @@ -33,30 +34,38 @@ export function BuyOnrampItem({
onClick();
}, [onClick, setIsDropdownOpen]);

// Debit and Apple Pay have a minimum purchase amount of $5
const isDisabled =
!amountUSDC || (Number.parseFloat(amountUSDC) < 5 && name !== 'Coinbase');

const message = useMemo(() => {
if (isDisabled) {
return 'Minimum purchase amount is $5';
}
return description;
}, [isDisabled, description]);

return (
<button
className={cn(
'flex items-center gap-2 rounded-lg p-2',
'hover:bg-[var(--ock-bg-inverse)]',
text.label2,
!isDisabled && pressable.default,
isDisabled && color.foregroundMuted,
)}
onClick={handleClick}
type="button"
data-testid={`ock-${icon}OnrampItem`}
disabled={isDisabled}
>
<div className="flex h-9 w-9 items-center justify-center">
{ONRAMP_ICON_MAP[icon]}
</div>
<div className="flex flex-col items-start">
<div className="relative flex items-center gap-1">
<div>{name}</div>
{name === 'Apple Pay' && (
<Tooltip content="Only on mobile and Safari" />
)}
</div>
<div className={cn('text-xs', color.foregroundMuted)}>
{description}
</div>
<div className={cn('text-xs', color.foregroundMuted)}>{message}</div>
</div>
</button>
);
Expand Down
63 changes: 63 additions & 0 deletions src/buy/utils/isApplePaySupported.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { afterEach, describe, expect, it } from 'vitest';
import { isApplePaySupported } from './isApplePaySupported';

describe('isApplePaySupported', () => {
const originalUserAgent = navigator.userAgent;

afterEach(() => {
Object.defineProperty(navigator, 'userAgent', {
value: originalUserAgent,
configurable: true,
});
});

it('should return true for iPhone', () => {
Object.defineProperty(navigator, 'userAgent', {
value:
'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1',
configurable: true,
});

expect(isApplePaySupported()).toBe(true);
});

it('should return true for Safari on macOS', () => {
Object.defineProperty(navigator, 'userAgent', {
value:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Safari/605.1.15',
configurable: true,
});

expect(isApplePaySupported()).toBe(true);
});

it('should return false for Chrome on macOS', () => {
Object.defineProperty(navigator, 'userAgent', {
value:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36',
configurable: true,
});

expect(isApplePaySupported()).toBe(false);
});

it('should return false for Edge on macOS', () => {
Object.defineProperty(navigator, 'userAgent', {
value:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.67',
configurable: true,
});

expect(isApplePaySupported()).toBe(false);
});

it('should return false for non-Apple devices', () => {
Object.defineProperty(navigator, 'userAgent', {
value:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36',
configurable: true,
});

expect(isApplePaySupported()).toBe(false);
});
});
8 changes: 8 additions & 0 deletions src/buy/utils/isApplePaySupported.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export function isApplePaySupported() {
return (
/iPhone|iPad|iPod/.test(navigator.userAgent) ||
(/Safari/.test(navigator.userAgent) &&
!/Chrome/.test(navigator.userAgent) &&
!/Edg/.test(navigator.userAgent))
);
}

0 comments on commit bfe044d

Please sign in to comment.