- Lot G: Recherche avancée (musical_key, tri pertinence, autocomplete, facettes, historique) - Lot H: Analytics créateur (stats, charts, completion rate, export CSV/JSON) - Lot F: Seller dashboard (GET /sell/stats, liste produits) - Lot C: Player (crossfade, gapless preload, PiP) - Lot D2: Autoplay (GET /tracks/recommendations, section À écouter ensuite) Backend: GetRecommendations handler, route /tracks/recommendations Frontend: PlayerQueue recommendations, fix TS errors (GlobalPlayer, AnalyticsViewKpiGrid, etc.) Docs: FEATURE_STATUS, PROJECT_STATE, CHANGELOG, SCOPE_CONTROL
108 lines
3.2 KiB
TypeScript
108 lines
3.2 KiB
TypeScript
import type { Meta, StoryObj } from '@storybook/react';
|
|
import { useEffect } from 'react';
|
|
import { PlayerQueue } from './PlayerQueue';
|
|
import { usePlayerStore } from '../store/playerStore';
|
|
import { useAuthStore } from '@/features/auth/store/authStore';
|
|
|
|
const meta: Meta<typeof PlayerQueue> = {
|
|
title: 'Components/Features/Player/PlayerQueue',
|
|
component: PlayerQueue,
|
|
parameters: {
|
|
layout: 'padded',
|
|
},
|
|
tags: ['autodocs'],
|
|
argTypes: {
|
|
onClose: { action: 'onClose' },
|
|
onPlay: { action: 'onPlay' },
|
|
},
|
|
};
|
|
|
|
export default meta;
|
|
type Story = StoryObj<typeof PlayerQueue>;
|
|
|
|
const mockTracks = [
|
|
{ id: '1', title: 'Start Me Up', artist: 'The Rolling Stones', cover: 'https://picsum.photos/200', duration: 200, url: '' },
|
|
{ id: '2', title: 'Bohemian Rhapsody', artist: 'Queen', cover: 'https://picsum.photos/201', duration: 354, url: '' },
|
|
{ id: '3', title: 'Hotel California', artist: 'Eagles', cover: 'https://picsum.photos/202', duration: 391, url: '' },
|
|
];
|
|
|
|
const StoreInitializer = ({ tracks, currentIndex = 0 }: { tracks: any[], currentIndex?: number }) => {
|
|
const { addToQueue, clearQueue } = usePlayerStore();
|
|
|
|
useEffect(() => {
|
|
clearQueue();
|
|
// We add tracks one by one or batch if supported, here we simluate adding
|
|
// Note: usePlayerStore actions might need adjustment if they don't support direct manipulation for stories
|
|
// But addToQueue takes Track[].
|
|
|
|
// We clear first
|
|
usePlayerStore.setState({ queue: [], currentIndex: -1 });
|
|
|
|
// Set state directly for storybook purposes to ensure consistency
|
|
usePlayerStore.setState({
|
|
queue: tracks,
|
|
currentIndex,
|
|
currentTrack: tracks[currentIndex]
|
|
});
|
|
|
|
}, [tracks, currentIndex, addToQueue, clearQueue]);
|
|
|
|
return null;
|
|
};
|
|
|
|
export const Default: Story = {
|
|
args: {
|
|
isOpen: true,
|
|
},
|
|
decorators: [
|
|
(Story) => (
|
|
<>
|
|
<StoreInitializer tracks={mockTracks} currentIndex={0} />
|
|
<div className="h-[600px] w-full relative bg-background overflow-hidden">
|
|
<Story />
|
|
</div>
|
|
</>
|
|
),
|
|
],
|
|
};
|
|
|
|
const AuthInitializer = ({ authenticated }: { authenticated: boolean }) => {
|
|
useEffect(() => {
|
|
useAuthStore.setState({ isAuthenticated: authenticated });
|
|
return () => useAuthStore.setState({ isAuthenticated: false });
|
|
}, [authenticated]);
|
|
return null;
|
|
};
|
|
|
|
export const Empty: Story = {
|
|
args: {
|
|
isOpen: true,
|
|
},
|
|
decorators: [
|
|
(Story) => (
|
|
<>
|
|
<StoreInitializer tracks={[]} />
|
|
<div className="h-[600px] w-full relative bg-background overflow-hidden">
|
|
<Story />
|
|
</div>
|
|
</>
|
|
),
|
|
],
|
|
};
|
|
|
|
export const EmptyWithRecommendations: Story = {
|
|
args: {
|
|
isOpen: true,
|
|
},
|
|
decorators: [
|
|
(Story) => (
|
|
<>
|
|
<AuthInitializer authenticated />
|
|
<StoreInitializer tracks={[]} />
|
|
<div className="h-[600px] w-full relative bg-background overflow-hidden">
|
|
<Story />
|
|
</div>
|
|
</>
|
|
),
|
|
],
|
|
};
|