import { Accordion, For, Span, Stack, Text, Box, AbsoluteCenter, Button, Separator, HStack, Flex, Badge, IconButton, Container, Collapsible } from '@chakra-ui/react';
import { JsonPlayObject, PlayActivity } from '../../../core/Atomic.js';
import { ShortDateDisplay } from '../DateDisplay.js';
import { TextMuted } from '../TextMuted.js';
import { LuChevronRight } from "react-icons/lu"
import { capitalize } from '../../../core/StringUtils.js';
import { ComponentProps, useMemo, forwardRef, Fragment } from "react"
import dayjs, { Dayjs } from 'dayjs';
import doy from 'dayjs/plugin/dayOfYear.js';
import { VscDebugRestart } from "react-icons/vsc";
import { GroupedVirtuoso } from 'react-virtuoso'
import { ActivityDetails } from '../ActivityDetail.js';
import { sortByNewestPlayDate, sortByNewestSeenDate } from '../../../core/PlayUtils.js';
import "./PlayList.scss";
dayjs.extend(doy);
export interface ActivityLogProps {
data: PlayActivity[]
sortBy?: 'played' | 'seen'
render?: 'virtCollapse' | 'virtAccordian' | 'accordian'
}
interface GroupInfo {
count: number
date: Dayjs
}
interface GroupData {
plays: PlayActivity[]
date: Dayjs
}
const generateGroupInfo = (data: PlayActivity[]): GroupInfo[] => {
const groupsReduced = data.reduce((acc: { groups: GroupInfo[], active?: GroupInfo }, curr, index) => {
const date = dayjs(curr.play.data.playDate);
if (acc.active === undefined) {
return { ...acc, active: { count: 1, date } };
}
if (acc.active.date.dayOfYear() !== date.dayOfYear()) {
return { groups: [...acc.groups, acc.active], active: { count: 1, date } }
}
return { groups: acc.groups, active: { ...acc.active, count: acc.active.count + 1 } };
}, { groups: [] });
return groupsReduced.groups.concat(groupsReduced.active);
}
const generateGroupPlays = (data: PlayActivity[]): GroupData[] => {
const groupsReduced = data.reduce((acc: { groups: GroupData[], active?: GroupData }, curr, index) => {
const date = dayjs(curr.play.data.playDate);
if (acc.active === undefined) {
return { ...acc, active: { plays: [curr], date } };
}
if (acc.active.date.dayOfYear() !== date.dayOfYear()) {
return { groups: [...acc.groups, acc.active], active: { plays: [curr], date } }
}
return { groups: acc.groups, active: { ...acc.active, plays: acc.active.plays.concat(curr) } };
}, { groups: [] });
return groupsReduced.groups.concat(groupsReduced.active);
}
export const PlayList = (props: ActivityLogProps) => {
const {
data = [],
sortBy = 'played',
render = 'accordian'
} = props;
const sorted = useMemo(() => props.data.toSorted((a, b) => {
if(sortBy === 'played') {
return sortByNewestPlayDate(a.play, b.play)
}
return sortByNewestSeenDate(a.play, b.play);
}), [data, sortBy]);
if (render === 'accordian') {
return
}
if (render === 'virtCollapse') {
return
}
if (render === 'virtAccordian') {
return ;
}
}
const VirtualizedCollapse = (props: { data: PlayActivity[] }) => {
const {
data,
} = props;
const groups = useMemo(() => generateGroupInfo(data), [data]);
return (
{
// return {args.children}
}
// }}
groupCounts={groups.map(x => x.count)}
groupContent={(index) => {
const gData = groups[index];
let headerText: string;
if (gData.date.isToday()) {
headerText = 'Today';
} else {
headerText = gData.date.format('MMM DD');
if (gData.date.year() !== dayjs().year()) {
headerText += `, ${gData.date.year()}`;
}
}
return (
{headerText}
)
}}
itemContent={(index, groupIndex) => {
const activity = data[index];
const { play } = activity;
return (
{play.data.track}
{play.data.artists.join(' / ')}
{play.meta?.source}
{activity.status === 'error' ?
: null}
)
}}
/>
);
}
const VirtualizedAccordian = (props: { data: PlayActivity[] }) => {
const {
data,
} = props;
const groups = useMemo(() => generateGroupInfo(data), [data]);
return (
{
// @ts-ignore
if (args.children.length === 1 && args.children[0].type.name === 'Group') {
// @ts-ignore
return {args.children}
}
// @ts-ignore
return {args.children}
}),
Group: (args) => {
return {args.children}
}
}}
groupCounts={groups.map(x => x.count)}
groupContent={(index) => {
const gData = groups[index];
let headerText: string;
if (gData.date.isToday()) {
headerText = 'Today';
} else {
headerText = gData.date.format('MMM DD');
if (gData.date.year() !== dayjs().year()) {
headerText += `, ${gData.date.year()}`;
}
}
return (
{headerText}
)
}}
itemContent={(index, groupIndex) => {
const activity = data[index];
const { play } = activity;
return (
{play.data.track}
{play.data.artists.join(' / ')}
{play.meta?.source}
{activity.status === 'error' ?
: null}
)
}}
/>
);
}
const PlainAccordian = (props: { data: PlayActivity[], sortBy: 'played' | 'seen' }) => {
const {
data = [],
sortBy
} = props;
const groups = generateGroupPlays(data);
return (
{groups.map((g) => {
let headerText: string;
if (g.date.isToday()) {
headerText = 'Today';
} else {
headerText = g.date.format('MMM DD');
if (g.date.year() !== dayjs().year()) {
headerText += `, ${g.date.year()}`;
}
}
return (
{headerText}
{g.plays.map((activity, index) => {
const { play } = activity;
return (
{play.data.track}
{play.data.artists.join(' / ')}
{play.meta?.source}
{activity.status === 'error' ?
: null}
)
})}
)
})}
);
}
const StatusBadge = (props: ComponentProps & { data: PlayActivity }) => {
const { data, ...rest } = props;
let badgeColor = undefined,
badgeText = capitalize(data.status);
switch (data.status) {
case 'queued':
badgeColor = 'gray';
break;
case 'scrobbled':
badgeColor = 'green';
break;
case 'error':
badgeColor = 'red';
break;
}
return {badgeText}
}
export const ListContainer = (props?: ComponentProps) => {
return
}