Skip to content

Commit 0c42075

Browse files
authored
Merge pull request #270 from NIAEFEUP/feature/analytics
Setup features and faq analytics
2 parents 599f756 + 53f57c7 commit 0c42075

File tree

12 files changed

+95
-8
lines changed

12 files changed

+95
-8
lines changed

src/components/faqs/PlannerFaqs.tsx

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import classNames from 'classnames'
22
import { Transition, Disclosure } from '@headlessui/react'
33
import { ChevronUpIcon } from '@heroicons/react/24/outline'
4+
import { AnalyticsTracker } from '../../utils/AnalyticsTracker'
45

56
const PlannerFaqs = () => {
67
const data = [
@@ -158,7 +159,14 @@ const PlannerFaqs = () => {
158159
as="div"
159160
defaultOpen={faqIdx === 0}
160161
key={`planner-faq-${faqIdx}`}
161-
className="rounded-2xl bg-white p-3 dark:bg-dark"
162+
className={`rounded-2xl bg-white p-3 dark:bg-dark faq-disclosure-${faqIdx}`}
163+
onClick={() => {
164+
const disclosure = document.querySelector(`.faq-disclosure-${faqIdx}`);
165+
const isOpen = disclosure?.getAttribute('data-headlessui-state') !== 'open';
166+
if (isOpen && faq.question.type === 'span') {
167+
AnalyticsTracker.trackFaq(faq.question.props.children)
168+
}
169+
}}
162170
>
163171
{({ open }) => (
164172
<>

src/components/planner/schedule/PrintSchedule.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Button } from '../../ui/button'
44
import { CameraIcon } from '@heroicons/react/24/outline'
55
import { toPng } from 'html-to-image'
66
import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from '../../ui/tooltip'
7+
import { AnalyticsTracker, Feature } from '../../../utils/AnalyticsTracker'
78

89
const PrintSchedule = ({ component }) => {
910
const { enabled } = useContext(ThemeContext)
@@ -24,6 +25,8 @@ const PrintSchedule = ({ component }) => {
2425
.catch((err) => {
2526
console.log(err)
2627
})
28+
29+
AnalyticsTracker.trackFeature(Feature.SCREENSHOT)
2730
},
2831
[component]
2932
)

src/components/planner/schedule/ToggleScheduleGrid.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Button } from '../../ui/button'
22
import { ViewColumnsIcon } from '@heroicons/react/24/outline'
33
import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from '../../ui/tooltip'
4+
import { AnalyticsTracker, Feature } from '../../../utils/AnalyticsTracker'
45

56
const ToggleScheduleGrid = ({ showGridHook }) => {
67
const [showGrid, setShowGrid] = showGridHook
@@ -12,7 +13,10 @@ const ToggleScheduleGrid = ({ showGridHook }) => {
1213
<Button
1314
variant="icon"
1415
className="bg-lightish text-black dark:bg-darkish dark:text-white"
15-
onClick={() => setShowGrid(!showGrid)}
16+
onClick={() => {
17+
setShowGrid(!showGrid)
18+
AnalyticsTracker.trackFeature(Feature.GRID)
19+
}}
1620
>
1721
<ViewColumnsIcon className="h-5 w-5" />
1822
</Button>

src/components/planner/sidebar/CoursesController/ClassSelector.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { teacherIdsFromCourseInfo, uniqueTeachersFromCourseInfo, getAllPickedSlo
99
import { Button } from '../../../ui/button'
1010
import ProfessorItem from './ProfessorItem'
1111
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuPortal, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from '../../../ui/dropdown-menu'
12+
import { AnalyticsTracker, Feature } from '../../../../utils/AnalyticsTracker'
1213
import ClassSelectorDropdownController from './ClassSelectorDropdownController'
1314

1415
type Props = {
@@ -58,6 +59,8 @@ const ClassSelector = ({ course }: Props) => {
5859
newMultipleOptions[selectedOption].course_options = courseOptions;
5960
setMultipleOptions(newMultipleOptions);
6061
setLocked(!locked)
62+
63+
AnalyticsTracker.trackFeature(Feature.LOCK_TOGGLE);
6164
}
6265

6366
useEffect(() => {

src/components/planner/sidebar/OptionsController.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { EllipsisHorizontalIcon } from '@heroicons/react/24/outline'
44
import { useContext } from 'react'
55
import MultipleOptionsContext from '../../../contexts/MultipleOptionsContext';
66
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../ui/tooltip';
7+
import { AnalyticsTracker, Feature } from '../../../utils/AnalyticsTracker';
78

89
/**
910
* Sortable list of schedule options
@@ -28,6 +29,9 @@ const OptionsController = () => {
2829
animation={200}
2930
delay={2}
3031
multiDrag
32+
onEnd={() => {
33+
AnalyticsTracker.trackFeature(Feature.OPTION_REORDER);
34+
}}
3135
>
3236
{multipleOptions.map((option: Option) => (
3337
<OptionButton

src/components/planner/sidebar/SelectedOptionController.tsx

+6-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { CourseOption } from '../../../@types'
88
import { ThemeContext } from '../../../contexts/ThemeContext'
99
import { Popover, PopoverContent, PopoverTrigger } from '../../ui/popover'
1010
import RandomFill from './selectedOptionController/RandomFill'
11+
import { AnalyticsTracker, Feature } from '../../../utils/AnalyticsTracker'
1112

1213
type Props = {
1314
currentOption: CourseOption[]
@@ -62,15 +63,18 @@ const SelectedOptionController = ({
6263
)
6364
return updatedMultipleOptions;
6465
})
66+
AnalyticsTracker.trackFeature(Feature.OPTION_RENAME);
6567
}
6668

6769
const changeOptionIcon = (newIcon) => {
6870
setMultipleOptions((prevMultipleOptions) => {
6971
const updatedMultipleOptions = prevMultipleOptions.map((item) =>
70-
item.id === multipleOptions[selectedOption].id ? { ...item, icon: newIcon } : item
72+
item.id === multipleOptions[selectedOption].id ? { ...item, icon: newIcon.imageUrl } : item
7173
)
7274
return updatedMultipleOptions;
7375
})
76+
AnalyticsTracker.trackFeature(Feature.OPTION_EMOJI);
77+
AnalyticsTracker.emoji(newIcon.emoji);
7478
}
7579

7680
return (
@@ -92,7 +96,7 @@ const SelectedOptionController = ({
9296
suggestedEmojisMode={SuggestionMode.RECENT}
9397
emojiStyle={EmojiStyle.APPLE}
9498
onEmojiClick={(emojiData, e) => {
95-
changeOptionIcon(emojiData.imageUrl)
99+
changeOptionIcon(emojiData)
96100
setEmojiPickerOpen(false)
97101
}}
98102
/>

src/components/planner/sidebar/selectedOptionController/CopyOption.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { useToast } from '../../../ui/use-toast'
55
import { Buffer } from 'buffer'
66
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../../ui/tooltip'
77
import { CourseOption } from '../../../../@types'
8+
import { plausible } from '../../../../utils'
9+
import { AnalyticsTracker, Feature } from '../../../../utils/AnalyticsTracker'
810

911
type Props = {
1012
currentOption: CourseOption[]
@@ -48,6 +50,7 @@ const CopyOption = ({ currentOption, className }: Props) => {
4850
setTimeout(() => {
4951
setIcon(false)
5052
}, 1500)
53+
AnalyticsTracker.trackFeature(Feature.COPY);
5154
}
5255

5356
return (

src/components/planner/sidebar/selectedOptionController/PasteOption.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import MultipleOptionsContext from '../../../../contexts/MultipleOptionsContext'
1111
import { convertCourseInfoToCourseOption } from '../../../../utils'
1212
import { Button } from '../../../ui/button'
1313
import { useToast } from '../../../ui/use-toast'
14+
import { AnalyticsTracker, Feature } from '../../../../utils/AnalyticsTracker'
1415

1516
const PasteOption = () => {
1617
const { multipleOptions, setMultipleOptions, selectedOption } = useContext(MultipleOptionsContext)
@@ -97,6 +98,8 @@ const PasteOption = () => {
9798
description: 'A opção foi colada com sucesso',
9899
duration: 1500,
99100
})
101+
102+
AnalyticsTracker.trackFeature(Feature.PASTE);
100103
}
101104

102105
/**

src/components/planner/sidebar/selectedOptionController/RandomFill.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Checkbox } from '../../../ui/checkbox'
88
import { Separator } from '../../../ui/separator'
99
import CourseContext from '../../../../contexts/CourseContext'
1010
import MultipleOptionsContext from '../../../../contexts/MultipleOptionsContext'
11+
import { AnalyticsTracker, Feature } from '../../../../utils/AnalyticsTracker'
1112

1213
type Props = {
1314
className?: string
@@ -165,6 +166,8 @@ const RandomFill = ({ className }: Props) => {
165166
// Choose a random permutation
166167
const randomNumber = Math.floor(Math.random() * (newPermutations.length - 1))
167168
applySchedule(newPermutations[randomNumber])
169+
170+
AnalyticsTracker.trackFeature(Feature.RANDOM_FILL);
168171
}
169172

170173
const applySchedule = (classesCombinations: ClassInfo[]) => {

src/components/planner/sidebar/sessionController/CsvExport.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ArrowUpOnSquareIcon } from '@heroicons/react/24/outline'
22
import { useContext } from 'react'
33
import CourseContext from '../../../../contexts/CourseContext'
44
import MultipleOptionsContext from '../../../../contexts/MultipleOptionsContext'
5+
import { AnalyticsTracker, Feature } from '../../../../utils/AnalyticsTracker'
56

67
//TODO: utils??
78
const csvEncode = (text: string | null | undefined) => {
@@ -43,6 +44,8 @@ const CsvExport = () => {
4344
a.download = 'schedule.csv'
4445
a.click()
4546
URL.revokeObjectURL(url)
47+
48+
AnalyticsTracker.trackFeature(Feature.EXPORT_TO_CSV)
4649
}
4750

4851
return (
@@ -52,7 +55,7 @@ const CsvExport = () => {
5255
>
5356
<ArrowUpOnSquareIcon className="h-5 w-5 text-secondary black:hover:brightness-200" />
5457
<span className="pl-1"> Exportar Opções (CSV)</span>
55-
</button>
58+
</button>
5659
)
5760
}
5861

src/components/planner/sidebar/sessionController/course-picker/MajorSearchCombobox.tsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import MajorContext from '../../../../../contexts/MajorContext'
66
import { cn, plausible } from '../../../../../utils'
77
import { Button } from '../../../../ui/button'
88
import { Popover, PopoverContent, PopoverTrigger } from '../../../../ui/popover'
9+
import { AnalyticsTracker } from '../../../../../utils/AnalyticsTracker'
910

1011
interface Props {
1112
selectedMajor: Major | null
@@ -77,9 +78,7 @@ const MajorSearchCombobox = ({ selectedMajor, setSelectedMajor }: Props) => {
7778
setSelectedMajor(currentMajor.id === selectedMajor?.id ? null : currentMajor)
7879
setOpen(false)
7980

80-
const { trackEvent } = plausible
81-
trackEvent('Major Selected', { props: { major: currentMajor.name } })
82-
trackEvent('Faculty', { props: { faculty: currentMajor.faculty_id.toUpperCase() } })
81+
AnalyticsTracker.majorSelected(currentMajor)
8382
}}
8483
>
8584
{`${major.name} (${major.acronym}) - ${major.faculty_id.toUpperCase()}`}

src/utils/AnalyticsTracker.ts

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
2+
import Plausible from "plausible-tracker";
3+
import { Major } from "../@types";
4+
5+
const plausible = Plausible({
6+
domain: import.meta.env.VITE_APP_PLAUSIBLE_DOMAIN,
7+
apiHost: import.meta.env.VITE_APP_PLAUSIBLE_HOST,
8+
trackLocalhost: !Number(import.meta.env.VITE_APP_PROD),
9+
})
10+
11+
const { trackEvent } = plausible;
12+
13+
export enum Feature {
14+
COPY = 'Copy Schedule',
15+
PASTE = 'Paste Schedule',
16+
RANDOM_FILL = 'Random Fill',
17+
18+
OPTION_REORDER = 'Options Order Changed',
19+
OPTION_RENAME = 'Option Renamed',
20+
OPTION_EMOJI = 'Schedule Emoji Changed',
21+
22+
SCREENSHOT = 'Screenshot',
23+
GRID = 'Grid View Toggle',
24+
25+
EXPORT_TO_CSV = 'Export to CSV',
26+
27+
LOCK_TOGGLE = 'Class Lock Toggled',
28+
}
29+
30+
export class AnalyticsTracker {
31+
static majorSelected = (major: Major) => {
32+
if (major) {
33+
trackEvent('Major Selected', { props: { major: major.name } })
34+
trackEvent('Faculty', { props: { faculty: major.faculty_id.toUpperCase() } })
35+
}
36+
}
37+
38+
static trackFeature = (feature: Feature) => {
39+
trackEvent('Feature', { props: { feature_counter: feature } })
40+
}
41+
42+
static trackFaq = (faq: string) => {
43+
if (faq) trackEvent('FAQ', { props: { faq } })
44+
}
45+
46+
static emoji = (emoji: string) => {
47+
if (emoji) trackEvent('Emoji', { props: { emoji } })
48+
}
49+
}
50+

0 commit comments

Comments
 (0)