fix: snack stream re rendering other component and closing issue

This commit is contained in:
Vukasin 2025-07-19 16:30:41 +02:00
parent cfd937b65f
commit d7fd6ae811
4 changed files with 21 additions and 13 deletions

View File

@ -509,8 +509,11 @@ export default function ThreadPage({
setDebugMode(debugParam === 'true'); setDebugMode(debugParam === 'true');
}, [searchParams]); }, [searchParams]);
const hasCheckedUpgradeDialog = useRef(false);
useEffect(() => { useEffect(() => {
if (initialLoadCompleted && subscriptionData) { if (initialLoadCompleted && subscriptionData && !hasCheckedUpgradeDialog.current) {
hasCheckedUpgradeDialog.current = true;
const hasSeenUpgradeDialog = localStorage.getItem('suna_upgrade_dialog_displayed'); const hasSeenUpgradeDialog = localStorage.getItem('suna_upgrade_dialog_displayed');
const isFreeTier = subscriptionStatus === 'no_subscription'; const isFreeTier = subscriptionStatus === 'no_subscription';
if (!hasSeenUpgradeDialog && isFreeTier && !isLocalMode()) { if (!hasSeenUpgradeDialog && isFreeTier && !isLocalMode()) {

View File

@ -125,6 +125,7 @@ export const ChatInput = forwardRef<ChatInputHandles, ChatInputProps>(
const [configModalTab, setConfigModalTab] = useState('integrations'); const [configModalTab, setConfigModalTab] = useState('integrations');
const [registryDialogOpen, setRegistryDialogOpen] = useState(false); const [registryDialogOpen, setRegistryDialogOpen] = useState(false);
const [showSnackbar, setShowSnackbar] = useState(defaultShowSnackbar); const [showSnackbar, setShowSnackbar] = useState(defaultShowSnackbar);
const [userDismissedUsage, setUserDismissedUsage] = useState(false);
const [billingModalOpen, setBillingModalOpen] = useState(false); const [billingModalOpen, setBillingModalOpen] = useState(false);
const { const {
@ -161,12 +162,12 @@ export const ChatInput = forwardRef<ChatInputHandles, ChatInputProps>(
// Auto-show usage preview when we have subscription data // Auto-show usage preview when we have subscription data
useEffect(() => { useEffect(() => {
if (shouldShowUsage && defaultShowSnackbar !== false && (showSnackbar === false || showSnackbar === defaultShowSnackbar)) { if (shouldShowUsage && defaultShowSnackbar !== false && !userDismissedUsage && (showSnackbar === false || showSnackbar === defaultShowSnackbar)) {
setShowSnackbar('upgrade'); setShowSnackbar('upgrade');
} else if (!shouldShowUsage && showSnackbar !== false) { } else if (!shouldShowUsage && showSnackbar !== false) {
setShowSnackbar(false); setShowSnackbar(false);
} }
}, [subscriptionData, showSnackbar, defaultShowSnackbar, shouldShowUsage, subscriptionStatus, showToLowCreditUsers]); }, [subscriptionData, showSnackbar, defaultShowSnackbar, shouldShowUsage, subscriptionStatus, showToLowCreditUsers, userDismissedUsage]);
const textareaRef = useRef<HTMLTextAreaElement>(null); const textareaRef = useRef<HTMLTextAreaElement>(null);
const fileInputRef = useRef<HTMLInputElement>(null); const fileInputRef = useRef<HTMLInputElement>(null);
@ -340,7 +341,7 @@ export const ChatInput = forwardRef<ChatInputHandles, ChatInputProps>(
showToolPreview={showToolPreview} showToolPreview={showToolPreview}
showUsagePreview={showSnackbar} showUsagePreview={showSnackbar}
subscriptionData={subscriptionData} subscriptionData={subscriptionData}
onCloseUsage={() => setShowSnackbar(false)} onCloseUsage={() => { setShowSnackbar(false); setUserDismissedUsage(true); }}
onOpenUpgrade={() => setBillingModalOpen(true)} onOpenUpgrade={() => setBillingModalOpen(true)}
isVisible={showToolPreview || !!showSnackbar} isVisible={showToolPreview || !!showSnackbar}
/> />

View File

@ -56,6 +56,8 @@ export const ChatSnack: React.FC<ChatSnackProps> = ({
notifications.push('usage'); notifications.push('usage');
} }
const totalNotifications = notifications.length; const totalNotifications = notifications.length;
const hasMultiple = totalNotifications > 1; const hasMultiple = totalNotifications > 1;
@ -136,13 +138,15 @@ export const ChatSnack: React.FC<ChatSnackProps> = ({
type={showUsagePreview} type={showUsagePreview}
subscriptionData={subscriptionData} subscriptionData={subscriptionData}
onClose={() => { onClose={() => {
// First close the usage notification
if (onCloseUsage) onCloseUsage(); if (onCloseUsage) onCloseUsage();
// If there are other notifications, switch to them
if (totalNotifications > 1) { // Check what notifications will remain after closing usage
const remainingNotifications = notifications.filter(n => n !== 'usage'); const willHaveToolNotification = showToolPreview && toolCalls.length > 0;
if (remainingNotifications.length > 0) {
setCurrentView(0); // Switch to first remaining notification // If there will be other notifications, switch to them
} if (willHaveToolNotification) {
setCurrentView(0); // Switch to tool notification
} }
}} }}
hasMultiple={hasMultiple} hasMultiple={hasMultiple}

View File

@ -84,7 +84,7 @@ export const UsagePreview: React.FC<UsagePreviewProps> = ({
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<motion.div className="flex items-center gap-2 mb-1"> <motion.div className="flex items-center gap-2 mb-1">
<h4 className="text-sm font-medium text-foreground truncate"> <h4 className="text-sm font-medium text-foreground truncate">
Upgrade for more usage Upgrade for more usage & better AI Models
</h4> </h4>
</motion.div> </motion.div>
@ -124,8 +124,8 @@ export const UsagePreview: React.FC<UsagePreviewProps> = ({
</button> </button>
)} )}
<Button value='ghost' data-close-click className="bg-transparent hover:bg-transparent flex-shrink-0" onClick={onClose}> <Button variant="ghost" size="icon" className="h-8 w-8 flex-shrink-0 hover:bg-muted/50" onClick={(e) => { e.stopPropagation(); onClose?.(); }}>
<X className="h-4 w-4 text-muted-foreground group-hover:text-foreground transition-colors" /> <X className="h-4 w-4 text-muted-foreground hover:text-foreground transition-colors" />
</Button> </Button>
</div> </div>
); );