diff --git a/web-player/src/lib/components/ui/media/FollowButton.svelte b/web-player/src/lib/components/ui/media/FollowButton.svelte new file mode 100644 index 0000000..e477343 --- /dev/null +++ b/web-player/src/lib/components/ui/media/FollowButton.svelte @@ -0,0 +1,44 @@ + + +
diff --git a/web-player/src/lib/server/followActions.ts b/web-player/src/lib/server/followActions.ts new file mode 100644 index 0000000..9a7e8df --- /dev/null +++ b/web-player/src/lib/server/followActions.ts @@ -0,0 +1,28 @@ +import { fail, type RequestEvent } from '@sveltejs/kit'; +import { createApiClient, requireAccessTokenAction } from '$lib/server/api'; + +async function setFollowing({ request, params, locals, fetch }: RequestEvent, follow: boolean) { + const accessToken = requireAccessTokenAction(locals); + if (typeof accessToken !== 'string') return accessToken; + + const form = await request.formData(); + const id = String(form.get('userId') ?? '') || String(params.id ?? ''); + if (!id) return fail(400, { message: 'Falta el usuario.' }); + + const api = createApiClient({ fetch, accessToken }); + const options = { params: { path: { id } } }; + const { error } = follow + ? await api.POST('/users/{id}/follow', options) + : await api.DELETE('/users/{id}/follow', options); + + if (error) { + return fail(502, { + message: follow ? 'No se pudo seguir al usuario.' : 'No se pudo dejar de seguir al usuario.' + }); + } + + return { following: follow, userId: id }; +} + +export const followUserAction = (event: RequestEvent) => setFollowing(event, true); +export const unfollowUserAction = (event: RequestEvent) => setFollowing(event, false); diff --git a/web-player/src/routes/(app)/explore/+page.server.ts b/web-player/src/routes/(app)/explore/+page.server.ts index 51f7f37..227e316 100644 --- a/web-player/src/routes/(app)/explore/+page.server.ts +++ b/web-player/src/routes/(app)/explore/+page.server.ts @@ -1,6 +1,7 @@ import type { PageServerLoad, Actions } from './$types'; import { createApiClient, unwrapOrError } from '$lib/server/api'; import { addAlbumToPlaylistAction, addTrackAction } from '$lib/server/playlistActions'; +import { followUserAction, unfollowUserAction } from '$lib/server/followActions'; import { EXPLORE_ALBUMS_PAGE_SIZE, EXPLORE_PAGE_SIZE as PAGE_SIZE, @@ -45,16 +46,38 @@ export const load: PageServerLoad = async ({ url, locals, fetch }) => { const tracks = unwrapOrError(tracksRes, 'No se pudieron cargar las canciones.'); + const userItems = usersRes?.data?.items ?? []; + const followedIds = user + ? await Promise.all( + userItems + .filter((u) => u.id !== user.sub) + .map((u) => + api + .GET('/users/{id}/is-following', { params: { path: { id: u.id } } }) + .then((res) => (res.data ? u.id : null)) + .catch(() => null) + ) + ) + : []; + const followed = new Set(followedIds); + return { query, tracks, albums: (albumsRes?.data?.items ?? []).map((item) => item.album), - users: usersRes?.data?.items ?? [], + users: userItems.map((u) => ({ + ...u, + isSelf: user?.sub === u.id, + isFollowing: followed.has(u.id) + })), + canFollow: !!user, playlists: playlistsRes?.data?.items ?? [] }; }; export const actions: Actions = { addTrack: addTrackAction, - addAlbumToPlaylist: addAlbumToPlaylistAction + addAlbumToPlaylist: addAlbumToPlaylistAction, + follow: followUserAction, + unfollow: unfollowUserAction }; diff --git a/web-player/src/routes/(app)/explore/+page.svelte b/web-player/src/routes/(app)/explore/+page.svelte index 4d90242..28de335 100644 --- a/web-player/src/routes/(app)/explore/+page.svelte +++ b/web-player/src/routes/(app)/explore/+page.svelte @@ -10,6 +10,7 @@ import InfiniteScroll from '$lib/components/ui/primitives/InfiniteScroll.svelte'; import Artwork from '$lib/components/ui/media/Artwork.svelte'; import Avatar from '$lib/components/ui/media/Avatar.svelte'; + import FollowButton from '$lib/components/ui/media/FollowButton.svelte'; import PlayButton from '$lib/components/ui/media/PlayButton.svelte'; import EqBars from '$lib/components/ui/media/EqBars.svelte'; import ListRow from '$lib/components/ui/media/ListRow.svelte'; @@ -400,12 +401,15 @@