65 lines
2.2 KiB
TypeScript
65 lines
2.2 KiB
TypeScript
|
|
import { useEffect, useState } from 'react'
|
||
|
|
import { getRecentPlays, type RecentPlay } from '../../furumiApi'
|
||
|
|
import styles from './header.module.css'
|
||
|
|
|
||
|
|
function timeAgo(iso: string): string {
|
||
|
|
const diff = Date.now() - new Date(iso).getTime()
|
||
|
|
const mins = Math.floor(diff / 60000)
|
||
|
|
if (mins < 1) return 'just now'
|
||
|
|
if (mins < 60) return `${mins}m ago`
|
||
|
|
const hrs = Math.floor(mins / 60)
|
||
|
|
if (hrs < 24) return `${hrs}h ago`
|
||
|
|
const days = Math.floor(hrs / 24)
|
||
|
|
return `${days}d ago`
|
||
|
|
}
|
||
|
|
|
||
|
|
export function RecentPlays({ onClose, onPlay }: { onClose: () => void; onPlay: (slug: string) => void }) {
|
||
|
|
const [plays, setPlays] = useState<RecentPlay[] | null>(null)
|
||
|
|
const [loading, setLoading] = useState(true)
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
getRecentPlays().then((data) => {
|
||
|
|
setPlays(data)
|
||
|
|
setLoading(false)
|
||
|
|
})
|
||
|
|
}, [])
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
function onKey(e: KeyboardEvent) {
|
||
|
|
if (e.key === 'Escape') onClose()
|
||
|
|
}
|
||
|
|
window.addEventListener('keydown', onKey)
|
||
|
|
return () => window.removeEventListener('keydown', onKey)
|
||
|
|
}, [onClose])
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className={styles.recentOverlay} onClick={onClose}>
|
||
|
|
<div className={styles.recentPanel} onClick={(e) => e.stopPropagation()}>
|
||
|
|
<div className={styles.recentHeader}>
|
||
|
|
<h2>Recent plays</h2>
|
||
|
|
<button className={styles.recentClose} onClick={onClose}>✕</button>
|
||
|
|
</div>
|
||
|
|
<div className={styles.recentList}>
|
||
|
|
{loading && <p className={styles.recentEmpty}>Loading...</p>}
|
||
|
|
{!loading && (!plays || plays.length === 0) && (
|
||
|
|
<p className={styles.recentEmpty}>No play history yet</p>
|
||
|
|
)}
|
||
|
|
{plays?.map((p, i) => (
|
||
|
|
<div
|
||
|
|
key={`${p.track_slug}-${i}`}
|
||
|
|
className={styles.recentItem}
|
||
|
|
onClick={() => { onPlay(p.track_slug); onClose() }}
|
||
|
|
>
|
||
|
|
<div className={styles.recentTrack}>
|
||
|
|
<div className={styles.recentTitle}>{p.track_title}</div>
|
||
|
|
<div className={styles.recentArtist}>{p.artist_name}</div>
|
||
|
|
</div>
|
||
|
|
<div className={styles.recentTime}>{timeAgo(p.played_at)}</div>
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|