Skip to content
Merged
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
258 changes: 182 additions & 76 deletions apps/code/src/renderer/features/inbox/components/InboxEmptyStates.tsx
Original file line number Diff line number Diff line change
@@ -1,95 +1,201 @@
import {
ArrowsClockwiseIcon,
CircleNotchIcon,
WarningIcon,
} from "@phosphor-icons/react";
import { Box, Button, Flex, Text } from "@radix-ui/themes";
import { AnimatedEllipsis } from "@features/inbox/components/utils/AnimatedEllipsis";
import { SOURCE_PRODUCT_META } from "@features/inbox/components/utils/SourceProductIcons";
import { ArrowDownIcon } from "@phosphor-icons/react";
import { Box, Button, Flex, Text, Tooltip } from "@radix-ui/themes";
import explorerHog from "@renderer/assets/images/explorer-hog.png";
import graphsHog from "@renderer/assets/images/graphs-hog.png";
import mailHog from "@renderer/assets/images/mail-hog.png";

export function SignalsLoadingState() {
// ── Full-width empty states ─────────────────────────────────────────────────

export function WelcomePane({ onEnableInbox }: { onEnableInbox: () => void }) {
return (
<Flex height="100%" style={{ minHeight: 0 }}>
<Box flexGrow="1" style={{ minWidth: 0 }}>
<Flex direction="column" height="100%">
<Flex
<Flex
direction="column"
align="center"
justify="center"
height="100%"
px="5"
>
<Flex direction="column" align="center" style={{ maxWidth: 420 }}>
<img src={graphsHog} alt="" style={{ width: 120, marginBottom: 16 }} />

<Text
size="4"
weight="bold"
align="center"
style={{ color: "var(--gray-12)" }}
>
Welcome to your Inbox
</Text>

<Flex
direction="column"
align="center"
gap="3"
mt="3"
style={{ maxWidth: 340 }}
>
<Text
size="1"
align="center"
style={{ color: "var(--gray-11)", lineHeight: 1.35 }}
>
<Text weight="medium" style={{ color: "var(--gray-12)" }}>
Background analysis of your data — while you sleep.
</Text>
<br />
Session recordings watched automatically. Issues, tickets, and evals
analyzed around the clock.
</Text>

<ArrowDownIcon size={14} style={{ color: "var(--gray-8)" }} />

<Text
size="1"
align="center"
justify="between"
px="3"
py="2"
style={{ borderBottom: "1px solid var(--gray-5)" }}
style={{ color: "var(--gray-11)", lineHeight: 1.35 }}
>
<Flex align="center" gap="2">
<CircleNotchIcon
size={12}
className="animate-spin text-gray-10"
/>
<Text size="1" color="gray" className="text-[12px]">
Loading signals
</Text>
</Flex>
</Flex>
<Flex direction="column">
{Array.from({ length: 5 }).map((_, index) => (
<Flex
// biome-ignore lint/suspicious/noArrayIndexKey: static local loading placeholders
key={index}
direction="column"
gap="2"
px="3"
py="3"
className="border-gray-5 border-b"
>
<Box className="h-[12px] w-[44%] animate-pulse rounded bg-gray-4" />
<Box className="h-[11px] w-[82%] animate-pulse rounded bg-gray-3" />
</Flex>
))}
</Flex>
<Text weight="medium" style={{ color: "var(--gray-12)" }}>
Ready-to-run fixes for real user problems.
</Text>
<br />
Each report includes evidence and impact numbers — just execute the
prompt in your agent.
</Text>
</Flex>
</Box>

<Button size="2" style={{ marginTop: 20 }} onClick={onEnableInbox}>
Enable Inbox
</Button>
</Flex>
</Flex>
);
}

export function SignalsErrorState({
onRetry,
isRetrying,
export function WarmingUpPane({
onConfigureSources,
enabledProducts,
}: {
onRetry: () => void;
isRetrying: boolean;
onConfigureSources: () => void;
enabledProducts: string[];
}) {
return (
<Flex align="center" justify="center" height="100%" p="4">
<Flex
direction="column"
align="center"
gap="3"
px="4"
py="4"
className="w-full max-w-[460px] rounded border border-gray-6 bg-gray-2 text-center"
>
<WarningIcon size={20} className="text-amber-10" weight="bold" />
<Flex direction="column" gap="2" align="center">
<Text size="4" weight="medium">
Could not load signals
</Text>
<Text size="1" color="gray" className="text-[12px]">
Check your connection or permissions, then retry.
</Text>
<Flex
direction="column"
align="center"
justify="center"
height="100%"
px="5"
>
<Flex direction="column" align="center" style={{ maxWidth: 420 }}>
<img
src={explorerHog}
alt=""
style={{ width: 120, marginBottom: 16 }}
/>

<Text
size="4"
weight="bold"
align="center"
style={{ color: "var(--gray-12)" }}
>
Inbox is warming up
<AnimatedEllipsis />
</Text>

<Text
size="1"
align="center"
mt="3"
style={{ color: "var(--gray-11)", lineHeight: 1.35 }}
>
Reports will appear here as soon as signals come in.
</Text>

<Flex align="center" gap="3" style={{ marginTop: 16 }}>
{enabledProducts.map((sp) => {
const meta = SOURCE_PRODUCT_META[sp];
if (!meta) return null;
const { Icon } = meta;
return (
<Tooltip key={sp} content={meta.label}>
<span style={{ color: meta.color }}>
<Icon size={16} />
</span>
</Tooltip>
);
})}
<Button
size="2"
variant="soft"
color="gray"
onClick={onConfigureSources}
>
Configure sources
</Button>
</Flex>
<Button
</Flex>
</Flex>
);
}

export function SelectReportPane() {
return (
<Flex
direction="column"
align="center"
justify="center"
height="100%"
px="5"
>
<Flex direction="column" align="center" style={{ maxWidth: 300 }}>
<img
src={mailHog}
alt=""
style={{ width: 100, marginBottom: 12, opacity: 0.8 }}
/>
<Text
size="2"
weight="medium"
align="center"
style={{ color: "var(--gray-10)" }}
>
Select a report
</Text>
<Text
size="1"
variant="soft"
onClick={onRetry}
className="text-[12px]"
disabled={isRetrying}
align="center"
mt="1"
style={{ color: "var(--gray-9)", lineHeight: 1.35 }}
>
{isRetrying ? (
<CircleNotchIcon size={12} className="animate-spin" />
) : (
<ArrowsClockwiseIcon size={12} />
)}
Retry
</Button>
Pick a report from the list to see details, signals, and evidence.
</Text>
</Flex>
</Flex>
);
}

// ── Skeleton rows for backdrop behind empty states ──────────────────────────

export function SkeletonBackdrop() {
return (
<Flex direction="column" style={{ opacity: 0.4 }}>
{Array.from({ length: 8 }).map((_, index) => (
<Flex
// biome-ignore lint/suspicious/noArrayIndexKey: static decorative placeholders
key={index}
direction="column"
gap="2"
px="3"
py="3"
className="border-gray-5 border-b"
>
<Box className="h-[12px] w-[44%] rounded bg-gray-4" />
<Box className="h-[11px] w-[82%] rounded bg-gray-3" />
</Flex>
))}
</Flex>
);
}
Loading
Loading