Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { AnimatedEllipsis } from "@features/inbox/components/utils/AnimatedEllipsis";
import { SOURCE_PRODUCT_META } from "@features/inbox/components/utils/source-product-icons";
import { ArrowDownIcon } from "@phosphor-icons/react";
import { ArrowDownIcon, CheckCircleIcon } from "@phosphor-icons/react";
import { Box, Button, Flex, Text, Tooltip } from "@radix-ui/themes";
import builderHog from "@renderer/assets/images/hedgehogs/builder-hog-03.png";
import explorerHog from "@renderer/assets/images/hedgehogs/explorer-hog.png";
import graphsHog from "@renderer/assets/images/hedgehogs/graphs-hog.png";
import mailHog from "@renderer/assets/images/mail-hog.png";
import { ANALYTICS_EVENTS } from "@shared/types/analytics";
import { track } from "@utils/analytics";
import { useState } from "react";

// ── Full-width empty states ─────────────────────────────────────────────────

Expand Down Expand Up @@ -130,6 +134,78 @@ export function WarmingUpPane({
);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Ephemeral registered state allows duplicate analytics events

registered is useState(false), so it resets to false every time GatedDueToScalePane unmounts (i.e., every navigation away from and back to Inbox). A user can fire INBOX_INTEREST_REGISTERED on every visit. If you want to track unique registrations accurately, persist the flag to localStorage (or treat the analytics event as idempotent and deduplicate server-side).

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/features/inbox/components/InboxEmptyStates.tsx
Line: 136

Comment:
**Ephemeral registered state allows duplicate analytics events**

`registered` is `useState(false)`, so it resets to `false` every time `GatedDueToScalePane` unmounts (i.e., every navigation away from and back to Inbox). A user can fire `INBOX_INTEREST_REGISTERED` on every visit. If you want to track unique registrations accurately, persist the flag to `localStorage` (or treat the analytics event as idempotent and deduplicate server-side).

How can I resolve this? If you propose a fix, please make it concise.

export function GatedDueToScalePane() {
const [registered, setRegistered] = useState(false);

const handleRegisterInterest = () => {
track(ANALYTICS_EVENTS.INBOX_INTEREST_REGISTERED);
setRegistered(true);
};

return (
<Flex
direction="column"
align="center"
justify="center"
height="100%"
px="5"
>
<Flex direction="column" align="center" className="max-w-[420px]">
<img src={builderHog} alt="" className="mb-[16px] w-[120px]" />

<Text
align="center"
className="font-bold text-(--gray-12) text-lg leading-6.5"
>
We're rolling out self-driving gradually
<AnimatedEllipsis />
</Text>

<Flex
direction="column"
align="center"
gap="3"
mt="3"
className="max-w-[340px]"
>
<Text
align="center"
className="text-(--gray-11) text-[13px] leading-[1.35]"
>
Inbox watches your sessions, issues, and evals around the clock, and
surfaces ready-to-run fixes.
<br />
<Text className="font-medium text-(--gray-12)">
We're scaling it up carefully so every report stays high-signal.
</Text>
</Text>
</Flex>

{registered ? (
<Flex align="center" gap="2" className="mt-[20px]">
<CheckCircleIcon
size={16}
weight="fill"
className="text-(--grass-9)"
/>
<Text className="text-(--gray-11) text-[13px]">
Got it — we'll let you know.
</Text>
</Flex>
) : (
<Button
size="2"
onClick={handleRegisterInterest}
className="mt-[20px]"
>
Let me know when self-driving is available for my organization
</Button>
)}
</Flex>
</Flex>
);
}

export function SelectReportPane() {
return (
<Flex
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { useFeatureFlag } from "@hooks/useFeatureFlag";
import { useSetHeaderContent } from "@hooks/useSetHeaderContent";
import { EnvelopeSimpleIcon } from "@phosphor-icons/react";
import { Flex, Text } from "@radix-ui/themes";
import { INBOX_GATED_DUE_TO_SCALE_FLAG } from "@shared/constants";
import { useMemo } from "react";
import { GatedDueToScalePane } from "./InboxEmptyStates";
import { InboxSignalsTab } from "./InboxSignalsTab";

export function InboxView() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Brief flash of InboxSignalsTab for gated customers

useFeatureFlag initialises to false (its defaultValue) when PostHog flags haven't loaded yet (see useFeatureFlag.ts lines 8–9). Until the onFeatureFlagsLoaded callback fires, isGatedDueToScale is false, so gated customers briefly see InboxSignalsTab before the gate pane replaces it. If flags are reliably loaded before the Inbox is reachable this is a non-issue, but if there's any race at startup it's worth adding a loading guard or initialising with null and rendering a neutral state until the flag resolves.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/features/inbox/components/InboxView.tsx
Line: 10

Comment:
**Brief flash of `InboxSignalsTab` for gated customers**

`useFeatureFlag` initialises to `false` (its `defaultValue`) when PostHog flags haven't loaded yet (see `useFeatureFlag.ts` lines 8–9). Until the `onFeatureFlagsLoaded` callback fires, `isGatedDueToScale` is `false`, so gated customers briefly see `InboxSignalsTab` before the gate pane replaces it. If flags are reliably loaded before the Inbox is reachable this is a non-issue, but if there's any race at startup it's worth adding a loading guard or initialising with `null` and rendering a neutral state until the flag resolves.

How can I resolve this? If you propose a fix, please make it concise.

const isGatedDueToScale = useFeatureFlag(INBOX_GATED_DUE_TO_SCALE_FLAG);

const headerContent = useMemo(
() => (
<Flex align="center" gap="2" className="w-full min-w-0">
Expand All @@ -24,7 +29,7 @@ export function InboxView() {

return (
<div className="h-full">
<InboxSignalsTab />
{isGatedDueToScale ? <GatedDueToScalePane /> : <InboxSignalsTab />}
</div>
);
}
1 change: 1 addition & 0 deletions apps/code/src/shared/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const BILLING_FLAG = "posthog-code-billing";
export const INBOX_GATED_DUE_TO_SCALE_FLAG = "inbox-gated-due-to-scale";
export const BRANCH_PREFIX = "posthog-code/";
export const DATA_DIR = ".posthog-code";
export const WORKTREES_DIR = ".posthog-code/worktrees";
Expand Down
6 changes: 6 additions & 0 deletions apps/code/src/shared/types/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,9 @@ export const ANALYTICS_EVENTS = {
// Error events
TASK_CREATION_FAILED: "Task creation failed",
AGENT_SESSION_ERROR: "Agent session error",

// Inbox events
INBOX_INTEREST_REGISTERED: "Inbox interest registered",
} as const;

// Event property mapping
Expand Down Expand Up @@ -383,4 +386,7 @@ export type EventPropertyMap = {
// Error events
[ANALYTICS_EVENTS.TASK_CREATION_FAILED]: TaskCreationFailedProperties;
[ANALYTICS_EVENTS.AGENT_SESSION_ERROR]: AgentSessionErrorProperties;

// Inbox events
[ANALYTICS_EVENTS.INBOX_INTEREST_REGISTERED]: never;
};
Loading