From 8162ed1f0d81a7e7fef8544b04da75f2aa0810ed Mon Sep 17 00:00:00 2001 From: Jan Berg Date: Mon, 23 Sep 2024 14:26:52 +0300 Subject: [PATCH] Added some booking related analytics events --- frontend/src/analytics/AnalyticsEvent.ts | 20 ++++++- .../googleAnalytics/googleAnalyticsEvents.ts | 31 +++++++++++ .../BookingDrawer/BookingDrawer.tsx | 52 +++++++++++++++++-- .../BookingView/StartingTimePicker.tsx | 34 ++++++++---- 4 files changed, 122 insertions(+), 15 deletions(-) diff --git a/frontend/src/analytics/AnalyticsEvent.ts b/frontend/src/analytics/AnalyticsEvent.ts index 86b2255..da162a8 100644 --- a/frontend/src/analytics/AnalyticsEvent.ts +++ b/frontend/src/analytics/AnalyticsEvent.ts @@ -4,7 +4,14 @@ export enum AnalyticsEventEnum { BOOKING_END, BOOKING_ADD_TIME, BOOKING_DEDUCT_TIME, - BUILDING_SELECT + BUILDING_SELECT, + QUICK_DURATION_SELECTION, + TIME_CONTROL_ADD_FIFTEEN, + TIME_CONTROL_DEDUCT_FIFTEEN, + TIME_CONTROL_NEXT_THIRTY_MINUTES, + TIME_CONTROL_NEXT_FULL_HOUR, + TIME_CONTROL_WHOLE_SLOT, + STARTING_TIME_SELECTION } // Defines the common event names to use across all analytics services @@ -13,5 +20,14 @@ export const analyticsEventMap: { [key in AnalyticsEventEnum]: string } = { [AnalyticsEventEnum.BOOKING_END]: 'bookingEnd', [AnalyticsEventEnum.BOOKING_ADD_TIME]: 'bookingAddTime', [AnalyticsEventEnum.BOOKING_DEDUCT_TIME]: 'bookingDeductTime', - [AnalyticsEventEnum.BUILDING_SELECT]: 'buildingSelect' + [AnalyticsEventEnum.BUILDING_SELECT]: 'buildingSelect', + [AnalyticsEventEnum.QUICK_DURATION_SELECTION]: 'quickDurationSelection', + [AnalyticsEventEnum.TIME_CONTROL_ADD_FIFTEEN]: 'timeControlAddFifteen', + [AnalyticsEventEnum.TIME_CONTROL_DEDUCT_FIFTEEN]: + 'timeControlDeductFifteen', + [AnalyticsEventEnum.TIME_CONTROL_NEXT_THIRTY_MINUTES]: + 'timeControlNextThirtyMinutes', + [AnalyticsEventEnum.TIME_CONTROL_NEXT_FULL_HOUR]: 'timeControlNextFullHour', + [AnalyticsEventEnum.TIME_CONTROL_WHOLE_SLOT]: 'timeControlWholeSlot', + [AnalyticsEventEnum.STARTING_TIME_SELECTION]: 'startingTimeSelection' }; diff --git a/frontend/src/analytics/googleAnalytics/googleAnalyticsEvents.ts b/frontend/src/analytics/googleAnalytics/googleAnalyticsEvents.ts index c505e2c..d8cb563 100644 --- a/frontend/src/analytics/googleAnalytics/googleAnalyticsEvents.ts +++ b/frontend/src/analytics/googleAnalytics/googleAnalyticsEvents.ts @@ -7,6 +7,15 @@ export interface GoogleAnalyticsEvent { eventObject: object; } +export class GenericGoogleAnalyticsEvent implements GoogleAnalyticsEvent { + eventObject: object = {}; + eventType: AnalyticsEventEnum; + + constructor(eventType: AnalyticsEventEnum) { + this.eventType = eventType; + } +} + export class BookingEvent implements GoogleAnalyticsEvent { eventType: AnalyticsEventEnum = AnalyticsEventEnum.BOOKING; eventObject: object; @@ -68,3 +77,25 @@ export class ChooseBuildingEvent implements GoogleAnalyticsEvent { }; } } + +export class QuickDurationEvent implements GoogleAnalyticsEvent { + eventType: AnalyticsEventEnum = AnalyticsEventEnum.QUICK_DURATION_SELECTION; + eventObject: object; + + constructor(quickDuration: String) { + this.eventObject = { + quickDuration: quickDuration + }; + } +} + +export class StartingTimeSelectionEvent implements GoogleAnalyticsEvent { + eventType: AnalyticsEventEnum = AnalyticsEventEnum.STARTING_TIME_SELECTION; + eventObject: object; + + constructor(startingTime: String) { + this.eventObject = { + startingTime: startingTime + }; + } +} diff --git a/frontend/src/components/BookingDrawer/BookingDrawer.tsx b/frontend/src/components/BookingDrawer/BookingDrawer.tsx index 0f671da..ac84003 100644 --- a/frontend/src/components/BookingDrawer/BookingDrawer.tsx +++ b/frontend/src/components/BookingDrawer/BookingDrawer.tsx @@ -10,6 +10,13 @@ import { theme } from '../../theme'; import DurationPicker from './DurationPicker'; import BottomDrawer, { DrawerContent } from '../BottomDrawer/BottomDrawer'; import { dateTimeToTimeString } from '../util/Time'; +import { triggerGoogleAnalyticsEvent } from '../../analytics/googleAnalytics/googleAnalyticsService'; +import { + GenericGoogleAnalyticsEvent, + QuickDurationEvent +} from '../../analytics/googleAnalytics/googleAnalyticsEvents'; +import { triggerClarityEvent } from '../../analytics/clarityService'; +import { AnalyticsEventEnum } from '../../analytics/AnalyticsEvent'; const MIN_DURATION = 15; @@ -359,9 +366,16 @@ const BookingDrawer = (props: Props) => { }); const handleDurationChange = (newDuration: number) => { + // In case of "custom" duration, the newDuration will be -1 if (newDuration !== -1) { setBookingDuration(newDuration); + triggerGoogleAnalyticsEvent( + new QuickDurationEvent(newDuration.toString()) + ); + } else { + triggerGoogleAnalyticsEvent(new QuickDurationEvent('Custom')); } + triggerClarityEvent(AnalyticsEventEnum.QUICK_DURATION_SELECTION); setAdditionalDuration(0); }; @@ -371,14 +385,38 @@ const BookingDrawer = (props: Props) => { const [showAlert, setShowAlert] = useState(false); const handleAdditionalTime = (minutes: number) => { + let analyticsEvent: AnalyticsEventEnum; + if (minutes == -15) { + analyticsEvent = AnalyticsEventEnum.TIME_CONTROL_DEDUCT_FIFTEEN; + } else { + analyticsEvent = AnalyticsEventEnum.TIME_CONTROL_ADD_FIFTEEN; + } + triggerGoogleAnalyticsEvent( + new GenericGoogleAnalyticsEvent(analyticsEvent) + ); + triggerClarityEvent(analyticsEvent); onAddTime(minutes); }; const handleNextHalfHour = () => { + triggerGoogleAnalyticsEvent( + new GenericGoogleAnalyticsEvent( + AnalyticsEventEnum.TIME_CONTROL_NEXT_THIRTY_MINUTES + ) + ); + triggerClarityEvent( + AnalyticsEventEnum.TIME_CONTROL_NEXT_THIRTY_MINUTES + ); onAddTimeUntilHalf(); }; const handleNextFullHour = () => { + triggerGoogleAnalyticsEvent( + new GenericGoogleAnalyticsEvent( + AnalyticsEventEnum.TIME_CONTROL_NEXT_FULL_HOUR + ) + ); + triggerClarityEvent(AnalyticsEventEnum.TIME_CONTROL_NEXT_FULL_HOUR); onAddTimeUntilFull(); }; @@ -494,6 +532,16 @@ const BookingDrawer = (props: Props) => { } }, [startingTime]); + const bookWholeFreeSlot = () => { + triggerGoogleAnalyticsEvent( + new GenericGoogleAnalyticsEvent( + AnalyticsEventEnum.TIME_CONTROL_WHOLE_SLOT + ) + ); + triggerClarityEvent(AnalyticsEventEnum.TIME_CONTROL_WHOLE_SLOT); + handleUntilNext(getTimeAvailableMinutes(room)); + }; + return ( { - handleUntilNext(getTimeAvailableMinutes(room)) - } + onClick={bookWholeFreeSlot} sx={{ margin: 0 }} diff --git a/frontend/src/components/BookingView/StartingTimePicker.tsx b/frontend/src/components/BookingView/StartingTimePicker.tsx index 04553ba..9b3a46e 100644 --- a/frontend/src/components/BookingView/StartingTimePicker.tsx +++ b/frontend/src/components/BookingView/StartingTimePicker.tsx @@ -5,6 +5,10 @@ import { Box, styled, Typography } from '@mui/material'; import { DateTime } from 'luxon'; import { formatTimeToHalfAndFullHours } from '../util/Time'; import AlertBox from '../util/alertBox'; +import { triggerGoogleAnalyticsEvent } from '../../analytics/googleAnalytics/googleAnalyticsService'; +import { StartingTimeSelectionEvent } from '../../analytics/googleAnalytics/googleAnalyticsEvents'; +import { triggerClarityEvent } from '../../analytics/clarityService'; +import { AnalyticsEventEnum } from '../../analytics/AnalyticsEvent'; const StartingTimeButton = styled(ToggleButton)(() => ({})); const StartingTimePickerContent = styled(Box)(({ theme }) => ({})); @@ -37,12 +41,22 @@ const StartingTimePicker = (props: StartingTimePickerProps) => { event: React.MouseEvent, newStartingTime: string ) => { - if (newStartingTime !== null) { - if (newStartingTime !== 'Custom') { - setStartingTime(newStartingTime); - } else { - setExpandTimePickerDrawer(true); - } + // Also handle the case when the starting time would be null (shouldnt happen) + // Adding this to analytics will let us see these erroneous events as well + const testId = event.currentTarget.getAttribute('data-testid'); + triggerGoogleAnalyticsEvent( + new StartingTimeSelectionEvent(testId ? testId : '') + ); + triggerClarityEvent(AnalyticsEventEnum.STARTING_TIME_SELECTION); + + if (newStartingTime == null) { + return; + } + + if (newStartingTime !== 'Custom') { + setStartingTime(newStartingTime); + } else { + setExpandTimePickerDrawer(true); } }; @@ -83,28 +97,28 @@ const StartingTimePicker = (props: StartingTimePickerProps) => { fullWidth > {startingTimeNow} {startingTime2} {startingTime3}