Changeset db5fb23 for frontend/src/pages
- Timestamp:
- 02/12/26 11:27:23 (5 months ago)
- Branches:
- main
- Children:
- d85e8e3
- Parents:
- 92db381
- File:
-
- 1 edited
-
frontend/src/pages/PublishSong.tsx (modified) (16 diffs)
Legend:
- Unmodified
- Added
- Removed
-
frontend/src/pages/PublishSong.tsx
r92db381 rdb5fb23 23 23 const [genre, setGenre] = useState(""); 24 24 const [link, setLink] = useState(""); 25 const [ _coverFile, setCoverFile] = useState<File | null>(null); // TODO: Use in API call25 const [coverFile, setCoverFile] = useState<File | null>(null); 26 26 const [coverPreview, setCoverPreview] = useState<string | null>(null); 27 27 const [contributors, setContributors] = useState<Contributor[]>([]); … … 93 93 `/users/search?type=ARTIST&q=${encodeURIComponent(query)}&limit=5`, 94 94 ); 95 96 95 const filtered = response.data.filter( 97 96 (artist: ArtistSearchResult) => … … 129 128 } 130 129 131 if (contributors.some((c) => c. username === artist.username)) {130 if (contributors.some((c) => c.id === artist.id)) { 132 131 toast.error("This contributor is already added"); 133 132 return; … … 137 136 ...contributors, 138 137 { 139 username: artist.username,138 id: artist.id, 140 139 fullName: artist.fullName, 141 140 role: selectedContributorRole, … … 148 147 149 148 // Remove contributor 150 const handleRemoveContributor = ( username: string) => {151 setContributors(contributors.filter((c) => c. username !== username));149 const handleRemoveContributor = (id: number) => { 150 setContributors(contributors.filter((c) => c.id !== id)); 152 151 }; 153 152 … … 242 241 } 243 242 244 if (song.contributors.some((c) => c. username === artist.username)) {243 if (song.contributors.some((c) => c.id === artist.id)) { 245 244 toast.error("This contributor is already added"); 246 245 return; … … 249 248 const role = albumSongSelectedRole[songIndex] || ROLE_OPTIONS[0].value; 250 249 const newContributor: Contributor = { 251 username: artist.username,250 id: artist.id, 252 251 fullName: artist.fullName, 253 252 role, … … 263 262 }; 264 263 265 const handleRemoveAlbumSongContributor = ( 266 songIndex: number, 267 username: string, 268 ) => { 264 const handleRemoveAlbumSongContributor = (songIndex: number, id: number) => { 269 265 const song = albumSongs[songIndex]; 270 266 handleAlbumSongChange( 271 267 songIndex, 272 268 "contributors", 273 song.contributors.filter((c) => c. username !== username),269 song.contributors.filter((c) => c.id !== id), 274 270 ); 275 271 }; 276 272 277 // Form submission278 273 const handleSubmit = async (e: React.FormEvent) => { 279 274 e.preventDefault(); 280 275 281 // Validation282 276 if (!title.trim()) { 283 277 toast.error("Please enter a title"); … … 295 289 } 296 290 } else { 297 // Album validation298 291 for (let i = 0; i < albumSongs.length; i++) { 299 292 if (!albumSongs[i].title.trim()) { … … 311 304 312 305 try { 313 // TODO: replace with API call 314 // const formData = new FormData(); 315 // formData.append('title', title); 316 // formData.append('genre', genre); 317 // if (coverFile) formData.append('cover', coverFile); 318 // ... 319 320 // Simulate API call 321 await new Promise((resolve) => setTimeout(resolve, 1000)); 306 const formData = new FormData(); 307 formData.append("title", title); 308 formData.append("genre", genre); 309 if (coverFile) formData.append("cover", coverFile); 310 311 // Helper to append contributors in indexed format for Spring @ModelAttribute 312 const appendContributors = ( 313 formData: FormData, 314 contributors: Contributor[], 315 prefix: string, 316 ) => { 317 contributors.forEach((c, i) => { 318 formData.append(`${prefix}[${i}].id`, c.id.toString()); 319 formData.append(`${prefix}[${i}].artistName`, c.fullName); 320 formData.append(`${prefix}[${i}].role`, c.role); 321 }); 322 }; 323 324 if (releaseType === "album") { 325 // Append album songs in indexed format 326 albumSongs.forEach((song, songIndex) => { 327 formData.append(`albumSongs[${songIndex}].title`, song.title); 328 formData.append(`albumSongs[${songIndex}].link`, song.link); 329 // Append nested contributors for each song 330 song.contributors.forEach((c, contribIndex) => { 331 formData.append( 332 `albumSongs[${songIndex}].contributors[${contribIndex}].id`, 333 c.id.toString(), 334 ); 335 formData.append( 336 `albumSongs[${songIndex}].contributors[${contribIndex}].artistName`, 337 c.fullName, 338 ); 339 formData.append( 340 `albumSongs[${songIndex}].contributors[${contribIndex}].role`, 341 c.role, 342 ); 343 }); 344 }); 345 await axiosInstance.post("/musical-entity/publish/album", formData, { 346 headers: { "Content-Type": "multipart/form-data" }, 347 }); 348 } else { 349 formData.append("link", link); 350 appendContributors(formData, contributors, "contributors"); 351 await axiosInstance.post("/musical-entity/publish/song", formData, { 352 headers: { "Content-Type": "multipart/form-data" }, 353 }); 354 } 322 355 323 356 toast.success( … … 612 645 {contributors.map((contributor) => ( 613 646 <div 614 key={contributor. username}647 key={contributor.id} 615 648 className="flex items-center gap-2 bg-[#282828] rounded-full py-1.5 px-3" 616 649 > … … 626 659 <button 627 660 type="button" 628 onClick={() => 629 handleRemoveContributor(contributor.username) 630 } 661 onClick={() => handleRemoveContributor(contributor.id)} 631 662 className="text-gray-400 hover:text-red-400 transition-colors" 632 663 > … … 687 718 searchResults.map((artist) => ( 688 719 <button 689 key={artist. username}720 key={artist.id} 690 721 type="button" 691 722 onClick={() => handleAddContributor(artist)} … … 808 839 {song.contributors.map((contributor) => ( 809 840 <div 810 key={contributor. username}841 key={contributor.id} 811 842 className="flex items-center gap-2 bg-[#1a1a2e] rounded-full py-1 px-2.5 text-sm" 812 843 > … … 826 857 handleRemoveAlbumSongContributor( 827 858 index, 828 contributor. username,859 contributor.id, 829 860 ) 830 861 } … … 902 933 (artist) => ( 903 934 <button 904 key={artist. username}935 key={artist.id} 905 936 type="button" 906 937 onClick={() =>
Note:
See TracChangeset
for help on using the changeset viewer.
