Roo-Code/webview-ui/src/hooks/useCloudUpsell.ts
Bruno Bergher 469a70fe5d
feat: In-extension dismissible upsells for Roo Code Cloud (#7850)
* First pass at separate upsell dialog

* Revert PR #7188 - Restore temperature parameter to fix TabbyApi/ExLlamaV2 crashes (#7594)

* fix: reduce CodeBlock button z-index to prevent overlap with popovers (#7783)

Fixes #7703 - CodeBlock language dropdown and copy button were appearing above popovers due to z-index: 100. Reduced to z-index: 40 to maintain proper layering hierarchy while keeping buttons functional.

* Make ollama models info transport work like lmstudio (#7679)

* feat: add click-to-edit, ESC-to-cancel, and fix padding consistency for chat messages (#7790)

* feat: add click-to-edit, ESC-to-cancel, and fix padding consistency

- Enable click-to-edit for past messages by making message text clickable
- Add ESC key handler to cancel edit mode in ChatTextArea
- Fix padding consistency between past and queued message editors
- Adjust right padding for edit mode to accommodate cancel button

Fixes #7788

* fix: adjust padding and layout for ChatTextArea in edit mode

* refactor: replace hardcoded pr-[72px] with standard Tailwind pr-20 class

---------

Co-authored-by: Roo Code <roomote@roocode.com>
Co-authored-by: Hannes Rudolph <hrudolph@gmail.com>
Co-authored-by: daniel-lxs <ricciodaniel98@gmail.com>

* Let people paste in the auth redirect url (#7805)

Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com>
Co-authored-by: Bruno Bergher <me@brunobergher.com>

* fix: resolve chat message edit/delete duplication issues (#7793)

* fix: add GIT_EDITOR env var to merge-resolver mode for non-interactive rebase (#7819)

* UI: Render reasoning as plain italic (match <thinking>) (#7752)

Co-authored-by: Roo Code <roomote@roocode.com>
Co-authored-by: Hannes Rudolph <hrudolph@gmail.com>
Co-authored-by: daniel-lxs <ricciodaniel98@gmail.com>

* Add taskSyncEnabled to userSettingsConfigSchema (#7827)

feat: add taskSyncEnabled to userSettingsConfigSchema

Co-authored-by: Roo Code <roomote@roocode.com>

* Release: v1.75.0 (#7829)

chore: bump version to v1.75.0

* fix: prevent negative cost values and improve label visibility in evals chart (#7830)

Co-authored-by: Roo Code <roomote@roocode.com>

* Fix Groq context window display (#7839)

* feat: add DismissibleUpsell component for dismissible messages

- Created DismissibleUpsell component with variant support (banner/default)
- Added dismissedUpsells to GlobalState for persistence
- Implemented message handlers for dismissing and retrieving dismissed upsells
- Added comprehensive tests for the component
- Uses VSCode extension globalState for persistent storage

* fix: Apply PR feedback for DismissibleUpsell component

- Changed from className to separate 'id' and 'className' props for better semantics
- Added i18n support for accessibility labels (aria-label and title)
- Fixed memory leak by adding mounted flag to prevent state updates after unmount
- Fixed race condition by sending dismiss message before hiding component
- Fixed inefficient array operations in webviewMessageHandler
- Added comprehensive test coverage for edge cases including:
  - Multiple rapid dismissals
  - Component unmounting during async operations
  - Invalid/malformed message handling
  - Proper message sending before unmount
- Added null checks for message data to handle edge cases gracefully

* New Cloud upsell dialog in task share and cloud view, shared component

* Properly working DismissibleUpsell

* Working upsell for long-running tasks

* CTA in AutoApproveMenu

* Home page CTA

* Fixes the autoapprove upsell and some tests

* Visual and copy fixes

* Test fix

* Translations

* Stray className attribute

* Cloud view fixes in a left-aligned layout

* Removes unnecessary test

* Less flaky tests

* Fixes sharebutton behavior and updates associated tests

* Update webview-ui/src/i18n/locales/it/cloud.json

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* Fix dismissed flicker

* Fix long task upsell

---------

Co-authored-by: Daniel <57051444+daniel-lxs@users.noreply.github.com>
Co-authored-by: ItsOnlyBinary <ItsOnlyBinary@users.noreply.github.com>
Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com>
Co-authored-by: Roo Code <roomote@roocode.com>
Co-authored-by: Hannes Rudolph <hrudolph@gmail.com>
Co-authored-by: daniel-lxs <ricciodaniel98@gmail.com>
Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com>
Co-authored-by: John Richmond <5629+jr@users.noreply.github.com>
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-09-10 13:06:13 -07:00

71 lines
2.1 KiB
TypeScript

import { useState, useCallback, useRef, useEffect } from "react"
import { TelemetryEventName } from "@roo-code/types"
import { vscode } from "@/utils/vscode"
import { telemetryClient } from "@/utils/TelemetryClient"
import { useExtensionState } from "@/context/ExtensionStateContext"
interface UseCloudUpsellOptions {
onAuthSuccess?: () => void
autoOpenOnAuth?: boolean
}
export const useCloudUpsell = (options: UseCloudUpsellOptions = {}) => {
const { onAuthSuccess, autoOpenOnAuth = false } = options
const [isOpen, setIsOpen] = useState(false)
const [shouldOpenOnAuth, setShouldOpenOnAuth] = useState(false)
const { cloudIsAuthenticated, sharingEnabled } = useExtensionState()
const wasUnauthenticatedRef = useRef(false)
const initiatedAuthRef = useRef(false)
// Track authentication state changes
useEffect(() => {
if (!cloudIsAuthenticated || !sharingEnabled) {
wasUnauthenticatedRef.current = true
} else if (wasUnauthenticatedRef.current && cloudIsAuthenticated && sharingEnabled) {
// User just authenticated
if (initiatedAuthRef.current) {
// Auth was initiated from this hook
telemetryClient.capture(TelemetryEventName.ACCOUNT_CONNECT_SUCCESS)
setIsOpen(false) // Close the upsell dialog
if (autoOpenOnAuth && shouldOpenOnAuth) {
onAuthSuccess?.()
setShouldOpenOnAuth(false)
}
initiatedAuthRef.current = false // Reset the flag
}
wasUnauthenticatedRef.current = false
}
}, [cloudIsAuthenticated, sharingEnabled, onAuthSuccess, autoOpenOnAuth, shouldOpenOnAuth])
const openUpsell = useCallback(() => {
setIsOpen(true)
}, [])
const closeUpsell = useCallback(() => {
setIsOpen(false)
setShouldOpenOnAuth(false)
}, [])
const handleConnect = useCallback(() => {
// Mark that authentication was initiated from this hook
initiatedAuthRef.current = true
setShouldOpenOnAuth(true)
// Send message to VS Code to initiate sign in
vscode.postMessage({ type: "rooCloudSignIn" })
// Close the upsell dialog
closeUpsell()
}, [closeUpsell])
return {
isOpen,
openUpsell,
closeUpsell,
handleConnect,
isAuthenticated: cloudIsAuthenticated,
sharingEnabled,
}
}