import '../../client/wdyr.js'; import preview from "../../../.storybook/preview.js"; import React from 'react'; import { http, HttpResponse, delay, sse, type StrictRequest, type DefaultBodyType, type JsonBodyType } from 'msw'; import { Container } from '@chakra-ui/react'; import { ListContainerFetchable, ListContainerFilterable, ActivityList } from "../../client/components/playActivity/ActivityList.js"; import {Provider} from "../../client/components/Provider.js"; import { generatePlay } from "../../core/tests/utils/PlayTestUtils.js"; import { type PlayState, qsOptions } from "../../core/Atomic.js"; import { randomPlayState} from '../../core/tests/utils/fixtures.js' import dayjs from "dayjs"; import qs from 'qs'; import { asJsonPlayObject } from "../../core/PlayMarshalUtils.js"; import { generatePlayApiCommonDetailed, generatePlayApiCommonDetailedList } from "../../core/tests/utils/apiFixtures.js"; import type { PaginatedResponse, QueryPlaysOptsJson} from "../../core/Api.js"; import type {MsSseEvent, PlayApiCommonDetailed} from "../../core/Api.js"; import { SSEProvider } from "@flamefrontend/sse-runtime-react"; import { sseProviderOptions } from '../../client/AppNext.js'; import { faker } from '@faker-js/faker'; // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export const meta = preview.meta({ title: 'Plays/List', component: ActivityList, parameters: { // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout layout: 'padded', }, // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs tags: ['autodocs'], // More on argTypes: https://storybook.js.org/docs/api/argtypes // args: { // data:[ // ] , // }, render: function Render(args, { loaded: { data } }) { return () }, decorators: [ (Story) => ( options={sseProviderOptions}>), ] // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args }); let playData: PlayApiCommonDetailed[] = []; const handlePlayListRequest = async ({ request, list }: {request: StrictRequest, list: PlayApiCommonDetailed[]}): Promise<[HttpResponse, PlayApiCommonDetailed[]]> => { const url = new URL(request.url) console.log(url.search); const query = qs.parse(url.search, qsOptions); console.log(query); let responseData: PlayApiCommonDetailed[] = []; if(list.length === 0) { list = await generatePlayApiCommonDetailedList(); responseData = list; } else { const startDate = dayjs(list[Math.min(Number.parseInt(query.offset as string) - 1, list.length - 1)].playedAt); const moreData = await generatePlayApiCommonDetailedList({endDate: startDate}); list = list.concat(moreData); responseData = moreData; } const res: PaginatedResponse = { data: responseData, meta: { offset: Number.parseInt(query.offset as string), limit: responseData.length, total: list.length, } } return [HttpResponse.json(res), list]; } type PlayRequestMock = Parameters>[1]>[0]; const handlePlayRequest = async ({params, request}: PlayRequestMock, list: PlayApiCommonDetailed[]): Promise<[HttpResponse, PlayApiCommonDetailed[]]> => { if(list.length === 0) { list = await generatePlayApiCommonDetailedList(); } const existing = list.find(x => x.uid === params.uid); if (existing !== undefined) { return [HttpResponse.json(existing), list]; } return [HttpResponse.json(generatePlayApiCommonDetailed()), list]; } let listLiveData: PlayApiCommonDetailed[] = []; export const ListLive = meta.story({ component: ListContainerFetchable, render: function Render(args, { loaded: { data } }) { return () }, args: { render: "virtDynamic", componentId: 1, componentType: 'source' }, parameters: { msw: { handlers: [ http.get<{ uid: string }>('/api/components/:componentId/plays', async ({ params, request }) => { const [res, newList] = await handlePlayListRequest({request, list: listLiveData}); await delay(1000); listLiveData = newList; return res; }), http.get<{ uid: string }>('/api/components/:componentId/plays/:uid', async (info) => { const [res, newList] = await handlePlayRequest(info, listLiveData); listLiveData = newList; await delay(1000); return res; }), ], }, }, //render: function Render(args) { return () } loaders: [ async () => { playData = await generatePlayApiCommonDetailedList() return { data: playData }; } ] }); let livePlayData: PlayApiCommonDetailed[] = []; export const ListLiveFilterable = meta.story({ component: ListContainerFilterable, render: function Render(args, { loaded: { data } }) { return () }, args: { render: "virtDynamic", componentId: 1, componentType: 'source' }, parameters: { msw: { handlers: [ http.get<{ uid: string }>('/api/components/:componentId/plays', async ({ params, request }) => { const [res, newList] = await handlePlayListRequest({request, list: livePlayData}); await delay(1000); livePlayData = newList; return res; }), http.get<{ uid: string }>('/api/components/:componentId/plays/:uid', async (info) => { const [res, newList] = await handlePlayRequest(info, livePlayData); livePlayData = newList; await delay(1000); return res; }), ], }, }, //render: function Render(args) { return () } loaders: [ async () => { playData = await generatePlayApiCommonDetailedList() return { data: playData }; } ] }); export const ListLiveEmpty = meta.story({ component: ListContainerFilterable, render: function Render(args, { loaded: { data } }) { return () }, args: { render: "virtDynamic", componentId: 1, componentType: 'source' }, parameters: { msw: { handlers: [ http.get<{ uid: string }>('/api/components/:componentId/plays', async ({ params, request }) => { await delay(2000); return HttpResponse.json({data: [], meta: {offset: 0, limit: 100}}); }), http.get<{ uid: string }>('/api/components/:componentId/plays/:uid', async ({ params }) => { return new HttpResponse('', {status: 404}); }), ], }, } }); let liveNoMorePlayData: PlayApiCommonDetailed[] = []; export const ListLiveNoMorePlay = meta.story({ component: ListContainerFilterable, render: function Render(args) { return () }, args: { render: "virtDynamic", componentId: 1, componentType: 'source' }, parameters: { msw: { handlers: [ http.get<{ uid: string }>('/api/components/:componentId/plays', async ({ params, request }) => { await delay(); const url = new URL(request.url) console.log(url.search); const query = qs.parse(url.search, qsOptions) as QueryPlaysOptsJson; console.log(query); const offset = Number.parseInt(query.offset as unknown as string); if(offset > 0) { return HttpResponse.json({ data: [], meta: { limit: liveNoMorePlayData.length, offset: query.offset } }); } if(liveNoMorePlayData.length === 0) { liveNoMorePlayData = await generatePlayApiCommonDetailedList(); } const res: PaginatedResponse = { data: liveNoMorePlayData, meta: { offset: 0, limit: livePlayData.length } } return HttpResponse.json(res); }), http.get<{ uid: string }>('/api/components/:componentId/plays/:uid', async (info) => { const [res, newList] = await handlePlayRequest(info, liveNoMorePlayData); liveNoMorePlayData = newList; await delay(1000); return res; }), ], }, }, }); let liveUpdateData: PlayApiCommonDetailed[] = []; export const ListLiveUpdates = meta.story({ component: ListContainerFilterable, render: function Render(args, { loaded: { data } }) { return () }, args: { render: "virtDynamic", componentId: 1, componentType: 'source' }, parameters: { msw: { handlers: [ http.get<{ uid: string }>('/api/components/:componentId/plays', async ({ params, request }) => { const [res, newList] = await handlePlayListRequest({request, list: liveUpdateData}); await delay(1000); liveUpdateData = newList; return res; }), http.get<{ uid: string }>('/api/components/:componentId/plays/:uid', async (info) => { const [res, newList] = await handlePlayRequest(info, liveUpdateData); liveUpdateData = newList; await delay(1000); return res; }), sse('/api/events?next=true', async ({ params, client }) => { setInterval(() => { const index = faker.number.int({min: 0, max: 7}); let newState: PlayState = liveUpdateData[index].state; while(newState === liveUpdateData[index].state) { newState = randomPlayState(); } liveUpdateData[index].state = newState; liveUpdateData[index].play.data.track = faker.music.songName(); liveUpdateData[index].updatedAt = dayjs().toISOString(); client.send({ //@ts-expect-error event: 'playUpdate', data: {componentId: 1, data: {uid: liveUpdateData[index].uid}}}) }, 2000); }) ], }, }, //render: function Render(args) { return () } loaders: [ async () => { playData = await generatePlayApiCommonDetailedList() return { data: playData }; } ] }); let livePlayInsertData: PlayApiCommonDetailed[] = []; export const ListLiveInsert = meta.story({ component: ListContainerFilterable, render: function Render(args, { loaded: { data } }) { return () }, args: { render: "virtDynamic", componentId: 1, componentType: 'source' }, parameters: { msw: { handlers: [ http.get<{ uid: string }>('/api/components/:componentId/plays', async ({ params, request }) => { const [res, newList] = await handlePlayListRequest({request, list: livePlayInsertData}); await delay(1000); livePlayInsertData = newList; return res; }), http.get<{ uid: string }>('/api/components/:componentId/plays/:uid', async (info) => { const [res, newList] = await handlePlayRequest(info, livePlayInsertData); livePlayInsertData = newList; await delay(1000); return res; }), sse('/api/events?next=true', async ({ params, client }) => { setInterval(() => { //const first = livePlayInsertData[0].play.data.playDate; //const last = livePlayInsertData[livePlayData.length - 1].play.data.playDate; const randomIndex = faker.number.int({min: 1, max: livePlayInsertData.length - 2}); const random = livePlayInsertData[randomIndex]; const generatedPlayData = generatePlayApiCommonDetailed({ playOpts: [{ play: asJsonPlayObject(generatePlay({playDate: dayjs(random.play.data.playDate).subtract(30, 's')})) }] }); livePlayInsertData.splice(randomIndex, 0, generatedPlayData); client.send({ //@ts-expect-error event: 'playInsert', data: {componentId: 1, data: generatedPlayData}}); }, 2000); }) ], }, }, //render: function Render(args) { return () } loaders: [ async () => { playData = await generatePlayApiCommonDetailedList() return { data: playData }; } ] });