import React, { useMemo, useCallback, useState, useEffect } from 'react' import { Card, CardContent, CardMedia, Collapse, makeStyles, Typography, useMediaQuery, withWidth, } from '@material-ui/core' import { useRecordContext, useTranslate, ArrayField, SingleFieldList, ChipField, Link, } from 'react-admin' import clsx from 'clsx' import Lightbox from 'react-image-lightbox' import 'react-image-lightbox/style.css' import subsonic from '../subsonic' import { ArtistLinkField, DurationField, formatRange, SizeField, LoveButton, RatingField, useAlbumsPerPage, } from '../common' import config from '../config' import { formatFullDate, intersperse } from '../utils' import AlbumExternalLinks from './AlbumExternalLinks' import AnchorMe from '../common/Linkify' const useStyles = makeStyles( (theme) => ({ root: { [theme.breakpoints.down('xs')]: { padding: '0.7em', minWidth: '20em', }, [theme.breakpoints.up('sm')]: { padding: '1em', minWidth: '32em', }, }, cardContents: { display: 'flex', }, details: { display: 'flex', flexDirection: 'column', }, content: { flex: '2 0 auto', }, coverParent: { [theme.breakpoints.down('xs')]: { height: '8em', width: '8em', minWidth: '8em', }, [theme.breakpoints.up('sm')]: { height: '10em', width: '10em', minWidth: '10em', }, [theme.breakpoints.up('lg')]: { height: '15em', width: '15em', minWidth: '15em', }, }, cover: { objectFit: 'contain', cursor: 'pointer', display: 'block', width: '100%', height: '100%', }, loveButton: { top: theme.spacing(-0.2), left: theme.spacing(0.5), }, commentBlock: { display: 'inline-block', marginTop: '1em', float: 'left', wordBreak: 'break-word', }, notes: { display: 'inline-block', marginTop: '1em', float: 'left', wordBreak: 'break-word', cursor: 'pointer', }, pointerCursor: { cursor: 'pointer', }, recordName: {}, recordArtist: {}, recordMeta: {}, genreList: { marginTop: theme.spacing(0.5), }, externalLinks: { marginTop: theme.spacing(1.5), }, }), { name: 'NDAlbumDetails', } ) const AlbumComment = ({ record }) => { const classes = useStyles() const [expanded, setExpanded] = React.useState(false) const lines = record.comment.split('\n') const formatted = useMemo(() => { return lines.map((line, idx) => (
)) }, [lines, record.id]) const handleExpandClick = useCallback(() => { setExpanded(!expanded) }, [expanded, setExpanded]) return ( 1 && classes.pointerCursor )} > {formatted} ) } export const useGetHandleGenreClick = (width) => { const [perPage] = useAlbumsPerPage(width) return (id) => { return `/album?filter={"genre_id":"${id}"}&order=ASC&sort=name&perPage=${perPage}` } } const GenreChipField = withWidth()(({ width, ...rest }) => { const record = useRecordContext(rest) const genreLink = useGetHandleGenreClick(width) return ( e.stopPropagation()}> {}} /> ) }) const GenreList = () => { const classes = useStyles() return ( ) } const Details = (props) => { const isXsmall = useMediaQuery((theme) => theme.breakpoints.down('xs')) const translate = useTranslate() const record = useRecordContext(props) let details = [] const addDetail = (obj) => { const id = details.length details.push({obj}) } const originalYearRange = formatRange(record, 'originalYear') const originalDate = record.originalDate ? formatFullDate(record.originalDate) : originalYearRange const yearRange = formatRange(record, 'year') const date = record.date ? formatFullDate(record.date) : yearRange const releaseDate = record.releaseDate ? formatFullDate(record.releaseDate) : date const showReleaseDate = date !== releaseDate && releaseDate.length > 3 const showOriginalDate = date !== originalDate && originalDate !== releaseDate && originalDate.length > 3 showOriginalDate && !isXsmall && addDetail( <> {[translate('resources.album.fields.originalDate'), originalDate].join( ' ' )} ) yearRange && addDetail(<>{['♫', !isXsmall ? date : yearRange].join(' ')}) showReleaseDate && addDetail( <> {(!isXsmall ? [translate('resources.album.fields.releaseDate'), releaseDate] : ['○', record.releaseDate.substring(0, 4)] ).join(' ')} ) const showReleases = record.releases > 1 showReleases && addDetail( <> {!isXsmall ? [ record.releases, translate('resources.album.fields.releases', { smart_count: record.releases, }), ].join(' ') : ['(', record.releases, ')))'].join(' ')} ) addDetail( <> {record.songCount + ' ' + translate('resources.song.name', { smart_count: record.songCount, })} ) !isXsmall && addDetail() !isXsmall && addDetail() return <>{intersperse(details, ' · ')} } const AlbumDetails = (props) => { const record = useRecordContext(props) const isXsmall = useMediaQuery((theme) => theme.breakpoints.down('xs')) const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('lg')) const classes = useStyles() const [isLightboxOpen, setLightboxOpen] = React.useState(false) const [expanded, setExpanded] = useState(false) const [albumInfo, setAlbumInfo] = useState() let notes = albumInfo?.notes?.replace(new RegExp('<.*>', 'g'), '') || record.notes if (notes !== undefined) { notes += '..' } useEffect(() => { subsonic .getAlbumInfo(record.id) .then((resp) => resp.json['subsonic-response']) .then((data) => { if (data.status === 'ok') { setAlbumInfo(data.albumInfo) } }) .catch((e) => { console.error('error on album page', e) }) }, [record]) const imageUrl = subsonic.getCoverArtUrl(record, 300) const fullImageUrl = subsonic.getCoverArtUrl(record) const handleOpenLightbox = React.useCallback(() => setLightboxOpen(true), []) const handleCloseLightbox = React.useCallback( () => setLightboxOpen(false), [] ) return (
{record.name}
{config.enableStarRating && (
)} {isDesktop ? ( ) : ( {record.genre} )} {!isXsmall && ( {config.enableExternalServices && ( )} )} {isDesktop && ( setExpanded(!expanded)} > )} {isDesktop && record['comment'] && }
{!isDesktop && record['comment'] && } {!isDesktop && (
setExpanded(!expanded)} >
)} {isLightboxOpen && ( )}
) } export default AlbumDetails