Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions android/app/capacitor.build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ android {
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
dependencies {
implementation project(':capacitor-app')
implementation project(':capacitor-app-launcher')
implementation project(':capacitor-browser')
implementation project(':capacitor-camera')
implementation project(':capacitor-clipboard')
Expand All @@ -20,6 +21,7 @@ dependencies {
implementation project(':capacitor-splash-screen')
implementation project(':capacitor-status-bar')
implementation project(':capgo-capacitor-crisp')
implementation project(':capgo-capacitor-in-app-review')
implementation project(':capgo-capacitor-native-biometric')
implementation project(':capgo-capacitor-passkey')
implementation project(':capgo-capacitor-updater')
Expand Down
6 changes: 6 additions & 0 deletions android/capacitor.settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ project(':capacitor-android').projectDir = new File('../node_modules/.pnpm/@capa
include ':capacitor-app'
project(':capacitor-app').projectDir = new File('../node_modules/.pnpm/@capacitor+app@8.1.0_@capacitor+core@8.2.0/node_modules/@capacitor/app/android')

include ':capacitor-app-launcher'
project(':capacitor-app-launcher').projectDir = new File('../node_modules/.pnpm/@capacitor+app-launcher@8.0.1_@capacitor+core@8.2.0/node_modules/@capacitor/app-launcher/android')

include ':capacitor-browser'
project(':capacitor-browser').projectDir = new File('../node_modules/.pnpm/@capacitor+browser@8.0.3_@capacitor+core@8.2.0/node_modules/@capacitor/browser/android')

Expand Down Expand Up @@ -35,6 +38,9 @@ project(':capacitor-status-bar').projectDir = new File('../node_modules/.pnpm/@c
include ':capgo-capacitor-crisp'
project(':capgo-capacitor-crisp').projectDir = new File('../node_modules/.pnpm/@capgo+capacitor-crisp@8.0.27_@capacitor+core@8.2.0/node_modules/@capgo/capacitor-crisp/android')

include ':capgo-capacitor-in-app-review'
project(':capgo-capacitor-in-app-review').projectDir = new File('../node_modules/.pnpm/@capgo+capacitor-in-app-review@8.2.3_@capacitor+core@8.2.0/node_modules/@capgo/capacitor-in-app-review/android')

include ':capgo-capacitor-native-biometric'
project(':capgo-capacitor-native-biometric').projectDir = new File('../node_modules/.pnpm/@capgo+capacitor-native-biometric@8.6.0_@capacitor+core@8.2.0/node_modules/@capgo/capacitor-native-biometric/android')

Expand Down
9 changes: 8 additions & 1 deletion instrumentation-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { withoutBrowserTracing } from '@/utils/sentry-integrations'
import { posthogErrorMirror } from '@/utils/sentry-posthog-mirror'
import { whenIdle } from '@/utils/defer-analytics'
import { startWebVitalsShim } from '@/utils/web-vitals-shim'
import { noteAppReviewFriction } from '@/utils/app-review-friction'
import { installPaymentNetworkGoogleAnalyticsGuard, isPaymentNetworkExplorerPath } from '@/utils/private-routes'

// Same conditions as the GA bootstrap in app/layout.tsx: with no GA to disable
Expand Down Expand Up @@ -49,7 +50,13 @@ if (
capture_pageleave: true,
// The payment explorer contains team-only identity and relationship data.
// Drop every event on client navigation; direct loads skip init above.
before_send: (event) => (isPaymentNetworkExplorerPath(window.location.pathname) ? null : event),
// Doubles as the review nudge's friction tap: every money-flow failure
// already funnels through here, so the suppressor needs no call sites.
before_send: (event) => {
if (isPaymentNetworkExplorerPath(window.location.pathname)) return null
if (event?.event) noteAppReviewFriction(event.event)
return event
},
// autocapture walks the DOM ancestor chain on every tap, which costs frames
// in the in-app WebView renderer for data that 220+ explicit
// posthog.capture calls already cover. Native keeps the explicit events only.
Expand Down
4 changes: 4 additions & 0 deletions ios/App/CapApp-SPM/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ let package = Package(
dependencies: [
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", exact: "8.2.0"),
.package(name: "CapacitorApp", path: "../../../node_modules/.pnpm/@capacitor+app@8.1.0_@capacitor+core@8.2.0/node_modules/@capacitor/app"),
.package(name: "CapacitorAppLauncher", path: "../../../node_modules/.pnpm/@capacitor+app-launcher@8.0.1_@capacitor+core@8.2.0/node_modules/@capacitor/app-launcher"),
.package(name: "CapacitorBrowser", path: "../../../node_modules/.pnpm/@capacitor+browser@8.0.3_@capacitor+core@8.2.0/node_modules/@capacitor/browser"),
.package(name: "CapacitorCamera", path: "../../../node_modules/.pnpm/@capacitor+camera@8.2.0_@capacitor+core@8.2.0/node_modules/@capacitor/camera"),
.package(name: "CapacitorClipboard", path: "../../../node_modules/.pnpm/@capacitor+clipboard@8.0.1_@capacitor+core@8.2.0/node_modules/@capacitor/clipboard"),
Expand All @@ -23,6 +24,7 @@ let package = Package(
.package(name: "CapacitorSplashScreen", path: "../../../node_modules/.pnpm/@capacitor+splash-screen@8.0.1_@capacitor+core@8.2.0/node_modules/@capacitor/splash-screen"),
.package(name: "CapacitorStatusBar", path: "../../../node_modules/.pnpm/@capacitor+status-bar@8.0.2_@capacitor+core@8.2.0/node_modules/@capacitor/status-bar"),
.package(name: "CapgoCapacitorCrisp", path: "../../../node_modules/.pnpm/@capgo+capacitor-crisp@8.0.27_@capacitor+core@8.2.0/node_modules/@capgo/capacitor-crisp"),
.package(name: "CapgoCapacitorInAppReview", path: "../../../node_modules/.pnpm/@capgo+capacitor-in-app-review@8.2.3_@capacitor+core@8.2.0/node_modules/@capgo/capacitor-in-app-review"),
.package(name: "CapgoCapacitorNativeBiometric", path: "../../../node_modules/.pnpm/@capgo+capacitor-native-biometric@8.6.0_@capacitor+core@8.2.0/node_modules/@capgo/capacitor-native-biometric"),
.package(name: "CapgoCapacitorPasskey", path: "../../../node_modules/@capgo/capacitor-passkey"),
.package(name: "CapgoCapacitorUpdater", path: "../../../node_modules/.pnpm/@capgo+capacitor-updater@8.51.14_@capacitor+core@8.2.0/node_modules/@capgo/capacitor-updater"),
Expand All @@ -36,6 +38,7 @@ let package = Package(
.product(name: "Capacitor", package: "capacitor-swift-pm"),
.product(name: "Cordova", package: "capacitor-swift-pm"),
.product(name: "CapacitorApp", package: "CapacitorApp"),
.product(name: "CapacitorAppLauncher", package: "CapacitorAppLauncher"),
.product(name: "CapacitorBrowser", package: "CapacitorBrowser"),
.product(name: "CapacitorCamera", package: "CapacitorCamera"),
.product(name: "CapacitorClipboard", package: "CapacitorClipboard"),
Expand All @@ -46,6 +49,7 @@ let package = Package(
.product(name: "CapacitorSplashScreen", package: "CapacitorSplashScreen"),
.product(name: "CapacitorStatusBar", package: "CapacitorStatusBar"),
.product(name: "CapgoCapacitorCrisp", package: "CapgoCapacitorCrisp"),
.product(name: "CapgoCapacitorInAppReview", package: "CapgoCapacitorInAppReview"),
.product(name: "CapgoCapacitorNativeBiometric", package: "CapgoCapacitorNativeBiometric"),
.product(name: "CapgoCapacitorPasskey", package: "CapgoCapacitorPasskey"),
.product(name: "CapgoCapacitorUpdater", package: "CapgoCapacitorUpdater"),
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"dependencies": {
"@capacitor/android": "8.2.0",
"@capacitor/app": "^8.1.0",
"@capacitor/app-launcher": "8.0.1",
Comment thread
innolope-dev marked this conversation as resolved.
"@capacitor/browser": "^8.0.3",
"@capacitor/camera": "^8.2.0",
"@capacitor/cli": "8.2.0",
Expand All @@ -65,6 +66,7 @@
"@capacitor/splash-screen": "^8.0.1",
"@capacitor/status-bar": "^8.0.2",
"@capgo/capacitor-crisp": "^8.0.27",
"@capgo/capacitor-in-app-review": "8.2.3",
"@capgo/capacitor-native-biometric": "8.6.0",
"@capgo/capacitor-passkey": "^8.2.2",
"@capgo/capacitor-updater": "8.51.14",
Expand Down
24 changes: 24 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions scripts/native-fingerprint.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ let repoRoot = defaultRoot
export const NATIVE_DEPENDENCIES = [
'@capacitor/android',
'@capacitor/app',
'@capacitor/app-launcher',
'@capacitor/browser',
'@capacitor/camera',
'@capacitor/clipboard',
Expand All @@ -96,6 +97,7 @@ export const NATIVE_DEPENDENCIES = [
'@capacitor/splash-screen',
'@capacitor/status-bar',
'@capgo/capacitor-crisp',
'@capgo/capacitor-in-app-review',
'@capgo/capacitor-native-biometric',
'@capgo/capacitor-passkey',
'@capgo/capacitor-updater',
Expand Down
5 changes: 5 additions & 0 deletions src/app/(mobile-ui)/qr-pay/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ import { STAR_STRAIGHT_ICON } from '@/assets/icons'
import { useAuth } from '@/context/authContext'
import { PointsAction } from '@/services/services.types'
import { usePointsConfetti } from '@/hooks/usePointsConfetti'
import { useAppReviewNudge } from '@/hooks/useAppReviewNudge'
import { usePointsCalculation } from '@/hooks/usePointsCalculation'
import { useModalsContext } from '@/context/ModalsContext'
import maintenanceConfig from '@/config/underMaintenance.config'
Expand Down Expand Up @@ -1221,6 +1222,10 @@ export default function QRPayPage() {
}
}, [isSuccess, queryClient])

// the success here is optimistic — a post-factum claim failure keeps the
// user on this screen with an error, and that is not a moment to ask
useAppReviewNudge(user?.user.userId, 'qr_payment_completed', isSuccess && !errorMessage)

useEffect(() => {
if (waitingForMerchantAmount && !isLoadingPaymentLock) {
setWaitingForMerchantAmount(false)
Expand Down
4 changes: 4 additions & 0 deletions src/components/Claim/Link/Onchain/Success.view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import CreateAccountButton from '@/components/Global/CreateAccountButton'
import { PeanutCheering } from '@/assets/mascot'
import Image from 'next/image'
import { useAppHaptic } from '@/hooks/useAppHaptic'
import { useAppReviewNudge } from '@/hooks/useAppReviewNudge'
import { useTranslations } from 'next-intl'
import { Notification } from '@/components/0_Bruddle/Notification'
import Loading from '@/components/Global/Loading'
Expand Down Expand Up @@ -181,6 +182,9 @@ export const SuccessClaimLinkView = ({
triggerHaptic()
}, [isClaimed, triggerHaptic])

// same gate as the haptic: a confirmed claim, never the optimistic mount
useAppReviewNudge(authUser?.user.userId, 'money_received', isClaimed && !claimFailure)

// The optimistic 202 lands here with no outcome yet. Hold the processing
// state until the claim is confirmed — rendering success before that would
// claim money that has not moved.
Expand Down
6 changes: 6 additions & 0 deletions src/components/Home/HomeCarouselCTA/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useAuth } from '@/context/authContext'
import { useWebSocket } from '@/hooks/useWebSocket'
import { extractInviteeName } from '@/utils/general.utils'
import PerkClaimModal from '../PerkClaimModal'
import { useAppReviewNudge } from '@/hooks/useAppReviewNudge'

const HomeCarouselCTA = () => {
const t = useTranslations('home.carousel')
Expand Down Expand Up @@ -86,6 +87,11 @@ const HomeCarouselCTA = () => {
setSelectedPerk(null)
}, [])

// reward claimed and our modal gone: a friend joined, money landed, and
// nothing of ours is on screen. Lives here rather than in PerkClaimModal,
// which unmounts with `selectedPerk` and would take the pending ask with it.
useAppReviewNudge(user?.user.userId, 'reward_claimed', claimedPerkIds.size > 0 && !selectedPerk)

// don't render carousel if there are no CTAs
if (!allCTAs.length) return null

Expand Down
90 changes: 0 additions & 90 deletions src/components/Migration/ReviewPromptModal.tsx

This file was deleted.

28 changes: 28 additions & 0 deletions src/components/Profile/views/About.view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import { LEGAL_POLICIES } from '@/constants/legal-policies'
import { useAuth } from '@/context/authContext'
import { claimPeanutTeamBadge } from '@/services/peanut-team-badge'
import { useAppVersion } from '@/hooks/useAppVersion'
import { DeviceType, useDeviceType } from '@/hooks/useGetDeviceType'
import { openStoreReviewPage } from '@/utils/app-review'
import { isNativeBridge } from '@/utils/capacitor'
import { useSafeBack } from '@/hooks/useSafeBack'
import { useTranslations } from 'next-intl'
import { useEffect, useRef, useState } from 'react'
Expand All @@ -32,6 +35,12 @@ export const AboutView = ({ appVersion }: { appVersion: string }) => {
const betaAccess = useBetaUpdatesAccess()
const betaCardRef = useRef<HTMLDivElement>(null)
const { fetchUser } = useAuth()
const { deviceType } = useDeviceType()
const store = deviceType === DeviceType.ANDROID ? 'android' : 'ios'
// false through SSR and the first client render — a render-time bridge check
// disagrees with the prerendered html and hard-fails hydration in the WebView
const [isNative, setIsNative] = useState(false)
useEffect(() => setIsNative(isNativeBridge()), [])

useEffect(() => {
if (betaRevealed) betaCardRef.current?.scrollIntoView?.({ behavior: 'smooth', block: 'nearest' })
Expand Down Expand Up @@ -88,6 +97,25 @@ export const AboutView = ({ appVersion }: { appVersion: string }) => {
))}
</div>

{/* Native only: the web has no store listing to review against.
A row the user taps themselves, never a prompt — see
utils/app-review.ts for why that distinction is the whole rule. */}
{isNative && (
<div>
<h1 className="mb-2 font-bold text-black">{t('rateHeading')}</h1>
<Card position="first">
<button
type="button"
onClick={() => void openStoreReviewPage(store)}
className="flex w-full cursor-pointer justify-between py-1"
>
<span className="text-body-s text-black">{t('rate')}</span>
<NavigationArrow size={24} className="fill-black" />
</button>
</Card>
</div>
)}

{betaRevealed && (
<div ref={betaCardRef}>
<BetaUpdatesCard />
Expand Down
Loading
Loading