Files
furumi-ng/furumi-node-player/client/src/components/header/RecentPlays.tsx
T

65 lines
2.2 KiB
TypeScript
Raw Normal View History

2026-04-08 17:08:54 +01:00
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}>&#10005;</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>
)
}