feat: Add batch genre assignment functionality to song uploads, including UI for selection and post-upload API calls.
This commit is contained in:
@@ -106,6 +106,9 @@ export default function AdminPage() {
|
||||
const [uploadGenreIds, setUploadGenreIds] = useState<number[]>([]);
|
||||
const [uploadExcludeFromGlobal, setUploadExcludeFromGlobal] = useState(false);
|
||||
|
||||
// Batch upload genre selection
|
||||
const [batchUploadGenreIds, setBatchUploadGenreIds] = useState<number[]>([]);
|
||||
|
||||
// AI Categorization state
|
||||
const [isCategorizing, setIsCategorizing] = useState(false);
|
||||
const [categorizationResults, setCategorizationResults] = useState<any>(null);
|
||||
@@ -548,6 +551,28 @@ export default function AdminPage() {
|
||||
setUploadResults(results);
|
||||
setFiles([]);
|
||||
setIsUploading(false);
|
||||
|
||||
// Assign genres to successfully uploaded songs
|
||||
if (batchUploadGenreIds.length > 0) {
|
||||
const successfulUploads = results.filter(r => r.success && r.song);
|
||||
for (const result of successfulUploads) {
|
||||
try {
|
||||
await fetch('/api/songs', {
|
||||
method: 'PUT',
|
||||
headers: getAuthHeaders(),
|
||||
body: JSON.stringify({
|
||||
id: result.song.id,
|
||||
title: result.song.title,
|
||||
artist: result.song.artist,
|
||||
genreIds: batchUploadGenreIds
|
||||
}),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`Failed to assign genres to ${result.song.title}:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fetchSongs();
|
||||
fetchGenres();
|
||||
fetchSpecials(); // Update special counts
|
||||
@@ -564,6 +589,13 @@ export default function AdminPage() {
|
||||
if (failedCount > 0) {
|
||||
msg += `\n❌ ${failedCount} failed`;
|
||||
}
|
||||
if (batchUploadGenreIds.length > 0) {
|
||||
const selectedGenreNames = genres
|
||||
.filter(g => batchUploadGenreIds.includes(g.id))
|
||||
.map(g => g.name)
|
||||
.join(', ');
|
||||
msg += `\n🏷️ Assigned genres: ${selectedGenreNames}`;
|
||||
}
|
||||
msg += '\n\n🤖 Starting auto-categorization...';
|
||||
setMessage(msg);
|
||||
// Small delay to let user see the message
|
||||
@@ -1219,6 +1251,48 @@ export default function AdminPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{ marginBottom: '1rem' }}>
|
||||
<label style={{ fontWeight: '500', display: 'block', marginBottom: '0.5rem' }}>
|
||||
Assign Genres (optional)
|
||||
</label>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem' }}>
|
||||
{genres.map(genre => (
|
||||
<label
|
||||
key={genre.id}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '0.25rem',
|
||||
padding: '0.25rem 0.5rem',
|
||||
background: batchUploadGenreIds.includes(genre.id) ? '#dbeafe' : '#f3f4f6',
|
||||
border: batchUploadGenreIds.includes(genre.id) ? '2px solid #3b82f6' : '2px solid transparent',
|
||||
borderRadius: '0.25rem',
|
||||
cursor: 'pointer',
|
||||
fontSize: '0.875rem',
|
||||
transition: 'all 0.2s'
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={batchUploadGenreIds.includes(genre.id)}
|
||||
onChange={e => {
|
||||
if (e.target.checked) {
|
||||
setBatchUploadGenreIds([...batchUploadGenreIds, genre.id]);
|
||||
} else {
|
||||
setBatchUploadGenreIds(batchUploadGenreIds.filter(id => id !== genre.id));
|
||||
}
|
||||
}}
|
||||
style={{ margin: 0 }}
|
||||
/>
|
||||
{genre.name}
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
<p style={{ fontSize: '0.875rem', color: '#666', marginTop: '0.25rem' }}>
|
||||
Selected genres will be assigned to all uploaded songs.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '1rem' }}>
|
||||
<label style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', cursor: 'pointer' }}>
|
||||
<input
|
||||
|
||||
Reference in New Issue
Block a user