From 6067bdbb446c7c2c3d8129a387632ce4c44ba115 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 24 Jan 2023 02:54:53 -0500 Subject: [PATCH] Redirect signup to Stripe if plan was selected --- packages/fakeyou.com/package.json | 3 +- .../src/common/BeginStripeCheckoutFlow.ts | 15 ++++++++++ .../src/common/FrontendUrlConfig.ts | 4 +++ .../src/v2/view/pages/premium/PricingPage.tsx | 29 ++++++------------- .../src/v2/view/pages/signup/SignupPage.tsx | 28 ++++++++++++++++-- yarn.lock | 24 +++++++++++++++ 6 files changed, 79 insertions(+), 24 deletions(-) create mode 100644 packages/fakeyou.com/src/common/BeginStripeCheckoutFlow.ts diff --git a/packages/fakeyou.com/package.json b/packages/fakeyou.com/package.json index 3ccc961a85..b31b2c553f 100644 --- a/packages/fakeyou.com/package.json +++ b/packages/fakeyou.com/package.json @@ -32,6 +32,7 @@ "howler": "^2.2.0", "i18next": "^21.6.11", "js-cookie": "^3.0.1", + "query-string": "^8.1.0", "react": "^16.13.1", "react-autocomplete": "^1.8.1", "react-dom": "^16.13.1", @@ -41,10 +42,10 @@ "react-scripts": "5.0.0", "react-select": "^5.7.0", "react-share": "^4.4.1", + "react-wavesurfer.js": "^0.0.8", "sass": "^1.57.1", "typescript": "^3.7.5", "uuid": "^8.3.2", - "react-wavesurfer.js": "^0.0.8", "wavesurfer.js": "^6.4.0" }, "scripts": { diff --git a/packages/fakeyou.com/src/common/BeginStripeCheckoutFlow.ts b/packages/fakeyou.com/src/common/BeginStripeCheckoutFlow.ts new file mode 100644 index 0000000000..bd85790bca --- /dev/null +++ b/packages/fakeyou.com/src/common/BeginStripeCheckoutFlow.ts @@ -0,0 +1,15 @@ +import { CreateStripeCheckoutRedirect, CreateStripeCheckoutRedirectIsError, CreateStripeCheckoutRedirectIsSuccess } from "@storyteller/components/src/api/premium/CreateStripeCheckoutRedirect"; + +// Redirect the user to a stripe checkout page (new users without an existing subscription only!) +// Returns false is the checkout link creation failed. +export async function BeginStripeCheckoutFlow (internal_plan_key: string): Promise { + const response = await CreateStripeCheckoutRedirect(internal_plan_key); + + if (CreateStripeCheckoutRedirectIsSuccess(response)) { + window.location.href = response.stripe_checkout_redirect_url; + return true; + } else if (CreateStripeCheckoutRedirectIsError(response)) { + // TODO + } + return false; +}; diff --git a/packages/fakeyou.com/src/common/FrontendUrlConfig.ts b/packages/fakeyou.com/src/common/FrontendUrlConfig.ts index 7fbb6eef0b..27bef5d090 100644 --- a/packages/fakeyou.com/src/common/FrontendUrlConfig.ts +++ b/packages/fakeyou.com/src/common/FrontendUrlConfig.ts @@ -14,6 +14,10 @@ class FrontendUrlConfig { return '/signup'; } + static signupPageWithPurchaseIntent(pricingPlanKey: string) : string { + return `/signup?sub=${pricingPlanKey}`; + } + // Standalone pages static aboutUsPage(): string { diff --git a/packages/fakeyou.com/src/v2/view/pages/premium/PricingPage.tsx b/packages/fakeyou.com/src/v2/view/pages/premium/PricingPage.tsx index e73bd3a69b..2031999d82 100644 --- a/packages/fakeyou.com/src/v2/view/pages/premium/PricingPage.tsx +++ b/packages/fakeyou.com/src/v2/view/pages/premium/PricingPage.tsx @@ -5,11 +5,6 @@ import { faCheck, faHeart } from "@fortawesome/free-solid-svg-icons"; import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper"; import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper"; import { FAKEYOU_PRICES as FYP } from "../../../../data/PriceTiers"; -import { - CreateStripeCheckoutRedirect, - CreateStripeCheckoutRedirectIsError, - CreateStripeCheckoutRedirectIsSuccess, -} from "@storyteller/components/src/api/premium/CreateStripeCheckoutRedirect"; import { CreateStripePortalRedirect, CreateStripePortalRedirectIsError, @@ -19,6 +14,8 @@ import { motion } from "framer-motion"; import { container, item, panel } from "../../../../data/animation"; import { FakeYouFrontendEnvironment } from "@storyteller/components/src/env/FakeYouFrontendEnvironment"; import { Analytics } from "../../../../common/Analytics"; +import { FrontendUrlConfig } from "../../../../common/FrontendUrlConfig"; +import { BeginStripeCheckoutFlow } from "../../../../common/BeginStripeCheckoutFlow"; interface Props { sessionWrapper: SessionWrapper; @@ -28,18 +25,6 @@ interface Props { function PricingPage(props: Props) { let history = useHistory(); - const beginStripeCheckoutFlow = async ( - internal_plan_key: string - ): Promise => { - const response = await CreateStripeCheckoutRedirect(internal_plan_key); - if (CreateStripeCheckoutRedirectIsSuccess(response)) { - window.location.href = response.stripe_checkout_redirect_url; - } else if (CreateStripeCheckoutRedirectIsError(response)) { - // TODO - } - return false; - }; - const beginStripePortalFlow = async (): Promise => { const response = await CreateStripePortalRedirect(); if (CreateStripePortalRedirectIsSuccess(response)) { @@ -73,14 +58,18 @@ function PricingPage(props: Props) { if (!props.sessionWrapper.isLoggedIn()) { // TODO: This needs to bring the user back to purchase flow. Analytics.premiumBounceToSignup(); - history.push("/signup"); + + const signupUrl = FrontendUrlConfig.signupPageWithPurchaseIntent(internal_plan_key); + history.push(signupUrl); + return false; + } else if (props.sessionSubscriptionsWrapper.hasPaidFeatures()) { Analytics.premiumForwardToStripePortal(); - return await beginStripePortalFlow(); + return await beginStripePortalFlow(); // NB: This redirects the user to Stripe } else { Analytics.premiumForwardToStripeCheckout(); - return await beginStripeCheckoutFlow(internal_plan_key); + return await BeginStripeCheckoutFlow(internal_plan_key); // NB: This redirects the user to Stripe } }; diff --git a/packages/fakeyou.com/src/v2/view/pages/signup/SignupPage.tsx b/packages/fakeyou.com/src/v2/view/pages/signup/SignupPage.tsx index ea3947dfd5..f705b2f6c0 100644 --- a/packages/fakeyou.com/src/v2/view/pages/signup/SignupPage.tsx +++ b/packages/fakeyou.com/src/v2/view/pages/signup/SignupPage.tsx @@ -8,11 +8,14 @@ import { } from "@storyteller/components/src/api/user/CreateAccount"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faUser, faEnvelope, faKey } from "@fortawesome/free-solid-svg-icons"; -import { Link } from "react-router-dom"; +import { Link, useHistory } from "react-router-dom"; import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper"; import { motion } from "framer-motion"; import { container, panel } from "../../../../data/animation"; import { Analytics } from "../../../../common/Analytics"; +import queryString from "query-string"; +import { FrontendUrlConfig } from "../../../../common/FrontendUrlConfig"; +import { BeginStripeCheckoutFlow } from "../../../../common/BeginStripeCheckoutFlow"; enum FieldTriState { EMPTY_FALSE, @@ -26,6 +29,10 @@ interface Props { } function SignupPage(props: Props) { + let history = useHistory(); + + const parsedQueryString = queryString.parse(window.location.search); + const [username, setUsername] = useState(""); const [usernameValid, setUsernameValid] = useState(FieldTriState.EMPTY_FALSE); const [usernameInvalidReason, setUsernameInvalidReason] = useState(""); @@ -234,13 +241,28 @@ function SignupPage(props: Props) { Analytics.accountSignupComplete(); - // TODO: Switch to functional component. - window.location.href = "/pricing"; + let redirectWasSuccessful = await afterSignupRedirect(); + if (!redirectWasSuccessful) { + window.location.href = FrontendUrlConfig.pricingPage(); + } } return false; }; + const afterSignupRedirect = async () => { + const maybeInternalPlanKey = parsedQueryString['sub'] as string | undefined; + + if (maybeInternalPlanKey !== undefined) { + return await BeginStripeCheckoutFlow(maybeInternalPlanKey); + } + + let redirectUrl = FrontendUrlConfig.pricingPage(); + history.push(redirectUrl); + + return true; + } + if (props.sessionWrapper.isLoggedIn()) { return (
diff --git a/yarn.lock b/yarn.lock index c4cb70bdda..71d9dbc837 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5729,6 +5729,11 @@ decode-uri-component@^0.2.0: resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= +decode-uri-component@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.4.1.tgz#2ac4859663c704be22bf7db760a1494a49ab2cc5" + integrity sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ== + dedent@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" @@ -6869,6 +6874,11 @@ filter-obj@^1.1.0: resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" integrity sha1-mzERErxsYSehbgFsbF1/GeCAXFs= +filter-obj@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-5.1.0.tgz#5bd89676000a713d7db2e197f660274428e524ed" + integrity sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng== + finalhandler@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" @@ -11403,6 +11413,15 @@ query-string@^6.13.8: split-on-first "^1.0.0" strict-uri-encode "^2.0.0" +query-string@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-8.1.0.tgz#e7f95367737219544cd360a11a4f4ca03836e115" + integrity sha512-BFQeWxJOZxZGix7y+SByG3F36dA0AbTy9o6pSmKFcFz7DAj0re9Frkty3saBn3nHo3D0oZJ/+rx3r8H8r8Jbpw== + dependencies: + decode-uri-component "^0.4.1" + filter-obj "^5.1.0" + split-on-first "^3.0.0" + querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -12701,6 +12720,11 @@ split-on-first@^1.0.0: resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== +split-on-first@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-3.0.0.tgz#f04959c9ea8101b9b0bbf35a61b9ebea784a23e7" + integrity sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA== + split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"