1- import { memo , ReactNode , useEffect , useState , useRef } from "react"
2- import { vscode } from "@src/utils/vscode"
1+ import { memo , ReactNode } from "react"
32import { useAppTranslation } from "@src/i18n/TranslationContext"
3+ import { DismissedUpsellsProvider , useDismissedUpsells } from "@src/context/DismissedUpsellsContext"
44
55interface DismissibleUpsellProps {
66 /** Required unique identifier for this upsell */
@@ -32,7 +32,8 @@ const DismissIcon = () => (
3232 </ svg >
3333)
3434
35- const DismissibleUpsell = memo (
35+ // Internal component that uses the context
36+ const DismissibleUpsellInternal = memo (
3637 ( {
3738 upsellId,
3839 className,
@@ -44,55 +45,21 @@ const DismissibleUpsell = memo(
4445 dismissOnClick = false ,
4546 } : DismissibleUpsellProps ) => {
4647 const { t } = useAppTranslation ( )
47- const [ isVisible , setIsVisible ] = useState ( false )
48- const isMountedRef = useRef ( true )
48+ const { isUpsellVisible, dismissUpsell, isLoading } = useDismissedUpsells ( )
4949
50- useEffect ( ( ) => {
51- // Track mounted state
52- isMountedRef . current = true
50+ // Check if this upsell is visible
51+ const isVisible = isUpsellVisible ( upsellId )
5352
54- // Request the current list of dismissed upsells from the extension
55- vscode . postMessage ( { type : "getDismissedUpsells" } )
56-
57- // Listen for the response
58- const handleMessage = ( event : MessageEvent ) => {
59- // Only update state if component is still mounted
60- if ( ! isMountedRef . current ) return
61-
62- const message = event . data
63- // Add null/undefined check for message
64- if ( message && message . type === "dismissedUpsells" && Array . isArray ( message . list ) ) {
65- // Check if this upsell has been dismissed
66- if ( ! message . list . includes ( upsellId ) ) {
67- setIsVisible ( true )
68- }
69- }
70- }
71-
72- window . addEventListener ( "message" , handleMessage )
73- return ( ) => {
74- isMountedRef . current = false
75- window . removeEventListener ( "message" , handleMessage )
76- }
77- } , [ upsellId ] )
78-
79- const handleDismiss = async ( ) => {
80- // First notify the extension to persist the dismissal
81- // This ensures the message is sent even if the component unmounts quickly
82- vscode . postMessage ( {
83- type : "dismissUpsell" ,
84- upsellId : upsellId ,
85- } )
86-
87- // Then hide the upsell
88- setIsVisible ( false )
53+ const handleDismiss = ( ) => {
54+ // Dismiss the upsell through the context
55+ dismissUpsell ( upsellId )
8956
9057 // Call the optional callback
9158 onDismiss ?.( )
9259 }
9360
94- // Don't render if not visible
95- if ( ! isVisible ) {
61+ // Don't render if not visible or still loading
62+ if ( ! isVisible || isLoading ) {
9663 return null
9764 }
9865
@@ -107,6 +74,7 @@ const DismissibleUpsell = memo(
10774 button : "text-vscode-notifications-foreground" ,
10875 } ,
10976 }
77+
11078 // Build container classes based on variant and presence of click handler
11179 const containerClasses = [
11280 "relative flex items-start justify-between gap-2" ,
@@ -158,6 +126,17 @@ const DismissibleUpsell = memo(
158126 } ,
159127)
160128
129+ DismissibleUpsellInternal . displayName = "DismissibleUpsellInternal"
130+
131+ // Wrapper component that provides the context
132+ const DismissibleUpsell = memo ( ( props : DismissibleUpsellProps ) => {
133+ return (
134+ < DismissedUpsellsProvider >
135+ < DismissibleUpsellInternal { ...props } />
136+ </ DismissedUpsellsProvider >
137+ )
138+ } )
139+
161140DismissibleUpsell . displayName = "DismissibleUpsell"
162141
163142export default DismissibleUpsell
0 commit comments