List cleanup on remove (#1069)
* 💄 Hide Add to List option on own profile * ✨ Remove Lists tab when last list is removed * ✨ Add listener to list delete on profile screen * ✨ Only show save changes in list modal when changes are madezio/stable
parent
38d78e16bf
commit
eec300d772
|
@ -217,6 +217,8 @@ export class ListModel {
|
|||
records.map(record => createDel(record.uri)),
|
||||
),
|
||||
})
|
||||
|
||||
this.rootStore.emitListDeleted(this.uri)
|
||||
}
|
||||
|
||||
async subscribe() {
|
||||
|
|
|
@ -48,9 +48,24 @@ export class ListsListModel {
|
|||
return this.hasLoaded && !this.hasContent
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes posts from the feed upon deletion.
|
||||
*/
|
||||
onListDeleted(uri: string) {
|
||||
this.lists = this.lists.filter(l => l.uri !== uri)
|
||||
}
|
||||
|
||||
// public api
|
||||
// =
|
||||
|
||||
/**
|
||||
* Register any event listeners. Returns a cleanup function.
|
||||
*/
|
||||
registerListeners() {
|
||||
const sub = this.rootStore.onListDeleted(this.onListDeleted.bind(this))
|
||||
return () => sub.remove()
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
return this.loadMore(true)
|
||||
}
|
||||
|
|
|
@ -188,6 +188,14 @@ export class RootStoreModel {
|
|||
DeviceEventEmitter.emit('post-deleted', uri)
|
||||
}
|
||||
|
||||
// a list was deleted by the local user
|
||||
onListDeleted(handler: (uri: string) => void): EmitterSubscription {
|
||||
return DeviceEventEmitter.addListener('list-deleted', handler)
|
||||
}
|
||||
emitListDeleted(uri: string) {
|
||||
DeviceEventEmitter.emit('list-deleted', uri)
|
||||
}
|
||||
|
||||
// the session has started and been fully hydrated
|
||||
onSessionLoaded(handler: () => void): EmitterSubscription {
|
||||
return DeviceEventEmitter.addListener('session-loaded', handler)
|
||||
|
|
|
@ -87,7 +87,10 @@ export class ProfileUiModel {
|
|||
}
|
||||
|
||||
get selectedView() {
|
||||
return this.selectorItems[this.selectedViewIndex]
|
||||
// If, for whatever reason, the selected view index is not available, default back to posts
|
||||
// This can happen when the user was focused on a view but performed an action that caused
|
||||
// the view to disappear (e.g. deleting the last list in their list of lists https://imgflip.com/i/7txu1y)
|
||||
return this.selectorItems[this.selectedViewIndex] || Sections.Posts
|
||||
}
|
||||
|
||||
get uiItems() {
|
||||
|
|
|
@ -20,6 +20,7 @@ import {sanitizeHandle} from 'lib/strings/handles'
|
|||
import {s} from 'lib/styles'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {isDesktopWeb, isAndroid} from 'platform/detection'
|
||||
import isEqual from 'lodash.isequal'
|
||||
|
||||
export const snapPoints = ['fullscreen']
|
||||
|
||||
|
@ -37,6 +38,9 @@ export const Component = observer(
|
|||
const pal = usePalette('default')
|
||||
const palPrimary = usePalette('primary')
|
||||
const palInverted = usePalette('inverted')
|
||||
const [originalSelections, setOriginalSelections] = React.useState<
|
||||
string[]
|
||||
>([])
|
||||
const [selected, setSelected] = React.useState<string[]>([])
|
||||
|
||||
const listsList: ListsListModel = React.useMemo(
|
||||
|
@ -51,7 +55,9 @@ export const Component = observer(
|
|||
listsList.refresh()
|
||||
memberships.fetch().then(
|
||||
() => {
|
||||
setSelected(memberships.memberships.map(m => m.value.list))
|
||||
const ids = memberships.memberships.map(m => m.value.list)
|
||||
setOriginalSelections(ids)
|
||||
setSelected(ids)
|
||||
},
|
||||
err => {
|
||||
store.log.error('Failed to fetch memberships', {err})
|
||||
|
@ -156,6 +162,10 @@ export const Component = observer(
|
|||
)
|
||||
}, [onPressNewMuteList])
|
||||
|
||||
// Only show changes button if there are some items on the list to choose from AND user has made changes in selection
|
||||
const canSaveChanges =
|
||||
!listsList.isEmpty && !isEqual(selected, originalSelections)
|
||||
|
||||
return (
|
||||
<View testID="listAddRemoveUserModal" style={s.hContentRegion}>
|
||||
<Text style={[styles.title, pal.text]}>Add {displayName} to Lists</Text>
|
||||
|
@ -178,16 +188,18 @@ export const Component = observer(
|
|||
onAccessibilityEscape={onPressCancel}
|
||||
label="Cancel"
|
||||
/>
|
||||
<Button
|
||||
testID="saveBtn"
|
||||
type="primary"
|
||||
onPress={onPressSave}
|
||||
style={styles.footerBtn}
|
||||
accessibilityLabel="Save changes"
|
||||
accessibilityHint=""
|
||||
onAccessibilityEscape={onPressSave}
|
||||
label="Save Changes"
|
||||
/>
|
||||
{canSaveChanges && (
|
||||
<Button
|
||||
testID="saveBtn"
|
||||
type="primary"
|
||||
onPress={onPressSave}
|
||||
style={styles.footerBtn}
|
||||
accessibilityLabel="Save changes"
|
||||
accessibilityHint=""
|
||||
onAccessibilityEscape={onPressSave}
|
||||
label="Save Changes"
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
|
|
|
@ -56,6 +56,13 @@ export const ProfileScreen = withAuthRequired(
|
|||
setHasSetup(false)
|
||||
}, [route.params.name])
|
||||
|
||||
// We don't need this to be reactive, so we can just register the listeners once
|
||||
useEffect(() => {
|
||||
const listCleanup = uiState.lists.registerListeners()
|
||||
return () => listCleanup()
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
const softResetSub = store.onScreenSoftReset(onSoftReset)
|
||||
|
@ -126,6 +133,7 @@ export const ProfileScreen = withAuthRequired(
|
|||
/>
|
||||
)
|
||||
}, [uiState, onRefresh, route.params.hideBackButton])
|
||||
|
||||
const Footer = React.useMemo(() => {
|
||||
return uiState.showLoadingMoreFooter ? LoadingMoreFooter : undefined
|
||||
}, [uiState.showLoadingMoreFooter])
|
||||
|
|
Loading…
Reference in New Issue