extract resolveAllowGroupInvites helper, fix optimistic cache

Address review feedback: dedupe the allowGroupInvites fallback chain into
a single helper next to canBeAddedToGroup, used by the settings display,
the save path, and onMutate. The optimistic cache now stores the same
resolved value the server receives, so cache and persisted record stay
aligned before the next profile refetch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Samuel Newman
2026-06-05 17:57:54 +03:00
parent 764e84557d
commit aad42020bb
3 changed files with 39 additions and 17 deletions
+16
View File
@@ -47,6 +47,22 @@ export function canBeAddedToGroup(profile: bsky.profile.AnyProfileView) {
}
}
/**
* Resolves the effective `allowGroupInvites` value for a chat declaration.
* When unset, group invites follow the general DM preference
* (`allowIncoming`), which itself defaults to `following`. This mirrors the
* `undefined` fallthrough in canBeAddedToGroup, and is the single source of
* truth for both displaying and persisting the setting.
*/
export function resolveAllowGroupInvites(
chat: {allowIncoming?: string; allowGroupInvites?: string} | undefined,
): 'all' | 'none' | 'following' {
return (chat?.allowGroupInvites ?? chat?.allowIncoming ?? 'following') as
| 'all'
| 'none'
| 'following'
}
export function localDateString(date: Date) {
// can't use toISOString because it should be in local time
const mm = date.getMonth()
+2 -9
View File
@@ -13,6 +13,7 @@ import {AgeRestrictedScreen} from '#/components/ageAssurance/AgeRestrictedScreen
import {useAgeAssuranceCopy} from '#/components/ageAssurance/useAgeAssuranceCopy'
import * as Dialog from '#/components/Dialog'
import {Divider} from '#/components/Divider'
import {resolveAllowGroupInvites} from '#/components/dms/util'
import * as Toggle from '#/components/forms/Toggle'
import {Bell_Stroke2_Corner0_Rounded as BellIcon} from '#/components/icons/Bell'
import {Car_Stroke2_Corner2_Rounded as CarIcon} from '#/components/icons/Car'
@@ -199,15 +200,7 @@ export function MessagesSettingsScreenInner({}: Props) {
<Toggle.Group
label={l`Allow group chat invites from`}
type="radio"
values={[
(profile?.associated?.chat
?.allowGroupInvites as AllowIncoming) ??
// when unset, group invites follow the general DM
// preference (see canBeAddedToGroup)
(profile?.associated?.chat
?.allowIncoming as AllowIncoming) ??
'following',
]}
values={[resolveAllowGroupInvites(profile?.associated?.chat)]}
onChange={onSelectGroupInvitesFrom}>
<View>
{allowGroupInvitesFromOptions.map(option => (
@@ -7,6 +7,7 @@ import {useMutation, useQueryClient} from '@tanstack/react-query'
import {logger} from '#/logger'
import {useAgent, useSession} from '#/state/session'
import {resolveAllowGroupInvites} from '#/components/dms/util'
import {RQKEY as PROFILE_RKEY} from '../profile'
export function useUpdateActorDeclaration({
@@ -34,12 +35,12 @@ export function useUpdateActorDeclaration({
update.allowIncoming ??
current?.associated?.chat?.allowIncoming ??
'following'
const allowGroupInvites =
update.allowGroupInvites ??
current?.associated?.chat?.allowGroupInvites ??
// when unset, group invites follow the general DM preference
// (see canBeAddedToGroup), so mirror that when persisting
allowIncoming
const allowGroupInvites = resolveAllowGroupInvites({
allowIncoming,
allowGroupInvites:
update.allowGroupInvites ??
current?.associated?.chat?.allowGroupInvites,
})
const result = await agent.com.atproto.repo.putRecord({
repo: currentAccount.did,
collection: 'chat.bsky.actor.declaration',
@@ -58,14 +59,26 @@ export function useUpdateActorDeclaration({
PROFILE_RKEY(currentAccount?.did),
(old?: AppBskyActorDefs.ProfileViewDetailed) => {
if (!old) return old
const allowIncoming =
update.allowIncoming ??
old.associated?.chat?.allowIncoming ??
'following'
// resolve the same concrete value the server will receive, so
// optimistic cache and persisted record stay aligned
const allowGroupInvites = resolveAllowGroupInvites({
allowIncoming,
allowGroupInvites:
update.allowGroupInvites ??
old.associated?.chat?.allowGroupInvites,
})
return {
...old,
associated: {
...old.associated,
chat: {
allowIncoming: 'following',
...old.associated?.chat,
...update,
allowIncoming,
allowGroupInvites,
},
},
} satisfies AppBskyActorDefs.ProfileViewDetailed