mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-14 22:02:36 +00:00
Begin tracking more events
This commit is contained in:
1 parent
f5fec15b01
commit
59a8b16db5
5 files changed
+96
-7
No files matched your search
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Send Analytics to Google Analytics.
|
||||
*
|
||||
* Keeping track of events in a singular space lets us easily update them and keep track of what we're analyzing at a high level.
|
||||
*
|
||||
* Currently we use Universal Analytics (UA), but support for that ends July 2023. We need to update to Google Analytics 4 (GA4).
|
||||
*
|
||||
* Here is some reading material:
|
||||
* - [Events usage in UA - really good resource on how to bucket events](https://support.google.com/analytics/answer/1033068)
|
||||
* - [GTag events for multiple Google products: UA, GA4, etc.](https://developers.google.com/tag-platform/devguides/events)
|
||||
* - [Sending events to both UA and GA4](https://support.google.com/analytics/answer/11091026)
|
||||
*/
|
||||
class Analytics {
|
||||
|
||||
// ========== USER ==========
|
||||
|
||||
static accountSignupAttempt() {
|
||||
Analytics.sendCategorizedEvent('account', 'signup_attempt');
|
||||
}
|
||||
|
||||
static accountSignupComplete() {
|
||||
Analytics.sendCategorizedEvent('account', 'signup_complete');
|
||||
}
|
||||
|
||||
static accountLoginAttempt() {
|
||||
Analytics.sendCategorizedEvent('account', 'login_attempt');
|
||||
}
|
||||
|
||||
static accountLoginSuccess() {
|
||||
Analytics.sendCategorizedEvent('account', 'login_success');
|
||||
}
|
||||
|
||||
// ========== PREMIUM ==========
|
||||
|
||||
static premiumForwardToStripeCheckout() {
|
||||
Analytics.sendCategorizedEvent('premium', 'forward_to_stripe_checkout');
|
||||
}
|
||||
|
||||
static premiumForwardToStripePortal() {
|
||||
Analytics.sendCategorizedEvent('premium', 'forward_to_stripe_portal');
|
||||
}
|
||||
|
||||
|
||||
static premiumBounceToSignup() {
|
||||
Analytics.sendCategorizedEvent('premium', 'bounce_to_signup');
|
||||
}
|
||||
|
||||
|
||||
// ========== TTS ==========
|
||||
|
||||
static ttsGenerate(modelToken: string, ttsLength: number) {
|
||||
Analytics.sendCategorizedEvent('TTS', 'generate_tts', modelToken, ttsLength);
|
||||
}
|
||||
|
||||
static ttsClear(modelToken?: string) {
|
||||
Analytics.sendCategorizedEvent('TTS', 'clear', modelToken);
|
||||
}
|
||||
|
||||
// ========== (impl) ==========
|
||||
|
||||
private static sendEvent(actionName: string, eventLabel?: string, value?: number) {
|
||||
gtag('event', actionName, {
|
||||
'event_category': undefined,
|
||||
'event_label': eventLabel,
|
||||
'value': value,
|
||||
});
|
||||
}
|
||||
|
||||
private static sendCategorizedEvent(eventCategory: string, actionName: string, eventLabel?: string, value?: number) {
|
||||
gtag('event', actionName, {
|
||||
'event_category': eventCategory,
|
||||
'event_label': eventLabel,
|
||||
'value': value,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { Analytics }
|
||||
@@ -11,6 +11,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faUser, faKey } from "@fortawesome/free-solid-svg-icons";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, panel } from "../../../data/animation";
|
||||
import { Analytics } from "../../../common/Analytics";
|
||||
|
||||
interface Props {
|
||||
sessionWrapper: SessionWrapper;
|
||||
@@ -57,14 +58,16 @@ function LoginPage(props: Props) {
|
||||
password: password,
|
||||
};
|
||||
|
||||
Analytics.accountLoginAttempt();
|
||||
|
||||
const response = await CreateSession(request);
|
||||
|
||||
if (CreateSessionIsError(response)) {
|
||||
setErrorMessage(response.error_message);
|
||||
} else if (CreateSessionIsSuccess(response)) {
|
||||
console.log("querying new session");
|
||||
props.querySessionAction();
|
||||
props.querySessionSubscriptionsAction();
|
||||
Analytics.accountLoginSuccess();
|
||||
history.push("/");
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
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";
|
||||
|
||||
interface Props {
|
||||
sessionWrapper: SessionWrapper;
|
||||
@@ -54,11 +55,14 @@ function PricingPage(props: Props) {
|
||||
): Promise<boolean> => {
|
||||
if (!props.sessionWrapper.isLoggedIn()) {
|
||||
// TODO: This needs to bring the user back to purchase flow.
|
||||
Analytics.premiumBounceToSignup();
|
||||
history.push("/signup");
|
||||
return false;
|
||||
} else if (props.sessionSubscriptionsWrapper.hasPaidFeatures()) {
|
||||
Analytics.premiumForwardToStripePortal();
|
||||
return await beginStripePortalFlow();
|
||||
} else {
|
||||
Analytics.premiumForwardToStripeCheckout();
|
||||
return await beginStripeCheckoutFlow(internal_plan_key);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ import { Link } 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";
|
||||
|
||||
enum FieldTriState {
|
||||
EMPTY_FALSE,
|
||||
@@ -166,6 +167,8 @@ function SignupPage(props: Props) {
|
||||
): Promise<boolean> => {
|
||||
ev.preventDefault();
|
||||
|
||||
Analytics.accountSignupAttempt();
|
||||
|
||||
if (
|
||||
!usernameValid ||
|
||||
!emailValid ||
|
||||
@@ -194,9 +197,10 @@ function SignupPage(props: Props) {
|
||||
setUsernameInvalidReason(response.error_fields["username"] || "");
|
||||
}
|
||||
} else if (CreateAccountIsSuccess(response)) {
|
||||
console.log("querying new session");
|
||||
props.querySessionCallback();
|
||||
|
||||
Analytics.accountSignupComplete();
|
||||
|
||||
// TODO: Switch to functional component.
|
||||
window.location.href = "/";
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ import { motion } from "framer-motion";
|
||||
import { container, panel } from "../../../../data/animation";
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
import { TtsPageHero } from "./TtsPageHero";
|
||||
import { Analytics } from "../../../../common/Analytics";
|
||||
|
||||
export interface EnqueueJobResponsePayload {
|
||||
success: boolean;
|
||||
@@ -192,11 +193,7 @@ function TtsModelListPage(props: Props) {
|
||||
|
||||
const response = await GenerateTtsAudio(request);
|
||||
|
||||
gtag('event', 'generate_tts', {
|
||||
'event_category': 'TTS',
|
||||
'event_label': modelToken,
|
||||
'value': props.textBuffer.length,
|
||||
});
|
||||
Analytics.ttsGenerate(modelToken, props.textBuffer.length);
|
||||
|
||||
if (GenerateTtsAudioIsOk(response)) {
|
||||
setMaybeTtsError(undefined);
|
||||
@@ -211,6 +208,9 @@ function TtsModelListPage(props: Props) {
|
||||
const handleClearClick = (ev: React.FormEvent<HTMLButtonElement>) => {
|
||||
ev.preventDefault();
|
||||
props.clearTextBuffer();
|
||||
|
||||
Analytics.ttsClear(props.maybeSelectedTtsModel?.model_token);
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user