this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Pass correct log context to suggested user metrics (#10074)

authored by

DS Boyce and committed by
GitHub
d44060a3 2c828b57

+98 -76
+17 -12
src/analytics/metrics/types.ts
··· 480 480 'suggestedUser:follow': { 481 481 logContext: 482 482 | 'Explore' 483 - | 'InterstitialDiscover' 484 - | 'InterstitialProfile' 485 - | 'Profile' 483 + | 'DiscoverInterstitial' 484 + | 'ProfileInterstitial' 485 + | 'ProfileHeader' 486 486 | 'Onboarding' 487 + | 'SeeMoreSuggestedUsers' 488 + | 'ProgressGuide' 487 489 location: 'Card' | 'Profile' | 'FollowAll' 488 490 recId?: number | string 489 491 position: number ··· 493 495 'suggestedUser:press': { 494 496 logContext: 495 497 | 'Explore' 496 - | 'InterstitialDiscover' 497 - | 'InterstitialProfile' 498 + | 'DiscoverInterstitial' 499 + | 'ProfileInterstitial' 500 + | 'ProfileHeader' 498 501 | 'Onboarding' 502 + | 'SeeMoreSuggestedUsers' 499 503 recId?: number | string 500 504 position: number 501 505 suggestedDid: string ··· 504 508 'suggestedUser:seen': { 505 509 logContext: 506 510 | 'Explore' 507 - | 'InterstitialDiscover' 508 - | 'InterstitialProfile' 509 - | 'Profile' 511 + | 'DiscoverInterstitial' 512 + | 'ProfileInterstitial' 513 + | 'ProfileHeader' 510 514 | 'Onboarding' 515 + | 'SeeMoreSuggestedUsers' 511 516 | 'ProgressGuide' 512 517 recId?: number | string 513 518 position: number ··· 517 522 'suggestedUser:seeMore': { 518 523 logContext: 519 524 | 'Explore' 520 - | 'InterstitialDiscover' 521 - | 'InterstitialProfile' 522 - | 'Profile' 525 + | 'DiscoverInterstitial' 526 + | 'ProfileInterstitial' 527 + | 'ProfileHeader' 523 528 | 'Onboarding' 524 529 recId?: number | string 525 530 } 526 531 'suggestedUser:dismiss': { 527 - logContext: 'InterstitialDiscover' | 'InterstitialProfile' 532 + logContext: 'DiscoverInterstitial' | 'ProfileInterstitial' | 'ProfileHeader' 528 533 recId?: number | string 529 534 position: number 530 535 suggestedDid: string
+19 -29
src/components/FeedInterstitials.tsx
··· 8 8 LinearTransition, 9 9 } from 'react-native-reanimated' 10 10 import {type AppBskyFeedDefs, AtUri} from '@atproto/api' 11 - import {msg} from '@lingui/core/macro' 12 - import {useLingui} from '@lingui/react' 13 - import {Trans} from '@lingui/react/macro' 11 + import {Trans, useLingui} from '@lingui/react/macro' 14 12 import {useNavigation} from '@react-navigation/native' 15 13 16 14 import {type NavigationProp} from '#/lib/routes/types' ··· 295 293 }) { 296 294 const t = useTheme() 297 295 const ax = useAnalytics() 298 - const {_} = useLingui() 296 + const {t: l} = useLingui() 299 297 const moderationOpts = useModerationOpts() 300 298 const {gtMobile} = useBreakpoints() 301 299 const followDialogControl = useDialogControl() ··· 312 310 const containerRef = useRef<View>(null) 313 311 const hasTrackedRef = useRef(false) 314 312 const logContext: Metrics['suggestedUser:seen']['logContext'] = isFeedContext 315 - ? 'InterstitialDiscover' 313 + ? 'DiscoverInterstitial' 316 314 : isProfileHeaderContext 317 - ? 'Profile' 318 - : 'InterstitialProfile' 315 + ? 'ProfileHeader' 316 + : 'ProfileInterstitial' 319 317 320 318 // Callback to fire seen events 321 319 const fireSeen = useCallback(() => { ··· 336 334 }) 337 335 } 338 336 }) 339 - }, [ax, isLoading, error, profiles, maxLength, logContext]) 337 + }, [isLoading, error, profiles, maxLength, ax, logContext]) 340 338 341 339 // For profile header, fire when isVisible becomes true 342 340 useEffect(() => { ··· 424 422 profile={profile.actor} 425 423 onPress={() => { 426 424 ax.metric('suggestedUser:press', { 427 - logContext: isFeedContext 428 - ? 'InterstitialDiscover' 429 - : 'InterstitialProfile', 425 + logContext, 430 426 recId: profile.recId, 431 427 position: index, 432 428 suggestedDid: profile.actor.did, ··· 442 438 <ProfileCard.Outer> 443 439 {onDismiss && ( 444 440 <Button 445 - label={_(msg`Dismiss this suggestion`)} 441 + label={l`Dismiss this suggestion`} 446 442 onPress={e => { 447 443 e.preventDefault() 448 444 onDismiss(profile.actor.did) 449 445 ax.metric('suggestedUser:dismiss', { 450 - logContext: isFeedContext 451 - ? 'InterstitialDiscover' 452 - : 'InterstitialProfile', 446 + logContext, 453 447 position: index, 454 448 suggestedDid: profile.actor.did, 455 449 recId: profile.recId, ··· 515 509 style={[a.rounded_sm]} 516 510 onFollow={() => { 517 511 ax.metric('suggestedUser:follow', { 518 - logContext: isFeedContext 519 - ? 'InterstitialDiscover' 520 - : 'InterstitialProfile', 521 - location: 'Card', 512 + logContext, 513 + location: 'Profile', 522 514 recId: profile.recId, 523 515 position: index, 524 516 suggestedDid: profile.actor.did, ··· 570 562 </Text> 571 563 {!isProfileHeaderContext && ( 572 564 <Button 573 - label={_(msg`See more suggested profiles`)} 565 + label={l`See more suggested profiles`} 574 566 onPress={() => { 575 567 followDialogControl.open() 576 568 ax.metric('suggestedUser:seeMore', { 577 - logContext: isFeedContext ? 'Explore' : 'Profile', 569 + logContext, 578 570 recId, 579 571 }) 580 572 }}> ··· 595 587 </Button> 596 588 )} 597 589 </View> 598 - 599 590 <FollowDialogWithoutGuide control={followDialogControl} /> 600 - 601 591 <LayoutAnimationConfig skipExiting skipEntering> 602 592 {gtMobile ? ( 603 593 <View style={[a.p_lg, a.pt_md]}> ··· 620 610 onPress={() => { 621 611 followDialogControl.open() 622 612 ax.metric('suggestedUser:seeMore', { 623 - logContext: 'Explore', 613 + logContext, 624 614 }) 625 615 }} 626 616 /> ··· 634 624 } 635 625 636 626 function SeeMoreSuggestedProfilesCard({onPress}: {onPress: () => void}) { 637 - const {_} = useLingui() 627 + const {t: l} = useLingui() 638 628 639 629 return ( 640 630 <Button 641 - label={_(msg`Browse more accounts`)} 631 + label={l`Browse more accounts`} 642 632 onPress={onPress} 643 633 style={[ 644 634 a.flex_col, ··· 662 652 export function SuggestedFeeds() { 663 653 const t = useTheme() 664 654 const ax = useAnalytics() 665 - const {_} = useLingui() 655 + const {t: l} = useLingui() 666 656 const {data, isLoading, error} = useGetPopularFeedsQuery({ 667 657 limit: numFeedsToDisplay, 668 658 }) ··· 749 739 a.gap_md, 750 740 ]}> 751 741 <InlineLinkText 752 - label={_(msg`Browse more suggestions`)} 742 + label={l`Browse more suggestions`} 753 743 to="/search" 754 744 style={[t.atoms.text_contrast_medium]}> 755 745 <Trans>Browse more suggestions</Trans> ··· 768 758 {content} 769 759 770 760 <Button 771 - label={_(msg`Browse more feeds on the Explore page`)} 761 + label={l`Browse more feeds on the Explore page`} 772 762 onPress={() => { 773 763 navigation.navigate('SearchTab') 774 764 }}
+62 -35
src/components/ProgressGuide/FollowDialog.tsx
··· 1 1 import {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react' 2 2 import {TextInput, View, type ViewToken} from 'react-native' 3 3 import {type ModerationOpts} from '@atproto/api' 4 - import {msg} from '@lingui/core/macro' 5 - import {useLingui} from '@lingui/react' 6 - import {Trans} from '@lingui/react/macro' 4 + import {Trans, useLingui} from '@lingui/react/macro' 7 5 8 6 import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' 9 7 import {popularInterests, useInterestsDisplayNames} from '#/lib/interests' ··· 64 62 showArrow?: boolean 65 63 }) { 66 64 const ax = useAnalytics() 67 - const {_} = useLingui() 65 + const {t: l} = useLingui() 68 66 const control = Dialog.useDialogControl() 69 67 const {gtPhone} = useBreakpoints() 70 68 71 69 return ( 72 70 <> 73 71 <Button 74 - label={_(msg`Find people to follow`)} 72 + label={l`Find people to follow`} 75 73 onPress={() => { 76 74 control.open() 77 75 ax.metric('progressGuide:followDialog:open', {}) ··· 112 110 let lastSearchText = '' 113 111 114 112 function DialogInner({guide}: {guide?: Follow10ProgressGuide}) { 115 - const {_} = useLingui() 113 + const {t: l} = useLingui() 116 114 const ax = useAnalytics() 117 115 const interestsDisplayNames = useInterestsDisplayNames() 118 116 const {data: preferences} = usePreferencesQuery() ··· 182 180 _items.push({ 183 181 type: 'empty', 184 182 key: 'empty', 185 - message: _(msg`We're having network issues, try again`), 183 + message: l`We're having network issues, try again`, 186 184 }) 187 185 } else { 188 186 const seen = new Set<string>() ··· 208 206 !_items.length && 209 207 !isSearchResultsError 210 208 ) { 211 - _items.push({type: 'empty', key: 'empty', message: _(msg`No results`)}) 209 + _items.push({type: 'empty', key: 'empty', message: l`No results`}) 212 210 } 213 211 214 212 return _items 215 213 }, [ 216 - _, 214 + l, 217 215 suggestions, 218 216 suggestionsError, 219 217 isFetchingSuggestions, ··· 225 223 resultsKey, 226 224 isSearchResultsError, 227 225 ]) 226 + 227 + const isGuide = Boolean(guide) 228 + const recIdForLogging = hasSearchText ? undefined : suggestions?.recId 228 229 229 230 const renderItems = useCallback( 230 231 ({item, index}: {item: Item; index: number}) => { ··· 235 236 profile={item.profile} 236 237 moderationOpts={moderationOpts!} 237 238 noBorder={index === 0} 239 + position={index} 240 + recId={recIdForLogging} 241 + isGuide={isGuide} 238 242 /> 239 243 ) 240 244 } ··· 248 252 return null 249 253 } 250 254 }, 251 - [moderationOpts], 255 + [moderationOpts, recIdForLogging, isGuide], 252 256 ) 253 257 254 258 // Track seen profiles ··· 269 273 i => i.type === 'profile' && i.profile.did === item.profile.did, 270 274 ) 271 275 ax.metric('suggestedUser:seen', { 272 - logContext: 'ProgressGuide', 273 - recId: hasSearchText ? undefined : suggestions?.recId, 276 + logContext: isGuide ? 'ProgressGuide' : 'SeeMoreSuggestedUsers', 277 + recId: recIdForLogging, 274 278 position: position !== -1 ? position : 0, 275 279 suggestedDid: item.profile.did, 276 280 category: selectedInterestRef.current, ··· 404 408 Header = memo(Header) 405 409 406 410 function HeaderTop({guide}: {guide?: Follow10ProgressGuide}) { 407 - const {_} = useLingui() 411 + const {t: l} = useLingui() 408 412 const t = useTheme() 409 413 const control = Dialog.useDialogContext() 410 414 return ( ··· 438 442 )} 439 443 {IS_WEB ? ( 440 444 <Button 441 - label={_(msg`Close`)} 445 + label={l`Close`} 442 446 size="small" 443 447 shape="round" 444 448 variant={IS_WEB ? 'ghost' : 'solid'} ··· 474 478 onLayout: (index: number, x: number, width: number) => void 475 479 }): React.ReactNode => { 476 480 const t = useTheme() 477 - const {_} = useLingui() 481 + const {t: l} = useLingui() 478 482 const label = active 479 - ? _( 480 - msg({ 481 - message: `Search for "${interestsDisplayName}" (active)`, 482 - comment: 483 - 'Accessibility label for a tab that searches for accounts in a category (e.g. Art, Video Games, Sports, etc.) that are suggested for the user to follow. The tab is currently selected.', 484 - }), 485 - ) 486 - : _( 487 - msg({ 488 - message: `Search for "${interestsDisplayName}"`, 489 - comment: 490 - 'Accessibility label for a tab that searches for accounts in a category (e.g. Art, Video Games, Sports, etc.) that are suggested for the user to follow. The tab is not currently active and can be selected.', 491 - }), 492 - ) 483 + ? l({ 484 + message: `Search for "${interestsDisplayName}" (active)`, 485 + comment: 486 + 'Accessibility label for a tab that searches for accounts in a category (e.g. Art, Video Games, Sports, etc.) that are suggested for the user to follow. The tab is currently selected.', 487 + }) 488 + : l({ 489 + message: `Search for "${interestsDisplayName}"`, 490 + comment: 491 + 'Accessibility label for a tab that searches for accounts in a category (e.g. Art, Video Games, Sports, etc.) that are suggested for the user to follow. The tab is not currently active and can be selected.', 492 + }) 493 493 return ( 494 494 <View 495 495 key={interest} ··· 532 532 profile, 533 533 moderationOpts, 534 534 noBorder, 535 + position, 536 + recId, 537 + isGuide, 535 538 }: { 536 539 profile: bsky.profile.AnyProfileView 537 540 moderationOpts: ModerationOpts 538 541 noBorder?: boolean 542 + position: number 543 + recId?: string 544 + isGuide: boolean 539 545 }): React.ReactNode => { 540 546 return ( 541 547 <FollowProfileCardInner 542 548 profile={profile} 543 549 moderationOpts={moderationOpts} 544 550 noBorder={noBorder} 551 + position={position} 552 + recId={recId} 553 + isGuide={isGuide} 545 554 /> 546 555 ) 547 556 } ··· 552 561 moderationOpts, 553 562 onFollow, 554 563 noBorder, 564 + position, 565 + recId, 566 + isGuide, 555 567 }: { 556 568 profile: bsky.profile.AnyProfileView 557 569 moderationOpts: ModerationOpts 558 570 onFollow?: () => void 559 571 noBorder?: boolean 572 + position: number 573 + recId?: string 574 + isGuide: boolean 560 575 }) { 561 576 const control = Dialog.useDialogContext() 562 577 const t = useTheme() 578 + const ax = useAnalytics() 563 579 return ( 564 580 <ProfileCard.Link 565 581 profile={profile} ··· 588 604 moderationOpts={moderationOpts} 589 605 logContext="PostOnboardingFindFollows" 590 606 shape="round" 591 - onPress={onFollow} 607 + onPress={() => { 608 + ax.metric('suggestedUser:follow', { 609 + logContext: isGuide 610 + ? 'ProgressGuide' 611 + : 'SeeMoreSuggestedUsers', 612 + location: 'Card', 613 + recId, 614 + position, 615 + suggestedDid: profile.did, 616 + category: null, 617 + }) 618 + onFollow?.() 619 + }} 592 620 colorInverted 593 621 /> 594 622 </ProfileCard.Header> ··· 632 660 defaultValue: string 633 661 }) { 634 662 const t = useTheme() 635 - const {_} = useLingui() 663 + const {t: l} = useLingui() 636 664 const { 637 665 state: hovered, 638 666 onIn: onMouseEnter, ··· 652 680 size="md" 653 681 fill={interacted ? t.palette.primary_500 : t.palette.contrast_300} 654 682 /> 655 - 656 683 <TextInput 657 684 ref={inputRef} 658 - placeholder={_(msg`Search by name or interest`)} 685 + placeholder={l`Search by name or interest`} 659 686 defaultValue={defaultValue} 660 687 onChangeText={onChangeText} 661 688 onFocus={onFocus} ··· 674 701 autoCorrect={false} 675 702 autoComplete="off" 676 703 autoCapitalize="none" 677 - accessibilityLabel={_(msg`Search profiles`)} 678 - accessibilityHint={_(msg`Searches for profiles`)} 704 + accessibilityLabel={l`Search profiles`} 705 + accessibilityHint={l`Searches for profiles`} 679 706 /> 680 707 </View> 681 708 )