diff --git a/api/src/routes/artists/[slug]/streams/+server.ts b/api/src/routes/artists/[slug]/streams/+server.ts new file mode 100644 index 0000000..93954b4 --- /dev/null +++ b/api/src/routes/artists/[slug]/streams/+server.ts @@ -0,0 +1,10 @@ +import { handlePostgrestQuery, supabase } from '$lib/server/supabase'; +import { TABLES } from '../../../../../../shared/config'; +import type { StreamLog } from '../../../../../../shared/types/core'; + +export async function GET({ params }) { + return handlePostgrestQuery( + async () => await supabase.from(TABLES.streams).select('*').eq('artist_id', params.slug), + { errorMessage: 'Failed to fetch streams for artist' } + ); +} diff --git a/api/src/routes/artists/[slug]/tracks/+server.ts b/api/src/routes/artists/[slug]/tracks/+server.ts new file mode 100644 index 0000000..e663880 --- /dev/null +++ b/api/src/routes/artists/[slug]/tracks/+server.ts @@ -0,0 +1,10 @@ +import { handlePostgrestQuery, supabase } from '$lib/server/supabase'; +import { TABLES } from '../../../../../../shared/config'; +import type { Track } from '../../../../../../shared/types/core'; + +export async function GET({ params }) { + return handlePostgrestQuery( + async () => await supabase.from(TABLES.tracks).select().eq('artist_id', params.slug), + { errorMessage: 'Failed to fetch tracks for artist' } + ); +} diff --git a/api/src/routes/users/[slug]/artists/+server.ts b/api/src/routes/users/[slug]/artists/+server.ts new file mode 100644 index 0000000..45530b3 --- /dev/null +++ b/api/src/routes/users/[slug]/artists/+server.ts @@ -0,0 +1,37 @@ +import { TABLES } from '../../../../../../shared/config'; +import { supabase } from '$lib/server/supabase'; +import { json } from '@sveltejs/kit'; +import type { ArtistHydrated } from '../../../../../../shared/types/hydrated'; + +export async function GET({ params }) { + const userId = params.slug; + + const { data: relatedArtistsData, error } = await supabase + .from(TABLES.artistMembers) + .select('artist_id') + .eq('user_id', userId); + + if (error) { + console.error('Error fetching user artists:', error); + return json({ error: 'Failed to fetch user artists' }, { status: 500 }); + } + + const { + data: connectedArtists, + error: artistsError + }: { + data: ArtistHydrated[] | null; + error: Error | null; + } = await supabase + .from(TABLES.artistsRich) + .select('*') + .in( + 'id', + relatedArtistsData.map((u) => u.artist_id) + ); + if (artistsError) { + console.error('Error fetching connected artists:', artistsError); + return json({ error: 'Failed to fetch connected artists' }, { status: 500 }); + } + return json(connectedArtists); +} diff --git a/api/src/routes/users/[slug]/collections/+server.ts b/api/src/routes/users/[slug]/collections/+server.ts index 4627f51..63e85bb 100644 --- a/api/src/routes/users/[slug]/collections/+server.ts +++ b/api/src/routes/users/[slug]/collections/+server.ts @@ -1,8 +1,9 @@ import { handlePostgrestQuery, supabase } from '$lib/server/supabase'; import { TABLES } from '../../../../../../shared/config/index'; +import type { CollectionHydrated } from '../../../../../../shared/types/hydrated'; export async function GET({ params }) { - return handlePostgrestQuery( + return handlePostgrestQuery( async () => supabase.from(TABLES.collectionsRich).select('*').eq('user_id', params.slug), { errorMessage: 'Failed to fetch collections' } ); diff --git a/dashboard/src/lib/remote-functions/artist.remote.ts b/dashboard/src/lib/remote-functions/artist.remote.ts index 6573619..e8f4a1a 100644 --- a/dashboard/src/lib/remote-functions/artist.remote.ts +++ b/dashboard/src/lib/remote-functions/artist.remote.ts @@ -1,6 +1,9 @@ import { form, getRequestEvent, query } from '$app/server'; -import { API_BASE, DOMAIN_BASE } from '$lib/config'; +import { API_BASE, DOMAIN_BASE, REQUEST_HEADER_BOILERPLATE } from '$lib/config'; import * as z from 'zod'; +import type { Track } from '../../../../shared/types/core'; +import { sortReleasesByDate } from '../../../../shared/utils'; +import type { ReleaseHydrated } from '../../../../shared/types/hydrated'; const ArtistDetailsForm = z.object({ artistId: z.string(), @@ -34,3 +37,33 @@ export const signOut = query(async () => { await locals.supabase.auth.signOut(); } }); + +export const getArtistReleases = query(z.string(), async (artistId) => { + const response = await fetch(`${API_BASE}/artists/${artistId}/releases`, { + method: 'GET', + headers: REQUEST_HEADER_BOILERPLATE + }); + if (!response.ok) { + throw new Error('Failed to fetch artist releases'); + } + const releases = (await response.json()) as ReleaseHydrated[]; + const releasesSorted = sortReleasesByDate(releases); + return releasesSorted; +}); + +export const getArtistTracks = query(z.string(), async (artistId) => { + const response = await fetch(`${API_BASE}/artists/${artistId}/tracks`, { + method: 'GET', + headers: REQUEST_HEADER_BOILERPLATE + }); + if (!response.ok) { + throw new Error('Failed to fetch artist tracks'); + } + const tracks = (await response.json()) as Track[]; + const tracksSorted = tracks.sort((a, b) => { + if (a.title < b.title) return -1; + if (a.title > b.title) return 1; + return 0; + }); + return tracksSorted; +}); diff --git a/dashboard/src/lib/remote-functions/stats.remote.ts b/dashboard/src/lib/remote-functions/stats.remote.ts new file mode 100644 index 0000000..1b97900 --- /dev/null +++ b/dashboard/src/lib/remote-functions/stats.remote.ts @@ -0,0 +1,14 @@ +import { query } from '$app/server'; +import { API_BASE, REQUEST_HEADER_BOILERPLATE } from '$lib/config'; +import * as z from 'zod'; + +export const getArtistStreams = query(z.string(), async (artistId) => { + const response = await fetch(`${API_BASE}/artists/${artistId}/streams`, { + method: 'GET', + headers: REQUEST_HEADER_BOILERPLATE + }); + if (!response.ok) { + throw new Error('Failed to fetch artist streams'); + } + return response.json(); +}); diff --git a/dashboard/src/routes/+layout.server.ts b/dashboard/src/routes/+layout.server.ts index 8e066de..549d6e7 100644 --- a/dashboard/src/routes/+layout.server.ts +++ b/dashboard/src/routes/+layout.server.ts @@ -1,11 +1,10 @@ import { fail } from '@sveltejs/kit'; import { supabase } from '$lib/server/supabase'; -import type { StreamLog } from '../../../shared/types/core'; -import { sortReleasesByDate } from '../../../shared/utils'; import type { LayoutServerLoad } from './$types'; -import type { Artist, Track } from '../../../shared/types/core'; -import type { ReleaseHydrated } from '../../../shared/types/hydrated'; +import type { Track } from '../../../shared/types/core'; +import type { ArtistHydrated } from '../../../shared/types/hydrated'; import { TABLES } from '../../../shared/config'; +import { API_BASE, REQUEST_HEADER_BOILERPLATE } from '$lib/config'; export const load: LayoutServerLoad = async ({ locals: { safeGetSession }, cookies }) => { const { session, user } = await safeGetSession(); @@ -16,7 +15,6 @@ export const load: LayoutServerLoad = async ({ locals: { safeGetSession }, cooki user, cookies: cookies.getAll(), artists: [], - releases: [], songs: [], streams: [] }; @@ -24,73 +22,10 @@ export const load: LayoutServerLoad = async ({ locals: { safeGetSession }, cooki const userID = session.user.id; - const { - data: userData, - error: userError - }: { - data: { artist_id: string }[] | null; - error: Error | null; - } = await supabase.from(TABLES.artistMembers).select('artist_id').eq('user_id', userID); - - if (userError || !userData) { - console.error('Error fetching user data:', userError); - return fail(500, { error: 'Failed to fetch user data' }); - } - - // Get all artist IDs for the user - const { - data: connectedArtists, - error: artistsError - }: { - data: Artist[] | null; - error: Error | null; - } = await supabase - .from(TABLES.artists) - .select('*') - .in( - 'id', - userData.map((u) => u.artist_id) - ); - - if (artistsError || !connectedArtists) { - console.error('Error fetching artists:', artistsError); - return fail(500, { error: 'Failed to fetch artists' }); - } - - const { - data: songs, - error: songsError - }: { - data: Track[] | null; - error: Error | null; - } = await supabase.from(TABLES.tracks).select('*'); - - const { - data: releases, - error: releasesError - }: { - data: ReleaseHydrated[] | null; // Adjust type as needed - error: Error | null; - } = await supabase.from(TABLES.releasesRich).select('*'); - - if (artistsError || !connectedArtists) { - console.error('Error fetching artists:', artistsError); - return fail(500, { error: 'Failed to fetch artists' }); - } - if (songsError || !songs) { - console.error('Error fetching songs:', songsError); - return fail(500, { error: 'Failed to fetch songs' }); - } - if (releasesError || !releases) { - console.error('Error fetching releases:', releasesError); - return fail(500, { error: 'Failed to fetch releases' }); - } - - songs.sort((a, b) => { - if (a.title < b.title) return -1; - if (a.title > b.title) return 1; - return 0; - }); + const connectedArtists: ArtistHydrated[] = await fetch(`${API_BASE}/users/${userID}/artists`, { + method: 'GET', + headers: REQUEST_HEADER_BOILERPLATE + }).then((res) => res.json()); connectedArtists.sort((a, b) => { if (a.name < b.name) return -1; @@ -98,26 +33,10 @@ export const load: LayoutServerLoad = async ({ locals: { safeGetSession }, cooki return 0; }); - // Get all streams for the artist - const { - data: streams, - error: streamsError - }: { - data: StreamLog[] | null; - error: Error | null; - } = await supabase.from(TABLES.streams).select('*'); - if (streamsError || !streams) { - console.error('Error fetching streams:', streamsError); - return fail(500, { error: 'Failed to fetch streams' }); - } - return { session, user, cookies: cookies.getAll(), - artists: connectedArtists, - releases: sortReleasesByDate(releases), - songs, - streams + artists: connectedArtists }; }; diff --git a/dashboard/src/routes/+layout.svelte b/dashboard/src/routes/+layout.svelte index 3491715..409d3ba 100644 --- a/dashboard/src/routes/+layout.svelte +++ b/dashboard/src/routes/+layout.svelte @@ -23,7 +23,6 @@ { id: 'profile', name: 'Profile' }, { id: 'music', name: 'Music' }, { id: 'stats', name: 'Stats' } - // { id: "payouts", name: "Payouts" }, ]; diff --git a/dashboard/src/routes/+layout.ts b/dashboard/src/routes/+layout.ts index 73f0608..6603396 100644 --- a/dashboard/src/routes/+layout.ts +++ b/dashboard/src/routes/+layout.ts @@ -29,9 +29,6 @@ export const load: LayoutLoad = async ({ fetch, data, depends }) => { supabase, session: data.session ?? null, user: data.user, - artists: data.artists, - releases: data.releases, - songs: data.songs, - streams: data.streams + artists: data.artists }; }; diff --git a/dashboard/src/routes/+page.svelte b/dashboard/src/routes/+page.svelte index 2aa5852..75324aa 100644 --- a/dashboard/src/routes/+page.svelte +++ b/dashboard/src/routes/+page.svelte @@ -6,6 +6,8 @@ import type { ReleaseHydrated } from '../../../shared/types/hydrated'; import StatsView from '$lib/components/views/stats/StatsView.svelte'; import MusicView from '$lib/components/views/music/MusicView.svelte'; + import { getArtistReleases, getArtistTracks } from '$lib/remote-functions/artist.remote'; + import { getArtistStreams } from '$lib/remote-functions/stats.remote'; let { data @@ -21,15 +23,24 @@ let activeArtist: Artist | null = $derived( data.artists.find((artist) => artist.id === dashboardState.activeArtist?.id) || null ); - let activeArtistSongs = $derived( - data.songs.filter((song) => song.artist_id === activeArtist?.id) - ); - let activeArtistReleases = $derived( - data.releases.filter((release) => release.artist_id === activeArtist?.id) - ); - let activeArtistStreams = $derived( - data.streams.filter((stream) => stream.artist_id === activeArtist?.id) - ); + let activeArtistStreams: StreamLog[] = $state([]); + let activeArtistSongs: Track[] = $state([]); + let activeArtistReleases: ReleaseHydrated[] = $state([]); + + $effect(() => { + const fetchArtistData = async () => { + if (activeArtist) { + activeArtistStreams = await getArtistStreams(activeArtist.id); + activeArtistSongs = await getArtistTracks(activeArtist.id); + activeArtistReleases = await getArtistReleases(activeArtist.id); + } else { + activeArtistStreams = []; + activeArtistSongs = []; + activeArtistReleases = []; + } + }; + fetchArtistData(); + }); diff --git a/shared/types/core.ts b/shared/types/core.ts index a56a414..8b4f812 100644 --- a/shared/types/core.ts +++ b/shared/types/core.ts @@ -1,5 +1,3 @@ -import type { ReleaseHydrated } from './hydrated'; - export interface User { first_name: string; tokens_balance: number;