From 87312f90ca8ea620ca036050e5d1eb57c2e890b0 Mon Sep 17 00:00:00 2001 From: Fredrik Strand Oseberg Date: Tue, 28 Feb 2023 14:29:14 +0100 Subject: [PATCH] feat: implement plausible tracking (#3212) Adds plausible event tracking for notifications. Refactors Feedback component to be reusable and to ask whether or not this functionality is useful. --- .../Feedback}/Feedback.tsx | 16 ++++++++++----- .../common/Notifications/Notifications.tsx | 20 ++++++++++++++++++- .../Project/ProjectStats/HelpPopper.tsx | 8 ++++++-- frontend/src/hooks/usePlausibleTracker.ts | 5 +++-- 4 files changed, 39 insertions(+), 10 deletions(-) rename frontend/src/component/{project/Project/ProjectStats => common/Feedback}/Feedback.tsx (84%) diff --git a/frontend/src/component/project/Project/ProjectStats/Feedback.tsx b/frontend/src/component/common/Feedback/Feedback.tsx similarity index 84% rename from frontend/src/component/project/Project/ProjectStats/Feedback.tsx rename to frontend/src/component/common/Feedback/Feedback.tsx index 4f29d3b2049..e3e654954c3 100644 --- a/frontend/src/component/project/Project/ProjectStats/Feedback.tsx +++ b/frontend/src/component/common/Feedback/Feedback.tsx @@ -1,11 +1,13 @@ import { useState, VFC } from 'react'; import { Box, Paper, Button, styled } from '@mui/material'; -import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; +import { CustomEvents, usePlausibleTracker } from 'hooks/usePlausibleTracker'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import { createLocalStorage } from 'utils/createLocalStorage'; interface IFeedbackProps { id: string; + eventName: CustomEvents; + localStorageKey: string; } const StyledBox = styled(Box)(({ theme }) => ({ @@ -14,11 +16,15 @@ const StyledBox = styled(Box)(({ theme }) => ({ marginTop: theme.spacing(0.5), })); -export const Feedback: VFC = ({ id }) => { +export const Feedback: VFC = ({ + id, + localStorageKey, + eventName, +}) => { const { uiConfig } = useUiConfig(); const { value: selectedValue, setValue: setSelectedValue } = createLocalStorage<{ value?: 'yes' | 'no' }>( - `ProjectOverviewFeedback:v1:${id}`, + `${uiConfig.baseUriPath}:${localStorageKey}:v1:${id}`, {} ); const [selected, setSelected] = useState<'yes' | 'no' | undefined>( @@ -26,14 +32,14 @@ export const Feedback: VFC = ({ id }) => { ); const { trackEvent } = usePlausibleTracker(); - if (!uiConfig?.flags?.T) { + if (!uiConfig?.flags?.T || Boolean(selected)) { return null; } const onTrackFeedback = (value: 'yes' | 'no') => { setSelected(value); setSelectedValue({ value }); - trackEvent('project_overview', { + trackEvent(eventName, { props: { eventType: id, wasHelpful: value === 'yes', diff --git a/frontend/src/component/common/Notifications/Notifications.tsx b/frontend/src/component/common/Notifications/Notifications.tsx index c1a34595903..d78bdbb3fd0 100644 --- a/frontend/src/component/common/Notifications/Notifications.tsx +++ b/frontend/src/component/common/Notifications/Notifications.tsx @@ -9,7 +9,7 @@ import { Button, } from '@mui/material'; import { useNotifications } from 'hooks/api/getters/useNotifications/useNotifications'; -import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender'; +import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import NotificationsIcon from '@mui/icons-material/Notifications'; import { NotificationsHeader } from './NotificationsHeader'; import { NotificationsList } from './NotificationsList'; @@ -18,6 +18,9 @@ import { EmptyNotifications } from './EmptyNotifications'; import { NotificationsSchemaItem } from 'openapi'; import { useNavigate } from 'react-router-dom'; import { useNotificationsApi } from 'hooks/api/actions/useNotificationsApi/useNotificationsApi'; +import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; +import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; +import { Feedback } from 'component/common/Feedback/Feedback'; const StyledPrimaryContainerBox = styled(Box)(() => ({ position: 'relative', @@ -63,11 +66,20 @@ export const Notifications = () => { }); const navigate = useNavigate(); const { markAsRead } = useNotificationsApi(); + const { uiConfig } = useUiConfig(); + const { trackEvent } = usePlausibleTracker(); const onNotificationClick = (notification: NotificationsSchemaItem) => { if (notification.link) { navigate(notification.link); } + + if (uiConfig?.flags?.T) { + trackEvent('notifications', { + props: { eventType: notification.notificationType }, + }); + } + setShowNotifications(false); // Intentionally not wait for this request. We don't want to hold the user back @@ -154,6 +166,12 @@ export const Notifications = () => { /> ))} + +
} diff --git a/frontend/src/component/project/Project/ProjectStats/HelpPopper.tsx b/frontend/src/component/project/Project/ProjectStats/HelpPopper.tsx index da9b91e970c..7b10e2c0e29 100644 --- a/frontend/src/component/project/Project/ProjectStats/HelpPopper.tsx +++ b/frontend/src/component/project/Project/ProjectStats/HelpPopper.tsx @@ -8,7 +8,7 @@ import { ClickAwayListener, styled, } from '@mui/material'; -import { Feedback } from './Feedback'; +import { Feedback } from 'component/common/Feedback/Feedback'; interface IHelpPopperProps { id: string; @@ -66,7 +66,11 @@ export const HelpPopper: FC = ({ children, id }) => { /> {children} - + diff --git a/frontend/src/hooks/usePlausibleTracker.ts b/frontend/src/hooks/usePlausibleTracker.ts index 51060484040..09f1ad65a28 100644 --- a/frontend/src/hooks/usePlausibleTracker.ts +++ b/frontend/src/hooks/usePlausibleTracker.ts @@ -8,7 +8,7 @@ import { EventOptions, PlausibleOptions } from 'plausible-tracker'; * @see https://plausible.io/docs/custom-event-goals#2-create-a-custom-event-goal-in-your-plausible-analytics-account * @example `'download | 'invite' | 'signup'` **/ -type CustomEvents = +export type CustomEvents = | 'invite' | 'upgrade_plan_clicked' | 'change_request' @@ -20,7 +20,8 @@ type CustomEvents = | 'suggest_tags' | 'unknown_ui_error' | 'export_import' - | 'project_api_tokens'; + | 'project_api_tokens' + | 'notifications'; export const usePlausibleTracker = () => { const plausible = useContext(PlausibleContext);