import { MarkdownRenderer } from "@/components/markdown/renderer";
import { isWeb } from "@/constants/platform";
import type { Theme } from "@/styles/theme";
import { ChevronRight } from "lucide-react-native";
import { useCallback, useMemo, useState, type ReactNode } from "react";
import { useTranslation } from "react-i18next";
import { Pressable, Text, View } from "react-native";
import { StyleSheet, withUnistyles } from "react-native-unistyles";
export type PlanOutcome = "pending" | "approved" | "rejected" | "canceled";
interface PlanCardProps {
title?: string;
description?: string;
text: string;
outcome?: PlanOutcome;
footer?: ReactNode;
disableOuterSpacing?: boolean;
testID?: string;
}
const ThemedChevron = withUnistyles(ChevronRight);
const chevronColor = (theme: Theme) => ({ color: theme.colors.foregroundMuted });
export function PlanCard(props: PlanCardProps) {
// A resolution starts its own presentation state; subsequent taps stay local.
return ;
}
function PlanCardContent({
title,
description,
text,
outcome,
footer,
disableOuterSpacing = false,
testID,
}: PlanCardProps) {
const { t } = useTranslation();
const [expanded, setExpanded] = useState(outcome !== "rejected" && outcome !== "canceled");
const labels = {
pending: title ?? t("agentStream.permission.plan"),
rejected: t("agentStream.permission.rejectedPlan"),
approved: t("agentStream.permission.approvedPlan"),
canceled: t("agentStream.permission.canceledPlan"),
};
const resolvedTitle = labels[outcome ?? "pending"];
const accessibilityState = useMemo(() => ({ expanded }), [expanded]);
const webExpandedState = useMemo(
() => (isWeb ? ({ "aria-expanded": expanded } as const) : null),
[expanded],
);
const toggleExpanded = useCallback(() => setExpanded((value) => !value), []);
const containerStyle = useMemo(
() => [styles.container, disableOuterSpacing && styles.containerCompact],
[disableOuterSpacing],
);
const chevronStyle = useMemo(
() => [styles.chevron, expanded && styles.chevronExpanded],
[expanded],
);
return (
{resolvedTitle}
{expanded ? (
{description ? {description} : null}
) : null}
{footer ? {footer} : null}
);
}
const styles = StyleSheet.create((theme) => ({
container: {
marginVertical: theme.spacing[3],
padding: theme.spacing[3],
borderRadius: theme.spacing[2],
borderWidth: 1,
backgroundColor: theme.colors.surface1,
borderColor: theme.colors.border,
gap: theme.spacing[2],
},
containerCompact: {
marginVertical: 0,
},
header: {
flexDirection: "row",
alignItems: "center",
gap: theme.spacing[2],
minHeight: 24,
},
chevron: {},
chevronExpanded: { transform: [{ rotate: "90deg" }] },
body: { gap: theme.spacing[2] },
title: {
color: theme.colors.foreground,
flexShrink: 1,
fontSize: theme.fontSize.base,
lineHeight: 22,
},
description: {
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.base,
lineHeight: 20,
},
footer: {
gap: theme.spacing[2],
},
}));