veza/apps/web/src/mocks/handlers-playlists.ts
senke ac182d9f35
Some checks failed
Backend API CI / test-unit (push) Failing after 0s
Backend API CI / test-integration (push) Failing after 0s
Frontend CI / test (push) Failing after 0s
Storybook Audit / Build & audit Storybook (push) Failing after 0s
feat(v0.10.4): Playlists collaboratives - F136, F140, F141, F143, F145
Backend:
- F141: GET /discover/playlists/editorial for editorial playlists
- F143: GET /playlists/shared/:token (public, no auth)
- F145: POST /playlists/import (JSON), GET /playlists/:id/export/m3u
- F136: GET /playlists/favoris (creates Favoris playlist if needed)
- Repo: GetFavorisByUserID, service GetOrCreateFavorisPlaylist

Frontend:
- SharedPlaylistPage at /playlists/shared/:token (public route)
- Editorial playlists section in DiscoverPage
- Export M3U in ExportPlaylistButton dropdown
- Import JSON via ImportPlaylistButton (PlaylistListPage)
- Favoris sidebar link, FavorisRedirectPage, AddToFavorisButton on tracks

Roadmap: v0.10.4 marked DONE
2026-03-09 16:49:05 +01:00

259 lines
7.5 KiB
TypeScript

/**
* MSW handlers for playlists endpoints
*/
import { http, HttpResponse } from 'msw';
export const handlersPlaylists = [
http.get('*/api/v1/playlists', () => {
return HttpResponse.json({
success: true,
data: {
playlists: [
{ id: 'pl-1', name: 'My Playlist', title: 'My Playlist', track_count: 10, cover_url: 'https://picsum.photos/300' },
],
total: 1,
page: 1,
limit: 20,
},
});
}),
http.post('*/api/v1/playlists/import', async ({ request }) => {
const body = (await request.json()) as { playlist?: { title?: string }; tracks?: unknown[] };
const title = body?.playlist?.title ?? 'Imported Playlist';
const trackCount = body?.tracks?.length ?? 0;
return HttpResponse.json({
success: true,
data: {
playlist: {
id: 'pl-imported-1',
name: title,
title,
track_count: trackCount,
like_count: 0,
user_id: 'user-1',
description: '',
is_public: true,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
},
},
});
}),
http.post('*/api/v1/playlists', async ({ request }) => {
const body = (await request.json()) as { title?: string };
const title = body?.title ?? 'New Playlist';
return HttpResponse.json({
success: true,
data: {
playlist: {
id: 'pl-new',
name: title,
title,
track_count: 0,
like_count: 0,
user_id: 'user-1',
description: '',
is_public: true,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
},
},
});
}),
http.get('*/api/v1/playlists/recommendations', () => {
return HttpResponse.json({
success: true,
data: [
{ id: 'pl-rec-1', title: 'Recommended Playlist', name: 'Recommended Playlist', track_count: 8, cover_url: 'https://picsum.photos/300' },
],
});
}),
http.get('*/api/v1/playlists/search', ({ request }) => {
const url = new URL(request.url);
const q = url.searchParams.get('q') ?? url.searchParams.get('query') ?? '';
const page = parseInt(url.searchParams.get('page') ?? '1', 10);
const limit = parseInt(url.searchParams.get('limit') ?? '20', 10);
const playlists =
q === 'NonExistentPlaylist'
? []
: [
{ id: 'pl-search-1', user_id: 'u1', title: 'Summer Vibes', description: 'Sun-soaked tracks', is_public: true, track_count: 12, created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-01T00:00:00Z' },
{ id: 'pl-search-2', user_id: 'u1', title: 'Workout Mix', description: 'High energy', is_public: false, track_count: 8, created_at: '2024-01-02T00:00:00Z', updated_at: '2024-01-02T00:00:00Z' },
];
const total = playlists.length;
return HttpResponse.json({
success: true,
data: {
playlists,
total,
page,
limit,
},
});
}),
http.get('*/api/v1/playlists/favoris', () => {
return HttpResponse.json({
success: true,
data: {
playlist: {
id: 'pl-favoris-1',
user_id: 'user-1',
name: 'Favoris',
title: 'Favoris',
description: '',
is_public: false,
track_count: 0,
is_default_favorites: true,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
},
},
});
}),
http.get('*/api/v1/playlists/shared/:token', ({ params }) => {
return HttpResponse.json({
success: true,
data: {
playlist: {
id: 'pl-shared-1',
user_id: 'user-1',
name: 'Shared Playlist',
title: 'Shared Playlist',
description: 'A shared playlist',
is_public: true,
track_count: 2,
tracks: [
{
id: 'pt-1',
playlist_id: 'pl-shared-1',
track_id: 'tr-1',
position: 1,
added_at: new Date().toISOString(),
track: { id: 'tr-1', title: 'Track One', duration_ms: 180000 },
},
{
id: 'pt-2',
playlist_id: 'pl-shared-1',
track_id: 'tr-2',
position: 2,
added_at: new Date().toISOString(),
track: { id: 'tr-2', title: 'Track Two', duration_ms: 240000 },
},
],
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
},
},
});
}),
http.get('*/api/v1/playlists/:id', ({ params }) => {
return HttpResponse.json({
success: true,
data: {
id: params.id,
name: 'Playlist Detail',
title: 'Playlist Detail',
description: 'A mock playlist',
tracks: [],
owner: { id: 'user-1', username: 'Owner' },
},
});
}),
http.put('*/api/v1/playlists/:id', () => {
return HttpResponse.json({
success: true,
data: { name: 'Updated Playlist' },
});
}),
http.delete('*/api/v1/playlists/:id', () => HttpResponse.json({ success: true })),
http.post('*/api/v1/playlists/:id/tracks', () => HttpResponse.json({ success: true, data: {} })),
http.delete('*/api/v1/playlists/:id/tracks/:trackId', () => HttpResponse.json({ success: true })),
http.post('*/api/v1/playlists/:id/duplicate', async ({ params, request }) => {
const body = (await request.json()) as { new_title?: string; new_description?: string; is_public?: boolean };
const newTitle = body?.new_title ?? `Playlist (copie)`;
return HttpResponse.json({
success: true,
message: 'playlist duplicated successfully',
playlist: {
id: `pl-dup-${params.id}`,
name: newTitle,
title: newTitle,
track_count: 0,
like_count: 0,
user_id: 'user-1',
description: body?.new_description ?? '',
is_public: body?.is_public ?? true,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
},
});
}),
http.post('*/api/v1/playlists/:id/share', ({ params }) => {
return HttpResponse.json({
success: true,
data: {
share_url: `https://veza.example/playlists/${params.id}/share/abc123`,
},
});
}),
http.get('*/api/v1/playlists/:id/collaborators', () => {
return HttpResponse.json({
success: true,
data: [],
});
}),
http.get('*/api/v1/playlists/:id/export/:format', ({ params }) => {
const format = params.format as string;
if (format === 'json') {
return new HttpResponse(
JSON.stringify({
playlist: { id: params.id, title: 'Mock Playlist', tracks: [] },
}),
{
headers: {
'Content-Type': 'application/json',
'Content-Disposition': `attachment; filename="playlist_${params.id}.json"`,
},
},
);
}
if (format === 'csv') {
return new HttpResponse('title,artist\nTrack 1,Artist 1\n', {
headers: {
'Content-Type': 'text/csv',
'Content-Disposition': `attachment; filename="playlist_${params.id}.csv"`,
},
});
}
return HttpResponse.json({ error: 'Invalid format' }, { status: 400 });
}),
http.get('*/api/v1/playlists/:id/analytics', () => {
return HttpResponse.json({
success: true,
data: {
stats: {
plays: 120,
shares: 5,
likes: 42,
},
},
});
}),
];