feat(telemetry): product interaction events
- h2h_viewed from match card, dock, profile, stats, predictions - reaction_sent with emoji and surface; score_report_opened from all three report entry points - stats_filtered and stats_sorted on stats route and profile - rules/teams/players/bracket/tournament view events with sources - match_history_viewed, badge_viewed, player_searched (count only)
This commit is contained in:
@@ -19,6 +19,7 @@ import PlayerList from '@/features/players/components/player-list';
|
||||
import { useAuth } from '@/contexts/auth-context';
|
||||
import { Player } from '@/features/players/types';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import { track } from '@/lib/telemetry/client';
|
||||
|
||||
const BadgeStatsTable = () => {
|
||||
const { data: allBadges } = useAllBadges();
|
||||
@@ -141,7 +142,13 @@ const BadgeStatRow: React.FC<BadgeStatRowProps> = ({
|
||||
|
||||
return (
|
||||
<Box key={badge.id}>
|
||||
<UnstyledButton onClick={badgeSheet.open} w='100%'>
|
||||
<UnstyledButton
|
||||
onClick={() => {
|
||||
track("badge_viewed", { badge: badge.key });
|
||||
badgeSheet.open();
|
||||
}}
|
||||
w='100%'
|
||||
>
|
||||
<Grid p={'xs'} align='center'>
|
||||
<Grid.Col span={2} style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<BadgeIcon badge={badge} filled={true} />
|
||||
|
||||
@@ -399,7 +399,7 @@ export const MatchCard: React.FC<MatchCardProps> = ({
|
||||
</Sheet>
|
||||
</Flex>
|
||||
|
||||
{!showControls && <MatchReport match={match} compact />}
|
||||
{!showControls && <MatchReport match={match} compact source="match_card" />}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -24,6 +24,7 @@ import { MatchReport } from "./match-report";
|
||||
import Sheet from "@/components/sheet/sheet";
|
||||
import { useSheet } from "@/hooks/use-sheet";
|
||||
import { Trans, useLingui } from "@lingui/react/macro";
|
||||
import { track } from "@/lib/telemetry/client";
|
||||
|
||||
const EASE: [number, number, number, number] = [0.32, 0.72, 0, 1];
|
||||
|
||||
@@ -155,7 +156,7 @@ const MatchDock = ({ match, onClose }: MatchDockProps) => {
|
||||
ended={ended}
|
||||
/>
|
||||
|
||||
<MatchReport match={match} />
|
||||
<MatchReport match={match} source="match_dock" />
|
||||
|
||||
<Group justify="space-between" wrap="nowrap" gap="sm">
|
||||
<Box style={{ flex: 1, minWidth: 0 }}>
|
||||
@@ -166,7 +167,7 @@ const MatchDock = ({ match, onClose }: MatchDockProps) => {
|
||||
</Center>
|
||||
}
|
||||
>
|
||||
<EmojiBar matchId={match.id} />
|
||||
<EmojiBar matchId={match.id} source="match_dock" />
|
||||
</Suspense>
|
||||
</Box>
|
||||
{!hasPrivate && (
|
||||
@@ -174,7 +175,10 @@ const MatchDock = ({ match, onClose }: MatchDockProps) => {
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
size="sm"
|
||||
onClick={h2hSheet.open}
|
||||
onClick={() => {
|
||||
track("h2h_viewed", { source: "match_card" });
|
||||
h2hSheet.open();
|
||||
}}
|
||||
aria-label={t`View head-to-head`}
|
||||
w={40}
|
||||
style={{ flexShrink: 0 }}
|
||||
|
||||
@@ -13,6 +13,7 @@ import Sheet from "@/components/sheet/sheet";
|
||||
import { MatchForm } from "./match-form";
|
||||
import toast from "@/lib/sonner";
|
||||
import { Trans, useLingui } from "@lingui/react/macro";
|
||||
import { track } from "@/lib/telemetry/client";
|
||||
|
||||
const teamId = (t: Match["home"]): string | undefined =>
|
||||
!t ? undefined : typeof t === "string" ? t : t.id;
|
||||
@@ -26,9 +27,10 @@ const teamName = (t: Match["home"]): string | undefined =>
|
||||
interface MatchReportProps {
|
||||
match: Match;
|
||||
compact?: boolean;
|
||||
source?: string;
|
||||
}
|
||||
|
||||
export const MatchReport: React.FC<MatchReportProps> = ({ match, compact }) => {
|
||||
export const MatchReport: React.FC<MatchReportProps> = ({ match, compact, source }) => {
|
||||
const { user } = useAuth();
|
||||
const formSheet = useSheet();
|
||||
const { t } = useLingui();
|
||||
@@ -129,8 +131,9 @@ export const MatchReport: React.FC<MatchReportProps> = ({ match, compact }) => {
|
||||
|
||||
const openForm = useCallback(() => {
|
||||
setAcknowledgedReport(pendingSignature);
|
||||
track("score_report_opened", source ? { source } : undefined);
|
||||
formSheet.open();
|
||||
}, [pendingSignature, formSheet.open]);
|
||||
}, [pendingSignature, formSheet.open, source]);
|
||||
|
||||
const dismissTakeover = useCallback(() => {
|
||||
setAcknowledgedReport(pendingSignature);
|
||||
|
||||
@@ -10,6 +10,7 @@ import Sheet from "@/components/sheet/sheet";
|
||||
import TeamHeadToHeadSheet from "./team-head-to-head-sheet";
|
||||
import AnimatedScore from "./animated-score";
|
||||
import { Trans, useLingui } from "@lingui/react/macro";
|
||||
import { track } from "@/lib/telemetry/client";
|
||||
|
||||
interface MatchCardProps {
|
||||
match: Match;
|
||||
@@ -41,6 +42,7 @@ const MatchCard = ({ match, hideH2H = false }: MatchCardProps) => {
|
||||
|
||||
const handleH2HClick = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
track("h2h_viewed", { source: "match_card" });
|
||||
h2hSheet.open();
|
||||
};
|
||||
|
||||
@@ -218,7 +220,7 @@ const MatchCard = ({ match, hideH2H = false }: MatchCardProps) => {
|
||||
}}
|
||||
>
|
||||
<Suspense>
|
||||
<EmojiBar matchId={match.id} />
|
||||
<EmojiBar matchId={match.id} source="match_card" />
|
||||
</Suspense>
|
||||
</Paper>
|
||||
</Box>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Stack, Text, TextInput, Box, Paper, Group, Divider, ActionIcon, Button } from "@mantine/core";
|
||||
import { useState, useMemo } from "react";
|
||||
import { useState, useMemo, useRef } from "react";
|
||||
import { MagnifyingGlassIcon, XIcon, ArrowRightIcon, PlusIcon } from "@phosphor-icons/react";
|
||||
import { Trans, useLingui } from "@lingui/react/macro";
|
||||
import { useAllPlayerStats } from "../queries";
|
||||
@@ -8,6 +8,7 @@ import { useSheet } from "@/hooks/use-sheet";
|
||||
import Sheet from "@/components/sheet/sheet";
|
||||
import PlayerHeadToHeadSheet from "./player-head-to-head-sheet";
|
||||
import PlayerAvatar from "@/components/player-avatar";
|
||||
import { track } from "@/lib/telemetry/client";
|
||||
|
||||
const LeagueHeadToHead = () => {
|
||||
const { t } = useLingui();
|
||||
@@ -15,6 +16,7 @@ const LeagueHeadToHead = () => {
|
||||
const [player1Id, setPlayer1Id] = useState<string | null>(null);
|
||||
const [player2Id, setPlayer2Id] = useState<string | null>(null);
|
||||
const [search, setSearch] = useState("");
|
||||
const searchedRef = useRef(false);
|
||||
const { data: allPlayerStats } = useAllPlayerStats();
|
||||
const h2hSheet = useSheet();
|
||||
|
||||
@@ -51,6 +53,7 @@ const LeagueHeadToHead = () => {
|
||||
setPlayer1Id(playerId);
|
||||
} else {
|
||||
setPlayer2Id(playerId);
|
||||
track("h2h_viewed", { source: "stats" });
|
||||
h2hSheet.open();
|
||||
}
|
||||
};
|
||||
@@ -128,7 +131,14 @@ const LeagueHeadToHead = () => {
|
||||
<TextInput
|
||||
placeholder={t`Search players`}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
onChange={(e) => {
|
||||
const value = e.currentTarget.value;
|
||||
if (value && !searchedRef.current) {
|
||||
searchedRef.current = true;
|
||||
track("player_searched");
|
||||
}
|
||||
setSearch(value);
|
||||
}}
|
||||
leftSection={<MagnifyingGlassIcon size={16} />}
|
||||
size="md"
|
||||
px="md"
|
||||
|
||||
@@ -28,6 +28,7 @@ import { useNavigate } from "@tanstack/react-router";
|
||||
import { useAllPlayerStats } from "../queries";
|
||||
import { PlayerListItemSkeleton } from "./player-stats-table-skeleton";
|
||||
import { Trans, useLingui } from "@lingui/react/macro";
|
||||
import { track } from "@/lib/telemetry/client";
|
||||
|
||||
type SortKey = keyof PlayerStats | "mmr";
|
||||
type SortDirection = "asc" | "desc";
|
||||
@@ -177,6 +178,7 @@ const PlayerStatsTable = ({ viewType = 'all' }: PlayerStatsTableProps) => {
|
||||
const navigate = useNavigate();
|
||||
const [search, setSearch] = useState("");
|
||||
const deferredSearch = useDeferredValue(search);
|
||||
const searchedRef = useRef(false);
|
||||
const [sortConfig, setSortConfig] = useState<SortConfig>({
|
||||
key: "mmr" as SortKey,
|
||||
direction: "desc",
|
||||
@@ -291,6 +293,7 @@ const PlayerStatsTable = ({ viewType = 'all' }: PlayerStatsTableProps) => {
|
||||
}, [navigate]);
|
||||
|
||||
const handleSort = (key: SortKey) => {
|
||||
track("stats_sorted", { value: key });
|
||||
setSortConfig((prev) => ({
|
||||
key,
|
||||
direction: prev.key === key && prev.direction === "desc" ? "asc" : "desc",
|
||||
@@ -328,7 +331,14 @@ const PlayerStatsTable = ({ viewType = 'all' }: PlayerStatsTableProps) => {
|
||||
<TextInput
|
||||
placeholder={t`Search players`}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
onChange={(e) => {
|
||||
const value = e.currentTarget.value;
|
||||
if (value && !searchedRef.current) {
|
||||
searchedRef.current = true;
|
||||
track("player_searched");
|
||||
}
|
||||
setSearch(value);
|
||||
}}
|
||||
leftSection={<MagnifyingGlassIcon size={16} />}
|
||||
size="md"
|
||||
px="md"
|
||||
|
||||
@@ -9,6 +9,7 @@ import PlayerAvatar from "@/components/player-avatar";
|
||||
import { useSheet } from "@/hooks/use-sheet";
|
||||
import { Player } from "../../types";
|
||||
import PlayerHeadToHeadSheet from "../player-head-to-head-sheet";
|
||||
import { track } from "@/lib/telemetry/client";
|
||||
|
||||
interface HeaderProps {
|
||||
player: Player;
|
||||
@@ -53,7 +54,10 @@ const Header = ({ player }: HeaderProps) => {
|
||||
variant="subtle"
|
||||
size="sm"
|
||||
radius="xl"
|
||||
onClick={h2hSheet.open}
|
||||
onClick={() => {
|
||||
track("h2h_viewed", { source: "profile" });
|
||||
h2hSheet.open();
|
||||
}}
|
||||
w={40}
|
||||
display={!owner ? 'block' : 'none'}
|
||||
>
|
||||
|
||||
@@ -10,6 +10,7 @@ import StatsOverview, { StatsSkeleton } from "@/components/stats-overview";
|
||||
import MatchList from "@/features/matches/components/match-list";
|
||||
import BadgeShowcase from "@/features/badges/components/badge-showcase";
|
||||
import BadgeShowcaseSkeleton from "@/features/badges/components/badge-showcase-skeleton";
|
||||
import { track } from "@/lib/telemetry/client";
|
||||
|
||||
interface ProfileProps {
|
||||
id: string;
|
||||
@@ -20,14 +21,20 @@ const StatsWithFilter = ({ id }: { id: string }) => {
|
||||
const deferredViewType = useDeferredValue(viewType);
|
||||
const isStale = viewType !== deferredViewType;
|
||||
|
||||
const changeViewType = (next: typeof viewType) => {
|
||||
if (next === viewType) return;
|
||||
track("stats_filtered", { value: next, source: "profile" });
|
||||
setViewType(next);
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<Group gap="xs" px="md" justify="space-between" align="center">
|
||||
<Text size="md" fw={700}><Trans>Statistics</Trans></Text>
|
||||
<Group gap="xs">
|
||||
<Button variant={viewType === 'all' ? 'filled' : 'light'} size="compact-xs" onClick={() => setViewType('all')}><Trans>All</Trans></Button>
|
||||
<Button variant={viewType === 'mainline' ? 'filled' : 'light'} size="compact-xs" onClick={() => setViewType('mainline')}><Trans>Mainline</Trans></Button>
|
||||
<Button variant={viewType === 'regional' ? 'filled' : 'light'} size="compact-xs" onClick={() => setViewType('regional')}><Trans>Regional</Trans></Button>
|
||||
<Button variant={viewType === 'all' ? 'filled' : 'light'} size="compact-xs" onClick={() => changeViewType('all')}><Trans>All</Trans></Button>
|
||||
<Button variant={viewType === 'mainline' ? 'filled' : 'light'} size="compact-xs" onClick={() => changeViewType('mainline')}><Trans>Mainline</Trans></Button>
|
||||
<Button variant={viewType === 'regional' ? 'filled' : 'light'} size="compact-xs" onClick={() => changeViewType('regional')}><Trans>Regional</Trans></Button>
|
||||
</Group>
|
||||
</Group>
|
||||
<Box style={{ opacity: isStale ? 0.6 : 1, transition: 'opacity 150ms' }}>
|
||||
@@ -90,7 +97,12 @@ const Profile = ({ id }: ProfileProps) => {
|
||||
<>
|
||||
<Header player={player} />
|
||||
<Box mt="lg">
|
||||
<SwipeableTabs tabs={tabs} />
|
||||
<SwipeableTabs
|
||||
tabs={tabs}
|
||||
onTabChange={(_, tab) => {
|
||||
if (tab.value === "matches") track("match_history_viewed", { source: "profile" });
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
import { PredictionBracket } from "./prediction-bracket";
|
||||
import { MatchupSheet } from "./matchup-sheet";
|
||||
import { WinnerSelector } from "./winner-selector";
|
||||
import { track } from "@/lib/telemetry/client";
|
||||
|
||||
interface PredictionEditorProps {
|
||||
tournament: Tournament;
|
||||
@@ -215,7 +216,12 @@ export const PredictionEditor: React.FC<PredictionEditorProps> = ({
|
||||
variant="default"
|
||||
size="lg"
|
||||
radius="md"
|
||||
onClick={matchupSheet.open}
|
||||
onClick={() => {
|
||||
if (activeResolved?.home && activeResolved?.away) {
|
||||
track("h2h_viewed", { source: "predictions" });
|
||||
}
|
||||
matchupSheet.open();
|
||||
}}
|
||||
disabled={!activeResolved?.home && !activeResolved?.away}
|
||||
aria-label={t`Matchup details`}
|
||||
>
|
||||
|
||||
@@ -17,11 +17,13 @@ import EmojiPicker from "./emoji-picker";
|
||||
import { useMatchReactions, useToggleMatchReaction } from "../queries";
|
||||
import { useAuth } from "@/contexts/auth-context";
|
||||
import { Reaction } from "@/features/matches/server";
|
||||
import { track } from "@/lib/telemetry/client";
|
||||
import classes from "./emoji-bar.module.css";
|
||||
|
||||
interface EmojiBarProps {
|
||||
matchId: string;
|
||||
onReactionPress?: (emoji: string) => void;
|
||||
source?: string;
|
||||
}
|
||||
|
||||
const EASE: [number, number, number, number] = [0.32, 0.72, 0, 1];
|
||||
@@ -56,6 +58,7 @@ const TickingCount = ({ value, ...textProps }: TickingCountProps) => {
|
||||
const EmojiBar = ({
|
||||
matchId,
|
||||
onReactionPress,
|
||||
source,
|
||||
}: EmojiBarProps) => {
|
||||
const { user } = useAuth();
|
||||
const { t } = useLingui();
|
||||
@@ -85,6 +88,7 @@ const EmojiBar = ({
|
||||
if (onReactionPress) {
|
||||
onReactionPress(emoji);
|
||||
} else {
|
||||
if (!userReactions.includes(emoji)) track("reaction_sent", { emoji, source });
|
||||
toggleReaction.mutate({ data: { matchId, emoji } });
|
||||
}
|
||||
};
|
||||
@@ -198,7 +202,10 @@ const EmojiBar = ({
|
||||
</AnimatePresence>
|
||||
</Group>
|
||||
<EmojiPicker
|
||||
onSelect={onReactionPress || ((emoji) => toggleReaction.mutate({ data: { matchId, emoji } }))}
|
||||
onSelect={onReactionPress || ((emoji) => {
|
||||
if (!userReactions.includes(emoji)) track("reaction_sent", { emoji, source });
|
||||
toggleReaction.mutate({ data: { matchId, emoji } });
|
||||
})}
|
||||
userReactions={userReactions}
|
||||
/>
|
||||
</Group>
|
||||
|
||||
@@ -302,11 +302,17 @@ export const getSessionTimeline = createServerFn()
|
||||
|
||||
for (const event of events.items) {
|
||||
if (event.name.startsWith("vital.")) continue;
|
||||
const props = event.props as
|
||||
| { emoji?: string; source?: string; tournament?: string; value?: string }
|
||||
| null
|
||||
| undefined;
|
||||
const breakdown =
|
||||
props?.emoji ?? props?.value ?? props?.source ?? props?.tournament;
|
||||
entries.push({
|
||||
ts: event.created,
|
||||
kind: event.name === "page_view" ? "page_view" : "event",
|
||||
label: event.name === "page_view" ? event.path || event.route_id || "?" : event.name,
|
||||
detail: event.name === "page_view" ? undefined : event.path,
|
||||
detail: event.name === "page_view" ? undefined : (breakdown ?? event.path),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useMemo } from "react";
|
||||
import { useEffect, useMemo, useRef } from "react";
|
||||
import { Box } from "@mantine/core";
|
||||
import Header from "./header";
|
||||
import TeamList from "@/features/teams/components/team-list";
|
||||
@@ -7,6 +7,7 @@ import { useTournament } from "../../queries";
|
||||
import MatchList from "@/features/matches/components/match-list";
|
||||
import { TournamentStats } from "../tournament-stats";
|
||||
import { useLingui } from "@lingui/react/macro";
|
||||
import { track } from "@/lib/telemetry/client";
|
||||
|
||||
interface ProfileProps {
|
||||
id: string;
|
||||
@@ -15,6 +16,14 @@ interface ProfileProps {
|
||||
const Profile = ({ id }: ProfileProps) => {
|
||||
const { t } = useLingui();
|
||||
const { data: tournament } = useTournament(id);
|
||||
const trackedId = useRef<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!tournament || trackedId.current === tournament.id) return;
|
||||
trackedId.current = tournament.id;
|
||||
track("tournament_viewed", { tournament: tournament.name });
|
||||
}, [tournament]);
|
||||
|
||||
if (!tournament) return null;
|
||||
|
||||
const tabs = useMemo(() => [
|
||||
|
||||
@@ -24,6 +24,7 @@ import { useSheet } from "@/hooks/use-sheet";
|
||||
import TeamList from "@/features/teams/components/team-list";
|
||||
import WizardOrbIcon from "@/components/wizard-orb-icon";
|
||||
import { Tournament } from "../../../types";
|
||||
import { track } from "@/lib/telemetry/client";
|
||||
import classes from "./nav-grid.module.css";
|
||||
|
||||
const RulesContent = lazy(
|
||||
@@ -86,9 +87,10 @@ const NavGrid = ({
|
||||
<NavTile
|
||||
label={t`Bracket`}
|
||||
Icon={TreeStructureIcon}
|
||||
onClick={() =>
|
||||
navigate({ to: `/tournaments/${tournament.id}/bracket` })
|
||||
}
|
||||
onClick={() => {
|
||||
track("bracket_viewed", { source: "nav_grid" });
|
||||
navigate({ to: `/tournaments/${tournament.id}/bracket` });
|
||||
}}
|
||||
/>
|
||||
{isPredictable && !predictionsLocked && (
|
||||
<NavTile
|
||||
@@ -118,9 +120,19 @@ const NavGrid = ({
|
||||
: t`Teams`
|
||||
}
|
||||
Icon={UsersIcon}
|
||||
onClick={teamsSheet.open}
|
||||
onClick={() => {
|
||||
track("teams_viewed", { source: "nav_grid" });
|
||||
teamsSheet.open();
|
||||
}}
|
||||
/>
|
||||
<NavTile
|
||||
label={t`Rules`}
|
||||
Icon={ListIcon}
|
||||
onClick={() => {
|
||||
track("rules_viewed", { source: "nav_grid" });
|
||||
rulesSheet.open();
|
||||
}}
|
||||
/>
|
||||
<NavTile label={t`Rules`} Icon={ListIcon} onClick={rulesSheet.open} />
|
||||
</SimpleGrid>
|
||||
|
||||
<Sheet title={t`Enrolled Teams`} {...teamsSheet.props}>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useNavigate } from "@tanstack/react-router";
|
||||
import { Trans, useLingui } from "@lingui/react/macro";
|
||||
import MatchCard from "@/features/matches/components/match-card";
|
||||
import { Match } from "@/features/matches/types";
|
||||
import { track } from "@/lib/telemetry/client";
|
||||
import SectionHeading from "./section-heading";
|
||||
|
||||
interface RecentResultsProps {
|
||||
@@ -39,9 +40,10 @@ const RecentResults = ({ matches, tournamentId, max = 5 }: RecentResultsProps) =
|
||||
type="button"
|
||||
size="xs"
|
||||
fw={600}
|
||||
onClick={() =>
|
||||
navigate({ to: `/tournaments/${tournamentId}/bracket` })
|
||||
}
|
||||
onClick={() => {
|
||||
track("bracket_viewed", { source: "recent_results" });
|
||||
navigate({ to: `/tournaments/${tournamentId}/bracket` });
|
||||
}}
|
||||
>
|
||||
<Group gap={2} align="center" wrap="nowrap">
|
||||
<Trans>View all results</Trans>
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ const ScoreReportCta = ({ matches }: ScoreReportCtaProps) => {
|
||||
)}
|
||||
</Group>
|
||||
</Group>
|
||||
<MatchReport match={match} />
|
||||
<MatchReport match={match} source="score_cta" />
|
||||
</Stack>
|
||||
</Paper>
|
||||
))}
|
||||
|
||||
+5
-1
@@ -9,6 +9,7 @@ import { Text } from "@mantine/core";
|
||||
import PlayerList from "@/features/players/components/player-list";
|
||||
import { Player } from "@/features/players/types";
|
||||
import { NavTile } from "../started-tournament/sections/nav-grid";
|
||||
import { track } from "@/lib/telemetry/client";
|
||||
|
||||
interface EnrolledPlayersListButtonProps {
|
||||
tournamentId: string;
|
||||
@@ -33,7 +34,10 @@ const EnrolledPlayersListButton: React.FC<EnrolledPlayersListButtonProps> = ({ t
|
||||
values: { count },
|
||||
})}
|
||||
Icon={UserListIcon}
|
||||
onClick={open}
|
||||
onClick={() => {
|
||||
track("players_viewed", { source: "upcoming" });
|
||||
open();
|
||||
}}
|
||||
/>
|
||||
|
||||
<Sheet title={t`Enrolled Players`} opened={isOpen} onChange={toggle}>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useTournament } from "../../queries"
|
||||
import { Button, Flex, Loader, Stack } from "@mantine/core"
|
||||
import { lazy, Suspense } from "react"
|
||||
import { NavTile } from "../started-tournament/sections/nav-grid"
|
||||
import { track } from "@/lib/telemetry/client"
|
||||
|
||||
const RulesContent = lazy(() => import("./rules-content"));
|
||||
|
||||
@@ -20,7 +21,14 @@ const RulesListButton: React.FC<RulesListButtonProps> = ({ tournamentId }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<NavTile label={t`Rules`} Icon={ListIcon} onClick={open} />
|
||||
<NavTile
|
||||
label={t`Rules`}
|
||||
Icon={ListIcon}
|
||||
onClick={() => {
|
||||
track("rules_viewed", { source: "upcoming" });
|
||||
open();
|
||||
}}
|
||||
/>
|
||||
|
||||
<Sheet title={t`Tournament Rules`} opened={isOpen} onChange={toggle}>
|
||||
<Stack gap="xs">
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useMemo } from "react"
|
||||
import { useLingui } from "@lingui/react/macro"
|
||||
import { msg } from "@lingui/core/macro"
|
||||
import { NavTile } from "../started-tournament/sections/nav-grid"
|
||||
import { track } from "@/lib/telemetry/client"
|
||||
|
||||
interface TeamListButtonProps {
|
||||
teams: TeamInfo[]
|
||||
@@ -25,7 +26,10 @@ const TeamListButton: React.FC<TeamListButtonProps> = ({ teams, isRegional }) =>
|
||||
values: { count },
|
||||
})}
|
||||
Icon={UsersIcon}
|
||||
onClick={open}
|
||||
onClick={() => {
|
||||
track("teams_viewed", { source: "upcoming" });
|
||||
open();
|
||||
}}
|
||||
/>
|
||||
|
||||
<Sheet title={t`Enrolled Teams`} opened={isOpen} onChange={toggle}>
|
||||
|
||||
Reference in New Issue
Block a user