remove final usage of old modal, delete it

This commit is contained in:
Samuel Newman
2025-04-17 18:29:38 +03:00
parent e5de53f33d
commit 14e11991ba
5 changed files with 75 additions and 370 deletions
-10
View File
@@ -10,15 +10,6 @@ export interface CreateOrEditListModal {
onSave?: (uri: string) => void
}
export interface UserAddRemoveListsModal {
name: 'user-add-remove-lists'
subject: string
handle: string
displayName: string
onAdd?: (listUri: string) => void
onRemove?: (listUri: string) => void
}
export interface DeleteAccountModal {
name: 'delete-account'
}
@@ -54,7 +45,6 @@ export type Modal =
// Lists
| CreateOrEditListModal
| UserAddRemoveListsModal
// Bluesky access
| WaitlistModal
+75 -55
View File
@@ -1,12 +1,11 @@
import React, {useCallback} from 'react'
import {Dimensions, type StyleProp, View, type ViewStyle} from 'react-native'
import {type AppBskyGraphDefs} from '@atproto/api'
import {type AppBskyGraphDefs, type ModerationOpts} from '@atproto/api'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {cleanError} from '#/lib/strings/errors'
import {logger} from '#/logger'
import {useModalControls} from '#/state/modals'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {useListMembersQuery} from '#/state/queries/list-members'
import {useSession} from '#/state/session'
@@ -16,6 +15,8 @@ import {ProfileCardFeedLoadingPlaceholder} from '#/view/com/util/LoadingPlacehol
import {LoadMoreRetryBtn} from '#/view/com/util/LoadMoreRetryBtn'
import {atoms as a, useTheme} from '#/alf'
import {Button, ButtonText} from '#/components/Button'
import {useDialogControl} from '#/components/Dialog'
import {UserAddRemoveListsDialog} from '#/components/dialogs/lists/UserAddRemoveListsDialog'
import {ListFooter} from '#/components/Lists'
import * as ProfileCard from '#/components/ProfileCard'
import type * as bsky from '#/types/bsky'
@@ -48,10 +49,8 @@ export function ListMembers({
headerOffset?: number
desktopFixedHeightOffset?: number
}) {
const t = useTheme()
const {_} = useLingui()
const [isRefreshing, setIsRefreshing] = React.useState(false)
const {openModal} = useModalControls()
const {currentAccount} = useSession()
const moderationOpts = useModerationOpts()
@@ -118,18 +117,6 @@ export function ListMembers({
fetchNextPage()
}, [fetchNextPage])
const onPressEditMembership = React.useCallback(
(profile: bsky.profile.AnyProfileView) => {
openModal({
name: 'user-add-remove-lists',
subject: profile.did,
displayName: profile.displayName || profile.handle,
handle: profile.handle,
})
},
[openModal],
)
// rendering
// =
@@ -161,43 +148,12 @@ export function ListMembers({
if (!moderationOpts) return null
return (
<View
style={[a.py_md, a.px_xl, a.border_t, t.atoms.border_contrast_low]}>
<ProfileCard.Link profile={profile}>
<ProfileCard.Outer>
<ProfileCard.Header>
<ProfileCard.Avatar
profile={profile}
moderationOpts={moderationOpts}
/>
<ProfileCard.NameAndHandle
profile={profile}
moderationOpts={moderationOpts}
/>
{isOwner && (
<Button
testID={`user-${profile.handle}-editBtn`}
label={_(msg({message: 'Edit', context: 'action'}))}
onPress={() => onPressEditMembership(profile)}
size="small"
variant="solid"
color="secondary">
<ButtonText>
<Trans context="action">Edit</Trans>
</ButtonText>
</Button>
)}
</ProfileCard.Header>
<ProfileCard.Labels
profile={profile}
moderationOpts={moderationOpts}
/>
<ProfileCard.Description profile={profile} />
</ProfileCard.Outer>
</ProfileCard.Link>
</View>
<ListMember
profile={profile}
moderationOpts={moderationOpts}
isOwner={isOwner}
list={list}
/>
)
},
[
@@ -207,9 +163,8 @@ export function ListMembers({
onPressRetryLoadMore,
moderationOpts,
isOwner,
onPressEditMembership,
_,
t,
list,
],
)
@@ -258,3 +213,68 @@ export function ListMembers({
</View>
)
}
function ListMember({
profile,
moderationOpts,
isOwner,
list,
}: {
profile: bsky.profile.AnyProfileView
moderationOpts: ModerationOpts
isOwner?: boolean
list: string
}) {
const t = useTheme()
const {_} = useLingui()
const editMembershipDialogControl = useDialogControl()
return (
<View style={[a.py_md, a.px_xl, a.border_t, t.atoms.border_contrast_low]}>
<ProfileCard.Link profile={profile}>
<ProfileCard.Outer>
<ProfileCard.Header>
<ProfileCard.Avatar
profile={profile}
moderationOpts={moderationOpts}
/>
<ProfileCard.NameAndHandle
profile={profile}
moderationOpts={moderationOpts}
/>
{isOwner && (
<Button
testID={`user-${profile.handle}-editBtn`}
label={_(msg({message: 'Edit', context: 'action'}))}
onPress={editMembershipDialogControl.open}
size="small"
variant="solid"
color="secondary">
<ButtonText>
<Trans context="action">Edit</Trans>
</ButtonText>
</Button>
)}
</ProfileCard.Header>
<ProfileCard.Labels
profile={profile}
moderationOpts={moderationOpts}
/>
<ProfileCard.Description profile={profile} />
</ProfileCard.Outer>
</ProfileCard.Link>
<UserAddRemoveListsDialog
control={editMembershipDialogControl}
profile={profile}
onChange={(type, {uri}) => {
if (type === 'remove' && uri === list) {
editMembershipDialogControl.close()
}
}}
/>
</View>
)
}
-4
View File
@@ -13,7 +13,6 @@ import * as DeleteAccountModal from './DeleteAccount'
import * as InviteCodesModal from './InviteCodes'
import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguagesSettings'
import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings'
import * as UserAddRemoveListsModal from './UserAddRemoveLists'
const DEFAULT_SNAPPOINTS = ['90%']
const HANDLE_HEIGHT = 24
@@ -49,9 +48,6 @@ export function ModalsContainer() {
if (activeModal?.name === 'create-or-edit-list') {
snapPoints = CreateOrEditListModal.snapPoints
element = <CreateOrEditListModal.Component {...activeModal} />
} else if (activeModal?.name === 'user-add-remove-lists') {
snapPoints = UserAddRemoveListsModal.snapPoints
element = <UserAddRemoveListsModal.Component {...activeModal} />
} else if (activeModal?.name === 'delete-account') {
snapPoints = DeleteAccountModal.snapPoints
element = <DeleteAccountModal.Component />
-3
View File
@@ -12,7 +12,6 @@ import * as DeleteAccountModal from './DeleteAccount'
import * as InviteCodesModal from './InviteCodes'
import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguagesSettings'
import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings'
import * as UserAddRemoveLists from './UserAddRemoveLists'
export function ModalsContainer() {
const {isModalActive, activeModals} = useModals()
@@ -52,8 +51,6 @@ function Modal({modal}: {modal: ModalIface}) {
let element
if (modal.name === 'create-or-edit-list') {
element = <CreateOrEditListModal.Component {...modal} />
} else if (modal.name === 'user-add-remove-lists') {
element = <UserAddRemoveLists.Component {...modal} />
} else if (modal.name === 'delete-account') {
element = <DeleteAccountModal.Component />
} else if (modal.name === 'invite-codes') {
-298
View File
@@ -1,298 +0,0 @@
import React, {useCallback} from 'react'
import {
ActivityIndicator,
StyleSheet,
useWindowDimensions,
View,
} from 'react-native'
import {AppBskyGraphDefs as GraphDefs} from '@atproto/api'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {usePalette} from '#/lib/hooks/usePalette'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {cleanError} from '#/lib/strings/errors'
import {sanitizeHandle} from '#/lib/strings/handles'
import {s} from '#/lib/styles'
import {isAndroid, isMobileWeb, isWeb} from '#/platform/detection'
import {useModalControls} from '#/state/modals'
import {
getMembership,
ListMembersip,
useDangerousListMembershipsQuery,
useListMembershipAddMutation,
useListMembershipRemoveMutation,
} from '#/state/queries/list-memberships'
import {useSession} from '#/state/session'
import {MyLists} from '../lists/MyLists'
import {Button} from '../util/forms/Button'
import {Text} from '../util/text/Text'
import * as Toast from '../util/Toast'
import {UserAvatar} from '../util/UserAvatar'
export const snapPoints = ['fullscreen']
export function Component({
subject,
handle,
displayName,
onAdd,
onRemove,
}: {
subject: string
handle: string
displayName: string
onAdd?: (listUri: string) => void
onRemove?: (listUri: string) => void
}) {
const {closeModal} = useModalControls()
const pal = usePalette('default')
const {height: screenHeight} = useWindowDimensions()
const {_} = useLingui()
const {data: memberships} = useDangerousListMembershipsQuery()
const onPressDone = useCallback(() => {
closeModal()
}, [closeModal])
const listStyle = React.useMemo(() => {
if (isMobileWeb) {
return [pal.border, {height: screenHeight / 2}]
} else if (isWeb) {
return [pal.border, {height: screenHeight / 1.5}]
}
return [pal.border, {flex: 1, borderTopWidth: StyleSheet.hairlineWidth}]
}, [pal.border, screenHeight])
const headerStyles = [
{
textAlign: 'center',
fontWeight: '600',
fontSize: 20,
marginBottom: 12,
paddingHorizontal: 12,
} as const,
pal.text,
]
return (
<View testID="userAddRemoveListsModal" style={s.hContentRegion}>
<Text style={headerStyles} numberOfLines={1}>
<Trans>
Update{' '}
<Text style={headerStyles} numberOfLines={1}>
{displayName}
</Text>{' '}
in Lists
</Trans>
</Text>
<MyLists
filter="all"
inline
renderItem={(list, index) => (
<ListItem
key={list.uri}
index={index}
list={list}
memberships={memberships}
subject={subject}
handle={handle}
onAdd={onAdd}
onRemove={onRemove}
/>
)}
style={listStyle}
/>
<View style={[styles.btns, pal.border]}>
<Button
testID="doneBtn"
type="default"
onPress={onPressDone}
style={styles.footerBtn}
accessibilityLabel={_(msg({message: `Done`, context: 'action'}))}
accessibilityHint=""
onAccessibilityEscape={onPressDone}
label={_(msg({message: `Done`, context: 'action'}))}
/>
</View>
</View>
)
}
function ListItem({
index,
list,
memberships,
subject,
handle,
onAdd,
onRemove,
}: {
index: number
list: GraphDefs.ListView
memberships: ListMembersip[] | undefined
subject: string
handle: string
onAdd?: (listUri: string) => void
onRemove?: (listUri: string) => void
}) {
const pal = usePalette('default')
const {_} = useLingui()
const {currentAccount} = useSession()
const [isProcessing, setIsProcessing] = React.useState(false)
const membership = React.useMemo(
() => getMembership(memberships, list.uri, subject),
[memberships, list.uri, subject],
)
const listMembershipAddMutation = useListMembershipAddMutation()
const listMembershipRemoveMutation = useListMembershipRemoveMutation()
const onToggleMembership = useCallback(async () => {
if (typeof membership === 'undefined') {
return
}
setIsProcessing(true)
try {
if (membership === false) {
await listMembershipAddMutation.mutateAsync({
listUri: list.uri,
actorDid: subject,
})
Toast.show(_(msg`Added to list`))
onAdd?.(list.uri)
} else {
await listMembershipRemoveMutation.mutateAsync({
listUri: list.uri,
actorDid: subject,
membershipUri: membership,
})
Toast.show(_(msg`Removed from list`))
onRemove?.(list.uri)
}
} catch (e) {
Toast.show(cleanError(e), 'xmark')
} finally {
setIsProcessing(false)
}
}, [
_,
list,
subject,
membership,
setIsProcessing,
onAdd,
onRemove,
listMembershipAddMutation,
listMembershipRemoveMutation,
])
return (
<View
testID={`toggleBtn-${list.name}`}
style={[
styles.listItem,
pal.border,
index !== 0 && {borderTopWidth: StyleSheet.hairlineWidth},
]}>
<View style={styles.listItemAvi}>
<UserAvatar size={40} avatar={list.avatar} type="list" />
</View>
<View style={styles.listItemContent}>
<Text
type="lg"
style={[s.bold, pal.text]}
numberOfLines={1}
lineHeight={1.2}>
{sanitizeDisplayName(list.name)}
</Text>
<Text type="md" style={[pal.textLight]} numberOfLines={1}>
{list.purpose === 'app.bsky.graph.defs#curatelist' &&
(list.creator.did === currentAccount?.did ? (
<Trans>User list by you</Trans>
) : (
<Trans>
User list by {sanitizeHandle(list.creator.handle, '@')}
</Trans>
))}
{list.purpose === 'app.bsky.graph.defs#modlist' &&
(list.creator.did === currentAccount?.did ? (
<Trans>Moderation list by you</Trans>
) : (
<Trans>
Moderation list by {sanitizeHandle(list.creator.handle, '@')}
</Trans>
))}
</Text>
</View>
<View>
{isProcessing || typeof membership === 'undefined' ? (
<ActivityIndicator />
) : (
<Button
testID={`user-${handle}-addBtn`}
type="default"
label={membership === false ? _(msg`Add`) : _(msg`Remove`)}
onPress={onToggleMembership}
/>
)}
</View>
</View>
)
}
const styles = StyleSheet.create({
container: {
paddingHorizontal: isWeb ? 0 : 16,
},
btns: {
position: 'relative',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
gap: 10,
paddingTop: 10,
paddingBottom: isAndroid ? 10 : 0,
borderTopWidth: StyleSheet.hairlineWidth,
},
footerBtn: {
paddingHorizontal: 24,
paddingVertical: 12,
},
listItem: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 14,
paddingVertical: 10,
},
listItemAvi: {
width: 54,
paddingLeft: 4,
paddingTop: 8,
paddingBottom: 10,
},
listItemContent: {
flex: 1,
paddingRight: 10,
paddingTop: 10,
paddingBottom: 10,
},
checkbox: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
borderWidth: 1,
width: 24,
height: 24,
borderRadius: 6,
marginRight: 8,
},
loadingContainer: {
position: 'absolute',
top: 10,
right: 0,
bottom: 0,
justifyContent: 'center',
},
})