From 609c4f617fa6913b0e6b97146810abd57ea516a3 Mon Sep 17 00:00:00 2001 From: ciregenz Date: Thu, 4 Jun 2026 04:02:05 -0700 Subject: [PATCH] [eric] overlays: extract PlanPickerModal from MessageBubble for reuse --- .../components/overlays/PlanPickerModal.tsx | 81 +++++++++++++++++++ .../pages/AgentChat/bubbles/MessageBubble.tsx | 44 ++-------- 2 files changed, 89 insertions(+), 36 deletions(-) create mode 100644 frontend/src/app/components/overlays/PlanPickerModal.tsx diff --git a/frontend/src/app/components/overlays/PlanPickerModal.tsx b/frontend/src/app/components/overlays/PlanPickerModal.tsx new file mode 100644 index 00000000..0e1321be --- /dev/null +++ b/frontend/src/app/components/overlays/PlanPickerModal.tsx @@ -0,0 +1,81 @@ +import React from 'react'; +import Box from '@mui/material/Box'; +import Typography from '@mui/material/Typography'; +import Modal from '@mui/material/Modal'; +import IconButton from '@mui/material/IconButton'; +import CloseIcon from '@mui/icons-material/Close'; +import { useClaudeTokens } from '@/shared/styles/ThemeContext'; +import PlanPicker from './PlanPicker'; +import type { + OpenSwarmPlan, + CheckoutSource, +} from '@/shared/subscription/checkout'; + +interface Props { + open: boolean; + onClose: () => void; + title: string; + subtitle?: string; + source: CheckoutSource; + defaultPlan?: OpenSwarmPlan; + currentPlan?: OpenSwarmPlan; + onSubscribed?: (plan: OpenSwarmPlan) => void; +} + +/** Centered modal around the compact PlanPicker; keeps pricing out of the page flow until asked for. */ +const PlanPickerModal: React.FC = ({ + open, + onClose, + title, + subtitle, + source, + defaultPlan, + currentPlan, + onSubscribed, +}) => { + const c = useClaudeTokens(); + return ( + + + + + {title} + + + + + + {subtitle && ( + + {subtitle} + + )} + + + + ); +}; + +export default PlanPickerModal; diff --git a/frontend/src/app/pages/AgentChat/bubbles/MessageBubble.tsx b/frontend/src/app/pages/AgentChat/bubbles/MessageBubble.tsx index 5656c969..e8275c9c 100644 --- a/frontend/src/app/pages/AgentChat/bubbles/MessageBubble.tsx +++ b/frontend/src/app/pages/AgentChat/bubbles/MessageBubble.tsx @@ -24,7 +24,7 @@ import { shallowEqual } from 'react-redux'; import { useAppDispatch, useAppSelector } from '@/shared/hooks'; import { useClaudeTokens } from '@/shared/styles/ThemeContext'; import { SKILL_COLOR } from '@/app/components/editor/richEditorUtils'; -import PlanPicker from '@/app/components/overlays/PlanPicker'; +import PlanPickerModal from '@/app/components/overlays/PlanPickerModal'; import { ErrorSlime } from '@/app/components/feedback/ErrorSlime'; const streamingCursorKeyframes = ` @@ -1189,43 +1189,15 @@ const MessageBubble: React.FC = React.memo(({ message, editing = false, o )} - setPickerOpen(false)} - sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center', p: 2 }} - > - - - - Upgrade your plan - - setPickerOpen(false)} - sx={{ color: c.text.tertiary }} - aria-label="Close" - > - - - - - Pick a plan to keep going. Cancel anytime from Stripe. - - setPickerOpen(false)} - /> - - + title="Upgrade your plan" + subtitle="Pick a plan to keep going. Cancel anytime from Stripe." + source="upgrade_cta" + defaultPlan="pro_plus" + onSubscribed={() => setPickerOpen(false)} + /> ); });