Skip to content

Commit 0f028e1

Browse files
feat: Kasandra Analytics (#618)
1 parent ab0d81d commit 0f028e1

File tree

8 files changed

+192
-21
lines changed

8 files changed

+192
-21
lines changed

packages/frontend/src/api/hooks/useActivityLogger.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ interface IActivityLogger {
1616
logKeywordSelected: (id: number) => void;
1717
logWalletConnection: (method: EWalletConnectionMethod) => void;
1818
logShareSuperfeedItem: (item: TSuperfeedItem) => void;
19+
logButtonClicked: (buttonName: string, data?: JSONValue) => void;
1920
}
2021

2122
export const useActivityLogger = (): IActivityLogger => {
@@ -134,11 +135,33 @@ export const useActivityLogger = (): IActivityLogger => {
134135
);
135136
};
136137

138+
const logButtonClicked = (buttonName: string, data?: JSONValue) => {
139+
sendActivityLog({
140+
event_type: EActivityLogEventTypes.ButtonClicked,
141+
object_name: buttonName,
142+
data,
143+
})
144+
.unwrap()
145+
.then((resp) =>
146+
Logger.debug(
147+
"useActivityLogger::logButtonClicked: updated button clicked activity log",
148+
resp
149+
)
150+
)
151+
.catch((err) =>
152+
Logger.error(
153+
"useActivityLogger::logButtonClicked: error updating button clicked activity log",
154+
err
155+
)
156+
);
157+
};
158+
137159
return {
138160
logViewVisited,
139161
logCookieChoice,
140162
logKeywordSelected,
141163
logWalletConnection,
142164
logShareSuperfeedItem,
165+
logButtonClicked,
143166
};
144167
};
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { logEvent } from "firebase/analytics";
2+
import { EActivityLogEventTypes } from "../services/activity-log/types";
3+
import { analytics } from "../utils/firebaseUtils";
4+
5+
import { Logger } from "../utils/logging";
6+
import { useActivityLogger } from "./useActivityLogger";
7+
8+
export type TButtonClickEventPayload = {
9+
buttonName:
10+
| "kasandra-coin"
11+
| "kasandra-case"
12+
| "kasandra-date-range"
13+
| "kasandra-disclaimer"
14+
| "kasandra-datapoint";
15+
data?: JSONValue;
16+
};
17+
18+
export const useCustomAnalytics = () => {
19+
const { logButtonClicked: logButtonClickedActivity } = useActivityLogger();
20+
21+
const logButtonClicked = (payload: TButtonClickEventPayload) => {
22+
const key = EActivityLogEventTypes.ButtonClicked;
23+
logEvent(analytics, key, payload);
24+
logButtonClickedActivity(payload.buttonName, payload.data);
25+
Logger.debug("logButtonClicked", key, payload);
26+
};
27+
28+
return {
29+
logButtonClicked,
30+
};
31+
};

packages/frontend/src/api/services/activity-log/types.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export enum EActivityLogEventTypes {
55
CookieChoiceSet = "COOKIE_CHOICE_SET",
66
WalletConnection = "WALLET_CONNECT",
77
ShareSuperfeedItem = "SHARE_ITEM",
8+
ButtonClicked = "BUTTON_CLICKED",
89
}
910

1011
export enum EActivityLogObjectTypes {
@@ -13,6 +14,7 @@ export enum EActivityLogObjectTypes {
1314
View,
1415
WalletConnection,
1516
ShareSuperfeedItem,
17+
Button,
1618
}
1719

1820
export type TKeywordActivityLog = {
@@ -54,13 +56,20 @@ export type TShareSuperfeedItemActivityLog = {
5456
data: JSONValue;
5557
};
5658

59+
export type TButtonClickedActivityLog = {
60+
event_type: EActivityLogEventTypes.ButtonClicked;
61+
object_name: string;
62+
data?: JSONValue;
63+
};
64+
5765
export type TRemoteActivityLog =
5866
| TKeywordActivityLog
5967
| TWidgetActivityLog
6068
| TViewActivityLog
6169
| TCookieActivityLog
6270
| TWalletConnectionActivityLog
63-
| TShareSuperfeedItemActivityLog;
71+
| TShareSuperfeedItemActivityLog
72+
| TButtonClickedActivityLog;
6473

6574
export type TActivityLogRequest = TRemoteActivityLog;
6675
export type TActivityLogResponse = TRemoteActivityLog;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import { getAnalytics } from "firebase/analytics";
12
import { initializeApp } from "firebase/app";
23
import CONFIG from "src/config/config";
34

45
// Initialize Firebase
56
const { APP_CONFIG } = CONFIG.FIREBASE;
67
export const isConfigured = !!APP_CONFIG.apiKey;
78
export const firebaseApp = isConfigured ? initializeApp(APP_CONFIG) : undefined;
9+
export const analytics = getAnalytics(firebaseApp);

packages/frontend/src/components/kasandra/KasandraModule.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { FC, useMemo } from "react";
22
import { ModuleLoader } from "@alphaday/ui-kit";
33
import { useTranslation } from "react-i18next";
44
import useHeaderScroll from "src/api/hooks/useHeaderScroll";
5-
import {
5+
import type {
66
TChartRange,
77
TCoin,
88
TCoinMarketHistory,

packages/frontend/src/components/market/MarketsList.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { FC } from "react";
22
import { TabsBar } from "@alphaday/ui-kit";
3-
import { TCoin } from "src/api/types";
4-
import { TMarketMeta } from "./types";
3+
import type { TCoin } from "src/api/types";
4+
import type { TMarketMeta } from "./types";
55

66
interface IMarketsList {
77
markets?: TMarketMeta[] | undefined;

packages/frontend/src/containers/kasandra/KasandraContainer.tsx

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { FC, useEffect, useMemo, useCallback, Suspense } from "react";
22
import { useGlobalSearch, useWidgetHeight } from "src/api/hooks";
3+
import { useCustomAnalytics } from "src/api/hooks/useCustomAnalytics";
34
import {
45
useGetKasandraCoinsQuery,
56
useGetMarketHistoryQuery,
@@ -28,6 +29,7 @@ const KasandraContainer: FC<IModuleContainer> = ({ moduleData }) => {
2829
const WIDGET_HEIGHT = useWidgetHeight(moduleData);
2930

3031
const isAuthenticated = useAppSelector(selectIsAuthenticated);
32+
const { logButtonClicked } = useCustomAnalytics();
3133

3234
const selectedTimestamp = useAppSelector(
3335
(state) => state.widgets.kasandra?.[moduleData.hash]?.selectedTimestamp
@@ -125,12 +127,38 @@ const KasandraContainer: FC<IModuleContainer> = ({ moduleData }) => {
125127
limit: 24,
126128
});
127129

130+
const logData = useMemo(() => {
131+
return {
132+
selectedTimestamp: selectedTimestamp ?? 0,
133+
widgetName: moduleData.name,
134+
case: selectedCase,
135+
chartRange: selectedChartRange,
136+
marketId: selectedMarket?.id,
137+
marketTicker: selectedMarket?.ticker,
138+
};
139+
}, [
140+
moduleData.name,
141+
selectedCase,
142+
selectedChartRange,
143+
selectedMarket?.id,
144+
selectedMarket?.ticker,
145+
selectedTimestamp,
146+
]);
147+
128148
const handleSelectedMarket = useCallback(
129149
(market: TMarketMeta) => {
130150
dispatch(setKasandraData({ widgetHash: moduleData.hash, market }));
151+
logButtonClicked({
152+
buttonName: "kasandra-coin",
153+
data: {
154+
...logData,
155+
marketId: market.id,
156+
marketTicker: market.ticker,
157+
},
158+
});
131159
},
132160

133-
[dispatch, moduleData.hash]
161+
[dispatch, logButtonClicked, logData, moduleData.hash]
134162
);
135163

136164
const handleSelectedChartRange = useCallback(
@@ -141,18 +169,32 @@ const KasandraContainer: FC<IModuleContainer> = ({ moduleData }) => {
141169
chartRange,
142170
})
143171
);
172+
logButtonClicked({
173+
buttonName: "kasandra-date-range",
174+
data: {
175+
...logData,
176+
chartRange,
177+
},
178+
});
144179
},
145180

146-
[dispatch, moduleData.hash]
181+
[dispatch, logButtonClicked, logData, moduleData.hash]
147182
);
148183

149184
const handleSelectedCase = useCallback(
150185
(kase: TKasandraCase) => {
151186
dispatch(
152187
setKasandraData({ widgetHash: moduleData.hash, case: kase })
153188
);
189+
logButtonClicked({
190+
buttonName: "kasandra-case",
191+
data: {
192+
...logData,
193+
case: kase,
194+
},
195+
});
154196
},
155-
[dispatch, moduleData.hash]
197+
[dispatch, logButtonClicked, logData, moduleData.hash]
156198
);
157199

158200
const handleselectedTimestamp = useCallback(
@@ -163,8 +205,15 @@ const KasandraContainer: FC<IModuleContainer> = ({ moduleData }) => {
163205
timestamp,
164206
})
165207
);
208+
logButtonClicked({
209+
buttonName: "kasandra-datapoint",
210+
data: {
211+
...logData,
212+
selectedTimestamp: timestamp,
213+
},
214+
});
166215
},
167-
[dispatch, moduleData.hash]
216+
[dispatch, logButtonClicked, logData, moduleData.hash]
168217
);
169218

170219
const handleAcceptDisclaimer = useCallback(() => {
@@ -174,7 +223,13 @@ const KasandraContainer: FC<IModuleContainer> = ({ moduleData }) => {
174223
disclaimerAccepted: true,
175224
})
176225
);
177-
}, [dispatch, moduleData.hash]);
226+
logButtonClicked({
227+
buttonName: "kasandra-disclaimer",
228+
data: {
229+
widgetName: moduleData.name,
230+
},
231+
});
232+
}, [dispatch, logButtonClicked, moduleData.hash, moduleData.name]);
178233

179234
/**
180235
* if user searches for some keyword and tags are included, automatically set the selected market

0 commit comments

Comments
 (0)