Add metrics, clean up callbacks
This commit is contained in:
@@ -987,6 +987,17 @@ export type Events = {
|
|||||||
'share:press:recentDm': {}
|
'share:press:recentDm': {}
|
||||||
'share:press:embed': {}
|
'share:press:embed': {}
|
||||||
|
|
||||||
|
'embed:standardSite:view': {url: string}
|
||||||
|
'embed:standardSite:article:press': {url: string}
|
||||||
|
'embed:standardSite:article:longPress': {url: string}
|
||||||
|
'embed:standardSite:publication:press': {url: string}
|
||||||
|
'embed:standardSite:publication:longPress': {url: string}
|
||||||
|
'embed:standardSite:publicationCta:press': {url: string}
|
||||||
|
'embed:standardSite:publicationCta:longPress': {url: string}
|
||||||
|
'embed:standardSite:subscribe:press': {url: string}
|
||||||
|
'embed:standardSite:subscribe:longPress': {url: string}
|
||||||
|
'embed:standardSite:authorHandle:press': {handle: string}
|
||||||
|
|
||||||
'thread:click:showOtherReplies': {}
|
'thread:click:showOtherReplies': {}
|
||||||
'thread:click:hideReplyForMe': {}
|
'thread:click:hideReplyForMe': {}
|
||||||
'thread:click:hideReplyForEveryone': {}
|
'thread:click:hideReplyForEveryone': {}
|
||||||
|
|||||||
@@ -16,14 +16,18 @@ import {
|
|||||||
isStandardSitePublicationUri,
|
isStandardSitePublicationUri,
|
||||||
} from '#/components/Post/Embed/StandardSiteEmbed/utils'
|
} from '#/components/Post/Embed/StandardSiteEmbed/utils'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
export function StandardSiteMetaRow({
|
export function StandardSiteMetaRow({
|
||||||
|
preview,
|
||||||
type = 'document',
|
type = 'document',
|
||||||
view,
|
view,
|
||||||
}: {
|
}: {
|
||||||
|
preview?: boolean
|
||||||
type?: 'document' | 'publication'
|
type?: 'document' | 'publication'
|
||||||
view: AppBskyEmbedExternal.ViewExternal
|
view: AppBskyEmbedExternal.ViewExternal
|
||||||
}) {
|
}) {
|
||||||
|
const ax = useAnalytics()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {t: l} = useLingui()
|
const {t: l} = useLingui()
|
||||||
const highlightedPublisher = !!matchStandardSitePublisher(view)
|
const highlightedPublisher = !!matchStandardSitePublisher(view)
|
||||||
@@ -77,7 +81,15 @@ export function StandardSiteMetaRow({
|
|||||||
<InlineLinkText
|
<InlineLinkText
|
||||||
label={l`View @${authorProfile.handle}'s profile`}
|
label={l`View @${authorProfile.handle}'s profile`}
|
||||||
to={makeProfileLink(authorProfile)}
|
to={makeProfileLink(authorProfile)}
|
||||||
style={[metaTextStyle, a.pointer_events_auto]}>
|
style={[
|
||||||
|
metaTextStyle,
|
||||||
|
preview ? a.pointer_events_none : a.pointer_events_auto,
|
||||||
|
]}
|
||||||
|
onPress={() => {
|
||||||
|
ax.metric('embed:standardSite:authorHandle:press', {
|
||||||
|
handle: authorProfile.handle,
|
||||||
|
})
|
||||||
|
}}>
|
||||||
@{authorProfile.handle}
|
@{authorProfile.handle}
|
||||||
</InlineLinkText>
|
</InlineLinkText>
|
||||||
</Trans>
|
</Trans>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {plural} from '@lingui/core/macro'
|
|||||||
import {useLingui} from '@lingui/react/macro'
|
import {useLingui} from '@lingui/react/macro'
|
||||||
|
|
||||||
import {useHaptics} from '#/lib/haptics'
|
import {useHaptics} from '#/lib/haptics'
|
||||||
|
import {useCallOnce} from '#/lib/once'
|
||||||
import {shareUrl} from '#/lib/sharing'
|
import {shareUrl} from '#/lib/sharing'
|
||||||
import {niceDate} from '#/lib/strings/time'
|
import {niceDate} from '#/lib/strings/time'
|
||||||
import {toNiceDomain} from '#/lib/strings/url-helpers'
|
import {toNiceDomain} from '#/lib/strings/url-helpers'
|
||||||
@@ -22,6 +23,7 @@ import {StandardSiteMetaRow} from '#/components/Post/Embed/StandardSiteEmbed/Sta
|
|||||||
import {StandardSiteThemeProvider} from '#/components/Post/Embed/StandardSiteEmbed/StandardSiteThemeProvider'
|
import {StandardSiteThemeProvider} from '#/components/Post/Embed/StandardSiteEmbed/StandardSiteThemeProvider'
|
||||||
import {isStandardSitePublicationEmbed} from '#/components/Post/Embed/StandardSiteEmbed/utils'
|
import {isStandardSitePublicationEmbed} from '#/components/Post/Embed/StandardSiteEmbed/utils'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_NATIVE} from '#/env'
|
import {IS_NATIVE} from '#/env'
|
||||||
|
|
||||||
export type ThemeColors = {
|
export type ThemeColors = {
|
||||||
@@ -35,14 +37,20 @@ const PUBLICATION_AVATAR_STYLE = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const StandardSiteEmbed = ({
|
export const StandardSiteEmbed = ({
|
||||||
|
preview,
|
||||||
view,
|
view,
|
||||||
onOpen,
|
onEmbedInteractionCallback,
|
||||||
style,
|
style,
|
||||||
}: {
|
}: {
|
||||||
|
/**
|
||||||
|
* Indicates the card is showing the composer
|
||||||
|
*/
|
||||||
|
preview?: boolean
|
||||||
view: AppBskyEmbedExternal.ViewExternal
|
view: AppBskyEmbedExternal.ViewExternal
|
||||||
onOpen?: () => void
|
onEmbedInteractionCallback?: () => void
|
||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
}) => {
|
}) => {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {t: l, i18n} = useLingui()
|
const {t: l, i18n} = useLingui()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const playHaptic = useHaptics()
|
const playHaptic = useHaptics()
|
||||||
@@ -76,27 +84,51 @@ export const StandardSiteEmbed = ({
|
|||||||
onIn: onInteract,
|
onIn: onInteract,
|
||||||
onOut: onInteractOut,
|
onOut: onInteractOut,
|
||||||
} = useInteractionState()
|
} = useInteractionState()
|
||||||
|
|
||||||
const onPress = () => {
|
const onPress = () => {
|
||||||
playHaptic('Light')
|
playHaptic('Light')
|
||||||
onOpen?.()
|
onEmbedInteractionCallback?.()
|
||||||
|
ax.metric('embed:standardSite:article:press', {url: view.uri})
|
||||||
}
|
}
|
||||||
|
|
||||||
const onLongPress = () => {
|
const onLongPress = () => {
|
||||||
if (view.uri && IS_NATIVE) {
|
if (view.uri && IS_NATIVE) {
|
||||||
playHaptic('Heavy')
|
playHaptic('Heavy')
|
||||||
shareUrl(view.uri)
|
shareUrl(view.uri)
|
||||||
|
ax.metric('embed:standardSite:article:longPress', {url: view.uri})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const onPressPublication = () => {
|
||||||
|
playHaptic('Light')
|
||||||
|
onEmbedInteractionCallback?.()
|
||||||
|
ax.metric('embed:standardSite:publication:press', {
|
||||||
|
url: view.source?.uri || '',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const onLongPressPublication = () => {
|
||||||
|
if (view.source?.uri && IS_NATIVE) {
|
||||||
|
playHaptic('Heavy')
|
||||||
|
shareUrl(view.source.uri)
|
||||||
|
ax.metric('embed:standardSite:publication:longPress', {
|
||||||
|
url: view.source.uri,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useCallOnce(() => {
|
||||||
|
if (!preview) {
|
||||||
|
ax.metric('embed:standardSite:view', {url: view.uri})
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
|
||||||
if (isStandardPublication) {
|
if (isStandardPublication) {
|
||||||
return (
|
return (
|
||||||
<PublicationCard
|
<PublicationCard
|
||||||
|
preview={preview}
|
||||||
view={view}
|
view={view}
|
||||||
onPress={onPress}
|
onPress={onPressPublication}
|
||||||
onLongPress={onLongPress}
|
onLongPress={onLongPressPublication}
|
||||||
style={style}
|
style={style}
|
||||||
themeColors={themeColors}
|
themeColors={themeColors}
|
||||||
|
onEmbedInteractionCallback={onEmbedInteractionCallback}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -111,6 +143,7 @@ export const StandardSiteEmbed = ({
|
|||||||
a.border,
|
a.border,
|
||||||
t.atoms.bg,
|
t.atoms.bg,
|
||||||
interacted ? t.atoms.border_contrast_high : t.atoms.border_contrast_low,
|
interacted ? t.atoms.border_contrast_high : t.atoms.border_contrast_low,
|
||||||
|
preview && a.pointer_events_none,
|
||||||
style,
|
style,
|
||||||
]}>
|
]}>
|
||||||
<Link
|
<Link
|
||||||
@@ -224,7 +257,7 @@ export const StandardSiteEmbed = ({
|
|||||||
<View style={[a.px_md]}>
|
<View style={[a.px_md]}>
|
||||||
<Divider />
|
<Divider />
|
||||||
<View style={[a.py_sm]}>
|
<View style={[a.py_sm]}>
|
||||||
<StandardSiteMetaRow view={view} />
|
<StandardSiteMetaRow preview={preview} view={view} />
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
@@ -234,11 +267,13 @@ export const StandardSiteEmbed = ({
|
|||||||
<View style={[a.z_20]}>
|
<View style={[a.z_20]}>
|
||||||
<Divider />
|
<Divider />
|
||||||
<PublicationFooter
|
<PublicationFooter
|
||||||
|
preview={preview}
|
||||||
view={view}
|
view={view}
|
||||||
onPress={onPress}
|
onPress={onPressPublication}
|
||||||
onLongPress={onLongPress}
|
onLongPress={onLongPressPublication}
|
||||||
themeColors={themeColors}
|
themeColors={themeColors}
|
||||||
interactedOuter={interacted}
|
interactedOuter={interacted}
|
||||||
|
onEmbedInteractionCallback={onEmbedInteractionCallback}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
@@ -247,17 +282,21 @@ export const StandardSiteEmbed = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function PublicationCard({
|
export function PublicationCard({
|
||||||
|
preview,
|
||||||
view,
|
view,
|
||||||
onPress,
|
onPress,
|
||||||
onLongPress,
|
onLongPress,
|
||||||
themeColors,
|
themeColors,
|
||||||
style,
|
style,
|
||||||
|
onEmbedInteractionCallback,
|
||||||
}: {
|
}: {
|
||||||
|
preview?: boolean
|
||||||
view: AppBskyEmbedExternal.ViewExternal
|
view: AppBskyEmbedExternal.ViewExternal
|
||||||
onPress?: () => void
|
onPress?: () => void
|
||||||
onLongPress?: () => void
|
onLongPress?: () => void
|
||||||
themeColors: ThemeColors
|
themeColors: ThemeColors
|
||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
|
onEmbedInteractionCallback?: () => void
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {t: l} = useLingui()
|
const {t: l} = useLingui()
|
||||||
@@ -330,16 +369,20 @@ export function PublicationCard({
|
|||||||
style={[a.text_md, a.font_semi_bold, t.atoms.text]}>
|
style={[a.text_md, a.font_semi_bold, t.atoms.text]}>
|
||||||
{view.source?.title}
|
{view.source?.title}
|
||||||
</Text>
|
</Text>
|
||||||
<StandardSiteMetaRow type="publication" view={view} />
|
<StandardSiteMetaRow
|
||||||
|
preview={preview}
|
||||||
|
type="publication"
|
||||||
|
view={view}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{gtPhone && (
|
{gtPhone && (
|
||||||
<SubscribeButton
|
<SubscribeButton
|
||||||
|
preview={preview}
|
||||||
view={view}
|
view={view}
|
||||||
style={[!gtPhone && [a.w_full, a.justify_center]]}
|
style={[!gtPhone && [a.w_full, a.justify_center]]}
|
||||||
onPress={onPress}
|
onEmbedInteractionCallback={onEmbedInteractionCallback}
|
||||||
onLongPress={onLongPress}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
@@ -356,10 +399,10 @@ export function PublicationCard({
|
|||||||
{!gtPhone && (
|
{!gtPhone && (
|
||||||
<View style={[view.description && a.pt_sm]}>
|
<View style={[view.description && a.pt_sm]}>
|
||||||
<SubscribeButton
|
<SubscribeButton
|
||||||
|
preview={preview}
|
||||||
view={view}
|
view={view}
|
||||||
style={[!gtPhone && [a.w_full, a.justify_center]]}
|
style={[!gtPhone && [a.w_full, a.justify_center]]}
|
||||||
onPress={onPress}
|
onEmbedInteractionCallback={onEmbedInteractionCallback}
|
||||||
onLongPress={onLongPress}
|
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
@@ -369,17 +412,20 @@ export function PublicationCard({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function SubscribeButton({
|
export function SubscribeButton({
|
||||||
|
preview,
|
||||||
view,
|
view,
|
||||||
onPress,
|
|
||||||
onLongPress,
|
|
||||||
style,
|
style,
|
||||||
|
onEmbedInteractionCallback,
|
||||||
}: {
|
}: {
|
||||||
|
preview?: boolean
|
||||||
view: AppBskyEmbedExternal.ViewExternal
|
view: AppBskyEmbedExternal.ViewExternal
|
||||||
onPress?: () => void
|
|
||||||
onLongPress?: () => void
|
|
||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
|
onEmbedInteractionCallback?: () => void
|
||||||
}) {
|
}) {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {t: l} = useLingui()
|
const {t: l} = useLingui()
|
||||||
|
const playHaptic = useHaptics()
|
||||||
|
|
||||||
const highlightedPublisher = matchStandardSitePublisher(view)
|
const highlightedPublisher = matchStandardSitePublisher(view)
|
||||||
const cta = highlightedPublisher
|
const cta = highlightedPublisher
|
||||||
? l`Subscribe on ${highlightedPublisher.name}`
|
? l`Subscribe on ${highlightedPublisher.name}`
|
||||||
@@ -396,6 +442,36 @@ export function SubscribeButton({
|
|||||||
? l`View ${publicationTitle}`
|
? l`View ${publicationTitle}`
|
||||||
: l`View publication`
|
: l`View publication`
|
||||||
|
|
||||||
|
const onPress = () => {
|
||||||
|
playHaptic('Light')
|
||||||
|
onEmbedInteractionCallback?.()
|
||||||
|
if (highlightedPublisher) {
|
||||||
|
ax.metric('embed:standardSite:subscribe:press', {
|
||||||
|
url: view.source?.uri || '',
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ax.metric('embed:standardSite:publicationCta:press', {
|
||||||
|
url: view.source?.uri || '',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onLongPress = () => {
|
||||||
|
if (view.source?.uri && IS_NATIVE) {
|
||||||
|
playHaptic('Heavy')
|
||||||
|
shareUrl(view.source.uri)
|
||||||
|
if (highlightedPublisher) {
|
||||||
|
ax.metric('embed:standardSite:subscribe:longPress', {
|
||||||
|
url: view.source?.uri || '',
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ax.metric('embed:standardSite:publicationCta:longPress', {
|
||||||
|
url: view.source?.uri || '',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StandardSiteThemeProvider view={view}>
|
<StandardSiteThemeProvider view={view}>
|
||||||
<Link
|
<Link
|
||||||
@@ -404,7 +480,11 @@ export function SubscribeButton({
|
|||||||
label={label}
|
label={label}
|
||||||
size="small"
|
size="small"
|
||||||
color="secondary_inverted"
|
color="secondary_inverted"
|
||||||
style={[style, a.gap_sm, a.pointer_events_auto]}
|
style={[
|
||||||
|
style,
|
||||||
|
a.gap_sm,
|
||||||
|
preview ? a.pointer_events_none : a.pointer_events_auto,
|
||||||
|
]}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
onLongPress={onLongPress}>
|
onLongPress={onLongPress}>
|
||||||
{highlightedPublisher ? (
|
{highlightedPublisher ? (
|
||||||
@@ -470,17 +550,21 @@ function PublicationIcon({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function PublicationFooter({
|
export function PublicationFooter({
|
||||||
|
preview,
|
||||||
view,
|
view,
|
||||||
themeColors,
|
themeColors,
|
||||||
onPress,
|
onPress,
|
||||||
onLongPress,
|
onLongPress,
|
||||||
interactedOuter,
|
interactedOuter,
|
||||||
|
onEmbedInteractionCallback,
|
||||||
}: {
|
}: {
|
||||||
|
preview?: boolean
|
||||||
view: AppBskyEmbedExternal.ViewExternal
|
view: AppBskyEmbedExternal.ViewExternal
|
||||||
themeColors: ThemeColors
|
themeColors: ThemeColors
|
||||||
onPress?: () => void
|
onPress?: () => void
|
||||||
onLongPress?: () => void
|
onLongPress?: () => void
|
||||||
interactedOuter?: boolean
|
interactedOuter?: boolean
|
||||||
|
onEmbedInteractionCallback?: () => void
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {t: l} = useLingui()
|
const {t: l} = useLingui()
|
||||||
@@ -503,8 +587,8 @@ export function PublicationFooter({
|
|||||||
a.gap_md,
|
a.gap_md,
|
||||||
gtPhone && [a.flex_row, a.gap_sm],
|
gtPhone && [a.flex_row, a.gap_sm],
|
||||||
interactedOuter && t.atoms.bg_contrast_25,
|
interactedOuter && t.atoms.bg_contrast_25,
|
||||||
]}
|
preview && a.pointer_events_none,
|
||||||
testID="publication-embed-footer">
|
]}>
|
||||||
<Link
|
<Link
|
||||||
shouldProxy
|
shouldProxy
|
||||||
to={view.source.uri}
|
to={view.source.uri}
|
||||||
@@ -549,15 +633,19 @@ export function PublicationFooter({
|
|||||||
]}>
|
]}>
|
||||||
{view.source?.title}
|
{view.source?.title}
|
||||||
</Text>
|
</Text>
|
||||||
<StandardSiteMetaRow type="publication" view={view} />
|
<StandardSiteMetaRow
|
||||||
|
preview={preview}
|
||||||
|
type="publication"
|
||||||
|
view={view}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<SubscribeButton
|
<SubscribeButton
|
||||||
|
preview={preview}
|
||||||
view={view}
|
view={view}
|
||||||
style={[a.z_10, !gtPhone && [a.w_full, a.justify_center]]}
|
style={[a.z_10, !gtPhone && [a.w_full, a.justify_center]]}
|
||||||
onPress={onPress}
|
onEmbedInteractionCallback={onEmbedInteractionCallback}
|
||||||
onLongPress={onLongPress}
|
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ function MediaEmbed({
|
|||||||
activeStyle={[a.mt_sm]}>
|
activeStyle={[a.mt_sm]}>
|
||||||
<StandardSiteEmbed
|
<StandardSiteEmbed
|
||||||
view={embed.view.external}
|
view={embed.view.external}
|
||||||
|
onEmbedInteractionCallback={rest.onOpen}
|
||||||
style={[a.mt_sm, rest.style]}
|
style={[a.mt_sm, rest.style]}
|
||||||
/>
|
/>
|
||||||
</ContentHider>
|
</ContentHider>
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ export const ExternalEmbedLink = ({
|
|||||||
if (data.view && isStandardSiteEmbed(data.view.external)) {
|
if (data.view && isStandardSiteEmbed(data.view.external)) {
|
||||||
return (
|
return (
|
||||||
<StandardSiteEmbed
|
<StandardSiteEmbed
|
||||||
|
preview
|
||||||
view={{
|
view={{
|
||||||
...data.view?.external,
|
...data.view?.external,
|
||||||
title: data.view?.external?.title || data.title || uri,
|
title: data.view?.external?.title || data.title || uri,
|
||||||
|
|||||||
Reference in New Issue
Block a user