diff --git a/__tests__/lib/string.test.ts b/__tests__/lib/string.test.ts index 78478a26d4..7e11ce6219 100644 --- a/__tests__/lib/string.test.ts +++ b/__tests__/lib/string.test.ts @@ -1,6 +1,11 @@ import {RichText} from '@atproto/api' import {parseEmbedPlayerFromUrl} from 'lib/strings/embed-player' +import { + createStarterPackGooglePlayUri, + createStarterPackLinkFromAndroidReferrer, + parseStarterPackHttpUri, +} from 'lib/strings/starter-pack' import {cleanError} from '../../src/lib/strings/errors' import {createFullHandle, makeValidHandle} from '../../src/lib/strings/handles' import {enforceLen} from '../../src/lib/strings/helpers' @@ -870,3 +875,78 @@ describe('parseEmbedPlayerFromUrl', () => { } }) }) + +describe('createStarterPackLinkFromAndroidReferrer', () => { + const inputs = [ + 'utm_source=bluesky&utm_medium=starterpack&utm_content=starterpack-haileyok.com-rkey', + 'utm_source=bluesky&utm_content=starterpack-haileyok.com-rkey&utm_medium=starterpack', + 'utm_source=bluesky&utm_content=starterpack-haileyok.com-rkey', + 'utm_content=starterpack-haileyok.com-rkey', + 'utm_source=redsea&utm_content=starterpack-haileyok.com-rkey', + 'utm_source=bluesky&utm_content=starterpack-haileyok.com', + 'utm_source=bluesky&utm_content=starterpack', + 'utm_source=bluesky&utm_content=nope', + 'utm_source=bluesky', + 'utm_content=starterpack-haileyok.com-rkey', + ] + const outputs = [ + 'https://bsky.app/start/haileyok.com/rkey', + 'https://bsky.app/start/haileyok.com/rkey', + 'https://bsky.app/start/haileyok.com/rkey', + null, + null, + null, + null, + null, + null, + null, + ] + + it('returns a starter pack link when input is valid', () => { + for (let i = 0; i < inputs.length; i++) { + const result = createStarterPackLinkFromAndroidReferrer(inputs[i]) + expect(result).toEqual(outputs[i]) + } + }) +}) + +describe('parseStarterPackHttpUri', () => { + const inputs = [ + 'https://bsky.app/start/haileyok.com/rkey', + 'https://bsky.app/start/haileyok.com/ilovetesting', + 'https://bsky.app/start/testlover9000.com/rkey', + 'https://bsky.app/start/testlover9000.com', + 'https://bsky.app/start/testlover9000.com/rkey/other', + 'https://bsky.app/start', + ] + const outputs = [ + {name: 'haileyok.com', rkey: 'rkey'}, + {name: 'haileyok.com', rkey: 'ilovetesting'}, + {name: 'testlover9000.com', rkey: 'rkey'}, + null, + null, + null, + ] + + it('returns the correct name and rkey when input is valid', () => { + for (let i = 0; i < inputs.length; i++) { + const result = parseStarterPackHttpUri(inputs[i]) + expect(result).toEqual(outputs[i]) + } + }) +}) + +describe('createStarterPackGooglePlayUri', () => { + const base = + 'https://play.google.com/store/apps/details?id=xyz.blueskyweb.app&referrer=utm_source%3Dbluesky%26utm_medium%3Dstarterpack%26utm_content%3Dstarterpack-' + + const inputs = [['name', 'rkey'], ['name'], []] + const outputs = [base + 'name-rkey', null, null] + + it('returns valid google play uri when input is valid', () => { + for (let i = 0; i < inputs.length; i++) { + const result = createStarterPackGooglePlayUri(inputs[i][0], inputs[i][1]) + expect(result).toEqual(outputs[i]) + } + }) +}) diff --git a/src/components/hooks/useStarterPackEntry.native.ts b/src/components/hooks/useStarterPackEntry.native.ts index f7a5c55b72..44299dafd2 100644 --- a/src/components/hooks/useStarterPackEntry.native.ts +++ b/src/components/hooks/useStarterPackEntry.native.ts @@ -1,6 +1,6 @@ import React from 'react' -import {makeStarterPackLink} from 'lib/routes/links' +import {createStarterPackLinkFromAndroidReferrer} from 'lib/strings/starter-pack' import {isAndroid} from 'platform/detection' import {useSetCurrentStarterPack} from 'state/preferences/starter-pack' import {useUsedStarterPacks} from 'state/preferences/used-starter-packs' @@ -24,14 +24,7 @@ export function useStarterPackEntry() { const res = await GooglePlayReferrer.getReferrerInfoAsync() if (res && res.installReferrer) { - const parts = res.installReferrer.split('&') - const starterPackSource = parts - .find(part => part.startsWith('utm_content=')) - ?.split('=')[1] - const sourceParts = starterPackSource?.split('-') - if (sourceParts?.length === 3 && sourceParts[0] === 'starterpack') { - uri = makeStarterPackLink(sourceParts[1], sourceParts[2]) - } + uri = createStarterPackLinkFromAndroidReferrer(res.installReferrer) } } else { uri = await SwissArmyKnife.getStringValueAsync('starterPackUri', true) diff --git a/src/lib/strings/starter-pack.ts b/src/lib/strings/starter-pack.ts new file mode 100644 index 0000000000..36f6c7802d --- /dev/null +++ b/src/lib/strings/starter-pack.ts @@ -0,0 +1,54 @@ +import {makeStarterPackLink} from 'lib/routes/links' + +export function createStarterPackLinkFromAndroidReferrer( + referrerQueryString: string, +): string | null { + try { + // The referrer string is just some URL parameters, so lets add them to a fake URL + const url = new URL('http://throwaway.com/?' + referrerQueryString) + const utmContent = url.searchParams.get('utm_content') + const utmSource = url.searchParams.get('utm_source') + + if (!utmContent) return null + if (utmSource !== 'bluesky') return null + + // This should be a string like `starterpack-haileyok.com-rkey` + const contentParts = utmContent.split('-') + + if (contentParts[0] !== 'starterpack') return null + if (contentParts.length !== 3) return null + + return makeStarterPackLink(contentParts[1], contentParts[2]) + } catch (e) { + return null + } +} + +export function parseStarterPackHttpUri(uri: string): { + name?: string + rkey?: string +} | null { + try { + const url = new URL(uri) + const parts = url.pathname.split('/') + const name = parts[2] + const rkey = parts[3] + + if (parts.length !== 4) return null + if (!name || !rkey) return null + return { + name, + rkey, + } + } catch (e) { + return null + } +} + +export function createStarterPackGooglePlayUri( + name: string, + rkey: string, +): string | null { + if (!name || !rkey) return null + return `https://play.google.com/store/apps/details?id=xyz.blueskyweb.app&referrer=utm_source%3Dbluesky%26utm_medium%3Dstarterpack%26utm_content%3Dstarterpack-${name}-${rkey}` +} diff --git a/src/screens/StarterPack/StarterPackLandingScreen.tsx b/src/screens/StarterPack/StarterPackLandingScreen.tsx index 373393ca3c..64508a3e30 100644 --- a/src/screens/StarterPack/StarterPackLandingScreen.tsx +++ b/src/screens/StarterPack/StarterPackLandingScreen.tsx @@ -7,6 +7,10 @@ import {useLingui} from '@lingui/react' import {isAndroidWeb} from 'lib/browser' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import { + createStarterPackGooglePlayUri, + parseStarterPackHttpUri, +} from 'lib/strings/starter-pack' import {isWeb} from 'platform/detection' import { useCurrentStarterPack, @@ -41,27 +45,31 @@ function postAppClipMessage(message: AppClipMessage) { window.webkit.messageHandlers.onMessage.postMessage(JSON.stringify(message)) } -function parseStarterPackHttpUri(uri: string): {name?: string; rkey?: string} { - try { - const parsed = new URL(uri) - const [_, _path, name, rkey] = parsed.pathname.split('/') - return { - name, - rkey, - } - } catch (e) { - return {} - } -} - -function createGooglePlayLink(name: string, rkey: string) { - return `https://play.google.com/store/apps/details?id=xyz.blueskyweb.app&referrer=utm_source%3Dbluesky%26utm_medium%3Dstarterpack%26utm_content%3Dstarterpack-${name}-${rkey}` -} - export function LandingScreen({ setScreenState, }: { setScreenState: (state: LoggedOutScreenState) => void +}) { + const currentStarterPack = useCurrentStarterPack() + const parsed = parseStarterPackHttpUri(currentStarterPack?.uri || '') + + React.useEffect(() => { + if (!parsed) { + setScreenState(LoggedOutScreenState.S_LoginOrCreateAccount) + } + }, [parsed, setScreenState]) + + if (parsed) { + return null + } + + return +} + +export function LandingScreenInner({ + setScreenState, +}: { + setScreenState: (state: LoggedOutScreenState) => void }) { const currentStarterPack = useCurrentStarterPack() const {name, rkey} = @@ -98,14 +106,14 @@ export function LandingScreen({ } return ( - ) } -function LandingScreenInner({ +function LandingScreenLoaded({ starterPack, setScreenState, }: { @@ -326,7 +334,13 @@ function LandingScreenInner({ const rkey = new AtUri(starterPack.uri).rkey if (!rkey) return - window.location.href = createGooglePlayLink(creator.handle, rkey) + const googlePlayUri = createStarterPackGooglePlayUri( + creator.handle, + rkey, + ) + if (!googlePlayUri) return + + window.location.href = googlePlayUri }} />