-
Notifications
You must be signed in to change notification settings - Fork 357
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(llm): 🗒️ log content card impression when 50% of the card is sho…
…wn (#8526) * feat(llm): log category cards impression when 50% of the card is visible * feat(llm): do not run in view checks when no items is being watched * feat(llm): log portfolio content cards impression on 50% visibility * chore: update change log * feat(llm): log dynamic content card impression when 50% is shown * feat(llm): log notification impression when 50% is shown * chore(llm): rename IsInViewContext to InViewContext * chore(llm): add InViewContextProvider to the AppProviders * fix(llm): undefined order in null * feat(lld): log category impression when 50% is shown * chore(llm): use LLM alias in imports * feat(llm): trigger segment event on card impression * fix(llm): rewatch card when `LogContentCardWrapper.id` change * fix(llm): use mobileCardsSelector to find the card to log the impression * fix(llm): race condition between interval and inViewStatus * chore(llm): check "exhaustive-deps" on `useInViewContext` * chore(llm): remove unnecessary key
- Loading branch information
Showing
16 changed files
with
294 additions
and
81 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"live-mobile": minor | ||
--- | ||
|
||
Log content card impression when 50% of the card is shown |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
92 changes: 92 additions & 0 deletions
92
apps/ledger-live-mobile/src/newArch/contexts/InViewContext/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import React, { | ||
createContext, | ||
DependencyList, | ||
type ReactNode, | ||
type RefObject, | ||
useCallback, | ||
useContext, | ||
useEffect, | ||
useRef, | ||
useState, | ||
} from "react"; | ||
import { Dimensions, type View } from "react-native"; | ||
import { concatMap, from, interval } from "rxjs"; | ||
import type { InViewOptions, InViewContext, InViewEntry, WatchedItem } from "./types"; | ||
import { inViewStatus } from "./utils"; | ||
|
||
const InViewContext = createContext<InViewContext>({}); | ||
|
||
export function useInViewContext( | ||
onInViewUpdate: (entry: InViewEntry) => void, | ||
deps: DependencyList = [], | ||
target: RefObject<View>, | ||
) { | ||
const { addWatchedItem, removeWatchedItem } = useContext(InViewContext); | ||
const onInViewUpdateCb = useCallback(onInViewUpdate, deps); // eslint-disable-line react-hooks/exhaustive-deps | ||
|
||
useEffect(() => { | ||
const item = { target, onInViewUpdate: onInViewUpdateCb }; | ||
addWatchedItem?.(item); | ||
return () => removeWatchedItem?.(item); | ||
}, [target, onInViewUpdateCb, addWatchedItem, removeWatchedItem]); | ||
} | ||
|
||
export function InViewContextProvider({ | ||
inViewThreshold = 0.5, | ||
outOfViewThreshold = 0, | ||
interval: intervalDuration = 200, | ||
children, | ||
}: InViewOptions & { children: ReactNode }) { | ||
const items = useRef<WatchedItem[]>([]); | ||
const [hasItems, setHasItems] = useState(false); | ||
|
||
const addWatchedItem = useCallback((item: WatchedItem) => { | ||
if (items.current.length === 0) setHasItems(true); | ||
items.current.push(item); | ||
}, []); | ||
const removeWatchedItem = useCallback((item: WatchedItem) => { | ||
const index = items.current.indexOf(item); | ||
if (index === -1) return; | ||
items.current.splice(index, 1); | ||
if (items.current.length === 0) setHasItems(false); | ||
}, []); | ||
|
||
const watchedItem = useRef(new WeakMap<WatchedItem, boolean>()); | ||
|
||
useEffect(() => { | ||
if (!hasItems) return; | ||
|
||
const window = Dimensions.get("window"); | ||
const observer = interval(intervalDuration).pipe( | ||
concatMap(() => | ||
from( | ||
Promise.all( | ||
items.current.map(async item => { | ||
const threshold = watchedItem.current.get(item) | ||
? outOfViewThreshold | ||
: inViewThreshold; | ||
|
||
const entry = await inViewStatus(item.target, threshold, window); | ||
return { item, entry }; | ||
}), | ||
), | ||
), | ||
), | ||
); | ||
|
||
const subscription = observer.subscribe(res => { | ||
res.forEach(({ item, entry }) => { | ||
if (entry.isInView === watchedItem.current.get(item)) return; | ||
watchedItem.current.set(item, entry.isInView); | ||
item.onInViewUpdate(entry); | ||
}); | ||
}); | ||
return () => subscription.unsubscribe(); | ||
}, [hasItems, inViewThreshold, outOfViewThreshold, intervalDuration]); | ||
|
||
return ( | ||
<InViewContext.Provider value={{ addWatchedItem, removeWatchedItem }}> | ||
{children} | ||
</InViewContext.Provider> | ||
); | ||
} |
Oops, something went wrong.