Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions api/src/routes/artists/[slug]/streams/+server.ts
Original file line number Diff line number Diff line change
@@ -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<StreamLog[]>(
async () => await supabase.from(TABLES.streams).select('*').eq('artist_id', params.slug),
{ errorMessage: 'Failed to fetch streams for artist' }
);
}
10 changes: 10 additions & 0 deletions api/src/routes/artists/[slug]/tracks/+server.ts
Original file line number Diff line number Diff line change
@@ -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<Track[]>(
async () => await supabase.from(TABLES.tracks).select().eq('artist_id', params.slug),
{ errorMessage: 'Failed to fetch tracks for artist' }
);
}
37 changes: 37 additions & 0 deletions api/src/routes/users/[slug]/artists/+server.ts
Original file line number Diff line number Diff line change
@@ -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);
}
3 changes: 2 additions & 1 deletion api/src/routes/users/[slug]/collections/+server.ts
Original file line number Diff line number Diff line change
@@ -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<CollectionHydrated[]>(
async () => supabase.from(TABLES.collectionsRich).select('*').eq('user_id', params.slug),
{ errorMessage: 'Failed to fetch collections' }
);
Expand Down
35 changes: 34 additions & 1 deletion dashboard/src/lib/remote-functions/artist.remote.ts
Original file line number Diff line number Diff line change
@@ -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(),
Expand Down Expand Up @@ -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;
});
14 changes: 14 additions & 0 deletions dashboard/src/lib/remote-functions/stats.remote.ts
Original file line number Diff line number Diff line change
@@ -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();
});
97 changes: 8 additions & 89 deletions dashboard/src/routes/+layout.server.ts
Original file line number Diff line number Diff line change
@@ -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();
Expand All @@ -16,108 +15,28 @@ export const load: LayoutServerLoad = async ({ locals: { safeGetSession }, cooki
user,
cookies: cookies.getAll(),
artists: [],
releases: [],
songs: [],
streams: []
};
}

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;
if (a.name > b.name) return 1;
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
};
};
1 change: 0 additions & 1 deletion dashboard/src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
{ id: 'profile', name: 'Profile' },
{ id: 'music', name: 'Music' },
{ id: 'stats', name: 'Stats' }
// { id: "payouts", name: "Payouts" },
];
</script>

Expand Down
5 changes: 1 addition & 4 deletions dashboard/src/routes/+layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
};
29 changes: 20 additions & 9 deletions dashboard/src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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();
});
</script>

<svelte:head>
Expand Down
2 changes: 0 additions & 2 deletions shared/types/core.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type { ReleaseHydrated } from './hydrated';

export interface User {
first_name: string;
tokens_balance: number;
Expand Down