tts/vc pop up signup modal after 2 generations w/ 2 minute local storage ttl

This commit is contained in:
bflatastic committed 2024-08-29 10:56:52 +07:00
1 parent 7a2c5c3fc5
commit ecdf4c51a8
4 files changed
+108 -24

No files matched your search

@@ -80,6 +80,6 @@
}
.fy-modal-scrollable {
overflow-y: scroll;
overflow-y: auto;
}
}
}
@@ -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;
}
@@ -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<HTMLFormElement>) => {
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) {
<div className="d-flex gap-2 align-items-center w-100">
<div className="flex-grow-1">
<Label
label={`${selectedVoice
label={`${
selectedVoice
? t("label.selected")
: t("label.select")
}`}
}`}
/>
</div>
@@ -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<HTMLFormElement>) => {
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) {
<div className="d-flex gap-2 align-items-center w-100">
<div className="flex-grow-1">
<Label
label={`${selectedVoice
? t("label.selected")
: t("label.select")
}`}
label={`${
selectedVoice
? t("label.selected")
: t("label.select")
}`}
/>
</div>