fullscreen modal, filter out current owner of playlist, callbacks for functionality

This commit is contained in:
arijohn723
2026-03-09 20:32:34 -05:00
parent fdb3787c98
commit f07b5ff64f
4 changed files with 88 additions and 15 deletions

View File

@@ -8,10 +8,15 @@ import { useInfiniteQuery, useMutation, useQuery } from '@tanstack/react-query'
import { fetchUserPlaylists, fetchPublicPlaylists, fetchPlaylistTracks } from './utils'
import { ApiLimits } from '../../../configs/query.config'
import { getApi, getUser, useJellifyLibrary } from '../../../stores'
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client'
import { BaseItemDto, PlaylistUserPermissions, UserDto } from '@jellyfin/sdk/lib/generated-client'
import { QueryKeys } from '../../../enums/query-keys'
import { addPlaylistUser, getPlaylistUsers, removePlaylistUser } from './utils/users'
import { ONE_MINUTE } from '../../../constants/query-client'
import { ONE_MINUTE, queryClient } from '../../../constants/query-client'
import { User } from '@sentry/react-native'
import { triggerHaptic } from '@/src/hooks/use-haptic-feedback'
import { previous } from '@/src/hooks/player/functions/controls'
import { userEvent } from '@testing-library/react-native'
import Toast from 'react-native-toast-message'
export const useUserPlaylists = () => {
const api = getApi()
@@ -73,8 +78,8 @@ export const usePlaylistUsers = (playlist: BaseItemDto) => {
}
interface addPlaylistUserMutation {
playlistId: string
userId: string
playlist: BaseItemDto
user: UserDto
CanEdit: boolean
}
@@ -84,18 +89,53 @@ export const useAddPlaylistUser = () => {
return useMutation({
//playlistId: string, userId: string, CanEdit: boolean
mutationFn: (variables: addPlaylistUserMutation) =>
addPlaylistUser(variables.playlistId, variables.userId, variables.CanEdit),
addPlaylistUser(variables.playlist.Id!, variables.user.Id!, variables.CanEdit),
onSuccess: (data, variables) => {
triggerHaptic('notificationSuccess')
queryClient.setQueryData(
PlaylistUsersQueryKey(variables.playlist),
(previous: PlaylistUserPermissions[] | undefined) => {
if (previous == undefined) {
//return
return [{ userId: variables.user.Id, canEdit: true }]
} else {
return [...previous, { userId: variables.user.Id, canEdit: true }]
}
},
)
},
onError: (error, variables) => {
console.log(error)
Toast.show({ type: 'error', text1: 'Unable to add user to playlist.' })
},
})
}
interface removePlaylistUser {
playlistId: string
userId: string
playlist: BaseItemDto
user: UserDto
}
//remove user as playlist collaborator
export const useRemovePlaylistUser = () => {
return useMutation({
mutationFn: (variables: removePlaylistUser) =>
removePlaylistUser(variables.playlistId, variables.userId),
removePlaylistUser(variables.playlist.Id!, variables.user.Id!),
onSuccess: (data, variables) => {
triggerHaptic('notificationSuccess')
queryClient.setQueryData(
PlaylistUsersQueryKey(variables.playlist),
(previous: PlaylistUserPermissions[] | undefined) => {
if (previous == undefined) {
//return
return []
} else {
return previous.filter((user) => user.UserId != variables.user.Id)
}
},
)
},
})
}

View File

@@ -1,6 +1,6 @@
import { useQuery } from '@tanstack/react-query'
import { UserQueryKey } from './keys'
import { getApi } from '../../../stores'
import { getApi, getUser } from '../../../stores'
import { getUserApi } from '@jellyfin/sdk/lib/utils/api'
//hook to get users on server
@@ -14,11 +14,17 @@ const fetchUsers = async () => {
//use api (only get api when this function is called to get users)
const api = getApi()
//get owner of playlist (self)
const owner = getUser()
//check set
if (!api) {
throw new Error('API Instance not set')
}
const usersResponse = await getUserApi(api).getUsers()
//return users where there isn't a user with owner id in array
//return users from api
return (await getUserApi(api).getUsers()).data
return usersResponse.data.filter((user) => user.Id != owner?.id)
}

View File

@@ -1,7 +1,11 @@
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import LibraryStackParamList, { LibraryAddPlaylistUsers } from './types'
import { Paragraph, Text, View, XStack, YStack } from 'tamagui'
import { usePlaylistUsers } from '../../../src/api/queries/playlist'
import {
useAddPlaylistUser,
usePlaylistUsers,
useRemovePlaylistUser,
} from '../../../src/api/queries/playlist'
import { useUsers } from '../../../src/api/queries/users'
import ItemImage from '../../../src/components/Global/components/image'
import TextTicker from 'react-native-text-ticker'
@@ -23,6 +27,12 @@ export default function addPlaylistUsers({
} = usePlaylistUsers(playlist) //make this playlist an easy access variable (with const variable above)
const { data: users, isPending: useUsersIsPending, refetch: refetchUseUsers } = useUsers()
//invoke mutations on icon press
//add
const addUser = useAddPlaylistUser()
//remove
const removeUser = useRemovePlaylistUser()
//get string array of all playlist user IDs
const playlistUserIds = playlistUsers?.map((playlistUser) => playlistUser.UserId) ?? []
@@ -89,10 +99,27 @@ export default function addPlaylistUsers({
imageOptions={{ maxWidth: 85, maxHeight: 85, quality: 90 }}
/>
<Paragraph>{user.Name ?? 'Unknown User'}</Paragraph>
{playlistUserIds.includes(user.Id) ? (
<Icon name='account-remove' color='$warning' />
{playlistUserIds.includes(user.Id) ? ( //send playlist id and user id (with bang! because it likely won't be undefined)
<Icon
onPress={() =>
removeUser.mutate({ playlist: playlist, user: user })
}
name='account-remove'
color='$warning'
/>
) : (
<Icon name='account-plus' color='$borderColor' />
//same stuff and canEdit as true bcs you know anyone you're sharing with
<Icon
onPress={() =>
addUser.mutate({
playlist: playlist,
user: user,
CanEdit: true,
})
}
name='account-plus'
color='$borderColor'
/>
)}
</XStack>
)}

View File

@@ -89,7 +89,7 @@ export default function LibraryScreen(): React.JSX.Element {
options={{
title: 'Add Playlist Users',
presentation: 'formSheet',
sheetAllowedDetents: Platform.OS === 'ios' ? 'fitToContents' : [0.5],
sheetAllowedDetents: Platform.OS === 'ios' ? 'fitToContents' : [1.0], //screen full size
}}
/>