101 lines
3.5 KiB
TypeScript
101 lines
3.5 KiB
TypeScript
import type { ReleasePreview } from '../types.js'
|
|
import Cover from '../components/Cover.js'
|
|
|
|
export default function ConfirmView({
|
|
code,
|
|
preview,
|
|
matchAlbumId,
|
|
onSetMatch,
|
|
onClearMatch,
|
|
onAdd,
|
|
adding,
|
|
addError,
|
|
}: {
|
|
code: string | null
|
|
preview: ReleasePreview
|
|
matchAlbumId: number | null
|
|
onSetMatch: (albumId: number) => void
|
|
onClearMatch: () => void
|
|
onAdd: () => void
|
|
adding: boolean
|
|
addError: string | null
|
|
}) {
|
|
const { release, duplicate, ripMatch, matchCandidates } = preview
|
|
return (
|
|
<div className="space-y-4">
|
|
<div className="flex gap-4">
|
|
<Cover src={release.coverUrl ?? release.thumbUrl} alt="" className="size-28 shrink-0" />
|
|
<div className="min-w-0">
|
|
<h2 className="text-lg font-semibold leading-tight">{release.title}</h2>
|
|
<p className="text-neutral-400">{release.artist}</p>
|
|
<p className="text-xs text-neutral-500">
|
|
{[release.year, release.formats.join(', '), release.labels[0], release.catno]
|
|
.filter(Boolean)
|
|
.join(' · ')}
|
|
</p>
|
|
{code && <p className="mt-1 text-xs text-neutral-500">Barcode {code}</p>}
|
|
</div>
|
|
</div>
|
|
|
|
{ripMatch === 'ripped' && (
|
|
<p className="rounded-xl bg-emerald-500/10 px-4 py-3 text-sm text-emerald-400">
|
|
In your digital collection ✓
|
|
</p>
|
|
)}
|
|
{ripMatch === 'not_ripped' && (
|
|
<p className="rounded-xl bg-amber-500/10 px-4 py-3 text-sm text-amber-400">Not ripped yet</p>
|
|
)}
|
|
{ripMatch === 'ambiguous' && (
|
|
<fieldset className="rounded-xl bg-amber-500/10 px-4 py-3 text-sm text-amber-400">
|
|
<legend className="px-1">Possible matches in your library — which one is it?</legend>
|
|
<div className="mt-1 space-y-2">
|
|
{matchCandidates.map((m) => (
|
|
<label key={m.id} className="flex items-center gap-2 text-neutral-200">
|
|
<input
|
|
type="radio"
|
|
name="match"
|
|
checked={matchAlbumId === m.id}
|
|
onChange={() => onSetMatch(m.id)}
|
|
/>
|
|
{m.artist} — {m.title}
|
|
</label>
|
|
))}
|
|
<label className="flex items-center gap-2 text-neutral-200">
|
|
<input type="radio" name="match" checked={matchAlbumId === null} onChange={onClearMatch} />
|
|
None of these — just add it
|
|
</label>
|
|
</div>
|
|
</fieldset>
|
|
)}
|
|
|
|
{duplicate && (
|
|
<p className="rounded-xl bg-red-500/10 px-4 py-3 text-sm text-red-400">
|
|
Heads up: this release is already in your collection.
|
|
</p>
|
|
)}
|
|
|
|
<details className="rounded-xl border border-neutral-800 bg-neutral-900 p-3">
|
|
<summary className="cursor-pointer text-sm text-neutral-300">Tracklist</summary>
|
|
<ol className="mt-2 space-y-1 text-sm text-neutral-400">
|
|
{release.tracklist.map((t, i) => (
|
|
<li key={i} className="flex gap-2">
|
|
<span className="w-8 shrink-0 text-neutral-600">{t.position}</span>
|
|
<span>{t.title}</span>
|
|
</li>
|
|
))}
|
|
</ol>
|
|
</details>
|
|
|
|
{addError && <p className="text-sm text-red-400">{addError}</p>}
|
|
<button
|
|
type="button"
|
|
onClick={onAdd}
|
|
disabled={adding}
|
|
className="w-full rounded-xl bg-emerald-500 py-3 font-medium text-neutral-950 disabled:opacity-50"
|
|
>
|
|
{adding ? 'Adding…' : 'Add to collection'}
|
|
</button>
|
|
</div>
|
|
)
|
|
}
|