import React, { useCallback, useState, type ComponentProps, type PropsWithChildren } from 'react';
import { EmptyState, DataList, HStack, Tabs, Box, Badge, Stack, Text, Separator, IconButton, Container, Float, Link, Span, Menu, Group, Portal, type MenuItemProps, type MenuSelectionDetails } from "@chakra-ui/react"
import { LuCode, LuText } from "react-icons/lu"
import type { JsonPlayObject, PlayObjectMinimal } from '../../../core/Atomic.js';
import { shortTodayAwareFormat, timeToHumanTimestamp } from '../../../core/TimeUtils.js';
import dayjs from 'dayjs';
import { ChakraCodeBlock } from '../CodeBlock.js';
import { TextMuted } from '../TextMuted.js';
import { formatNumber } from '../../../core/DataUtils.js';
import { Muted } from '../Typography.js';
import { ArtistCreditTags } from '../ArtistCreditDisplay.js';
import { MSErrorBoundary } from '../ErrorBoundary.js';
import { EditIconRaw, EllipsisButton, EyeClosedIcon, EyeIcon, hasMusicServiceIcon } from '../icons/ChakraIcons.js';
import type { IconType } from 'react-icons/lib';
import { capitalize, capitalizeWords } from '../../../core/StringUtils.js';
import { getMusicServiceIconTooltip, MusicServiceIndicators } from '../musicServices/MusicServiceIndicators.js';
const EmptyPlayData = () => {
return (
No Play object was provided.
);
}
export type DisplayDates = false | 'all' | 'played' | 'seen';
export interface PlayInfoProps {
play?: JsonPlayObject | PlayObjectMinimal
final?: JsonPlayObject
showCodeToggle?: boolean
showCompare?: boolean
compareDefault?: 'Initial' | 'Final'
dates?: false | 'all' | 'played' | 'seen'
editable?: boolean
onEditClick?: () => void
codeContent?: React.JSX.Element
}
const primaryActionProps: ComponentProps = {
//margin: "1px",
variant: "outline",
size: 'xs'
}
const menuItem = (Icon: IconType, value: string, name?: string) => (props: Pick = {}) => ({name ?? capitalize(value)})
const MenuTextMode = menuItem(LuText, 'code', 'Show Text');
const MenuCodeMode = menuItem(LuCode, 'code', 'Show Code');
export const PlayData = (props?: PlayInfoProps) => {
const {
play,
final,
codeContent,
showCodeToggle = true,
showCompare = true,
compareDefault = 'Initial',
dates = 'all',
editable = false,
onEditClick
} = props ?? {};
const [codeMode, setCodeMode] = useState(false);
const menuCb = useCallback((select: MenuSelectionDetails) => {
if(select.value === 'code') {
setCodeMode((old) => !old);
}
}, [setCodeMode])
if (play === undefined) {
return
}
let primary: React.JSX.Element | null = null;
const comparable = showCompare && final !== undefined;
const menuItems: React.JSX.Element[] = [
];
if(editable && onEditClick !== undefined) {
primary = (
onEditClick()}>
);
if(showCodeToggle) {
menuItems.push(codeMode ? : );
}
} else if (showCodeToggle) {
primary = (
setCodeMode(!codeMode)}>
{codeMode ? : }
);
}
let content: React.JSX.Element;
if (!comparable) {
content = codeMode ? (codeContent ?? ) : ;
} else {
content = (
Initial
Final
{codeMode ? (codeContent ?? ) : }
{codeMode ? (codeContent ?? ) : }
)
}
return (
{primary}
{menuItems}
{content}
);
}
const SourceMaybeLink = (props: PropsWithChildren<{link?: string}>) => {
if(props.link === undefined) {
return props.children;
}
return {props.children}
}
export const PlayDataDataList = (props: { play: JsonPlayObject, dates: DisplayDates, showMbid?: boolean }) => {
const {
play,
dates,
showMbid = false
} = props;
let albumArtistElm: React.JSX.Element | undefined;
if (play.data.albumArtists !== undefined && play.data.albumArtists.length > 0) {
albumArtistElm = (
Album Artists
);
}
const {
data: {
track,
artists = [],
listenedFor,
duration,
repeat,
} = {},
meta: {
url: {
web: webUrl,
origin: originUrl
} = {},
source,
musicService
} = {}
} = play;
let sourceElm: React.JSX.Element | undefined = undefined;
if(musicService !== undefined && musicService !== source && source !== undefined) {
sourceElm = {hasMusicServiceIcon(musicService) ? getMusicServiceIconTooltip(musicService)({size: 'md'}) : capitalizeWords(musicService)} via {capitalizeWords(source)}
} else if(source !== undefined) {
sourceElm = {hasMusicServiceIcon(source) ? getMusicServiceIconTooltip(source)({size: 'md'}) : capitalizeWords(source)}
}
const titleElm = {track?.name}
return (
Title
{titleElm}
Artists
{artists.length === 0 ? (No Artists) :
}
{albumArtistElm}
Album
{play.data.album?.name}
Duration
Track Length: {duration === undefined ? 'N/A' : timeToHumanTimestamp(dayjs.duration(duration, 's'))}
{listenedFor !== undefined ? Listened For: {timeToHumanTimestamp(dayjs.duration(listenedFor, 's'))}{duration !== undefined && duration > 0 ? ` (${formatNumber((listenedFor / duration) * 100)}%)` : null} : null}
{sourceElm !== undefined ? (
Source
{sourceElm}
) : undefined}
)
}
export const PlayInfoContainer = (props?: PlayInfoProps) => {
return
}
export const PlayDatesStack = (props: { play: JsonPlayObject, dates: DisplayDates }) => {
const {
play,
play: {
data: {
repeat = false,
} = {}
} = {},
dates
} = props;
let datesItem: React.JSX.Element | null;
if (dates === false) {
datesItem = null;
} else {
const dateElements = [];
if (dates.includes('played') || dates.includes('all')) {
dateElements.push(({`Played ${shortTodayAwareFormat(dayjs(play.data.playDate))}`}{repeat ? Repeat : null}));
if (play.data.playDateCompleted !== undefined) {
dateElements.push(({`Played Until ${shortTodayAwareFormat(dayjs(play.data.playDateCompleted))}`}));
}
}
if (dates.includes('seen') || dates.includes('all')) {
dateElements.push(({`Seen ${shortTodayAwareFormat(dayjs(play.meta.seenAt))}`}));
}
datesItem = (
Dates
{dateElements}
)
}
return datesItem;
}
export const PlayDatesFooter = (props: { play: JsonPlayObject, dates: DisplayDates }) => {
const {
play,
dates
} = props;
let dateElm: React.JSX.Element | null = null;
if (dates !== false) {
let playDate: React.JSX.Element | undefined,
seenDate: React.JSX.Element | undefined;
if (play.data.playDate !== undefined && ['all', 'played'].includes(dates)) {
playDate = {`Played ${shortTodayAwareFormat(dayjs(play.data.playDate))}`}
}
// TODO implement seenAt for play data
if (play.meta.seenAt !== undefined && ['all', 'seen'].includes(dates)) {
seenDate = {`Seen ${shortTodayAwareFormat(dayjs(play.meta.seenAt))}`}
}
if (playDate !== undefined && seenDate !== undefined) {
dateElm = {playDate}{seenDate}
} else if (playDate !== undefined) {
dateElm = playDate;
} else if (seenDate !== undefined) {
dateElm = seenDate;
}
}
return dateElm;
}