diff --git a/src/view/shell/bottom-bar/BottomBar.tsx b/src/view/shell/bottom-bar/BottomBar.tsx
index c3fc5827a..b404a8f38 100644
--- a/src/view/shell/bottom-bar/BottomBar.tsx
+++ b/src/view/shell/bottom-bar/BottomBar.tsx
@@ -418,7 +418,7 @@ function Btn({
a.rounded_full,
{backgroundColor: t.palette.primary_500},
]}>
- 1
+ {notificationCount}
) : hasNew ? (
--
2.51.2
From da87515d0ae5e22827243e18c3e2adc2d9ccb9fc Mon Sep 17 00:00:00 2001
From: Eric Bailey
Date: Mon, 15 Dec 2025 13:35:28 -0600
Subject: [PATCH 02/13] [APP-1684] Some contact import tweaks (#9555)
* Handle download link
* Improve NUX geo gating from #9549
* Fix alignment of phone code select
* Show full name
* Add gate to nux banner
* Add gate to settings screen
* Invert gate check in settings, whoops
---
.../InternationalPhoneCodeSelect.tsx | 3 +-
.../contacts/FindContactsBannerNUX.tsx | 10 +++--
src/components/contacts/country-allowlist.ts | 18 ++++----
.../contacts/screens/ViewMatches.tsx | 6 +--
.../dialogs/nuxs/FindContactsAnnouncement.tsx | 31 ++++++++-----
src/components/dialogs/nuxs/index.tsx | 38 +++++++---------
src/components/dialogs/nuxs/utils.ts | 21 +++++++++
src/lib/statsig/gates.ts | 1 +
src/routes.ts | 2 +-
src/screens/Settings/Settings.tsx | 24 +++++-----
src/view/screens/Storybook/Forms.tsx | 44 +++++++++++++++++++
11 files changed, 138 insertions(+), 60 deletions(-)
diff --git a/src/components/InternationalPhoneCodeSelect.tsx b/src/components/InternationalPhoneCodeSelect.tsx
index 0cfd4d6b5..57d362ff6 100644
--- a/src/components/InternationalPhoneCodeSelect.tsx
+++ b/src/components/InternationalPhoneCodeSelect.tsx
@@ -1,4 +1,5 @@
import {Fragment, useMemo} from 'react'
+import {Text as RNText} from 'react-native'
import {Image} from 'expo-image'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
@@ -113,5 +114,5 @@ function Flag({unicodeFlag, svgFlag}: {unicodeFlag: string; svgFlag: any}) {
/>
)
}
- return unicodeFlag + ' '
+ return {unicodeFlag + ' '}
}
diff --git a/src/components/contacts/FindContactsBannerNUX.tsx b/src/components/contacts/FindContactsBannerNUX.tsx
index d2b2d1d3d..e08cf2edd 100644
--- a/src/components/contacts/FindContactsBannerNUX.tsx
+++ b/src/components/contacts/FindContactsBannerNUX.tsx
@@ -6,6 +6,7 @@ import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {HITSLOP_10} from '#/lib/constants'
+import {useGate} from '#/lib/statsig/statsig'
import {logger} from '#/logger'
import {isWeb} from '#/platform/detection'
import {Nux, useNux, useSaveNux} from '#/state/queries/nuxs'
@@ -20,9 +21,8 @@ export function FindContactsBannerNUX() {
const t = useTheme()
const {_} = useLingui()
const {visible, close} = useInternalState()
- const isFeatureEnabled = useIsFindContactsFeatureEnabledBasedOnGeolocation()
- if (!visible || !isFeatureEnabled) return null
+ if (!visible) return null
return (
@@ -88,13 +88,17 @@ function useInternalState() {
const {nux} = useNux(Nux.FindContactsDismissibleBanner)
const {mutate: save, variables} = useSaveNux()
const hidden = !!variables
+ const isFeatureEnabled = useIsFindContactsFeatureEnabledBasedOnGeolocation()
+ const gate = useGate()
const visible = useMemo(() => {
if (isWeb) return false
if (hidden) return false
if (nux && nux.completed) return false
+ if (!isFeatureEnabled) return false
+ if (gate('disable_settings_find_contacts')) return false
return true
- }, [hidden, nux])
+ }, [hidden, nux, isFeatureEnabled, gate])
const close = () => {
save({
diff --git a/src/components/contacts/country-allowlist.ts b/src/components/contacts/country-allowlist.ts
index 97d3d4458..35ba43c8f 100644
--- a/src/components/contacts/country-allowlist.ts
+++ b/src/components/contacts/country-allowlist.ts
@@ -18,7 +18,16 @@ const FIND_CONTACTS_FEATURE_COUNTRY_ALLOWLIST = [
'IT',
] satisfies CountryCode[] as string[]
-export function isFindContactsFeatureEnabled(countryCode: string): boolean {
+export function isFindContactsFeatureEnabled(countryCode?: string): boolean {
+ if (IS_DEV) return true
+
+ /*
+ * This should never happen unless geolocation fails entirely. In that
+ * case, let the user try, since it should work as long as they have a
+ * phone number from one of the allow-listed countries.
+ */
+ if (!countryCode) return true
+
return FIND_CONTACTS_FEATURE_COUNTRY_ALLOWLIST.includes(
countryCode.toUpperCase(),
)
@@ -26,12 +35,5 @@ export function isFindContactsFeatureEnabled(countryCode: string): boolean {
export function useIsFindContactsFeatureEnabledBasedOnGeolocation() {
const location = useGeolocation()
-
- if (IS_DEV) return true
-
- // they can try, by they'll need a phone number
- // from one of the allowlisted countries
- if (!location.countryCode) return true
-
return isFindContactsFeatureEnabled(location.countryCode)
}
diff --git a/src/components/contacts/screens/ViewMatches.tsx b/src/components/contacts/screens/ViewMatches.tsx
index 9b4ff9382..d92cb88b1 100644
--- a/src/components/contacts/screens/ViewMatches.tsx
+++ b/src/components/contacts/screens/ViewMatches.tsx
@@ -104,8 +104,6 @@ export function ViewMatches({
match => !state.dismissedMatches.includes(match.profile.did),
)
- console.log(matches)
-
const followableDids = matches.map(match => match.profile.did)
const [didFollowAll, setDidFollowAll] = useState(followableDids.length === 0)
@@ -449,7 +447,7 @@ function MatchItem({
const contactName = useMemo(() => {
if (!contact) return null
- const name = contact.firstName ?? contact.lastName ?? contact.name
+ const name = contact.name ?? contact.firstName ?? contact.lastName
if (name) return _(msg`Your contact ${name}`)
const phone =
contact.phoneNumbers?.find(p => p.isPrimary) ?? contact.phoneNumbers?.[0]
@@ -520,7 +518,7 @@ function ContactItem({
const {_} = useLingui()
const {currentAccount} = useSession()
- const name = contact.firstName ?? contact.lastName ?? contact.name
+ const name = contact.name ?? contact.firstName ?? contact.lastName
const phone =
contact.phoneNumbers?.find(phone => phone.isPrimary) ??
contact.phoneNumbers?.[0]
diff --git a/src/components/dialogs/nuxs/FindContactsAnnouncement.tsx b/src/components/dialogs/nuxs/FindContactsAnnouncement.tsx
index dd3aed013..b92ece98a 100644
--- a/src/components/dialogs/nuxs/FindContactsAnnouncement.tsx
+++ b/src/components/dialogs/nuxs/FindContactsAnnouncement.tsx
@@ -6,26 +6,33 @@ import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {logger} from '#/logger'
-import {isWeb} from '#/platform/detection'
+import {isNative, isWeb} from '#/platform/detection'
import {atoms as a, useTheme, web} from '#/alf'
import {Button, ButtonText} from '#/components/Button'
-import {useIsFindContactsFeatureEnabledBasedOnGeolocation} from '#/components/contacts/country-allowlist'
+import {isFindContactsFeatureEnabled} from '#/components/contacts/country-allowlist'
import * as Dialog from '#/components/Dialog'
import {useNuxDialogContext} from '#/components/dialogs/nuxs'
+import {
+ createIsEnabledCheck,
+ isExistingUserAsOf,
+} from '#/components/dialogs/nuxs/utils'
import {Text} from '#/components/Typography'
+import {IS_E2E} from '#/env'
import {navigate} from '#/Navigation'
-export function FindContactsAnnouncement() {
- const isFeatureEnabled = useIsFindContactsFeatureEnabledBasedOnGeolocation()
-
- if (!isFeatureEnabled) {
- return null
- }
-
- return
-}
+export const enabled = createIsEnabledCheck(props => {
+ return (
+ !IS_E2E &&
+ isNative &&
+ isExistingUserAsOf(
+ '2025-12-16T00:00:00.000Z',
+ props.currentProfile.createdAt,
+ ) &&
+ isFindContactsFeatureEnabled(props.geolocation.countryCode)
+ )
+})
-function Inner() {
+export function FindContactsAnnouncement() {
const t = useTheme()
const {_} = useLingui()
const nuxDialogs = useNuxDialogContext()
diff --git a/src/components/dialogs/nuxs/index.tsx b/src/components/dialogs/nuxs/index.tsx
index c0b1410e2..2ab319faf 100644
--- a/src/components/dialogs/nuxs/index.tsx
+++ b/src/components/dialogs/nuxs/index.tsx
@@ -10,7 +10,6 @@ import {type AppBskyActorDefs} from '@atproto/api'
import {useGate} from '#/lib/statsig/statsig'
import {logger} from '#/logger'
-import {isNative} from '#/platform/detection'
import {STALE} from '#/state/queries'
import {Nux, useNuxs, useResetNuxs, useSaveNux} from '#/state/queries/nuxs'
import {
@@ -20,13 +19,13 @@ import {
import {useProfileQuery} from '#/state/queries/profile'
import {type SessionAccount, useSession} from '#/state/session'
import {useOnboardingState} from '#/state/shell'
+import {
+ enabled as isFindContactsAnnouncementEnabled,
+ FindContactsAnnouncement,
+} from '#/components/dialogs/nuxs/FindContactsAnnouncement'
import {isSnoozed, snooze, unsnooze} from '#/components/dialogs/nuxs/snoozing'
-import {ENV} from '#/env'
-/*
- * NUXs
- */
-import {FindContactsAnnouncement} from './FindContactsAnnouncement'
-import {isExistingUserAsOf} from './utils'
+import {type EnabledCheckProps} from '#/components/dialogs/nuxs/utils'
+import {useGeolocation} from '#/geolocation'
type Context = {
activeNux: Nux | undefined
@@ -35,22 +34,11 @@ type Context = {
const queuedNuxs: {
id: Nux
- enabled?: (props: {
- gate: ReturnType
- currentAccount: SessionAccount
- currentProfile: AppBskyActorDefs.ProfileViewDetailed
- preferences: UsePreferencesQueryResponse
- }) => boolean
+ enabled?: (props: EnabledCheckProps) => boolean
}[] = [
{
id: Nux.FindContactsAnnouncement,
- enabled: ({currentProfile}) => {
- return (
- isNative &&
- ENV !== 'e2e' &&
- isExistingUserAsOf('2025-12-16T00:00:00.000Z', currentProfile.createdAt)
- )
- },
+ enabled: isFindContactsAnnouncementEnabled,
},
]
@@ -101,6 +89,7 @@ function Inner({
preferences: UsePreferencesQueryResponse
}) {
const gate = useGate()
+ const geolocation = useGeolocation()
const {nuxs} = useNuxs()
const [snoozed, setSnoozed] = useState(() => {
return isSnoozed()
@@ -143,7 +132,13 @@ function Inner({
// then check gate (track exposure)
if (
enabled &&
- !enabled({gate, currentAccount, currentProfile, preferences})
+ !enabled({
+ gate,
+ currentAccount,
+ currentProfile,
+ preferences,
+ geolocation,
+ })
) {
continue
}
@@ -178,6 +173,7 @@ function Inner({
currentAccount,
currentProfile,
preferences,
+ geolocation,
])
const ctx = useMemo(() => {
diff --git a/src/components/dialogs/nuxs/utils.ts b/src/components/dialogs/nuxs/utils.ts
index ba8f0169d..68ea38ebf 100644
--- a/src/components/dialogs/nuxs/utils.ts
+++ b/src/components/dialogs/nuxs/utils.ts
@@ -1,3 +1,24 @@
+import {type AppBskyActorDefs} from '@atproto/api'
+
+import {type useGate} from '#/lib/statsig/statsig'
+import {type UsePreferencesQueryResponse} from '#/state/queries/preferences'
+import {type SessionAccount} from '#/state/session'
+import {type Geolocation} from '#/geolocation'
+
+export type EnabledCheckProps = {
+ gate: ReturnType
+ currentAccount: SessionAccount
+ currentProfile: AppBskyActorDefs.ProfileViewDetailed
+ preferences: UsePreferencesQueryResponse
+ geolocation: Geolocation
+}
+
+export function createIsEnabledCheck(
+ cb: (props: EnabledCheckProps) => boolean,
+) {
+ return cb
+}
+
const ONE_DAY = 1000 * 60 * 60 * 24
export function isDaysOld(days: number, createdAt?: string) {
diff --git a/src/lib/statsig/gates.ts b/src/lib/statsig/gates.ts
index 8c757a016..ea67ac01b 100644
--- a/src/lib/statsig/gates.ts
+++ b/src/lib/statsig/gates.ts
@@ -4,6 +4,7 @@ export type Gate =
| 'debug_show_feedcontext'
| 'debug_subscriptions'
| 'disable_onboarding_find_contacts'
+ | 'disable_settings_find_contacts'
| 'explore_show_suggested_feeds'
| 'feed_reply_button_open_thread'
| 'old_postonboarding'
diff --git a/src/routes.ts b/src/routes.ts
index 614b24872..f325539c7 100644
--- a/src/routes.ts
+++ b/src/routes.ts
@@ -7,7 +7,7 @@ type AllNavigatableRoutes = Omit<
>
export const router = new Router({
- Home: '/',
+ Home: ['/', '/download'],
Search: '/search',
Feeds: '/feeds',
Notifications: '/notifications',
diff --git a/src/screens/Settings/Settings.tsx b/src/screens/Settings/Settings.tsx
index 6b0e184c0..2fa5aa7de 100644
--- a/src/screens/Settings/Settings.tsx
+++ b/src/screens/Settings/Settings.tsx
@@ -16,6 +16,7 @@ import {
type CommonNavigatorParams,
type NavigationProp,
} from '#/lib/routes/types'
+import {useGate} from '#/lib/statsig/statsig'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {sanitizeHandle} from '#/lib/strings/handles'
import {isIOS, isNative} from '#/platform/detection'
@@ -93,6 +94,7 @@ export function SettingsScreen({}: Props) {
const [showDevOptions, setShowDevOptions] = useState(false)
const findContactsEnabled =
useIsFindContactsFeatureEnabledBasedOnGeolocation()
+ const gate = useGate()
return (
@@ -211,16 +213,18 @@ export function SettingsScreen({}: Props) {
Content and media
- {isNative && findContactsEnabled && (
-
-
-
- Find friends from contacts
-
-
- )}
+ {isNative &&
+ findContactsEnabled &&
+ !gate('disable_settings_find_contacts') && (
+
+
+
+ Find friends from contacts
+
+
+ )}
diff --git a/src/view/screens/Storybook/Forms.tsx b/src/view/screens/Storybook/Forms.tsx
index c3dad8dec..ee859a827 100644
--- a/src/view/screens/Storybook/Forms.tsx
+++ b/src/view/screens/Storybook/Forms.tsx
@@ -1,6 +1,7 @@
import React from 'react'
import {type TextInput, View} from 'react-native'
+import {APP_LANGUAGES} from '#/lib/../locale/languages'
import {atoms as a} from '#/alf'
import {Button, ButtonText} from '#/components/Button'
import {DateField, LabelText} from '#/components/forms/DateField'
@@ -9,6 +10,8 @@ import * as TextField from '#/components/forms/TextField'
import * as Toggle from '#/components/forms/Toggle'
import * as ToggleButton from '#/components/forms/ToggleButton'
import {Globe_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe'
+import {InternationalPhoneCodeSelect} from '#/components/InternationalPhoneCodeSelect'
+import * as Select from '#/components/Select'
import {H1, H3} from '#/components/Typography'
export function Forms() {
@@ -22,6 +25,9 @@ export function Forms() {
const [value, setValue] = React.useState('')
const [date, setDate] = React.useState('2001-01-01')
+ const [countryCode, setCountryCode] = React.useState('US')
+ const [phoneNumber, setPhoneNumber] = React.useState('')
+ const [lang, setLang] = React.useState('en')
const inputRef = React.useRef(null)
@@ -29,6 +35,44 @@ export function Forms() {
Forms
+
+
+
+
+
+ (
+
+
+ {label}
+
+ )}
+ items={APP_LANGUAGES.map(l => ({
+ label: l.name,
+ value: l.code2,
+ }))}
+ />
+
+
+
+
+ setCountryCode(value)}
+ />
+
+
+
+
+
+
+
InputText
--
2.51.2
From f45e58e057284830527a258d3d47ef4fa2d04e7e Mon Sep 17 00:00:00 2001
From: Eric Bailey
Date: Mon, 15 Dec 2025 14:38:05 -0600
Subject: [PATCH 03/13] [AAv2] Add blurb for orgs (#9556)
* Add blurb for orgs
* Update
---
src/ageAssurance/components/NoAccessScreen.tsx | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/src/ageAssurance/components/NoAccessScreen.tsx b/src/ageAssurance/components/NoAccessScreen.tsx
index a8667bf0c..8b2a44c26 100644
--- a/src/ageAssurance/components/NoAccessScreen.tsx
+++ b/src/ageAssurance/components/NoAccessScreen.tsx
@@ -120,6 +120,15 @@ export function NoAccessScreen() {
)
+ const orgAdmonition = (
+
+
+ For organizational accounts, use the birthdate of the person who is
+ responsible for the account.
+
+
+ )
+
return (
<>
@@ -166,6 +175,8 @@ export function NoAccessScreen() {
{!isBlocked && birthdateUpdateText}
+
+ {orgAdmonition}
@@ -180,6 +191,8 @@ export function NoAccessScreen() {
{birthdateUpdateText}
+
+ {orgAdmonition}
)}
>
@@ -211,7 +224,7 @@ export function NoAccessScreen() {
- {isUsingAppPassword && (
+ {isUsingAppPassword ? (
Hmm, it looks like you're logged in with an{' '}
@@ -220,6 +233,8 @@ export function NoAccessScreen() {
password, or ask whomever controls this account to do so.
+ ) : (
+ orgAdmonition
)}
)}
--
2.51.2
From 2200cc95d841c4de3adf30cebb7508745fdfafec Mon Sep 17 00:00:00 2001
From: estrattonbailey <4732330+estrattonbailey@users.noreply.github.com>
Date: Mon, 15 Dec 2025 20:49:31 +0000
Subject: [PATCH 04/13] Nightly source-language update
---
src/locale/locales/en/messages.po | 248 +++++++++++++++---------------
1 file changed, 126 insertions(+), 122 deletions(-)
diff --git a/src/locale/locales/en/messages.po b/src/locale/locales/en/messages.po
index 0f1eab65d..e232dbf37 100644
--- a/src/locale/locales/en/messages.po
+++ b/src/locale/locales/en/messages.po
@@ -38,7 +38,7 @@ msgstr ""
msgid "{0, plural, one {# following} other {# following}}"
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:267
+#: src/components/contacts/screens/ViewMatches.tsx:265
msgid "{0, plural, one {# friend found!} other {# friends found!}}"
msgstr ""
@@ -576,8 +576,8 @@ msgstr ""
#: src/Navigation.tsx:534
#: src/screens/Settings/AboutSettings.tsx:75
-#: src/screens/Settings/Settings.tsx:258
-#: src/screens/Settings/Settings.tsx:261
+#: src/screens/Settings/Settings.tsx:262
+#: src/screens/Settings/Settings.tsx:265
msgid "About"
msgstr ""
@@ -604,8 +604,8 @@ msgid "Accept this language suggestion"
msgstr ""
#: src/screens/Settings/AccessibilitySettings.tsx:44
-#: src/screens/Settings/Settings.tsx:234
-#: src/screens/Settings/Settings.tsx:237
+#: src/screens/Settings/Settings.tsx:238
+#: src/screens/Settings/Settings.tsx:241
msgid "Accessibility"
msgstr ""
@@ -616,8 +616,8 @@ msgstr ""
#: src/Navigation.tsx:401
#: src/screens/Login/LoginForm.tsx:194
#: src/screens/Settings/AccountSettings.tsx:51
-#: src/screens/Settings/Settings.tsx:178
-#: src/screens/Settings/Settings.tsx:181
+#: src/screens/Settings/Settings.tsx:180
+#: src/screens/Settings/Settings.tsx:183
msgid "Account"
msgstr ""
@@ -648,7 +648,7 @@ msgstr ""
msgid "Account Muted by List"
msgstr ""
-#: src/screens/Settings/Settings.tsx:640
+#: src/screens/Settings/Settings.tsx:644
msgid "Account options"
msgstr ""
@@ -656,7 +656,7 @@ msgstr ""
msgid "Account provider"
msgstr ""
-#: src/screens/Settings/Settings.tsx:676
+#: src/screens/Settings/Settings.tsx:680
msgid "Account removed from quick access"
msgstr ""
@@ -741,8 +741,8 @@ msgstr ""
msgid "Add alt text (optional)"
msgstr ""
-#: src/screens/Settings/Settings.tsx:580
-#: src/screens/Settings/Settings.tsx:583
+#: src/screens/Settings/Settings.tsx:584
+#: src/screens/Settings/Settings.tsx:587
#: src/view/shell/desktop/LeftNav.tsx:262
#: src/view/shell/desktop/LeftNav.tsx:266
msgid "Add another account"
@@ -844,7 +844,7 @@ msgstr ""
msgid "Add user to list"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:210
+#: src/ageAssurance/components/NoAccessScreen.tsx:223
msgid "Add your birthdate"
msgstr ""
@@ -914,7 +914,7 @@ msgctxt "toast"
msgid "Age assurance inquiry was submitted"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:342
+#: src/ageAssurance/components/NoAccessScreen.tsx:357
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:191
msgid "Age assurance only takes a few minutes"
msgstr ""
@@ -934,7 +934,7 @@ msgstr ""
msgid "All accounts have been followed!"
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:143
+#: src/components/contacts/screens/ViewMatches.tsx:141
msgid "All friends followed!"
msgstr ""
@@ -1070,7 +1070,7 @@ msgstr ""
msgid "An error occurred while generating your starter pack. Want to try again?"
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:242
+#: src/components/contacts/screens/ViewMatches.tsx:240
msgid "An error occurred while hiding suggestion. {0}"
msgstr ""
@@ -1108,7 +1108,7 @@ msgid "An error occurred. {0}"
msgstr ""
#: src/components/contacts/components/HeroImage.tsx:28
-#: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:71
+#: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:78
msgid "An illustration depicting user avatars flowing from a contact book into the Bluesky app"
msgstr ""
@@ -1272,8 +1272,8 @@ msgstr ""
#: src/Navigation.tsx:393
#: src/screens/Settings/AppearanceSettings.tsx:73
-#: src/screens/Settings/Settings.tsx:226
-#: src/screens/Settings/Settings.tsx:229
+#: src/screens/Settings/Settings.tsx:230
+#: src/screens/Settings/Settings.tsx:233
msgid "Appearance"
msgstr ""
@@ -1282,8 +1282,8 @@ msgstr ""
msgid "Apply default recommended feeds"
msgstr ""
-#: src/screens/Settings/Settings.tsx:512
-#: src/screens/Settings/Settings.tsx:514
+#: src/screens/Settings/Settings.tsx:516
+#: src/screens/Settings/Settings.tsx:518
msgid "Apply Pull Request"
msgstr ""
@@ -1585,11 +1585,11 @@ msgstr ""
msgid "Bluesky is more fun with friends"
msgstr ""
-#: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:99
+#: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:106
msgid "Bluesky is more fun with friends! Import your contacts to see who’s already here."
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:314
+#: src/components/contacts/screens/ViewMatches.tsx:312
msgid "Bluesky is more fun with friends. Do you want to invite some of yours? <0/>"
msgstr ""
@@ -1761,7 +1761,7 @@ msgstr ""
#: src/screens/Settings/components/ChangeHandleDialog.tsx:85
#: src/screens/Settings/components/ChangePasswordDialog.tsx:247
#: src/screens/Settings/components/ChangePasswordDialog.tsx:253
-#: src/screens/Settings/Settings.tsx:303
+#: src/screens/Settings/Settings.tsx:307
#: src/screens/Takendown.tsx:107
#: src/screens/Takendown.tsx:110
#: src/view/com/composer/Composer.tsx:1050
@@ -1997,11 +1997,11 @@ msgstr ""
msgid "Choose your username"
msgstr ""
-#: src/screens/Settings/Settings.tsx:504
+#: src/screens/Settings/Settings.tsx:508
msgid "Clear all storage data"
msgstr ""
-#: src/screens/Settings/Settings.tsx:506
+#: src/screens/Settings/Settings.tsx:510
msgid "Clear all storage data (restart after this)"
msgstr ""
@@ -2026,7 +2026,7 @@ msgstr ""
msgid "Click here to contact our support team"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:233
+#: src/ageAssurance/components/NoAccessScreen.tsx:248
msgid "Click here to log out"
msgstr ""
@@ -2035,7 +2035,7 @@ msgid "Click here to restart the verification process."
msgstr ""
#: src/ageAssurance/components/NoAccessScreen.tsx:97
-#: src/ageAssurance/components/NoAccessScreen.tsx:207
+#: src/ageAssurance/components/NoAccessScreen.tsx:220
msgid "Click here to update your birthdate"
msgstr ""
@@ -2252,7 +2252,7 @@ msgstr ""
msgid "Confirm delete account"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:356
+#: src/ageAssurance/components/NoAccessScreen.tsx:371
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:87
#: src/components/dialogs/DeviceLocationRequestDialog.tsx:40
#: src/components/dialogs/DeviceLocationRequestDialog.tsx:105
@@ -2279,7 +2279,7 @@ msgstr ""
msgid "Connection issue"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:293
+#: src/ageAssurance/components/NoAccessScreen.tsx:308
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:130
#: src/components/ageAssurance/AgeAssuranceAppealDialog.tsx:29
msgid "Contact our moderation team"
@@ -2312,8 +2312,8 @@ msgstr ""
msgid "Content & Media"
msgstr ""
-#: src/screens/Settings/Settings.tsx:208
-#: src/screens/Settings/Settings.tsx:211
+#: src/screens/Settings/Settings.tsx:210
+#: src/screens/Settings/Settings.tsx:213
msgid "Content and media"
msgstr ""
@@ -2581,7 +2581,7 @@ msgstr ""
msgid "Could not upload contacts. You need to re-verify your phone number to proceed"
msgstr ""
-#: src/components/InternationalPhoneCodeSelect.tsx:79
+#: src/components/InternationalPhoneCodeSelect.tsx:80
msgid "Country code"
msgstr ""
@@ -2741,7 +2741,7 @@ msgstr ""
msgid "Deactivate account"
msgstr ""
-#: src/screens/Settings/Settings.tsx:469
+#: src/screens/Settings/Settings.tsx:473
msgid "Debug Moderation"
msgstr ""
@@ -2794,7 +2794,7 @@ msgstr ""
msgid "Delete chat"
msgstr ""
-#: src/screens/Settings/Settings.tsx:476
+#: src/screens/Settings/Settings.tsx:480
msgid "Delete chat declaration record"
msgstr ""
@@ -2907,8 +2907,8 @@ msgctxt "toast"
msgid "Developer mode enabled"
msgstr ""
-#: src/screens/Settings/Settings.tsx:285
-#: src/screens/Settings/Settings.tsx:288
+#: src/screens/Settings/Settings.tsx:289
+#: src/screens/Settings/Settings.tsx:292
msgid "Developer options"
msgstr ""
@@ -3068,8 +3068,8 @@ msgstr ""
#: src/components/contacts/components/InviteInfo.tsx:72
#: src/components/contacts/components/InviteInfo.tsx:78
-#: src/components/contacts/screens/ViewMatches.tsx:394
-#: src/components/contacts/screens/ViewMatches.tsx:411
+#: src/components/contacts/screens/ViewMatches.tsx:392
+#: src/components/contacts/screens/ViewMatches.tsx:409
#: src/components/dialogs/BirthDateSettings.tsx:183
#: src/components/dialogs/BirthDateSettings.tsx:190
#: src/components/dialogs/ServerInput.tsx:240
@@ -3695,15 +3695,15 @@ msgstr ""
msgid "Failed to follow all suggested accounts, please try again"
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:147
+#: src/components/contacts/screens/ViewMatches.tsx:145
msgid "Failed to follow all your friends, please try again"
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:235
+#: src/components/contacts/screens/ViewMatches.tsx:233
msgid "Failed to hide suggestion, please check your internet connection"
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:580
+#: src/components/contacts/screens/ViewMatches.tsx:578
msgid "Failed to launch SMS app"
msgstr ""
@@ -3991,8 +3991,8 @@ msgstr ""
msgid "Find Friends"
msgstr ""
-#: src/screens/Settings/Settings.tsx:217
-#: src/screens/Settings/Settings.tsx:220
+#: src/screens/Settings/Settings.tsx:221
+#: src/screens/Settings/Settings.tsx:224
msgid "Find friends from contacts"
msgstr ""
@@ -4013,7 +4013,7 @@ msgstr ""
msgid "Find posts, users, and feeds on Bluesky"
msgstr ""
-#: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:89
+#: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:96
msgid "Find your friends"
msgstr ""
@@ -4088,8 +4088,8 @@ msgstr ""
msgid "Follow account"
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:275
-#: src/components/contacts/screens/ViewMatches.tsx:290
+#: src/components/contacts/screens/ViewMatches.tsx:273
+#: src/components/contacts/screens/ViewMatches.tsx:288
#: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:265
#: src/screens/Onboarding/StepSuggestedStarterpacks/StarterPackCard.tsx:156
#: src/screens/Onboarding/StepSuggestedStarterpacks/StarterPackCard.tsx:163
@@ -4205,6 +4205,10 @@ msgstr ""
msgid "Food"
msgstr ""
+#: src/ageAssurance/components/NoAccessScreen.tsx:125
+msgid "For organizational accounts, use the birthdate of the person who is responsible for the account."
+msgstr ""
+
#: src/view/com/modals/DeleteAccount.tsx:125
msgid "For security reasons, we'll need to send a confirmation code to your email address."
msgstr ""
@@ -4527,8 +4531,8 @@ msgstr ""
msgid "Held by Bluesky for 7 days to prevent abuse, then deleted"
msgstr ""
-#: src/screens/Settings/Settings.tsx:250
#: src/screens/Settings/Settings.tsx:254
+#: src/screens/Settings/Settings.tsx:258
#: src/view/shell/desktop/RightNav.tsx:123
#: src/view/shell/desktop/RightNav.tsx:124
#: src/view/shell/Drawer.tsx:381
@@ -4548,11 +4552,11 @@ msgstr ""
msgid "Hey there 👋"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:158
+#: src/ageAssurance/components/NoAccessScreen.tsx:167
msgid "Hey there!"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:189
+#: src/ageAssurance/components/NoAccessScreen.tsx:202
msgid "Hi there!"
msgstr ""
@@ -4652,7 +4656,7 @@ msgstr ""
msgid "Hides the content"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:216
+#: src/ageAssurance/components/NoAccessScreen.tsx:229
msgid "Hmm, it looks like you're logged in with an <0>App Password0>. To set your birthdate, you'll need to log in with your main account password, or ask whomever controls this account to do so."
msgstr ""
@@ -4745,7 +4749,7 @@ msgstr ""
msgid "I understand"
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:576
+#: src/components/contacts/screens/ViewMatches.tsx:574
msgid "I'm on Bluesky as {0} - come find me! https://bsky.app/download"
msgstr ""
@@ -4835,8 +4839,8 @@ msgstr ""
msgid "Import contacts"
msgstr ""
-#: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:107
-#: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:118
+#: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:114
+#: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:125
msgid "Import Contacts"
msgstr ""
@@ -4845,7 +4849,7 @@ msgstr ""
msgid "Import contacts to find your friends"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:192
+#: src/ageAssurance/components/NoAccessScreen.tsx:205
msgid "In order to provide an age-appropriate experience, we need to know your birthdate. This is a one-time thing, and your data will be kept private."
msgstr ""
@@ -4918,7 +4922,7 @@ msgstr ""
msgid "Introducing activity notifications"
msgstr ""
-#: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:48
+#: src/components/dialogs/nuxs/FindContactsAnnouncement.tsx:55
msgid "Introducing finding friends via contacts"
msgstr ""
@@ -4953,11 +4957,11 @@ msgstr ""
msgid "Invalid Verification Code"
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:585
+#: src/components/contacts/screens/ViewMatches.tsx:583
msgid "Invite"
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:565
+#: src/components/contacts/screens/ViewMatches.tsx:563
msgid "Invite {name} to join Bluesky"
msgstr ""
@@ -4974,7 +4978,7 @@ msgstr ""
msgid "Invite Friends"
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:300
+#: src/components/contacts/screens/ViewMatches.tsx:298
msgid "Invite friends <0/>"
msgstr ""
@@ -4990,7 +4994,7 @@ msgstr ""
msgid "Invites, but personal"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:353
+#: src/ageAssurance/components/NoAccessScreen.tsx:368
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:84
msgid "Is your location not accurate? <0>Tap here to confirm your location.0>"
msgstr ""
@@ -5078,8 +5082,8 @@ msgid "Language Settings"
msgstr ""
#: src/screens/Settings/LanguageSettings.tsx:78
-#: src/screens/Settings/Settings.tsx:242
-#: src/screens/Settings/Settings.tsx:245
+#: src/screens/Settings/Settings.tsx:246
+#: src/screens/Settings/Settings.tsx:249
msgid "Languages"
msgstr ""
@@ -5087,12 +5091,12 @@ msgstr ""
msgid "Larger"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:336
+#: src/ageAssurance/components/NoAccessScreen.tsx:351
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:185
msgid "Last initiated {timeAgo} ago"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:334
+#: src/ageAssurance/components/NoAccessScreen.tsx:349
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:183
msgid "Last initiated just now"
msgstr ""
@@ -5628,8 +5632,8 @@ msgstr ""
#: src/Navigation.tsx:179
#: src/screens/Moderation/index.tsx:99
-#: src/screens/Settings/Settings.tsx:192
-#: src/screens/Settings/Settings.tsx:195
+#: src/screens/Settings/Settings.tsx:194
+#: src/screens/Settings/Settings.tsx:197
msgid "Moderation"
msgstr ""
@@ -5974,8 +5978,8 @@ msgstr ""
msgid "News"
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:394
-#: src/components/contacts/screens/ViewMatches.tsx:409
+#: src/components/contacts/screens/ViewMatches.tsx:392
+#: src/components/contacts/screens/ViewMatches.tsx:407
#: src/screens/Login/ForgotPasswordForm.tsx:137
#: src/screens/Login/ForgotPasswordForm.tsx:143
#: src/screens/Login/LoginForm.tsx:346
@@ -6006,11 +6010,11 @@ msgstr ""
msgid "No app passwords yet"
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:679
+#: src/components/contacts/screens/ViewMatches.tsx:677
msgid "No contacts found"
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:657
+#: src/components/contacts/screens/ViewMatches.tsx:655
msgid "No contacts with the name “{query}” found"
msgstr ""
@@ -6063,7 +6067,7 @@ msgstr ""
msgid "No more doomscrolling junk-filled algorithms. Find feeds that work for you, not against you."
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:561
+#: src/components/contacts/screens/ViewMatches.tsx:559
msgid "No name"
msgstr ""
@@ -6244,8 +6248,8 @@ msgstr ""
#: src/screens/Settings/NotificationSettings/ReplyNotificationSettings.tsx:30
#: src/screens/Settings/NotificationSettings/RepostNotificationSettings.tsx:30
#: src/screens/Settings/NotificationSettings/RepostsOnRepostsNotificationSettings.tsx:30
-#: src/screens/Settings/Settings.tsx:200
-#: src/screens/Settings/Settings.tsx:203
+#: src/screens/Settings/Settings.tsx:202
+#: src/screens/Settings/Settings.tsx:205
#: src/view/screens/Notifications.tsx:130
#: src/view/shell/bottom-bar/BottomBar.tsx:252
#: src/view/shell/desktop/LeftNav.tsx:709
@@ -6310,7 +6314,7 @@ msgstr ""
msgid "on<0><1/><2><3/>2>0>"
msgstr ""
-#: src/screens/Settings/Settings.tsx:402
+#: src/screens/Settings/Settings.tsx:406
msgid "Onboarding reset"
msgstr ""
@@ -6412,7 +6416,7 @@ msgstr ""
msgid "Open message options"
msgstr ""
-#: src/screens/Settings/Settings.tsx:467
+#: src/screens/Settings/Settings.tsx:471
msgid "Open moderation debug page"
msgstr ""
@@ -6441,12 +6445,12 @@ msgstr ""
msgid "Open starter pack menu"
msgstr ""
-#: src/screens/Settings/Settings.tsx:460
-#: src/screens/Settings/Settings.tsx:474
+#: src/screens/Settings/Settings.tsx:464
+#: src/screens/Settings/Settings.tsx:478
msgid "Open storybook page"
msgstr ""
-#: src/screens/Settings/Settings.tsx:453
+#: src/screens/Settings/Settings.tsx:457
msgid "Open system log"
msgstr ""
@@ -6509,7 +6513,7 @@ msgstr ""
msgid "Opens GIF select dialog"
msgstr ""
-#: src/screens/Settings/Settings.tsx:251
+#: src/screens/Settings/Settings.tsx:255
msgid "Opens helpdesk in browser"
msgstr ""
@@ -7116,8 +7120,8 @@ msgstr ""
msgid "Privacy"
msgstr ""
-#: src/screens/Settings/Settings.tsx:186
-#: src/screens/Settings/Settings.tsx:189
+#: src/screens/Settings/Settings.tsx:188
+#: src/screens/Settings/Settings.tsx:191
msgid "Privacy and security"
msgstr ""
@@ -7395,7 +7399,7 @@ msgstr ""
#: src/components/StarterPack/Wizard/WizardListCard.tsx:105
#: src/components/StarterPack/Wizard/WizardListCard.tsx:112
#: src/screens/Bookmarks/index.tsx:266
-#: src/screens/Settings/Settings.tsx:678
+#: src/screens/Settings/Settings.tsx:682
#: src/view/com/modals/UserAddRemoveLists.tsx:235
#: src/view/com/posts/PostFeedErrorMessage.tsx:220
msgid "Remove"
@@ -7409,8 +7413,8 @@ msgstr ""
msgid "Remove {historyItem}"
msgstr ""
-#: src/screens/Settings/Settings.tsx:657
-#: src/screens/Settings/Settings.tsx:660
+#: src/screens/Settings/Settings.tsx:661
+#: src/screens/Settings/Settings.tsx:664
msgid "Remove account"
msgstr ""
@@ -7455,7 +7459,7 @@ msgstr ""
msgid "Remove from my feeds"
msgstr ""
-#: src/screens/Settings/Settings.tsx:670
+#: src/screens/Settings/Settings.tsx:674
msgid "Remove from quick access?"
msgstr ""
@@ -7499,7 +7503,7 @@ msgstr ""
msgid "Remove subtitle file"
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:499
+#: src/components/contacts/screens/ViewMatches.tsx:497
#: src/screens/Settings/FindContactsSettings.tsx:323
msgid "Remove suggestion"
msgstr ""
@@ -7830,8 +7834,8 @@ msgstr ""
msgid "Resend Verification Email"
msgstr ""
-#: src/screens/Settings/Settings.tsx:496
-#: src/screens/Settings/Settings.tsx:498
+#: src/screens/Settings/Settings.tsx:500
+#: src/screens/Settings/Settings.tsx:502
msgid "Reset activity subscription nudge"
msgstr ""
@@ -7839,8 +7843,8 @@ msgstr ""
msgid "Reset code"
msgstr ""
-#: src/screens/Settings/Settings.tsx:481
-#: src/screens/Settings/Settings.tsx:483
+#: src/screens/Settings/Settings.tsx:485
+#: src/screens/Settings/Settings.tsx:487
msgid "Reset onboarding state"
msgstr ""
@@ -8042,7 +8046,7 @@ msgstr ""
msgid "Search by name or interest"
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:355
+#: src/components/contacts/screens/ViewMatches.tsx:353
msgid "Search contacts"
msgstr ""
@@ -8281,7 +8285,7 @@ msgstr ""
msgid "Select subtitle file (.vtt)"
msgstr ""
-#: src/components/InternationalPhoneCodeSelect.tsx:67
+#: src/components/InternationalPhoneCodeSelect.tsx:68
msgid "Select telephone code"
msgstr ""
@@ -8421,7 +8425,7 @@ msgstr ""
msgid "Set who can reply to your post"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:199
+#: src/ageAssurance/components/NoAccessScreen.tsx:212
msgid "Set your birthdate below and we'll get you back to posting and exploring in no time!"
msgstr ""
@@ -8430,7 +8434,7 @@ msgid "Sets email for password reset"
msgstr ""
#: src/Navigation.tsx:215
-#: src/screens/Settings/Settings.tsx:103
+#: src/screens/Settings/Settings.tsx:105
#: src/view/shell/desktop/LeftNav.tsx:805
#: src/view/shell/Drawer.tsx:609
msgid "Settings"
@@ -8680,7 +8684,7 @@ msgstr ""
msgid "Shows information about when this post was created"
msgstr ""
-#: src/screens/Settings/Settings.tsx:129
+#: src/screens/Settings/Settings.tsx:131
msgid "Shows other accounts you can switch to"
msgstr ""
@@ -8741,9 +8745,9 @@ msgstr ""
msgid "Sign in to view post"
msgstr ""
-#: src/screens/Settings/Settings.tsx:268
-#: src/screens/Settings/Settings.tsx:270
-#: src/screens/Settings/Settings.tsx:302
+#: src/screens/Settings/Settings.tsx:272
+#: src/screens/Settings/Settings.tsx:274
+#: src/screens/Settings/Settings.tsx:306
#: src/screens/SignupQueued.tsx:93
#: src/screens/SignupQueued.tsx:96
#: src/screens/Takendown.tsx:93
@@ -8757,7 +8761,7 @@ msgstr ""
msgid "Sign Out"
msgstr ""
-#: src/screens/Settings/Settings.tsx:299
+#: src/screens/Settings/Settings.tsx:303
#: src/view/shell/desktop/LeftNav.tsx:209
msgid "Sign out?"
msgstr ""
@@ -8983,7 +8987,7 @@ msgstr ""
msgid "Step {0} of {1}"
msgstr ""
-#: src/screens/Settings/Settings.tsx:407
+#: src/screens/Settings/Settings.tsx:411
msgid "Storage cleared, you need to restart the app now."
msgstr ""
@@ -8992,7 +8996,7 @@ msgid "Stored as part of a secure code for matching with others"
msgstr ""
#: src/Navigation.tsx:308
-#: src/screens/Settings/Settings.tsx:462
+#: src/screens/Settings/Settings.tsx:466
msgid "Storybook"
msgstr ""
@@ -9092,9 +9096,9 @@ msgstr ""
msgid "Support for this feature in your country has not been enabled yet! Please check back later."
msgstr ""
-#: src/screens/Settings/Settings.tsx:127
-#: src/screens/Settings/Settings.tsx:141
-#: src/screens/Settings/Settings.tsx:620
+#: src/screens/Settings/Settings.tsx:129
+#: src/screens/Settings/Settings.tsx:143
+#: src/screens/Settings/Settings.tsx:624
#: src/view/shell/desktop/LeftNav.tsx:247
msgid "Switch account"
msgstr ""
@@ -9122,7 +9126,7 @@ msgstr ""
#: src/screens/Log.tsx:58
#: src/screens/Settings/AboutSettings.tsx:107
#: src/screens/Settings/AboutSettings.tsx:110
-#: src/screens/Settings/Settings.tsx:455
+#: src/screens/Settings/Settings.tsx:459
msgid "System log"
msgstr ""
@@ -9222,7 +9226,7 @@ msgstr ""
msgid "Thanks, you have successfully verified your email address. You can close this dialog."
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:382
+#: src/ageAssurance/components/NoAccessScreen.tsx:397
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:113
msgid "Thanks! You're all set."
msgstr ""
@@ -9718,7 +9722,7 @@ msgstr ""
msgid "This will delete \"{0}\" from your muted words. You can always add it back later."
msgstr ""
-#: src/screens/Settings/Settings.tsx:672
+#: src/screens/Settings/Settings.tsx:676
msgid "This will remove @{0} from the quick access list."
msgstr ""
@@ -9766,7 +9770,7 @@ msgstr ""
msgid "To disable your email 2FA method, please verify your access to <0>{0}0>"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:230
+#: src/ageAssurance/components/NoAccessScreen.tsx:245
msgid "To log out, <0>click here0>."
msgstr ""
@@ -9897,11 +9901,11 @@ msgstr ""
msgid "Unable to delete"
msgstr ""
-#: src/screens/Settings/Settings.tsx:521
+#: src/screens/Settings/Settings.tsx:525
msgid "Unapply Pull Request"
msgstr ""
-#: src/screens/Settings/Settings.tsx:523
+#: src/screens/Settings/Settings.tsx:527
msgid "Unapply Pull Request {currentChannel}"
msgstr ""
@@ -9981,7 +9985,7 @@ msgstr ""
msgid "Unfortunately, none of your subscribed labelers supports this report type."
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:176
+#: src/ageAssurance/components/NoAccessScreen.tsx:187
msgid "Unfortunately, the birthdate you have saved to your profile makes you too young to access Bluesky."
msgstr ""
@@ -10089,8 +10093,8 @@ msgstr ""
msgid "Unpinned list"
msgstr ""
-#: src/screens/Settings/Settings.tsx:488
-#: src/screens/Settings/Settings.tsx:490
+#: src/screens/Settings/Settings.tsx:492
+#: src/screens/Settings/Settings.tsx:494
msgid "Unsnooze email reminder"
msgstr ""
@@ -10342,7 +10346,7 @@ msgstr ""
msgid "Verify account"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:319
+#: src/ageAssurance/components/NoAccessScreen.tsx:334
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:168
msgid "Verify again"
msgstr ""
@@ -10369,8 +10373,8 @@ msgstr ""
msgid "Verify email dialog"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:307
-#: src/ageAssurance/components/NoAccessScreen.tsx:321
+#: src/ageAssurance/components/NoAccessScreen.tsx:322
+#: src/ageAssurance/components/NoAccessScreen.tsx:336
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:156
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:170
msgid "Verify now"
@@ -10768,7 +10772,7 @@ msgstr ""
msgid "We're so excited to have you join us!"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:375
+#: src/ageAssurance/components/NoAccessScreen.tsx:390
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:106
msgid "We're sorry, but based on your device's location, you are currently located in a region that requires age assurance."
msgstr ""
@@ -10976,7 +10980,7 @@ msgstr ""
msgid "You are a trusted verifier"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:161
+#: src/ageAssurance/components/NoAccessScreen.tsx:170
msgid "You are accessing Bluesky from a region that legally requires us to verify your age before allowing you to access the app."
msgstr ""
@@ -10984,7 +10988,7 @@ msgstr ""
msgid "You are creating an account on"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:289
+#: src/ageAssurance/components/NoAccessScreen.tsx:304
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:126
msgid "You are currently unable to access Bluesky's Age Assurance flow. Please <0>contact our moderation team0> if you believe this is an error."
msgstr ""
@@ -11117,7 +11121,7 @@ msgstr ""
msgid "You don't have any saved feeds."
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:311
+#: src/components/contacts/screens/ViewMatches.tsx:309
msgid "You got here first"
msgstr ""
@@ -11272,7 +11276,7 @@ msgstr ""
msgid "You previously deactivated @{0}."
msgstr ""
-#: src/screens/Settings/Settings.tsx:418
+#: src/screens/Settings/Settings.tsx:422
msgid "You probably want to restart the app now."
msgstr ""
@@ -11289,7 +11293,7 @@ msgstr ""
msgid "You recently changed your birthdate"
msgstr ""
-#: src/screens/Settings/Settings.tsx:300
+#: src/screens/Settings/Settings.tsx:304
#: src/view/shell/desktop/LeftNav.tsx:210
msgid "You will be signed out of all your accounts."
msgstr ""
@@ -11456,7 +11460,7 @@ msgstr ""
msgid "Your contact {firstAuthorName} is on Bluesky"
msgstr ""
-#: src/components/contacts/screens/ViewMatches.tsx:453
+#: src/components/contacts/screens/ViewMatches.tsx:451
msgid "Your contact {name}"
msgstr ""
--
2.51.2
From f02b9c323f54bbd328ababb1562b20b177b73fc0 Mon Sep 17 00:00:00 2001
From: Samuel Newman
Date: Wed, 17 Dec 2025 22:10:39 +0200
Subject: [PATCH 05/13] Change empty states if not own profile (#9518)
* change empty states if not own profile
* Update ProfileFeedgens.tsx
* capitalise starter packs
---
src/view/com/feeds/ProfileFeedgens.tsx | 38 +++++++++---
src/view/com/lists/ProfileLists.tsx | 40 +++++++++----
src/view/screens/Profile.tsx | 82 ++++++++++++++++----------
3 files changed, 109 insertions(+), 51 deletions(-)
diff --git a/src/view/com/feeds/ProfileFeedgens.tsx b/src/view/com/feeds/ProfileFeedgens.tsx
index 34762dc15..5b09545f6 100644
--- a/src/view/com/feeds/ProfileFeedgens.tsx
+++ b/src/view/com/feeds/ProfileFeedgens.tsx
@@ -23,6 +23,7 @@ import {logger} from '#/logger'
import {isIOS, isNative, isWeb} from '#/platform/detection'
import {usePreferencesQuery} from '#/state/queries/preferences'
import {RQKEY, useProfileFeedgensQuery} from '#/state/queries/profile-feedgens'
+import {useSession} from '#/state/session'
import {EmptyState} from '#/view/com/util/EmptyState'
import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
import {List, type ListRef} from '#/view/com/util/List'
@@ -81,6 +82,8 @@ export function ProfileFeedgens({
const isEmpty = !isPending && !data?.pages[0]?.feeds.length
const {data: preferences} = usePreferencesQuery()
const navigation = useNavigation()
+ const {currentAccount} = useSession()
+ const isSelf = currentAccount?.did === did
const items = useMemo(() => {
let items: any[] = []
@@ -152,15 +155,23 @@ export function ProfileFeedgens({
navigation.navigate('Feeds' as never),
- size: 'small',
- color: 'secondary',
- }}
+ button={
+ isSelf
+ ? {
+ label: _(msg`Browse custom feeds`),
+ text: _(msg`Browse custom feeds`),
+ onPress: () => navigation.navigate('Feeds' as never),
+ size: 'small',
+ color: 'secondary',
+ }
+ : undefined
+ }
/>
)
} else if (item === ERROR_ITEM) {
@@ -194,7 +205,16 @@ export function ProfileFeedgens({
}
return null
},
- [_, t, error, refetch, onPressRetryLoadMore, preferences, navigation],
+ [
+ _,
+ t,
+ error,
+ refetch,
+ onPressRetryLoadMore,
+ preferences,
+ navigation,
+ isSelf,
+ ],
)
useEffect(() => {
diff --git a/src/view/com/lists/ProfileLists.tsx b/src/view/com/lists/ProfileLists.tsx
index c60fc42ee..35ab7b8a8 100644
--- a/src/view/com/lists/ProfileLists.tsx
+++ b/src/view/com/lists/ProfileLists.tsx
@@ -23,6 +23,7 @@ import {logger} from '#/logger'
import {isIOS, isNative, isWeb} from '#/platform/detection'
import {usePreferencesQuery} from '#/state/queries/preferences'
import {RQKEY, useProfileListsQuery} from '#/state/queries/profile-lists'
+import {useSession} from '#/state/session'
import {EmptyState} from '#/view/com/util/EmptyState'
import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
import {List, type ListRef} from '#/view/com/util/List'
@@ -81,6 +82,8 @@ export function ProfileLists({
const isEmpty = !isPending && !data?.pages[0]?.lists.length
const {data: preferences} = usePreferencesQuery()
const navigation = useNavigation()
+ const {currentAccount} = useSession()
+ const isSelf = currentAccount?.did === did
const items = useMemo(() => {
let items: any[] = []
@@ -151,17 +154,23 @@ export function ProfileLists({
return (
navigation.navigate('Lists' as never),
- size: 'small',
- color: 'primary',
- }}
+ button={
+ isSelf
+ ? {
+ label: _(msg`Create a list`),
+ text: _(msg`Create a list`),
+ onPress: () => navigation.navigate('Lists' as never),
+ size: 'small',
+ color: 'primary',
+ }
+ : undefined
+ }
/>
)
} else if (item === ERROR_ITEM) {
@@ -195,7 +204,16 @@ export function ProfileLists({
}
return null
},
- [_, t, error, refetch, onPressRetryLoadMore, preferences, navigation],
+ [
+ _,
+ t,
+ error,
+ refetch,
+ onPressRetryLoadMore,
+ preferences,
+ navigation,
+ isSelf,
+ ],
)
useEffect(() => {
diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx
index fddde55e1..5bb46f0d2 100644
--- a/src/view/screens/Profile.tsx
+++ b/src/view/screens/Profile.tsx
@@ -429,13 +429,17 @@ function ProfileScreenLoaded({
ignoreFilterFor={profile.did}
setScrollViewTag={setScrollViewTag}
emptyStateMessage={_(msg`No posts yet`)}
- emptyStateButton={{
- label: _(msg`Write a post`),
- text: _(msg`Write a post`),
- onPress: () => openComposer({}),
- size: 'small',
- color: 'primary',
- }}
+ emptyStateButton={
+ isMe
+ ? {
+ label: _(msg`Write a post`),
+ text: _(msg`Write a post`),
+ onPress: () => openComposer({}),
+ size: 'small',
+ color: 'primary',
+ }
+ : undefined
+ }
/>
)
: null}
@@ -465,13 +469,17 @@ function ProfileScreenLoaded({
ignoreFilterFor={profile.did}
setScrollViewTag={setScrollViewTag}
emptyStateMessage={_(msg`No media yet`)}
- emptyStateButton={{
- label: _(msg`Post a photo`),
- text: _(msg`Post a photo`),
- onPress: () => openComposer({}),
- size: 'small',
- color: 'primary',
- }}
+ emptyStateButton={
+ isMe
+ ? {
+ label: _(msg`Post a photo`),
+ text: _(msg`Post a photo`),
+ onPress: () => openComposer({}),
+ size: 'small',
+ color: 'primary',
+ }
+ : undefined
+ }
emptyStateIcon={ImageIcon}
/>
)
@@ -487,13 +495,17 @@ function ProfileScreenLoaded({
ignoreFilterFor={profile.did}
setScrollViewTag={setScrollViewTag}
emptyStateMessage={_(msg`No video posts yet`)}
- emptyStateButton={{
- label: _(msg`Post a video`),
- text: _(msg`Post a video`),
- onPress: () => openComposer({}),
- size: 'small',
- color: 'primary',
- }}
+ emptyStateButton={
+ isMe
+ ? {
+ label: _(msg`Post a video`),
+ text: _(msg`Post a video`),
+ onPress: () => openComposer({}),
+ size: 'small',
+ color: 'primary',
+ }
+ : undefined
+ }
emptyStateIcon={VideoIcon}
/>
)
@@ -535,16 +547,24 @@ function ProfileScreenLoaded({
headerOffset={headerHeight}
enabled={isFocused}
setScrollViewTag={setScrollViewTag}
- emptyStateMessage={_(
- msg`Starter packs let you share your favorite feeds and people with your friends.`,
- )}
- emptyStateButton={{
- label: _(msg`Create a Starter Pack`),
- text: _(msg`Create a Starter Pack`),
- onPress: wrappedNavToWizard,
- color: 'primary',
- size: 'small',
- }}
+ emptyStateMessage={
+ isMe
+ ? _(
+ msg`Starter Packs let you share your favorite feeds and people with your friends.`,
+ )
+ : _(msg`No Starter Packs yet`)
+ }
+ emptyStateButton={
+ isMe
+ ? {
+ label: _(msg`Create a Starter Pack`),
+ text: _(msg`Create a Starter Pack`),
+ onPress: wrappedNavToWizard,
+ color: 'primary',
+ size: 'small',
+ }
+ : undefined
+ }
emptyStateIcon={CircleAndSquareIcon}
/>
)
--
2.51.2
From e80e2f66c3d7c2542b73defd0a411c3e87e5d49f Mon Sep 17 00:00:00 2001
From: Alex Benzer
Date: Wed, 17 Dec 2025 13:45:21 -0800
Subject: [PATCH 06/13] Adds a dismiss button to user suggestions (#9484)
* Add dismiss button to user suggestions
* Adds dismiss button to suggested user cards, behind a feature gate
* Reverse gate check, best practice
* Sync DISMISS_ANIMATION_DURATION
---------
Co-authored-by: Eric Bailey
---
src/components/FeedInterstitials.tsx | 379 ++++++++++++++----
src/lib/statsig/gates.ts | 1 +
src/logger/metrics.ts | 6 +
.../Profile/Header/SuggestedFollows.tsx | 186 ++++++++-
4 files changed, 493 insertions(+), 79 deletions(-)
diff --git a/src/components/FeedInterstitials.tsx b/src/components/FeedInterstitials.tsx
index 7418c8d76..267d303be 100644
--- a/src/components/FeedInterstitials.tsx
+++ b/src/components/FeedInterstitials.tsx
@@ -1,12 +1,13 @@
import React, {useCallback, useEffect, useRef} from 'react'
import {ScrollView, View} from 'react-native'
+import Animated, {LinearTransition} from 'react-native-reanimated'
import {type AppBskyFeedDefs, AtUri} from '@atproto/api'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useNavigation} from '@react-navigation/native'
import {type NavigationProp} from '#/lib/routes/types'
-import {logEvent} from '#/lib/statsig/statsig'
+import {logEvent, useGate} from '#/lib/statsig/statsig'
import {logger} from '#/logger'
import {type MetricEvents} from '#/logger/metrics'
import {isIOS} from '#/platform/detection'
@@ -14,7 +15,10 @@ import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {useGetPopularFeedsQuery} from '#/state/queries/feed'
import {type FeedDescriptor} from '#/state/queries/post-feed'
import {useProfilesQuery} from '#/state/queries/profile'
-import {useSuggestedFollowsByActorQuery} from '#/state/queries/suggested-follows'
+import {
+ useSuggestedFollowsByActorQuery,
+ useSuggestedFollowsQuery,
+} from '#/state/queries/suggested-follows'
import {useSession} from '#/state/session'
import * as userActionHistory from '#/state/userActionHistory'
import {type SeenPost} from '#/state/userActionHistory'
@@ -31,6 +35,7 @@ import {useDialogControl} from '#/components/Dialog'
import * as FeedCard from '#/components/FeedCard'
import {ArrowRight_Stroke2_Corner0_Rounded as ArrowRight} from '#/components/icons/Arrow'
import {Hashtag_Stroke2_Corner0_Rounded as Hashtag} from '#/components/icons/Hashtag'
+import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
import {InlineLinkText} from '#/components/Link'
import * as ProfileCard from '#/components/ProfileCard'
import {Text} from '#/components/Typography'
@@ -38,6 +43,8 @@ import type * as bsky from '#/types/bsky'
import {FollowDialogWithoutGuide} from './ProgressGuide/FollowDialog'
import {ProgressGuideList} from './ProgressGuide/List'
+const DISMISS_ANIMATION_DURATION = 200
+
const MOBILE_CARD_WIDTH = 165
const FINAL_CARD_WIDTH = 120
@@ -202,6 +209,9 @@ export function SuggestedFollows({feed}: {feed: FeedDescriptor}) {
}
export function SuggestedFollowsProfile({did}: {did: string}) {
+ const {gtMobile} = useBreakpoints()
+ const moderationOpts = useModerationOpts()
+ const maxLength = gtMobile ? 4 : 6
const {
isLoading: isSuggestionsLoading,
data,
@@ -209,29 +219,194 @@ export function SuggestedFollowsProfile({did}: {did: string}) {
} = useSuggestedFollowsByActorQuery({
did,
})
+ const {
+ data: moreSuggestions,
+ fetchNextPage,
+ hasNextPage,
+ isFetchingNextPage,
+ } = useSuggestedFollowsQuery({limit: 25})
+
+ const [dismissedDids, setDismissedDids] = React.useState>(
+ new Set(),
+ )
+ const [dismissingDids, setDismissingDids] = React.useState>(
+ new Set(),
+ )
+
+ const onDismiss = React.useCallback((dismissedDid: string) => {
+ // Start the fade animation
+ setDismissingDids(prev => new Set(prev).add(dismissedDid))
+ // After animation completes, actually remove from list
+ setTimeout(() => {
+ setDismissedDids(prev => new Set(prev).add(dismissedDid))
+ setDismissingDids(prev => {
+ const next = new Set(prev)
+ next.delete(dismissedDid)
+ return next
+ })
+ }, DISMISS_ANIMATION_DURATION)
+ }, [])
+
+ // Combine profiles from the actor-specific query with fallback suggestions
+ const allProfiles = React.useMemo(() => {
+ const actorProfiles = data?.suggestions ?? []
+ const fallbackProfiles =
+ moreSuggestions?.pages.flatMap(page => page.actors) ?? []
+
+ // Dedupe by did, preferring actor-specific profiles
+ const seen = new Set()
+ const combined: bsky.profile.AnyProfileView[] = []
+
+ for (const profile of actorProfiles) {
+ if (!seen.has(profile.did)) {
+ seen.add(profile.did)
+ combined.push(profile)
+ }
+ }
+
+ for (const profile of fallbackProfiles) {
+ if (!seen.has(profile.did) && profile.did !== did) {
+ seen.add(profile.did)
+ combined.push(profile)
+ }
+ }
+
+ return combined
+ }, [data?.suggestions, moreSuggestions?.pages, did])
+
+ const filteredProfiles = React.useMemo(() => {
+ return allProfiles.filter(p => !dismissedDids.has(p.did))
+ }, [allProfiles, dismissedDids])
+
+ // Fetch more when running low
+ React.useEffect(() => {
+ if (
+ moderationOpts &&
+ filteredProfiles.length < maxLength &&
+ hasNextPage &&
+ !isFetchingNextPage
+ ) {
+ fetchNextPage()
+ }
+ }, [
+ filteredProfiles.length,
+ maxLength,
+ hasNextPage,
+ isFetchingNextPage,
+ fetchNextPage,
+ moderationOpts,
+ ])
+
return (
)
}
export function SuggestedFollowsHome() {
+ const {gtMobile} = useBreakpoints()
+ const moderationOpts = useModerationOpts()
+ const maxLength = gtMobile ? 4 : 6
const {
isLoading: isSuggestionsLoading,
- profiles,
- error,
+ profiles: experimentalProfiles,
+ error: experimentalError,
} = useExperimentalSuggestedUsersQuery()
+ const {
+ data: moreSuggestions,
+ fetchNextPage,
+ hasNextPage,
+ isFetchingNextPage,
+ error: suggestionsError,
+ } = useSuggestedFollowsQuery({limit: 25})
+
+ const [dismissedDids, setDismissedDids] = React.useState>(
+ new Set(),
+ )
+ const [dismissingDids, setDismissingDids] = React.useState>(
+ new Set(),
+ )
+
+ const onDismiss = React.useCallback((did: string) => {
+ // Start the fade animation
+ setDismissingDids(prev => new Set(prev).add(did))
+ // After animation completes, actually remove from list
+ setTimeout(() => {
+ setDismissedDids(prev => new Set(prev).add(did))
+ setDismissingDids(prev => {
+ const next = new Set(prev)
+ next.delete(did)
+ return next
+ })
+ }, DISMISS_ANIMATION_DURATION)
+ }, [])
+
+ // Combine profiles from experimental query with paginated suggestions
+ const allProfiles = React.useMemo(() => {
+ const fallbackProfiles =
+ moreSuggestions?.pages.flatMap(page => page.actors) ?? []
+
+ // Dedupe by did, preferring experimental profiles
+ const seen = new Set()
+ const combined: bsky.profile.AnyProfileView[] = []
+
+ for (const profile of experimentalProfiles) {
+ if (!seen.has(profile.did)) {
+ seen.add(profile.did)
+ combined.push(profile)
+ }
+ }
+
+ for (const profile of fallbackProfiles) {
+ if (!seen.has(profile.did)) {
+ seen.add(profile.did)
+ combined.push(profile)
+ }
+ }
+
+ return combined
+ }, [experimentalProfiles, moreSuggestions?.pages])
+
+ const filteredProfiles = React.useMemo(() => {
+ return allProfiles.filter(p => !dismissedDids.has(p.did))
+ }, [allProfiles, dismissedDids])
+
+ // Fetch more when running low
+ React.useEffect(() => {
+ if (
+ moderationOpts &&
+ filteredProfiles.length < maxLength &&
+ hasNextPage &&
+ !isFetchingNextPage
+ ) {
+ fetchNextPage()
+ }
+ }, [
+ filteredProfiles.length,
+ maxLength,
+ hasNextPage,
+ isFetchingNextPage,
+ fetchNextPage,
+ moderationOpts,
+ ])
+
return (
)
}
@@ -240,19 +415,26 @@ export function ProfileGrid({
isSuggestionsLoading,
error,
profiles,
+ totalProfileCount,
recId,
viewContext = 'feed',
+ onDismiss,
+ dismissingDids,
isVisible = true,
}: {
isSuggestionsLoading: boolean
profiles: bsky.profile.AnyProfileView[]
+ totalProfileCount?: number
recId?: number
error: Error | null
+ dismissingDids?: Set
viewContext: 'profile' | 'profileHeader' | 'feed'
+ onDismiss?: (did: string) => void
isVisible?: boolean
}) {
const t = useTheme()
const {_} = useLingui()
+ const gate = useGate()
const moderationOpts = useModerationOpts()
const {gtMobile} = useBreakpoints()
const followDialogControl = useDialogControl()
@@ -260,6 +442,7 @@ export function ProfileGrid({
const isLoading = isSuggestionsLoading || !moderationOpts
const isProfileHeaderContext = viewContext === 'profileHeader'
const isFeedContext = viewContext === 'feed'
+ const showDismissButton = onDismiss && gate('suggested_users_dismiss')
const maxLength = gtMobile ? 3 : isProfileHeaderContext ? 12 : 6
const minLength = gtMobile ? 3 : 4
@@ -363,20 +546,9 @@ export function ProfileGrid({
: error || !profiles.length
? null
: profiles.slice(0, maxLength).map((profile, index) => (
- {
- logEvent('suggestedUser:press', {
- logContext: isFeedContext
- ? 'InterstitialDiscover'
- : 'InterstitialProfile',
- recId,
- position: index,
- suggestedDid: profile.did,
- category: null,
- })
- }}
+ layout={LinearTransition.duration(DISMISS_ANIMATION_DURATION)}
style={[
a.flex_1,
gtMobile &&
@@ -385,68 +557,127 @@ export function ProfileGrid({
a.flex_grow,
{width: `calc(30% - ${a.gap_md.gap / 2}px)`},
]),
+ {
+ opacity: dismissingDids?.has(profile.did) ? 0 : 1,
+ transitionProperty: 'opacity',
+ transitionDuration: `${DISMISS_ANIMATION_DURATION}ms`,
+ },
]}>
- {({hovered, pressed}) => (
-
-
-
-
-
- {
+ logEvent('suggestedUser:press', {
+ logContext: isFeedContext
+ ? 'InterstitialDiscover'
+ : 'InterstitialProfile',
+ recId,
+ position: index,
+ suggestedDid: profile.did,
+ category: null,
+ })
+ }}>
+ {({hovered, pressed}) => (
+
+
+ {showDismissButton && (
+
+ )}
+
+
-
+
+
+
+
-
- {
- logEvent('suggestedUser:follow', {
- logContext: isFeedContext
- ? 'InterstitialDiscover'
- : 'InterstitialProfile',
- location: 'Card',
- recId,
- position: index,
- suggestedDid: profile.did,
- category: null,
- })
- }}
- />
-
-
- )}
-
+ {
+ logEvent('suggestedUser:follow', {
+ logContext: isFeedContext
+ ? 'InterstitialDiscover'
+ : 'InterstitialProfile',
+ location: 'Card',
+ recId,
+ position: index,
+ suggestedDid: profile.did,
+ category: null,
+ })
+ }}
+ />
+
+
+ )}
+
+
))
- if (error || (!isLoading && profiles.length < minLength)) {
+ // Use totalProfileCount (before dismissals) for minLength check on initial render.
+ const profileCountForMinCheck = totalProfileCount ?? profiles.length
+ if (error || (!isLoading && profileCountForMinCheck < minLength)) {
logger.debug(`Not enough profiles to show suggested follows`)
return null
}
diff --git a/src/lib/statsig/gates.ts b/src/lib/statsig/gates.ts
index ea67ac01b..357548d3b 100644
--- a/src/lib/statsig/gates.ts
+++ b/src/lib/statsig/gates.ts
@@ -12,5 +12,6 @@ export type Gate =
| 'onboarding_suggested_starterpacks'
| 'remove_show_latest_button'
| 'show_composer_prompt'
+ | 'suggested_users_dismiss'
| 'test_gate_1'
| 'test_gate_2'
diff --git a/src/logger/metrics.ts b/src/logger/metrics.ts
index 6908f3a05..949c883b7 100644
--- a/src/logger/metrics.ts
+++ b/src/logger/metrics.ts
@@ -379,6 +379,12 @@ export type MetricEvents = {
| 'Profile'
| 'Onboarding'
}
+ 'suggestedUser:dismiss': {
+ logContext: 'InterstitialDiscover' | 'InterstitialProfile'
+ recId?: number
+ position: number
+ suggestedDid: string
+ }
'profile:unfollow': {
logContext:
| 'RecommendedFollowsItem'
diff --git a/src/screens/Profile/Header/SuggestedFollows.tsx b/src/screens/Profile/Header/SuggestedFollows.tsx
index 48856cef7..239ad7d9f 100644
--- a/src/screens/Profile/Header/SuggestedFollows.tsx
+++ b/src/screens/Profile/Header/SuggestedFollows.tsx
@@ -1,20 +1,113 @@
+import React from 'react'
+import {type AppBskyActorDefs} from '@atproto/api'
+
import {AccordionAnimation} from '#/lib/custom-animations/AccordionAnimation'
import {isAndroid} from '#/platform/detection'
-import {useSuggestedFollowsByActorQuery} from '#/state/queries/suggested-follows'
+import {useModerationOpts} from '#/state/preferences/moderation-opts'
+import {
+ useSuggestedFollowsByActorQuery,
+ useSuggestedFollowsQuery,
+} from '#/state/queries/suggested-follows'
+import {useBreakpoints} from '#/alf'
import {ProfileGrid} from '#/components/FeedInterstitials'
+const DISMISS_ANIMATION_DURATION = 200
+
export function ProfileHeaderSuggestedFollows({actorDid}: {actorDid: string}) {
+ const {gtMobile} = useBreakpoints()
+ const moderationOpts = useModerationOpts()
+ const maxLength = gtMobile ? 4 : 12
const {isLoading, data, error} = useSuggestedFollowsByActorQuery({
did: actorDid,
})
+ const {
+ data: moreSuggestions,
+ fetchNextPage,
+ hasNextPage,
+ isFetchingNextPage,
+ } = useSuggestedFollowsQuery({limit: 25})
+
+ const [dismissedDids, setDismissedDids] = React.useState>(
+ new Set(),
+ )
+ const [dismissingDids, setDismissingDids] = React.useState>(
+ new Set(),
+ )
+
+ const onDismiss = React.useCallback((did: string) => {
+ // Start the fade animation
+ setDismissingDids(prev => new Set(prev).add(did))
+ // After animation completes, actually remove from list
+ setTimeout(() => {
+ setDismissedDids(prev => new Set(prev).add(did))
+ setDismissingDids(prev => {
+ const next = new Set(prev)
+ next.delete(did)
+ return next
+ })
+ }, DISMISS_ANIMATION_DURATION)
+ }, [])
+
+ // Combine profiles from the actor-specific query with fallback suggestions
+ const allProfiles = React.useMemo(() => {
+ const actorProfiles = data?.suggestions ?? []
+ const fallbackProfiles =
+ moreSuggestions?.pages.flatMap(page => page.actors) ?? []
+
+ // Dedupe by did, preferring actor-specific profiles
+ const seen = new Set()
+ const combined: AppBskyActorDefs.ProfileView[] = []
+
+ for (const profile of actorProfiles) {
+ if (!seen.has(profile.did)) {
+ seen.add(profile.did)
+ combined.push(profile)
+ }
+ }
+
+ for (const profile of fallbackProfiles) {
+ if (!seen.has(profile.did) && profile.did !== actorDid) {
+ seen.add(profile.did)
+ combined.push(profile)
+ }
+ }
+
+ return combined
+ }, [data?.suggestions, moreSuggestions?.pages, actorDid])
+
+ const filteredProfiles = React.useMemo(() => {
+ return allProfiles.filter(p => !dismissedDids.has(p.did))
+ }, [allProfiles, dismissedDids])
+
+ // Fetch more when running low
+ React.useEffect(() => {
+ if (
+ moderationOpts &&
+ filteredProfiles.length < maxLength &&
+ hasNextPage &&
+ !isFetchingNextPage
+ ) {
+ fetchNextPage()
+ }
+ }, [
+ filteredProfiles.length,
+ maxLength,
+ hasNextPage,
+ isFetchingNextPage,
+ fetchNextPage,
+ moderationOpts,
+ ])
return (
)
}
@@ -26,11 +119,91 @@ export function AnimatedProfileHeaderSuggestedFollows({
isExpanded: boolean
actorDid: string
}) {
+ const {gtMobile} = useBreakpoints()
+ const moderationOpts = useModerationOpts()
+ const maxLength = gtMobile ? 4 : 12
const {isLoading, data, error} = useSuggestedFollowsByActorQuery({
did: actorDid,
})
+ const {
+ data: moreSuggestions,
+ fetchNextPage,
+ hasNextPage,
+ isFetchingNextPage,
+ } = useSuggestedFollowsQuery({limit: 25})
+
+ const [dismissedDids, setDismissedDids] = React.useState>(
+ new Set(),
+ )
+ const [dismissingDids, setDismissingDids] = React.useState>(
+ new Set(),
+ )
+
+ const onDismiss = React.useCallback((did: string) => {
+ // Start the fade animation
+ setDismissingDids(prev => new Set(prev).add(did))
+ // After animation completes, actually remove from list
+ setTimeout(() => {
+ setDismissedDids(prev => new Set(prev).add(did))
+ setDismissingDids(prev => {
+ const next = new Set(prev)
+ next.delete(did)
+ return next
+ })
+ }, DISMISS_ANIMATION_DURATION)
+ }, [])
+
+ // Combine profiles from the actor-specific query with fallback suggestions
+ const allProfiles = React.useMemo(() => {
+ const actorProfiles = data?.suggestions ?? []
+ const fallbackProfiles =
+ moreSuggestions?.pages.flatMap(page => page.actors) ?? []
+
+ // Dedupe by did, preferring actor-specific profiles
+ const seen = new Set()
+ const combined: AppBskyActorDefs.ProfileView[] = []
+
+ for (const profile of actorProfiles) {
+ if (!seen.has(profile.did)) {
+ seen.add(profile.did)
+ combined.push(profile)
+ }
+ }
+
+ for (const profile of fallbackProfiles) {
+ if (!seen.has(profile.did) && profile.did !== actorDid) {
+ seen.add(profile.did)
+ combined.push(profile)
+ }
+ }
+
+ return combined
+ }, [data?.suggestions, moreSuggestions?.pages, actorDid])
+
+ const filteredProfiles = React.useMemo(() => {
+ return allProfiles.filter(p => !dismissedDids.has(p.did))
+ }, [allProfiles, dismissedDids])
+
+ // Fetch more when running low
+ React.useEffect(() => {
+ if (
+ moderationOpts &&
+ filteredProfiles.length < maxLength &&
+ hasNextPage &&
+ !isFetchingNextPage
+ ) {
+ fetchNextPage()
+ }
+ }, [
+ filteredProfiles.length,
+ maxLength,
+ hasNextPage,
+ isFetchingNextPage,
+ fetchNextPage,
+ moderationOpts,
+ ])
- if (!data?.suggestions?.length) return null
+ if (!allProfiles.length && !isLoading) return null
/* NOTE (caidanw):
* Android does not work well with this feature yet.
@@ -43,10 +216,13 @@ export function AnimatedProfileHeaderSuggestedFollows({
--
2.51.2
From f50b70e2b4db2a12fdfd13b662231a1b372d73ce Mon Sep 17 00:00:00 2001
From: Eric Bailey
Date: Wed, 17 Dec 2025 17:03:16 -0600
Subject: [PATCH 07/13] Bump to v1.113.0 (#9569)
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index d8f3dee7f..c1a3bb47b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bsky.app",
- "version": "1.112.0",
+ "version": "1.113.0",
"private": true,
"engines": {
"node": ">=20"
--
2.51.2
From e9524d8a83ee241da9761a1ceb98c9bf40c7d4dc Mon Sep 17 00:00:00 2001
From: pfrazee <1270099+pfrazee@users.noreply.github.com>
Date: Thu, 18 Dec 2025 02:42:38 +0000
Subject: [PATCH 08/13] Nightly source-language update
---
src/locale/locales/en/messages.po | 87 +++++++++++++++++++------------
1 file changed, 53 insertions(+), 34 deletions(-)
diff --git a/src/locale/locales/en/messages.po b/src/locale/locales/en/messages.po
index e232dbf37..6ea91d4a7 100644
--- a/src/locale/locales/en/messages.po
+++ b/src/locale/locales/en/messages.po
@@ -1637,25 +1637,25 @@ msgstr ""
msgid "Breaking site rules"
msgstr ""
-#: src/view/com/feeds/ProfileFeedgens.tsx:158
-#: src/view/com/feeds/ProfileFeedgens.tsx:159
+#: src/view/com/feeds/ProfileFeedgens.tsx:167
+#: src/view/com/feeds/ProfileFeedgens.tsx:168
msgid "Browse custom feeds"
msgstr ""
-#: src/components/FeedInterstitials.tsx:547
+#: src/components/FeedInterstitials.tsx:778
msgid "Browse more accounts"
msgstr ""
-#: src/components/FeedInterstitials.tsx:676
+#: src/components/FeedInterstitials.tsx:907
msgid "Browse more feeds on the Explore page"
msgstr ""
-#: src/components/FeedInterstitials.tsx:657
-#: src/components/FeedInterstitials.tsx:660
+#: src/components/FeedInterstitials.tsx:888
+#: src/components/FeedInterstitials.tsx:891
msgid "Browse more suggestions"
msgstr ""
-#: src/components/FeedInterstitials.tsx:685
+#: src/components/FeedInterstitials.tsx:916
msgid "Browse more suggestions on the Explore page"
msgstr ""
@@ -2593,8 +2593,8 @@ msgstr ""
msgid "Create"
msgstr ""
-#: src/view/com/lists/ProfileLists.tsx:159
-#: src/view/com/lists/ProfileLists.tsx:160
+#: src/view/com/lists/ProfileLists.tsx:166
+#: src/view/com/lists/ProfileLists.tsx:167
msgid "Create a list"
msgstr ""
@@ -2608,8 +2608,8 @@ msgstr ""
msgid "Create a starter pack"
msgstr ""
-#: src/view/screens/Profile.tsx:542
-#: src/view/screens/Profile.tsx:543
+#: src/view/screens/Profile.tsx:560
+#: src/view/screens/Profile.tsx:561
msgid "Create a Starter Pack"
msgstr ""
@@ -3018,6 +3018,10 @@ msgstr ""
msgid "Dismiss this section"
msgstr ""
+#: src/components/FeedInterstitials.tsx:587
+msgid "Dismiss this suggestion"
+msgstr ""
+
#: src/screens/Settings/AccessibilitySettings.tsx:69
#: src/screens/Settings/AccessibilitySettings.tsx:74
msgid "Display larger alt text badges"
@@ -5405,7 +5409,6 @@ msgid "Lists"
msgstr ""
#: src/view/com/lists/MyLists.tsx:72
-#: src/view/com/lists/ProfileLists.tsx:155
msgid "Lists allow you to see content from your favorite people."
msgstr ""
@@ -5936,7 +5939,7 @@ msgstr ""
#: src/screens/ProfileList/index.tsx:284
#: src/view/screens/Feeds.tsx:552
#: src/view/screens/Notifications.tsx:167
-#: src/view/screens/Profile.tsx:571
+#: src/view/screens/Profile.tsx:591
msgid "New post"
msgstr ""
@@ -6018,6 +6021,10 @@ msgstr ""
msgid "No contacts with the name “{query}” found"
msgstr ""
+#: src/view/com/feeds/ProfileFeedgens.tsx:161
+msgid "No custom feeds yet"
+msgstr ""
+
#: src/screens/Settings/components/ChangeHandleDialog.tsx:408
#: src/screens/Settings/components/ChangeHandleDialog.tsx:410
msgid "No DNS Panel"
@@ -6045,17 +6052,21 @@ msgstr ""
#: src/components/LikedByList.tsx:84
#: src/view/com/post-thread/PostLikedBy.tsx:84
-#: src/view/screens/Profile.tsx:511
+#: src/view/screens/Profile.tsx:523
msgid "No likes yet"
msgstr ""
+#: src/view/com/lists/ProfileLists.tsx:160
+msgid "No lists"
+msgstr ""
+
#: src/components/ProfileCard.tsx:531
#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:269
#: src/view/com/notifications/NotificationFeedItem.tsx:792
msgid "No longer following {0}"
msgstr ""
-#: src/view/screens/Profile.tsx:467
+#: src/view/screens/Profile.tsx:471
msgid "No media yet"
msgstr ""
@@ -6100,7 +6111,7 @@ msgstr ""
msgid "No quotes yet"
msgstr ""
-#: src/view/screens/Profile.tsx:452
+#: src/view/screens/Profile.tsx:456
msgid "No replies yet"
msgstr ""
@@ -6143,12 +6154,16 @@ msgstr ""
msgid "No search results found for \"{search}\"."
msgstr ""
+#: src/view/screens/Profile.tsx:555
+msgid "No Starter Packs yet"
+msgstr ""
+
#: src/components/dialogs/EmbedConsent.tsx:104
#: src/components/dialogs/EmbedConsent.tsx:111
msgid "No thanks"
msgstr ""
-#: src/view/screens/Profile.tsx:489
+#: src/view/screens/Profile.tsx:497
msgid "No video posts yet"
msgstr ""
@@ -6970,13 +6985,13 @@ msgctxt "action"
msgid "Post"
msgstr ""
-#: src/view/screens/Profile.tsx:469
-#: src/view/screens/Profile.tsx:470
+#: src/view/screens/Profile.tsx:475
+#: src/view/screens/Profile.tsx:476
msgid "Post a photo"
msgstr ""
-#: src/view/screens/Profile.tsx:491
-#: src/view/screens/Profile.tsx:492
+#: src/view/screens/Profile.tsx:501
+#: src/view/screens/Profile.tsx:502
msgid "Post a video"
msgstr ""
@@ -8153,12 +8168,12 @@ msgstr ""
msgid "See jobs at Bluesky"
msgstr ""
-#: src/components/FeedInterstitials.tsx:499
-#: src/components/FeedInterstitials.tsx:562
+#: src/components/FeedInterstitials.tsx:730
+#: src/components/FeedInterstitials.tsx:793
msgid "See more"
msgstr ""
-#: src/components/FeedInterstitials.tsx:481
+#: src/components/FeedInterstitials.tsx:712
msgid "See more suggested profiles"
msgstr ""
@@ -8776,7 +8791,7 @@ msgstr ""
msgid "Signed in as @{0}"
msgstr ""
-#: src/components/FeedInterstitials.tsx:476
+#: src/components/FeedInterstitials.tsx:707
msgid "Similar accounts"
msgstr ""
@@ -8827,7 +8842,7 @@ msgstr ""
msgid "Some of your verifications are invalid."
msgstr ""
-#: src/components/FeedInterstitials.tsx:639
+#: src/components/FeedInterstitials.tsx:870
msgid "Some other feeds you might like"
msgstr ""
@@ -8973,8 +8988,8 @@ msgstr ""
msgid "Starter packs let you easily share your favorite feeds and people with your friends."
msgstr ""
-#: src/view/screens/Profile.tsx:539
-msgid "Starter packs let you share your favorite feeds and people with your friends."
+#: src/view/screens/Profile.tsx:553
+msgid "Starter Packs let you share your favorite feeds and people with your friends."
msgstr ""
#: src/screens/Settings/AboutSettings.tsx:100
@@ -9066,7 +9081,7 @@ msgid "Suggested Accounts"
msgstr ""
#. Accounts suggested to the user for them to follow
-#: src/components/FeedInterstitials.tsx:474
+#: src/components/FeedInterstitials.tsx:705
#: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:155
msgid "Suggested for you"
msgstr ""
@@ -9413,8 +9428,8 @@ msgstr ""
msgid "There was an issue fetching your app passwords"
msgstr ""
-#: src/view/com/feeds/ProfileFeedgens.tsx:174
-#: src/view/com/lists/ProfileLists.tsx:175
+#: src/view/com/feeds/ProfileFeedgens.tsx:185
+#: src/view/com/lists/ProfileLists.tsx:184
msgid "There was an issue fetching your lists. Tap here to try again."
msgstr ""
@@ -10920,8 +10935,8 @@ msgstr ""
msgid "Write a message"
msgstr ""
-#: src/view/screens/Profile.tsx:433
-#: src/view/screens/Profile.tsx:434
+#: src/view/screens/Profile.tsx:435
+#: src/view/screens/Profile.tsx:436
msgid "Write a post"
msgstr ""
@@ -11198,7 +11213,11 @@ msgstr ""
msgid "You haven't created a starter pack yet!"
msgstr ""
-#: src/view/com/feeds/ProfileFeedgens.tsx:155
+#: src/view/com/lists/ProfileLists.tsx:159
+msgid "You haven't created any lists yet."
+msgstr ""
+
+#: src/view/com/feeds/ProfileFeedgens.tsx:160
msgid "You haven't made any custom feeds yet."
msgstr ""
--
2.51.2
From 89cffdf5d00be39422da8787020984c4f2808bdf Mon Sep 17 00:00:00 2001
From: Eric Bailey
Date: Thu, 18 Dec 2025 09:45:51 -0600
Subject: [PATCH 09/13] Ignore new flag SVGs in build output (#9567)
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index f15f673dc..38a12f24c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -124,3 +124,4 @@ bskyogcard/src/assets/fonts/noto-*
bskyweb/static/media/*.webp
bskyweb/static/media/*.jpg
bskyweb/static/media/*.png
+bskyweb/static/media/*.svg
--
2.51.2
From a355eedf85b557f49eeb8722aac4fbddf40a0afc Mon Sep 17 00:00:00 2001
From: Eric Bailey
Date: Thu, 18 Dec 2025 11:05:39 -0600
Subject: [PATCH 10/13] Improve instructions on NoAccessScreen and bday dialog
(#9571)
---
.../components/NoAccessScreen.tsx | 78 ++++++++-----------
src/components/dialogs/BirthDateSettings.tsx | 15 +++-
2 files changed, 47 insertions(+), 46 deletions(-)
diff --git a/src/ageAssurance/components/NoAccessScreen.tsx b/src/ageAssurance/components/NoAccessScreen.tsx
index 8b2a44c26..3aa69dc78 100644
--- a/src/ageAssurance/components/NoAccessScreen.tsx
+++ b/src/ageAssurance/components/NoAccessScreen.tsx
@@ -9,12 +9,11 @@ import {
useCreateSupportLink,
} from '#/lib/hooks/useCreateSupportLink'
import {dateDiff, useGetTimeAgo} from '#/lib/hooks/useTimeAgo'
-import {isAppPassword} from '#/lib/jwt'
import {logger} from '#/logger'
import {isWeb} from '#/platform/detection'
import {isNative} from '#/platform/detection'
import {useIsBirthdateUpdateAllowed} from '#/state/birthdate'
-import {useSession, useSessionApi} from '#/state/session'
+import {useSessionApi} from '#/state/session'
import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
import {Admonition} from '#/components/Admonition'
import {AgeAssuranceAppealDialog} from '#/components/ageAssurance/AgeAssuranceAppealDialog'
@@ -30,7 +29,7 @@ import {ShieldCheck_Stroke2_Corner0_Rounded as ShieldIcon} from '#/components/ic
import {createStaticClick, SimpleInlineLinkText} from '#/components/Link'
import {Outlet as PortalOutlet} from '#/components/Portal'
import * as Toast from '#/components/Toast'
-import {Span, Text} from '#/components/Typography'
+import {Text} from '#/components/Typography'
import {BottomSheetOutlet} from '#/../modules/bottom-sheet'
import {useAgeAssurance} from '#/ageAssurance'
import {useAgeAssuranceDataContext} from '#/ageAssurance/data'
@@ -55,9 +54,6 @@ export function NoAccessScreen() {
const {logoutCurrentAccount} = useSessionApi()
const createSupportLink = useCreateSupportLink()
- const {currentAccount} = useSession()
- const isUsingAppPassword = isAppPassword(currentAccount?.accessJwt || '')
-
const aa = useAgeAssurance()
const isBlocked = aa.state.status === aa.Status.Blocked
const isAARegion = !!region
@@ -89,22 +85,38 @@ export function NoAccessScreen() {
logoutCurrentAccount('AgeAssuranceNoAccessScreen')
}, [logoutCurrentAccount])
- const birthdateUpdateText = canUpdateBirthday ? (
-
+ const orgAdmonition = (
+
- If you believe your birthdate is incorrect, you can update it by{' '}
- {
- logger.metric('ageAssurance:noAccessScreen:openBirthdateDialog', {})
- birthdateControl.open()
- })}>
- clicking here
-
- .
+ For organizational accounts, use the birthdate of the person who is
+ responsible for the account.
-
+
+ )
+
+ const birthdateUpdateText = canUpdateBirthday ? (
+ <>
+
+
+ If you believe your birthdate is incorrect, you can update it by{' '}
+ {
+ logger.metric(
+ 'ageAssurance:noAccessScreen:openBirthdateDialog',
+ {},
+ )
+ birthdateControl.open()
+ })}>
+ clicking here
+
+ .
+
+
+
+ {orgAdmonition}
+ >
) : (
@@ -120,15 +132,6 @@ export function NoAccessScreen() {
)
- const orgAdmonition = (
-
-
- For organizational accounts, use the birthdate of the person who is
- responsible for the account.
-
-
- )
-
return (
<>
@@ -175,8 +178,6 @@ export function NoAccessScreen() {
{!isBlocked && birthdateUpdateText}
-
- {orgAdmonition}
@@ -191,8 +192,6 @@ export function NoAccessScreen() {
{birthdateUpdateText}
-
- {orgAdmonition}
)}
>
@@ -224,18 +223,7 @@ export function NoAccessScreen() {
- {isUsingAppPassword ? (
-
-
- Hmm, it looks like you're logged in with an{' '}
- App Password. To set your
- birthdate, you'll need to log in with your main account
- password, or ask whomever controls this account to do so.
-
-
- ) : (
- orgAdmonition
- )}
+ {orgAdmonition}
)}
diff --git a/src/components/dialogs/BirthDateSettings.tsx b/src/components/dialogs/BirthDateSettings.tsx
index c5205bf71..f258824a9 100644
--- a/src/components/dialogs/BirthDateSettings.tsx
+++ b/src/components/dialogs/BirthDateSettings.tsx
@@ -4,6 +4,7 @@ import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useCleanError} from '#/lib/hooks/useCleanError'
+import {isAppPassword} from '#/lib/jwt'
import {getAge, getDateAgo} from '#/lib/strings/time'
import {logger} from '#/logger'
import {isIOS, isWeb} from '#/platform/detection'
@@ -15,6 +16,7 @@ import {
usePreferencesQuery,
type UsePreferencesQueryResponse,
} from '#/state/queries/preferences'
+import {useSession} from '#/state/session'
import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
import {atoms as a, useTheme, web} from '#/alf'
import {Admonition} from '#/components/Admonition'
@@ -23,7 +25,7 @@ import * as Dialog from '#/components/Dialog'
import {DateField} from '#/components/forms/DateField'
import {SimpleInlineLinkText} from '#/components/Link'
import {Loader} from '#/components/Loader'
-import {Text} from '#/components/Typography'
+import {Span, Text} from '#/components/Typography'
export function BirthDateSettingsDialog({
control,
@@ -34,6 +36,8 @@ export function BirthDateSettingsDialog({
const {_} = useLingui()
const {isLoading, error, data: preferences} = usePreferencesQuery()
const isBirthdateUpdateAllowed = useIsBirthdateUpdateAllowed()
+ const {currentAccount} = useSession()
+ const isUsingAppPassword = isAppPassword(currentAccount?.accessJwt || '')
return (
@@ -65,6 +69,15 @@ export function BirthDateSettingsDialog({
}
style={[a.rounded_sm]}
/>
+ ) : isUsingAppPassword ? (
+
+
+ Hmm, it looks like you're logged in with an{' '}
+ App Password. To set your
+ birthdate, you'll need to log in with your main account
+ password, or ask whomever controls this account to do so.
+
+
) : (
)}
--
2.51.2
From 998ee78e3dab561778174b9370c904536f79982f Mon Sep 17 00:00:00 2001
From: Eric Bailey
Date: Thu, 18 Dec 2025 12:08:17 -0600
Subject: [PATCH 11/13] Move NUXDialogs into shell (#9573)
---
src/App.native.tsx | 2 --
src/App.web.tsx | 2 --
src/view/shell/index.tsx | 2 ++
src/view/shell/index.web.tsx | 2 ++
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/App.native.tsx b/src/App.native.tsx
index fb3008627..34c3cc204 100644
--- a/src/App.native.tsx
+++ b/src/App.native.tsx
@@ -61,7 +61,6 @@ import {Shell} from '#/view/shell'
import {ThemeProvider as Alf} from '#/alf'
import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
import {Provider as ContextMenuProvider} from '#/components/ContextMenu'
-import {NuxDialogs} from '#/components/dialogs/nuxs'
import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs'
import {Provider as PolicyUpdateOverlayProvider} from '#/components/PolicyUpdateOverlay'
@@ -165,7 +164,6 @@ function InnerApp() {
-
diff --git a/src/App.web.tsx b/src/App.web.tsx
index f4b514dfc..956c52005 100644
--- a/src/App.web.tsx
+++ b/src/App.web.tsx
@@ -48,7 +48,6 @@ import {Shell} from '#/view/shell/index'
import {ThemeProvider as Alf} from '#/alf'
import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
import {Provider as ContextMenuProvider} from '#/components/ContextMenu'
-import {NuxDialogs} from '#/components/dialogs/nuxs'
import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs'
import {Provider as PolicyUpdateOverlayProvider} from '#/components/PolicyUpdateOverlay'
@@ -138,7 +137,6 @@ function InnerApp() {
-
diff --git a/src/view/shell/index.tsx b/src/view/shell/index.tsx
index f27c982cb..7f53755fc 100644
--- a/src/view/shell/index.tsx
+++ b/src/view/shell/index.tsx
@@ -32,6 +32,7 @@ import {EmailDialog} from '#/components/dialogs/EmailDialog'
import {InAppBrowserConsentDialog} from '#/components/dialogs/InAppBrowserConsent'
import {LinkWarningDialog} from '#/components/dialogs/LinkWarning'
import {MutedWordsDialog} from '#/components/dialogs/MutedWords'
+import {NuxDialogs} from '#/components/dialogs/nuxs'
import {SigninDialog} from '#/components/dialogs/Signin'
import {
Outlet as PolicyUpdateOverlayPortalOutlet,
@@ -110,6 +111,7 @@ function ShellInner() {
+
{/* Until policy update has been completed by the user, don't render anything that is portaled */}
{policyUpdateState.completed && (
diff --git a/src/view/shell/index.web.tsx b/src/view/shell/index.web.tsx
index a37b68032..dc5c7d7bd 100644
--- a/src/view/shell/index.web.tsx
+++ b/src/view/shell/index.web.tsx
@@ -22,6 +22,7 @@ import {AgeAssuranceRedirectDialog} from '#/components/ageAssurance/AgeAssurance
import {EmailDialog} from '#/components/dialogs/EmailDialog'
import {LinkWarningDialog} from '#/components/dialogs/LinkWarning'
import {MutedWordsDialog} from '#/components/dialogs/MutedWords'
+import {NuxDialogs} from '#/components/dialogs/nuxs'
import {SigninDialog} from '#/components/dialogs/Signin'
import {useWelcomeModal} from '#/components/hooks/useWelcomeModal'
import {
@@ -86,6 +87,7 @@ function ShellInner() {
+
{welcomeModalControl.isOpen && (
--
2.51.2
From a14a9be1274006b881653f3f1dd979f18de3d762 Mon Sep 17 00:00:00 2001
From: pfrazee <1270099+pfrazee@users.noreply.github.com>
Date: Fri, 19 Dec 2025 02:44:03 +0000
Subject: [PATCH 12/13] Nightly source-language update
---
src/locale/locales/en/messages.po | 92 +++++++++++++++----------------
1 file changed, 46 insertions(+), 46 deletions(-)
diff --git a/src/locale/locales/en/messages.po b/src/locale/locales/en/messages.po
index 6ea91d4a7..a30f62432 100644
--- a/src/locale/locales/en/messages.po
+++ b/src/locale/locales/en/messages.po
@@ -844,7 +844,7 @@ msgstr ""
msgid "Add user to list"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:223
+#: src/ageAssurance/components/NoAccessScreen.tsx:222
msgid "Add your birthdate"
msgstr ""
@@ -914,7 +914,7 @@ msgctxt "toast"
msgid "Age assurance inquiry was submitted"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:357
+#: src/ageAssurance/components/NoAccessScreen.tsx:345
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:191
msgid "Age assurance only takes a few minutes"
msgstr ""
@@ -1448,7 +1448,7 @@ msgstr ""
msgid "Begin the age assurance process by completing the fields below."
msgstr ""
-#: src/components/dialogs/BirthDateSettings.tsx:149
+#: src/components/dialogs/BirthDateSettings.tsx:162
msgid "Birthdate"
msgstr ""
@@ -2022,11 +2022,11 @@ msgstr ""
msgid "click here"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:114
+#: src/ageAssurance/components/NoAccessScreen.tsx:126
msgid "Click here to contact our support team"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:248
+#: src/ageAssurance/components/NoAccessScreen.tsx:236
msgid "Click here to log out"
msgstr ""
@@ -2034,8 +2034,8 @@ msgstr ""
msgid "Click here to restart the verification process."
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:97
-#: src/ageAssurance/components/NoAccessScreen.tsx:220
+#: src/ageAssurance/components/NoAccessScreen.tsx:103
+#: src/ageAssurance/components/NoAccessScreen.tsx:219
msgid "Click here to update your birthdate"
msgstr ""
@@ -2121,7 +2121,7 @@ msgstr ""
msgid "Close dialog"
msgstr ""
-#: src/view/shell/index.web.tsx:111
+#: src/view/shell/index.web.tsx:113
msgid "Close drawer menu"
msgstr ""
@@ -2252,7 +2252,7 @@ msgstr ""
msgid "Confirm delete account"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:371
+#: src/ageAssurance/components/NoAccessScreen.tsx:359
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:87
#: src/components/dialogs/DeviceLocationRequestDialog.tsx:40
#: src/components/dialogs/DeviceLocationRequestDialog.tsx:105
@@ -2279,7 +2279,7 @@ msgstr ""
msgid "Connection issue"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:308
+#: src/ageAssurance/components/NoAccessScreen.tsx:296
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:130
#: src/components/ageAssurance/AgeAssuranceAppealDialog.tsx:29
msgid "Contact our moderation team"
@@ -3074,8 +3074,8 @@ msgstr ""
#: src/components/contacts/components/InviteInfo.tsx:78
#: src/components/contacts/screens/ViewMatches.tsx:392
#: src/components/contacts/screens/ViewMatches.tsx:409
-#: src/components/dialogs/BirthDateSettings.tsx:183
-#: src/components/dialogs/BirthDateSettings.tsx:190
+#: src/components/dialogs/BirthDateSettings.tsx:196
+#: src/components/dialogs/BirthDateSettings.tsx:203
#: src/components/dialogs/ServerInput.tsx:240
#: src/components/dialogs/ServerInput.tsx:242
#: src/components/dms/AfterReportDialog.tsx:142
@@ -3449,7 +3449,7 @@ msgstr ""
msgid "Enter the username or email address you used when you created your account"
msgstr ""
-#: src/components/dialogs/BirthDateSettings.tsx:150
+#: src/components/dialogs/BirthDateSettings.tsx:163
msgid "Enter your birthdate"
msgstr ""
@@ -4209,7 +4209,7 @@ msgstr ""
msgid "Food"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:125
+#: src/ageAssurance/components/NoAccessScreen.tsx:90
msgid "For organizational accounts, use the birthdate of the person who is responsible for the account."
msgstr ""
@@ -4556,11 +4556,11 @@ msgstr ""
msgid "Hey there 👋"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:167
+#: src/ageAssurance/components/NoAccessScreen.tsx:170
msgid "Hey there!"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:202
+#: src/ageAssurance/components/NoAccessScreen.tsx:201
msgid "Hi there!"
msgstr ""
@@ -4660,7 +4660,7 @@ msgstr ""
msgid "Hides the content"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:229
+#: src/components/dialogs/BirthDateSettings.tsx:74
msgid "Hmm, it looks like you're logged in with an <0>App Password0>. To set your birthdate, you'll need to log in with your main account password, or ask whomever controls this account to do so."
msgstr ""
@@ -4765,11 +4765,11 @@ msgstr ""
msgid "If you are not yet an adult according to the laws of your country, your parent or legal guardian must read these Terms on your behalf."
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:110
+#: src/ageAssurance/components/NoAccessScreen.tsx:122
msgid "If you believe your birthdate is incorrect, please <0>contact our support team0>."
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:94
+#: src/ageAssurance/components/NoAccessScreen.tsx:100
msgid "If you believe your birthdate is incorrect, you can update it by <0>clicking here0>."
msgstr ""
@@ -4853,7 +4853,7 @@ msgstr ""
msgid "Import contacts to find your friends"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:205
+#: src/ageAssurance/components/NoAccessScreen.tsx:204
msgid "In order to provide an age-appropriate experience, we need to know your birthdate. This is a one-time thing, and your data will be kept private."
msgstr ""
@@ -4998,7 +4998,7 @@ msgstr ""
msgid "Invites, but personal"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:368
+#: src/ageAssurance/components/NoAccessScreen.tsx:356
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:84
msgid "Is your location not accurate? <0>Tap here to confirm your location.0>"
msgstr ""
@@ -5095,12 +5095,12 @@ msgstr ""
msgid "Larger"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:351
+#: src/ageAssurance/components/NoAccessScreen.tsx:339
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:185
msgid "Last initiated {timeAgo} ago"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:349
+#: src/ageAssurance/components/NoAccessScreen.tsx:337
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:183
msgid "Last initiated just now"
msgstr ""
@@ -5825,8 +5825,8 @@ msgstr ""
msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
msgstr ""
-#: src/components/dialogs/BirthDateSettings.tsx:43
#: src/components/dialogs/BirthDateSettings.tsx:47
+#: src/components/dialogs/BirthDateSettings.tsx:51
msgid "My Birthdate"
msgstr ""
@@ -7935,7 +7935,7 @@ msgstr ""
msgid "Returns to the previous step"
msgstr ""
-#: src/components/dialogs/BirthDateSettings.tsx:190
+#: src/components/dialogs/BirthDateSettings.tsx:203
#: src/components/dialogs/lists/CreateOrEditListDialog.tsx:292
#: src/components/dialogs/lists/CreateOrEditListDialog.tsx:307
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:662
@@ -7961,7 +7961,7 @@ msgctxt "action"
msgid "Save"
msgstr ""
-#: src/components/dialogs/BirthDateSettings.tsx:183
+#: src/components/dialogs/BirthDateSettings.tsx:196
msgid "Save birthdate"
msgstr ""
@@ -8440,7 +8440,7 @@ msgstr ""
msgid "Set who can reply to your post"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:212
+#: src/ageAssurance/components/NoAccessScreen.tsx:211
msgid "Set your birthdate below and we'll get you back to posting and exploring in no time!"
msgstr ""
@@ -8899,8 +8899,8 @@ msgstr ""
msgid "Sorry, we're unable to load account suggestions at this time."
msgstr ""
-#: src/App.native.tsx:127
-#: src/App.web.tsx:100
+#: src/App.native.tsx:126
+#: src/App.web.tsx:99
msgid "Sorry! Your session expired. Please sign in again."
msgstr ""
@@ -9212,7 +9212,7 @@ msgstr ""
msgid "Terms"
msgstr ""
-#: src/components/dialogs/BirthDateSettings.tsx:169
+#: src/components/dialogs/BirthDateSettings.tsx:182
#: src/components/PolicyUpdateOverlay/updates/202508/index.tsx:30
#: src/components/PolicyUpdateOverlay/updates/202508/index.tsx:97
#: src/Navigation.tsx:338
@@ -9241,7 +9241,7 @@ msgstr ""
msgid "Thanks, you have successfully verified your email address. You can close this dialog."
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:397
+#: src/ageAssurance/components/NoAccessScreen.tsx:385
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:113
msgid "Thanks! You're all set."
msgstr ""
@@ -9287,7 +9287,7 @@ msgstr ""
msgid "The author of this thread has hidden this reply."
msgstr ""
-#: src/components/dialogs/BirthDateSettings.tsx:156
+#: src/components/dialogs/BirthDateSettings.tsx:169
msgid "The birthdate you've entered means you are under 18 years old. Certain content and features may be unavailable to you."
msgstr ""
@@ -9383,7 +9383,7 @@ msgstr ""
msgid "Theme"
msgstr ""
-#: src/components/dialogs/BirthDateSettings.tsx:91
+#: src/components/dialogs/BirthDateSettings.tsx:104
msgid "There is a limit to how often you can change your birthdate. You may need to wait a day or two before updating it again."
msgstr ""
@@ -9607,7 +9607,7 @@ msgstr ""
msgid "This handle is reserved. Please try a different one."
msgstr ""
-#: src/components/dialogs/BirthDateSettings.tsx:51
+#: src/components/dialogs/BirthDateSettings.tsx:55
msgid "This information is private and not shared with other users."
msgstr ""
@@ -9785,7 +9785,7 @@ msgstr ""
msgid "To disable your email 2FA method, please verify your access to <0>{0}0>"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:245
+#: src/ageAssurance/components/NoAccessScreen.tsx:233
msgid "To log out, <0>click here0>."
msgstr ""
@@ -10000,7 +10000,7 @@ msgstr ""
msgid "Unfortunately, none of your subscribed labelers supports this report type."
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:187
+#: src/ageAssurance/components/NoAccessScreen.tsx:188
msgid "Unfortunately, the birthdate you have saved to your profile makes you too young to access Bluesky."
msgstr ""
@@ -10361,7 +10361,7 @@ msgstr ""
msgid "Verify account"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:334
+#: src/ageAssurance/components/NoAccessScreen.tsx:322
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:168
msgid "Verify again"
msgstr ""
@@ -10388,8 +10388,8 @@ msgstr ""
msgid "Verify email dialog"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:322
-#: src/ageAssurance/components/NoAccessScreen.tsx:336
+#: src/ageAssurance/components/NoAccessScreen.tsx:310
+#: src/ageAssurance/components/NoAccessScreen.tsx:324
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:156
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:170
msgid "Verify now"
@@ -10728,7 +10728,7 @@ msgstr ""
msgid "We were unable to determine if you are allowed to upload videos. Please try again."
msgstr ""
-#: src/components/dialogs/BirthDateSettings.tsx:63
+#: src/components/dialogs/BirthDateSettings.tsx:67
msgid "We were unable to load your birthdate preferences. Please try again."
msgstr ""
@@ -10787,7 +10787,7 @@ msgstr ""
msgid "We're so excited to have you join us!"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:390
+#: src/ageAssurance/components/NoAccessScreen.tsx:378
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:106
msgid "We're sorry, but based on your device's location, you are currently located in a region that requires age assurance."
msgstr ""
@@ -10995,7 +10995,7 @@ msgstr ""
msgid "You are a trusted verifier"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:170
+#: src/ageAssurance/components/NoAccessScreen.tsx:173
msgid "You are accessing Bluesky from a region that legally requires us to verify your age before allowing you to access the app."
msgstr ""
@@ -11003,7 +11003,7 @@ msgstr ""
msgid "You are creating an account on"
msgstr ""
-#: src/ageAssurance/components/NoAccessScreen.tsx:304
+#: src/ageAssurance/components/NoAccessScreen.tsx:292
#: src/components/ageAssurance/AgeAssuranceAccountCard.tsx:126
msgid "You are currently unable to access Bluesky's Age Assurance flow. Please <0>contact our moderation team0> if you believe this is an error."
msgstr ""
@@ -11262,7 +11262,7 @@ msgstr ""
msgid "You must be 13 years of age or older to create an account."
msgstr ""
-#: src/components/dialogs/BirthDateSettings.tsx:165
+#: src/components/dialogs/BirthDateSettings.tsx:178
msgid "You must be at least 13 years old to use Bluesky. Read our <0>Terms of Service0> for more information."
msgstr ""
@@ -11307,8 +11307,8 @@ msgstr ""
msgid "You reacted {0} to {1}"
msgstr ""
-#: src/components/dialogs/BirthDateSettings.tsx:77
-#: src/components/dialogs/BirthDateSettings.tsx:87
+#: src/components/dialogs/BirthDateSettings.tsx:90
+#: src/components/dialogs/BirthDateSettings.tsx:100
msgid "You recently changed your birthdate"
msgstr ""
--
2.51.2
From 699fdbac018c134a7eae974f03f200555d69f321 Mon Sep 17 00:00:00 2001
From: hailey
Date: Mon, 22 Dec 2025 19:21:17 -0800
Subject: [PATCH 13/13] update actions (#9586)
* update actions
* update actions
* $
* procenv
---
.github/workflows/build-submit-android.yml | 8 +++++--
.github/workflows/build-submit-ios.yml | 8 +++++--
.../workflows/bundle-deploy-eas-update.yml | 21 +++++++++++++------
.github/workflows/pull-request-comment.yml | 10 ++++++---
.github/workflows/pull-request-commit.yml | 15 +++++++++----
.github/workflows/verify-yarn-lock.yml | 8 +++++--
6 files changed, 51 insertions(+), 19 deletions(-)
diff --git a/.github/workflows/build-submit-android.yml b/.github/workflows/build-submit-android.yml
index 595cfa74d..e76eacbc2 100644
--- a/.github/workflows/build-submit-android.yml
+++ b/.github/workflows/build-submit-android.yml
@@ -79,13 +79,15 @@ jobs:
echo "$json" > google-services.json
- name: 🏗️ EAS Build
+ env:
+ PROFILE: ${{ inputs.profile || 'testflight-android' }}
run: >
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_RELEASE=${{ steps.env.outputs.EXPO_PUBLIC_RELEASE_VERSION }}
SENTRY_DIST=${{ steps.env.outputs.EXPO_PUBLIC_BUNDLE_IDENTIFIER }}
yarn use-build-number-with-bump
eas build -p android
- --profile ${{ inputs.profile || 'testflight-android' }}
+ --profile $PROFILE
--local --output build.aab --non-interactive
- name: ✍️ Rename Testflight bundle
@@ -194,4 +196,6 @@ jobs:
- name: ✏️ Write commit hash to cache
if: ${{ inputs.profile == 'testflight-android' }}
- run: echo ${{ github.sha }} > most-recent-testflight-commit.txt
+ env:
+ GITHUB_SHA: ${{ github.sha }}
+ run: echo $GITHUB_SHA > most-recent-testflight-commit.txt
diff --git a/.github/workflows/build-submit-ios.yml b/.github/workflows/build-submit-ios.yml
index 24eba2489..391f95131 100644
--- a/.github/workflows/build-submit-ios.yml
+++ b/.github/workflows/build-submit-ios.yml
@@ -91,13 +91,15 @@ jobs:
echo "${{ secrets.GOOGLE_SERVICES_TOKEN }}" > google-services.json
- name: 🏗️ EAS Build
+ env:
+ PROFILE: ${{ inputs.profile || 'testflight' }}
run: >
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_RELEASE=${{ steps.env.outputs.EXPO_PUBLIC_RELEASE_VERSION }}
SENTRY_DIST=${{ steps.env.outputs.EXPO_PUBLIC_BUNDLE_IDENTIFIER }}
yarn use-build-number-with-bump
eas build -p ios
- --profile ${{ inputs.profile || 'testflight' }}
+ --profile $PROFILE
--local --output build.tar.gz --non-interactive
- name: 📂 Extract build artifact
@@ -147,5 +149,7 @@ jobs:
key: most-recent-testflight-commit
- name: ✏️ Write commit hash to cache
+ env:
+ GITHUB_SHA: ${{ github.sha }}
if: ${{ inputs.profile == 'testflight' }}
- run: echo ${{ github.sha }} > most-recent-testflight-commit.txt
+ run: echo $GITHUB_SHA > most-recent-testflight-commit.txt
diff --git a/.github/workflows/bundle-deploy-eas-update.yml b/.github/workflows/bundle-deploy-eas-update.yml
index 3204c7bb8..af629dd55 100644
--- a/.github/workflows/bundle-deploy-eas-update.yml
+++ b/.github/workflows/bundle-deploy-eas-update.yml
@@ -39,10 +39,12 @@ jobs:
# Validate the version if one is supplied. This should generally happen if the update is for a production client
- name: 🧐 Validate version
+ env:
+ RUNTIME_VERSION: ${{ inputs.runtimeVersion }}
if: ${{ inputs.runtimeVersion }}
run: |
- if [ -z "${{ inputs.runtimeVersion }}" ]; then
- [[ "${{ inputs.runtimeVersion }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && echo "Version is valid" || exit 1
+ if [ -z "$RUNTIME_VERSION" ]; then
+ [[ "$RUNTIME_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && echo "Version is valid" || exit 1
fi
- name: ⬇️ Checkout
@@ -103,12 +105,15 @@ jobs:
# eas.json not used here, set EXPO_PUBLIC_ENV
- name: Env
+ env:
+ CHANNEL: ${{ inputs.channel || 'testflight' }}
+ GITHUB_SHA: ${{ github.sha }}
id: env
if: ${{ !steps.fingerprint.outputs.includes-changes }}
run: |
export json='${{ secrets.GOOGLE_SERVICES_TOKEN }}'
echo "${{ secrets.ENV_TOKEN }}" > .env
- echo "EXPO_PUBLIC_ENV=${{ inputs.channel || 'testflight' }}" >> .env
+ echo "EXPO_PUBLIC_ENV=$CHANNEL" >> .env
echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> .env
echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> .env
@@ -145,7 +150,7 @@ jobs:
- name: ✏️ Write commit hash to cache
if: ${{ !steps.fingerprint.outputs.includes-changes }}
- run: echo ${{ github.sha }} > most-recent-testflight-commit.txt
+ run: echo $GITHUB_SHA > most-recent-testflight-commit.txt
# GitHub actions are horrible so let's just copy paste this in
buildIfNecessaryIOS:
@@ -249,7 +254,9 @@ jobs:
- name: ✏️ Write commit hash to cache
if: ${{ inputs.channel == 'testflight' }}
- run: echo ${{ github.sha }} > most-recent-testflight-commit.txt
+ env:
+ GITHUB_SHA: ${{ github.sha }}
+ run: echo $GITHUB_SHA > most-recent-testflight-commit.txt
buildIfNecessaryAndroid:
name: Build and Submit Android
@@ -363,5 +370,7 @@ jobs:
key: most-recent-testflight-commit
- name: ✏️ Write commit hash to cache
+ env:
+ GITHUB_SHA: ${{ github.sha }}
if: ${{ inputs.channel != 'testflight' && inputs.channel != 'production' }}
- run: echo ${{ github.sha }} > most-recent-testflight-commit.txt
+ run: echo $GITHUB_SHA > most-recent-testflight-commit.txt
diff --git a/.github/workflows/pull-request-comment.yml b/.github/workflows/pull-request-comment.yml
index 9fde88ad3..5668854f0 100644
--- a/.github/workflows/pull-request-comment.yml
+++ b/.github/workflows/pull-request-comment.yml
@@ -32,7 +32,7 @@ jobs:
fi
- if [[ "${{ github.event.comment.body }}" == *"ota"* ]]; then
+ if [[ "$COMMENT" == *"ota"* ]]; then
has_ota=true
else
has_ota=false
@@ -75,6 +75,8 @@ jobs:
steps:
- name: Get PR HEAD SHA
+ env:
+ ISSUE_NUMBER: ${{ github.event.issue.number }}
id: pr-info
uses: actions/github-script@v7
with:
@@ -82,7 +84,7 @@ jobs:
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
- pull_number: ${{ github.event.issue.number }}
+ pull_number: process.env.ISSUE_NUMBER,
});
console.log(`PR HEAD SHA: ${pr.data.head.sha}`);
@@ -184,13 +186,15 @@ jobs:
- name: 💬 Drop a comment
uses: marocchino/sticky-pull-request-comment@v2
+ env:
+ ISSUE_NUMBER: ${{ github.event.issue.number }}
with:
header: pull-request-eas-build-${{ steps.pr-info.outputs.head-sha }}
number: ${{ github.event.issue.number }}
message: |
Your requested OTA deployment was successful! You may now apply it by either scanning the QR code or opening the deep link below in your browser:
-
+
`bluesky://intent/apply-ota?channel=pull-request-${{ github.event.issue.number }}`
---
diff --git a/.github/workflows/pull-request-commit.yml b/.github/workflows/pull-request-commit.yml
index bca92d470..6e575148e 100644
--- a/.github/workflows/pull-request-commit.yml
+++ b/.github/workflows/pull-request-commit.yml
@@ -35,20 +35,27 @@ jobs:
cache: yarn
- name: Ensure tracking relevant branches and checkout base
+ env:
+ HEAD_REF: ${{ github.head_ref }}
+ BASE_REF: ${{ github.base_ref }}
run: |
- git checkout ${{ github.head_ref }}
- git checkout ${{ github.base_ref }}
+ git checkout $HEAD_REF
+ git checkout $BASE_REF
- name: Get the base commit
id: base-commit
- run: echo base-commit=$(git log -n 1 ${{ github.base_ref }} --pretty=format:'%H') >> "$GITHUB_OUTPUT"
+ env:
+ BASE_REF: ${{ github.base_ref }}
+ run: echo base-commit=$(git log -n 1 $BASE_REF --pretty=format:'%H') >> "$GITHUB_OUTPUT"
- name: Merge PR commit
+ env:
+ HEAD_REF: ${{ github.head_ref }}
run: |
# Have to set a git config for the merge to work
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"
- git merge --no-edit ${{ github.head_ref }}
+ git merge --no-edit $HEAD_REF
yarn install
yarn intl:build
diff --git a/.github/workflows/verify-yarn-lock.yml b/.github/workflows/verify-yarn-lock.yml
index afa554c59..6eadf7be7 100644
--- a/.github/workflows/verify-yarn-lock.yml
+++ b/.github/workflows/verify-yarn-lock.yml
@@ -17,7 +17,9 @@ jobs:
fetch-depth: 0
- name: Fetch base branch
- run: git fetch origin ${{ github.base_ref }} --depth=1
+ env:
+ BASE_REF: ${{ github.base_ref }}
+ run: git fetch origin $BASE_REF --depth=1
- name: Install node
uses: actions/setup-node@v6
@@ -25,7 +27,9 @@ jobs:
node-version-file: .nvmrc
- name: Reset yarn.lock to base
- run: git show "origin/${{ github.base_ref }}:yarn.lock" > yarn.lock
+ env:
+ BASE_REF: ${{ github.base_ref }}
+ run: git show "origin/$BASE_REF:yarn.lock" > yarn.lock
- name: Yarn install
uses: Wandalen/wretry.action@master