From b5ed984f058097564b8e80574f00a5142acbb64f Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Mon, 20 Mar 2023 23:24:04 +0000 Subject: [PATCH] feat: add checkout process --- .../components/UpgradeFreeTrial/index.ee.tsx | 20 +++++- packages/web/src/contexts/Paddle.ee.tsx | 72 +++++++++++++++++++ .../src/graphql/queries/get-paddle-info.ee.ts | 10 +++ packages/web/src/hooks/usePaddle.ee.ts | 14 ++++ packages/web/src/hooks/usePaddleInfo.ee.ts | 19 +++++ packages/web/src/index.tsx | 11 +-- 6 files changed, 141 insertions(+), 5 deletions(-) create mode 100644 packages/web/src/contexts/Paddle.ee.tsx create mode 100644 packages/web/src/graphql/queries/get-paddle-info.ee.ts create mode 100644 packages/web/src/hooks/usePaddle.ee.ts create mode 100644 packages/web/src/hooks/usePaddleInfo.ee.ts diff --git a/packages/web/src/components/UpgradeFreeTrial/index.ee.tsx b/packages/web/src/components/UpgradeFreeTrial/index.ee.tsx index 4fca59a0..9a0cfa90 100644 --- a/packages/web/src/components/UpgradeFreeTrial/index.ee.tsx +++ b/packages/web/src/components/UpgradeFreeTrial/index.ee.tsx @@ -16,14 +16,26 @@ import Paper from '@mui/material/Paper'; import LockIcon from '@mui/icons-material/Lock'; import usePaymentPlans from 'hooks/usePaymentPlans.ee'; +import useCurrentUser from 'hooks/useCurrentUser'; +import usePaddle from 'hooks/usePaddle.ee'; export default function UpgradeFreeTrial() { const { plans, loading } = usePaymentPlans(); + const currentUser = useCurrentUser(); + const { loaded: paddleLoaded } = usePaddle(); const [selectedIndex, setSelectedIndex] = React.useState(0); const selectedPlan = plans?.[selectedIndex]; const updateSelection = (index: number) => setSelectedIndex(index); + const handleCheckout = React.useCallback(() => { + window.Paddle.Checkout?.open({ + product: selectedPlan.productId, + email: currentUser.email, + passthrough: JSON.stringify({ id: currentUser.id, email: currentUser.email }) + }) + }, [selectedPlan, currentUser]); + if (loading || !plans.length) return null; return ( @@ -140,7 +152,13 @@ export default function UpgradeFreeTrial() { + VAT if applicable - diff --git a/packages/web/src/contexts/Paddle.ee.tsx b/packages/web/src/contexts/Paddle.ee.tsx new file mode 100644 index 00000000..e4c0d5b7 --- /dev/null +++ b/packages/web/src/contexts/Paddle.ee.tsx @@ -0,0 +1,72 @@ +import * as React from 'react'; + +import useCloud from 'hooks/useCloud'; +import usePaddleInfo from 'hooks/usePaddleInfo.ee'; + +declare global { + interface Window { + Paddle: any; + } +} + +export type PaddleContextParams = { + loaded: boolean; +}; + +export const PaddleContext = + React.createContext({ + loaded: false, + }); + +type PaddleProviderProps = { + children: React.ReactNode; +}; + +export const PaddleProvider = ( + props: PaddleProviderProps +): React.ReactElement => { + const { children } = props; + const isCloud = useCloud(); + const { sandbox, vendorId } = usePaddleInfo(); + const [loaded, setLoaded] = React.useState(false); + + const value = React.useMemo(() => { + return { + loaded, + }; + }, [loaded]); + + React.useEffect(function loadPaddleScript() { + if (!isCloud) return; + + const g = document.createElement('script') + const s = document.getElementsByTagName('script')[0]; + g.src = 'https://cdn.paddle.com/paddle/paddle.js'; + g.defer = true; + g.async = true; + + if (s.parentNode) { + s.parentNode.insertBefore(g, s); + } + + g.onload = function () { + setLoaded(true); + } + }, [isCloud]); + + React.useEffect(function initPaddleScript() { + if (!loaded || !vendorId) return; + + if (sandbox) { + window.Paddle.Environment.set('sandbox'); + } + + window.Paddle.Setup({ vendor: vendorId }); + }, [loaded, sandbox, vendorId]) + + return ( + + {children} + + ); +}; diff --git a/packages/web/src/graphql/queries/get-paddle-info.ee.ts b/packages/web/src/graphql/queries/get-paddle-info.ee.ts new file mode 100644 index 00000000..4e801865 --- /dev/null +++ b/packages/web/src/graphql/queries/get-paddle-info.ee.ts @@ -0,0 +1,10 @@ +import { gql } from '@apollo/client'; + +export const GET_PADDLE_INFO = gql` + query GetPaddleInfo { + getPaddleInfo { + sandbox + vendorId + } + } +`; diff --git a/packages/web/src/hooks/usePaddle.ee.ts b/packages/web/src/hooks/usePaddle.ee.ts new file mode 100644 index 00000000..747f0661 --- /dev/null +++ b/packages/web/src/hooks/usePaddle.ee.ts @@ -0,0 +1,14 @@ +import * as React from 'react'; +import { PaddleContext } from 'contexts/Paddle.ee'; + +type UsePaddleReturn = { + loaded: boolean; +}; + +export default function usePaddle(): UsePaddleReturn { + const paddleContext = React.useContext(PaddleContext); + + return { + loaded: paddleContext.loaded, + }; +} diff --git a/packages/web/src/hooks/usePaddleInfo.ee.ts b/packages/web/src/hooks/usePaddleInfo.ee.ts new file mode 100644 index 00000000..85ff5905 --- /dev/null +++ b/packages/web/src/hooks/usePaddleInfo.ee.ts @@ -0,0 +1,19 @@ +import { useQuery } from '@apollo/client'; + +import { GET_PADDLE_INFO } from 'graphql/queries/get-paddle-info.ee'; + +type UsePaddleInfoReturn = { + sandbox: boolean; + vendorId: string; + loading: boolean; +}; + +export default function usePaddleInfo(): UsePaddleInfoReturn { + const { data, loading } = useQuery(GET_PADDLE_INFO); + + return { + sandbox: data?.getPaddleInfo?.sandbox, + vendorId: data?.getPaddleInfo?.vendorId, + loading + }; +} diff --git a/packages/web/src/index.tsx b/packages/web/src/index.tsx index c2cd7099..bc657214 100644 --- a/packages/web/src/index.tsx +++ b/packages/web/src/index.tsx @@ -6,6 +6,7 @@ import ApolloProvider from 'components/ApolloProvider'; import SnackbarProvider from 'components/SnackbarProvider'; import { AuthenticationProvider } from 'contexts/Authentication'; import { AutomatischInfoProvider } from 'contexts/AutomatischInfo'; +import { PaddleProvider } from 'contexts/Paddle.ee'; import Router from 'components/Router'; import LiveChat from 'components/LiveChat/index.ee'; import routes from 'routes'; @@ -18,11 +19,13 @@ ReactDOM.render( - - {routes} + + + {routes} - - + + +