From ecdf4c51a8786037e3caa3301acf5d08fe86c19e Mon Sep 17 00:00:00 2001 From: bflatastic Date: Thu, 29 Aug 2024 10:56:52 +0700 Subject: [PATCH] tts/vc pop up signup modal after 2 generations w/ 2 minute local storage ttl --- .../providers/ModalProvider/ModalLayer.scss | 4 +- .../fakeyou.com/src/utils/localStorage.ts | 26 +++++++++ .../v2/view/pages/audio_gen/tts/NewTTS.tsx | 49 +++++++++++++---- .../src/v2/view/pages/audio_gen/vc/NewVC.tsx | 53 ++++++++++++++----- 4 files changed, 108 insertions(+), 24 deletions(-) create mode 100644 src/website/packages/fakeyou.com/src/utils/localStorage.ts diff --git a/src/website/packages/fakeyou.com/src/components/providers/ModalProvider/ModalLayer.scss b/src/website/packages/fakeyou.com/src/components/providers/ModalProvider/ModalLayer.scss index 74befd29aa..46ad56bd47 100644 --- a/src/website/packages/fakeyou.com/src/components/providers/ModalProvider/ModalLayer.scss +++ b/src/website/packages/fakeyou.com/src/components/providers/ModalProvider/ModalLayer.scss @@ -80,6 +80,6 @@ } .fy-modal-scrollable { - overflow-y: scroll; + overflow-y: auto; } -} \ No newline at end of file +} diff --git a/src/website/packages/fakeyou.com/src/utils/localStorage.ts b/src/website/packages/fakeyou.com/src/utils/localStorage.ts new file mode 100644 index 0000000000..62d5fd3ba3 --- /dev/null +++ b/src/website/packages/fakeyou.com/src/utils/localStorage.ts @@ -0,0 +1,26 @@ +export function setLocalStorageItem( + key: string, + value: string, + ttl: number +): void { + const now = new Date(); + const item = { + value: value, + expiry: now.getTime() + ttl, + }; + localStorage.setItem(key, JSON.stringify(item)); +} + +export function getLocalStorageItem(key: string): string | null { + const itemStr = localStorage.getItem(key); + if (!itemStr) { + return null; + } + const item = JSON.parse(itemStr); + const now = new Date(); + if (now.getTime() > item.expiry) { + localStorage.removeItem(key); + return null; + } + return item.value; +} diff --git a/src/website/packages/fakeyou.com/src/v2/view/pages/audio_gen/tts/NewTTS.tsx b/src/website/packages/fakeyou.com/src/v2/view/pages/audio_gen/tts/NewTTS.tsx index aa8da424eb..253af0a178 100644 --- a/src/website/packages/fakeyou.com/src/v2/view/pages/audio_gen/tts/NewTTS.tsx +++ b/src/website/packages/fakeyou.com/src/v2/view/pages/audio_gen/tts/NewTTS.tsx @@ -8,7 +8,13 @@ import { Panel, TextArea, } from "components/common"; -import { useDebounce, useInferenceJobs, useLocalize, useModal } from "hooks"; +import { + useDebounce, + useInferenceJobs, + useLocalize, + useModal, + useSession, +} from "hooks"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faDeleteLeft, @@ -33,6 +39,7 @@ import { useTtsStore } from "hooks"; import ExploreTts from "../ExploreVoices"; import { AITools } from "components/marketing"; import VoicePickerPreview from "../VoicePickerPreview"; +import { getLocalStorageItem, setLocalStorageItem } from "utils/localStorage"; interface Props { sessionSubscriptionsWrapper: any; @@ -41,6 +48,7 @@ interface Props { export default function NewTTS({ sessionSubscriptionsWrapper }: Props) { const { enqueueInferenceJob } = useInferenceJobs(); const { modalState, open, close } = useModal(); + const { loggedIn, loggedInOrModal } = useSession(); const [search, searchSet] = useState(""); const [updated, updatedSet] = useState(false); const { selectedVoice, setSelectedVoice, text, setText } = useTtsStore(); @@ -54,10 +62,10 @@ export default function NewTTS({ sessionSubscriptionsWrapper }: Props) { const searchChange = (setUpdate = true) => - ({ target }: { target: any }) => { - if (setUpdate) updatedSet(true); - searchSet(target.value); - }; + ({ target }: { target: any }) => { + if (setUpdate) updatedSet(true); + searchSet(target.value); + }; const handleResultSelect = (data: any) => { setSelectedVoice(data); @@ -112,6 +120,23 @@ export default function NewTTS({ sessionSubscriptionsWrapper }: Props) { const handleSpeak = async (ev: React.FormEvent) => { ev.preventDefault(); + const generationCountKey = "generationCountTTS"; + const promptShownKey = "promptShownTTS"; + const ttl = 2 * 60 * 1000; // 2 minutes in milliseconds + let generationCount = parseInt( + getLocalStorageItem(generationCountKey) || "0" + ); + const promptShown = getLocalStorageItem(promptShownKey); + + // Show sign up prompt after 2 generations, and dont show again until local storage expires + if (!loggedIn && generationCount >= 2 && !promptShown) { + loggedInOrModal({ + loginMessage: "Login to keep your generated audio history", + signupMessage: "Sign up to keep your generated audio history", + }); + setLocalStorageItem(promptShownKey, "true", ttl); + } + if (!selectedVoice || !text) return; setIsGenerating(true); @@ -139,13 +164,16 @@ export default function NewTTS({ sessionSubscriptionsWrapper }: Props) { } catch (error) { // @ts-ignore window.dataLayer.push({ - "event": "enqueue_failure", - "page": "/tts", - "user_id": "$user_id" + event: "enqueue_failure", + page: "/tts", + user_id: "$user_id", }); console.error("Unexpected error:", error); setIsGenerating(false); } + + generationCount += 1; + setLocalStorageItem(generationCountKey, generationCount.toString(), ttl); }; return ( @@ -207,10 +235,11 @@ export default function NewTTS({ sessionSubscriptionsWrapper }: Props) {
diff --git a/src/website/packages/fakeyou.com/src/v2/view/pages/audio_gen/vc/NewVC.tsx b/src/website/packages/fakeyou.com/src/v2/view/pages/audio_gen/vc/NewVC.tsx index a739b5e01c..40d7c694c8 100644 --- a/src/website/packages/fakeyou.com/src/v2/view/pages/audio_gen/vc/NewVC.tsx +++ b/src/website/packages/fakeyou.com/src/v2/view/pages/audio_gen/vc/NewVC.tsx @@ -8,7 +8,13 @@ import { Label, Panel, } from "components/common"; -import { useDebounce, useInferenceJobs, useLocalize, useModal } from "hooks"; +import { + useDebounce, + useInferenceJobs, + useLocalize, + useModal, + useSession, +} from "hooks"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faSearch, @@ -36,6 +42,7 @@ import VCUploadComponent from "./VCUploadComponent"; import VCPitchShiftComponent from "./VCPitchShiftComponent"; import VCPitchEstimateMethodComponent from "./VCPitchEstimateMethodComponent"; import { SessionVoiceConversionResultsList } from "v2/view/_common/SessionVoiceConversionResultsList"; +import { getLocalStorageItem, setLocalStorageItem } from "utils/localStorage"; interface Props { sessionSubscriptionsWrapper: any; @@ -44,6 +51,7 @@ interface Props { export default function NewVC({ sessionSubscriptionsWrapper }: Props) { const { enqueueInferenceJob } = useInferenceJobs(); const { modalState, open, close } = useModal(); + const { loggedIn, loggedInOrModal } = useSession(); const [search, searchSet] = useState(""); const [updated, updatedSet] = useState(false); const { @@ -73,10 +81,10 @@ export default function NewVC({ sessionSubscriptionsWrapper }: Props) { const searchChange = (setUpdate = true) => - ({ target }: { target: any }) => { - if (setUpdate) updatedSet(true); - searchSet(target.value); - }; + ({ target }: { target: any }) => { + if (setUpdate) updatedSet(true); + searchSet(target.value); + }; const handleResultSelect = (data: any) => { setSelectedVoice(data); @@ -144,6 +152,23 @@ export default function NewVC({ sessionSubscriptionsWrapper }: Props) { const handleConvert = async (ev: React.FormEvent) => { ev.preventDefault(); + const generationCountKey = "generationCountVC"; + const promptShownKey = "promptShownVC"; + const ttl = 2 * 60 * 1000; // 2 minutes in milliseconds + let generationCount = parseInt( + getLocalStorageItem(generationCountKey) || "0" + ); + const promptShown = getLocalStorageItem(promptShownKey); + + // Show sign up prompt after 2 generations, and dont show again until local storage expires + if (!loggedIn && generationCount >= 2 && !promptShown) { + loggedInOrModal({ + loginMessage: "Login to keep your generated audio history", + signupMessage: "Sign up to keep your generated audio history", + }); + setLocalStorageItem(promptShownKey, "true", ttl); + } + if (!selectedVoice || !mediaUploadToken) return; setIsGenerating(true); @@ -179,9 +204,9 @@ export default function NewVC({ sessionSubscriptionsWrapper }: Props) { } else { // @ts-ignore window.dataLayer.push({ - "event": "enqueue_failure", - "page": "/voice-conversion", - "user_id": "$user_id" + event: "enqueue_failure", + page: "/voice-conversion", + user_id: "$user_id", }); console.error("Error queuing VC:", "failed to enqueue"); setIsGenerating(false); @@ -190,6 +215,9 @@ export default function NewVC({ sessionSubscriptionsWrapper }: Props) { console.error("Unexpected error:", error); setIsGenerating(false); } + + generationCount += 1; + setLocalStorageItem(generationCountKey, generationCount.toString(), ttl); }; return ( @@ -251,10 +279,11 @@ export default function NewVC({ sessionSubscriptionsWrapper }: Props) {