From d2630a8eb0c639fe75cbb1643528d913e4318994 Mon Sep 17 00:00:00 2001 From: Reed <3893871+dharit-tan@users.noreply.github.com> Date: Sat, 29 Jul 2023 12:51:26 -0400 Subject: [PATCH] [PAY-1589] Wire up Stripe Onramp in mobile (#3814) --- .../common/src/store/account/selectors.ts | 4 + packages/mobile/.env.dev | 2 + packages/mobile/.env.prod | 2 + packages/mobile/.env.stage | 2 + packages/mobile/package-lock.json | 85 ++++++++++++++++++- packages/mobile/package.json | 2 + .../PremiumTrackPurchaseDrawer.tsx | 26 ++---- .../StripePurchaseConfirmationButton.tsx | 66 ++++++++++++++ .../stripe-onramp-embed/StripeOnrampEmbed.tsx | 85 +++++++++++++++++++ .../components/stripe-onramp-embed/index.ts | 1 + .../src/screens/app-screen/AppTabScreen.tsx | 3 + packages/mobile/src/services/buyCrypto.ts | 20 +++++ packages/mobile/src/services/env.ts | 4 +- 13 files changed, 281 insertions(+), 21 deletions(-) create mode 100644 packages/mobile/src/components/premium-track-purchase-drawer/StripePurchaseConfirmationButton.tsx create mode 100644 packages/mobile/src/components/stripe-onramp-embed/StripeOnrampEmbed.tsx create mode 100644 packages/mobile/src/components/stripe-onramp-embed/index.ts create mode 100644 packages/mobile/src/services/buyCrypto.ts diff --git a/packages/common/src/store/account/selectors.ts b/packages/common/src/store/account/selectors.ts index d536caa9bf..2f2c85a1ea 100644 --- a/packages/common/src/store/account/selectors.ts +++ b/packages/common/src/store/account/selectors.ts @@ -63,6 +63,10 @@ export const getAccountProfilePictureSizes = (state: CommonState) => { export const getPlaylistLibrary = (state: CommonState) => { return getAccountUser(state)?.playlist_library ?? null } +export const getAccountERCWallet = createSelector( + [internalGetAccountUser], + (user) => user?.erc_wallet ?? null +) /** * Gets the account and full playlist metadatas. diff --git a/packages/mobile/.env.dev b/packages/mobile/.env.dev index 5aeaa97967..6be6c0ac86 100644 --- a/packages/mobile/.env.dev +++ b/packages/mobile/.env.dev @@ -49,3 +49,5 @@ RECAPTCHA_SITE_KEY=6LfVR-0ZAAAAADFcqNM1P1IafKwQwN0E_l-gxQ9q HCAPTCHA_SITE_KEY=2abe61f1-af6e-4707-be19-a9a4146a9bea OPENSEA_API_URL=https://rinkeby-api.opensea.io/api/v1 + +REACT_APP_STRIPE_CLIENT_PUBLISHABLE_KEY= diff --git a/packages/mobile/.env.prod b/packages/mobile/.env.prod index 0ca8e1d860..e26adb9dc2 100644 --- a/packages/mobile/.env.prod +++ b/packages/mobile/.env.prod @@ -91,3 +91,5 @@ FINGERPRINT_PUBLIC_API_KEY=MNtDQ4NCsNSP7YOkOiQT FINGERPRINT_ENDPOINT=https://fp.audius.co OLD_WEB_APP_STATIC_SERVER_PORT=3100 + +REACT_APP_STRIPE_CLIENT_PUBLISHABLE_KEY=pk_live_51LPsGuCJOWtpH6AEKshlCs3L8QhAfevNvhev8K9a0u92O5ku83KRjLIqCdxgf3NhitdtmMGlw0Wjf33NjZJjZUBz006A3IoSiQ diff --git a/packages/mobile/.env.stage b/packages/mobile/.env.stage index e16890f564..5bc1eab5c7 100644 --- a/packages/mobile/.env.stage +++ b/packages/mobile/.env.stage @@ -76,3 +76,5 @@ FINGERPRINT_PUBLIC_API_KEY=Rz2A3Y5YGSg9K80VgKPi FINGERPRINT_ENDPOINT=https://fp.staging.audius.co OLD_WEB_APP_STATIC_SERVER_PORT=3101 + +REACT_APP_STRIPE_CLIENT_PUBLISHABLE_KEY=pk_test_51LPsGuCJOWtpH6AEZT3Wf2U2xmLZQrEV56yha7HEVTEyhYYVrWCdknml3t4gkSe9Nagd1o9Royy8zL3XEAmRzeHS00xAKTfgpi diff --git a/packages/mobile/package-lock.json b/packages/mobile/package-lock.json index 5172401cc2..016b9758bb 100644 --- a/packages/mobile/package-lock.json +++ b/packages/mobile/package-lock.json @@ -8851,6 +8851,16 @@ } } }, + "@stripe/crypto": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@stripe/crypto/-/crypto-0.0.4.tgz", + "integrity": "sha512-gcD/aG0N90ZrNVppWYf9ADPECptw6PVtF67VIeaFP7fhgd2NvNx8erkzlcvk3VIVSY+bZ6YGX7c7cASoySX74Q==" + }, + "@stripe/stripe-js": { + "version": "1.54.1", + "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-1.54.1.tgz", + "integrity": "sha512-smEXPu1GKMcAj9g2luT16+oXfg2jAwyc68t2Dm5wdtYl3p8PqQaZEiI8tQmboaQAjgF8pIGma6byz1T1vgmpbA==" + }, "@svgr/babel-plugin-add-jsx-attribute": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz", @@ -9740,6 +9750,70 @@ "use-deep-compare-effect": "1.6.1" }, "dependencies": { + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" + }, + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "requires": { + "boolbase": "^1.0.0" + } + }, "react-native-qrcode-svg": { "version": "6.0.6", "resolved": "https://registry.npmjs.org/react-native-qrcode-svg/-/react-native-qrcode-svg-6.0.6.tgz", @@ -9752,7 +9826,16 @@ "react-native-svg": { "version": "12.3.0", "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-12.3.0.tgz", - "integrity": "sha512-ESG1g1j7/WLD7X3XRFTQHVv0r6DpbHNNcdusngAODIxG88wpTWUZkhcM3A2HJTb+BbXTFDamHv7FwtRKWQ/ALg==" + "integrity": "sha512-ESG1g1j7/WLD7X3XRFTQHVv0r6DpbHNNcdusngAODIxG88wpTWUZkhcM3A2HJTb+BbXTFDamHv7FwtRKWQ/ALg==", + "requires": { + "css-select": "^4.2.1", + "css-tree": "^1.0.0-alpha.39" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" } } }, diff --git a/packages/mobile/package.json b/packages/mobile/package.json index 89b9fcd05d..0435fad76b 100644 --- a/packages/mobile/package.json +++ b/packages/mobile/package.json @@ -75,6 +75,8 @@ "@snapchat/snap-kit-react-native": "0.4.0", "@solana-mobile/mobile-wallet-adapter-protocol": "0.9.9", "@solana-mobile/mobile-wallet-adapter-protocol-web3js": "0.9.9", + "@stripe/crypto": "0.0.4", + "@stripe/stripe-js": "1.54.1", "@svgr/core": "5.5.0", "@walletconnect/react-native-dapp": "1.8.0", "array.prototype.flat": "1.2.5", diff --git a/packages/mobile/src/components/premium-track-purchase-drawer/PremiumTrackPurchaseDrawer.tsx b/packages/mobile/src/components/premium-track-purchase-drawer/PremiumTrackPurchaseDrawer.tsx index db9482e174..42cca911eb 100644 --- a/packages/mobile/src/components/premium-track-purchase-drawer/PremiumTrackPurchaseDrawer.tsx +++ b/packages/mobile/src/components/premium-track-purchase-drawer/PremiumTrackPurchaseDrawer.tsx @@ -1,5 +1,3 @@ -import { useCallback } from 'react' - import { cacheTracksSelectors, formatUSDCWeiToUSDString, @@ -9,14 +7,16 @@ import { View } from 'react-native' import { useSelector } from 'react-redux' import IconCart from 'app/assets/images/iconCart.svg' -import { LockedStatusBadge, Text, Button } from 'app/components/core' +import { LockedStatusBadge, Text } from 'app/components/core' import { NativeDrawer } from 'app/components/drawer' import { useDrawer } from 'app/hooks/useDrawer' import { makeStyles, flexRowCentered } from 'app/styles' -import { useThemeColors } from 'app/utils/theme' +import { useColor } from 'app/utils/theme' import { TrackDetailsTile } from '../track-details-tile' +import { StripePurchaseConfirmationButton } from './StripePurchaseConfirmationButton' + const { getTrack } = cacheTracksSelectors const PREMIUM_TRACK_PURCHASE_MODAL_NAME = 'PremiumTrackPurchase' @@ -31,8 +31,7 @@ const messages = { price: (price: string) => `$${price}`, payToUnlock: 'Pay-To-Unlock', disclaimer: - 'By clicking on "Buy", you agree to our Terms of Use. Your purchase will be made in USDC via 3rd party payment provider. Additional payment provider fees may apply. Any remaining USDC balance in your Audius wallet will be applied to this transaction. Once your payment is confirmed, your premium content will be unlocked and available to stream.', - buy: (price: string) => `Buy $${price}` + 'By clicking on "Buy", you agree to our Terms of Use. Your purchase will be made in USDC via 3rd party payment provider. Additional payment provider fees may apply. Any remaining USDC balance in your Audius wallet will be applied to this transaction. Once your payment is confirmed, your premium content will be unlocked and available to stream.' } const useStyles = makeStyles(({ spacing, typography, palette }) => ({ @@ -95,15 +94,11 @@ const useStyles = makeStyles(({ spacing, typography, palette }) => ({ export const PremiumTrackPurchaseDrawer = () => { const styles = useStyles() - const { neutralLight2, specialLightGreen1 } = useThemeColors() + const neutralLight2 = useColor('neutralLight2') const { data } = useDrawer('PremiumTrackPurchase') const { trackId } = data const track = useSelector((state) => getTrack(state, { id: trackId })) - const handleConfirmPress = useCallback(() => { - console.log('buy button pressed') - }, []) - const { premium_conditions: premiumConditions } = track ?? {} if (!track || !isPremiumContentUSDCPurchaseGated(premiumConditions)) @@ -153,14 +148,7 @@ export const PremiumTrackPurchaseDrawer = () => { {messages.disclaimer} -