From 9d7c056750f7d69d8b48e9434b480234f7b99701 Mon Sep 17 00:00:00 2001 From: Rob Gordon Date: Sun, 15 Sep 2024 07:44:48 -0400 Subject: [PATCH 1/2] Fix Experiment (#739) --- app/package.json | 2 +- app/src/components/ConvertToFlowchart.tsx | 2 - app/src/components/Layout.tsx | 8 ++-- app/src/components/PaywallModal.tsx | 5 ++- app/src/lib/getAIPaywallCopy.experiment.ts | 33 ---------------- app/src/lib/useGetAIPaywallCopy.experiment.ts | 38 +++++++++++++++++++ app/src/lib/usePromptStore.ts | 7 +++- pnpm-lock.yaml | 10 ++--- 8 files changed, 58 insertions(+), 47 deletions(-) delete mode 100644 app/src/lib/getAIPaywallCopy.experiment.ts create mode 100644 app/src/lib/useGetAIPaywallCopy.experiment.ts diff --git a/app/package.json b/app/package.json index dcea6613..5003e0a2 100644 --- a/app/package.json +++ b/app/package.json @@ -99,7 +99,7 @@ "papaparse": "^5.4.1", "phosphor-react": "^1.3.1", "postcss-flexbugs-fixes": "^5.0.2", - "posthog-js": "^1.150.0", + "posthog-js": "^1.161.3", "prettier": "^2.3.1", "re-resizable": "^6.9.0", "react": "^18.2.0", diff --git a/app/src/components/ConvertToFlowchart.tsx b/app/src/components/ConvertToFlowchart.tsx index ade61d56..4655e82d 100644 --- a/app/src/components/ConvertToFlowchart.tsx +++ b/app/src/components/ConvertToFlowchart.tsx @@ -15,7 +15,6 @@ import { AppContext } from "./AppContextProvider"; import { isError } from "../lib/helpers"; import { useHasProAccess } from "../lib/hooks"; import { showPaywall } from "../lib/usePaywallModalStore"; -import { getAIPaywallCopy } from "../lib/getAIPaywallCopy.experiment"; export function ConvertToFlowchart() { const convertIsRunning = usePromptStore((s) => s.isRunning); @@ -34,7 +33,6 @@ export function ConvertToFlowchart() { content: t`Uh oh, you're out of free requests! Upgrade to Flowchart Fun Pro for unlimited diagram conversions, and keep transforming text into clear, visual flowcharts as easily as copy and paste.`, imgUrl: "/images/ai-convert.png", toPricingCode: "ConvertToFlowchart", - buttonText: getAIPaywallCopy(), }); } else { if (error.message === RATE_LIMIT_EXCEEDED) { diff --git a/app/src/components/Layout.tsx b/app/src/components/Layout.tsx index a2ca2144..325e8483 100644 --- a/app/src/components/Layout.tsx +++ b/app/src/components/Layout.tsx @@ -1,6 +1,6 @@ import cx from "classnames"; import { X } from "phosphor-react"; -import { memo, ReactNode, Suspense } from "react"; +import { lazy, memo, ReactNode, Suspense } from "react"; import { Link } from "react-router-dom"; import { useFullscreen, useIsEditorView } from "../lib/hooks"; @@ -10,7 +10,7 @@ import { Header } from "./Header"; import styles from "./Layout.module.css"; import Loading from "./Loading"; import { VersionCheck } from "./VersionCheck"; -import { PaywallModal } from "./PaywallModal"; +const PaywallModal = lazy(() => import("./PaywallModal")); const Layout = memo(({ children }: { children: ReactNode }) => { const isFullscreen = useFullscreen(); @@ -49,7 +49,9 @@ const Layout = memo(({ children }: { children: ReactNode }) => { - + + + ); }); diff --git a/app/src/components/PaywallModal.tsx b/app/src/components/PaywallModal.tsx index fe5c28c9..486d5e5d 100644 --- a/app/src/components/PaywallModal.tsx +++ b/app/src/components/PaywallModal.tsx @@ -5,8 +5,9 @@ import { Trans } from "@lingui/macro"; import { Button2 } from "../ui/Shared"; import { useNavigate } from "react-router-dom"; import { usePaywallModalStore } from "../lib/usePaywallModalStore"; +import { usePostHog } from "posthog-js/react"; -export function PaywallModal() { +export default function PaywallModal() { const navigate = useNavigate(); const open = usePaywallModalStore((s) => s.open); const title = usePaywallModalStore((s) => s.title); @@ -15,6 +16,7 @@ export function PaywallModal() { const imgUrl = usePaywallModalStore((s) => s.imgUrl); const toPricingCode = usePaywallModalStore((s) => s.toPricingCode); const buttonText = usePaywallModalStore((s) => s.buttonText); + const posthog = usePostHog(); return ( { + posthog.capture("clicked-paywall-button"); navigate("/pricing"); }} > diff --git a/app/src/lib/getAIPaywallCopy.experiment.ts b/app/src/lib/getAIPaywallCopy.experiment.ts deleted file mode 100644 index 3f83fd2d..00000000 --- a/app/src/lib/getAIPaywallCopy.experiment.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { t } from "@lingui/macro"; -import { posthog } from "posthog-js"; - -type Variant = - | "unlimited-yearly" - | "join-creators" - | "boost-productivity" - | "anytime-yearly" - | "users-love" - | "unlock-unlimited"; - -/** - * Returns the copy for the button on the AI paywall modal - */ -export function getAIPaywallCopy(): string | undefined { - const variant = posthog.getFeatureFlag( - "ai-paywall-copy-conversion" - ) as Variant; - switch (variant) { - case "unlimited-yearly": - return t`Unlimited AI Flowcharts: $2/mo (billed yearly)`; - case "join-creators": - return t`Join 5,000+ AI Flowchart Creators. $4/mo`; - case "boost-productivity": - return t`Unlimited AI Flowcharts - Boost Productivity Now`; - case "anytime-yearly": - return t`AI Flowcharts Anytime - $2/mo (billed yearly)`; - case "users-love": - return t`5,000+ Users Love AI Flowcharts - Join Now`; - case "unlock-unlimited": - return t`Unlock Unlimited AI Flowcharts`; - } -} diff --git a/app/src/lib/useGetAIPaywallCopy.experiment.ts b/app/src/lib/useGetAIPaywallCopy.experiment.ts new file mode 100644 index 00000000..208ab94f --- /dev/null +++ b/app/src/lib/useGetAIPaywallCopy.experiment.ts @@ -0,0 +1,38 @@ +import { t } from "@lingui/macro"; +import { usePostHog } from "posthog-js/react"; +import { useCallback } from "react"; + +type Variant = + | "unlimited-yearly" + | "join-creators" + | "boost-productivity" + | "anytime-yearly" + | "users-love" + | "unlock-unlimited"; + +/** + * Returns the copy for the button on the AI paywall modal + */ +export function useGetAIPaywallCopy() { + const posthog = usePostHog(); + return useCallback(() => { + const variant = posthog.featureFlags.getFeatureFlag( + "ai-paywall-copy-conversion" + ) as Variant; + + switch (variant) { + case "unlimited-yearly": + return t`Unlimited AI Flowcharts: $2/mo (billed yearly)`; + case "join-creators": + return t`Join 5,000+ AI Flowchart Creators. $4/mo`; + case "boost-productivity": + return t`Unlimited AI Flowcharts - Boost Productivity Now`; + case "anytime-yearly": + return t`AI Flowcharts Anytime - $2/mo (billed yearly)`; + case "users-love": + return t`5,000+ Users Love AI Flowcharts - Join Now`; + case "unlock-unlimited": + return t`Unlock Unlimited AI Flowcharts`; + } + }, [posthog.featureFlags]); +} diff --git a/app/src/lib/usePromptStore.ts b/app/src/lib/usePromptStore.ts index f96fa63f..6e69f623 100644 --- a/app/src/lib/usePromptStore.ts +++ b/app/src/lib/usePromptStore.ts @@ -10,6 +10,7 @@ import { AppContext } from "../components/AppContextProvider"; import { unfreezeDoc } from "./useIsFrozen"; import { useDoc } from "./useDoc"; import { repairText } from "./repairText"; +import { useGetAIPaywallCopy } from "./useGetAIPaywallCopy.experiment"; export type Mode = "prompt" | "convert" | "edit"; type PromptStore = { @@ -90,17 +91,19 @@ export function useRunAiWithStore() { const hasProAccess = useHasProAccess(); const customer = useContext(AppContext).customer; const sid = customer?.subscription?.id; + const getAIPaywallCopy = useGetAIPaywallCopy(); const handleError = useCallback( (error: Error) => { if (!hasProAccess && error.message === RATE_LIMIT_EXCEEDED) { + const buttonText = getAIPaywallCopy(); // Show paywall showPaywall({ title: t`Get Unlimited AI Requests`, content: t`You've used all your free AI conversions. Upgrade to Pro for unlimited AI use, custom themes, private sharing, and more. Keep creating amazing flowcharts effortlessly!`, movieUrl: "/images/ai-convert.mp4", toPricingCode: "ConvertToFlowchart", - buttonText: t`Upgrade for Unlimited AI`, + buttonText, }); } else { if (error.message === RATE_LIMIT_EXCEEDED) { @@ -110,7 +113,7 @@ export function useRunAiWithStore() { } } }, - [hasProAccess] + [getAIPaywallCopy, hasProAccess] ); return useCallback(() => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e3f31ae0..2d6d122d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -340,8 +340,8 @@ importers: specifier: ^5.0.2 version: 5.0.2(postcss@8.4.31) posthog-js: - specifier: ^1.150.0 - version: 1.150.0 + specifier: ^1.161.3 + version: 1.161.3 prettier: specifier: ^2.3.1 version: 2.7.1 @@ -9915,8 +9915,8 @@ packages: resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==} engines: {node: ^10 || ^12 || >=14} - posthog-js@1.150.0: - resolution: {integrity: sha512-oTbMtVX8dsBlZrJ3/6P6l3Ivs14Q3i454Ly1Y0DfZDoxT67OMRc791uQ0rm2VCVxVGwpy7LYz+0VB14/rfrbOw==} + posthog-js@1.161.3: + resolution: {integrity: sha512-TQ77jtLemkUJUyJAPrwGay6tLqcAmXEM1IJgXOx5Tr4UohiTx8JTznzrCuh/SdwPIrbcSM1r2YPwb72XwTC3wg==} posthtml-parser@0.10.2: resolution: {integrity: sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==} @@ -23397,7 +23397,7 @@ snapshots: picocolors: 1.0.1 source-map-js: 1.2.0 - posthog-js@1.150.0: + posthog-js@1.161.3: dependencies: fflate: 0.4.8 preact: 10.20.2 From 358ed0a9be3e991818c740745886de56b4f517c5 Mon Sep 17 00:00:00 2001 From: Rob Gordon Date: Sun, 15 Sep 2024 07:45:41 -0400 Subject: [PATCH 2/2] chore: fix version --- app/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/package.json b/app/package.json index 5003e0a2..0ee7979b 100644 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "app", - "version": "1.57.3", + "version": "1.57.4", "main": "module/module.js", "license": "MIT", "scripts": {