Phill Pover 68eb24dc82
Some checks failed
Music Collection CI Workflow / test (./backend) (push) Successful in 29s
Music Collection CI Workflow / test (./frontend) (push) Successful in 36s
Music Collection CI Workflow / build-and-push-images (./backend/Dockerfile, git.anatid.net/tabris/music-collection-backend, ./backend) (push) Successful in 51s
Music Collection CI Workflow / build-and-push-images (./frontend/Dockerfile, git.anatid.net/tabris/music-collection-frontend, ./frontend) (push) Failing after 1m25s
Music Collection CI Workflow / deploy (push) Has been skipped
Adding a isblank check
2025-04-07 02:03:58 +01:00

188 lines
6.5 KiB
TypeScript

'use client'
import { FormEvent, MouseEvent, useState, useEffect } from 'react';
import { useParams } from 'next/navigation'
import { Album } from '@/entities/album.entity';
import { Song } from '@/entities/song.entity';
import { TimeUtils } from '@/utils/time.util';
import { StringUtils } from '@/utils/string.util';
import { createSong, deleteSong, getAlbum, getSong, updateSong } from '@/app/actions';
import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal';
import { IconButton } from '@mui/material';
import { AddCircleOutline, Delete, Edit } from '@mui/icons-material';
export default function Page() {
const [album, setAlbum] = useState<Album>();
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
const [formAlbumId, setFormAlbumId] = useState("");
const [formSongId, setFormSongId] = useState("");
const [formSongTitle, setFormSongTitle] = useState("");
const [formSongDuration, setFormSongDuration] = useState("");
const [formSongTrackNumber, setFormSongTrackNumber] = useState("");
const [formModalTitle, setFormModalTitle] = useState("Add Song");
const [formModalButtonLabel, setFormModalButtonLabel] = useState("Add");
const params = useParams<{ id: string }>();
const albumId = params.id;
useEffect(() => {
async function fetchAlbum(albumId: string) {
try {
const data = await getAlbum(parseInt(albumId));
setAlbum(data);
} catch (error) {
console.error(`Error getting album with id ${albumId}`, error);
}
}
fetchAlbum(albumId);
}, [albumId]);
const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
handleClose();
const formData = new FormData(event.currentTarget);
try {
if (StringUtils.isBlank(formData.get('id'))) {
const data = await createSong(formData);
console.log(data);
} else {
const data = await updateSong(formData);
console.log(data);
}
} catch (error) {
console.error("Error creating Song: ", error);
}
}
const handleCreate = async () => {
setFormModalTitle("Add Song");
setFormModalButtonLabel("Add");
setFormAlbumId(albumId);
setFormSongId("");
setFormSongTitle("");
setFormSongDuration("");
setFormSongTrackNumber("");
handleShow();
}
const handleEdit = async (event: MouseEvent<HTMLElement>) => {
const songId = event.currentTarget.getAttribute('song-id');
if (songId) {
try {
const data = await getSong(parseInt(songId));
setFormModalTitle("Edit Song");
setFormModalButtonLabel("Save");
setFormSongId(data.id)
setFormAlbumId(albumId);
setFormSongTitle(data.title);
setFormSongDuration(data.duration);
setFormSongTrackNumber(data.trackNumber);
handleShow();
} catch (error) {
console.error(`Error getting song with ID ${songId}:`, error);
}
} else {
console.error("Couldn't get ID of clicked element");
}
}
const handleDelete = async (event: MouseEvent<HTMLElement>) => {
const songId = event.currentTarget.getAttribute('song-id');
if (songId) {
try {
await deleteSong(parseInt(songId));
} catch (error) {
console.error(`Error deleting song with ID ${songId}:`, error);
}
} else {
console.error("Couldn't get ID of clicked element");
}
}
if (!album) return <div>Loading...</div>
return (
<>
<div className="container">
<div className="eight columns">
<div>
<em>{album.title}</em> by {album.artist} ({album.genre})
</div>
<IconButton aria-label="Add Album" size="large" onClick={handleCreate}>
<AddCircleOutline fontSize="inherit" color="success"/>
</IconButton>
<table className="u-full-width">
<thead>
<tr>
<th>#</th>
<th>Title</th>
<th>Duration</th>
<th>Controls</th>
</tr>
</thead>
<tbody>
{album.songs.map((song: Song) => (
<tr key={song.id}>
<td>{song.trackNumber}</td>
<td>{song.title}</td>
<td>{TimeUtils.fancyTimeFormat(song.duration)}</td>
<td>
<IconButton aria-label="Edit Song" size="small" song-id={song.id.toString()} onClick={handleEdit}>
<Edit fontSize="inherit" color="success"/>
</IconButton>
<IconButton aria-label="Delete Song" size="small" song-id={song.id.toString()} onClick={handleDelete}>
<Delete fontSize="inherit" color="success"/>
</IconButton>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
<Modal
show={show}
onHide={handleClose}
backdrop="static"
keyboard={false}
>
<Modal.Header closeButton>
<Modal.Title>{formModalTitle}</Modal.Title>
</Modal.Header>
<Modal.Body>
<div>
<form onSubmit={handleSubmit}>
<input name="id" id="song-id" value={formSongId} type="hidden" />
<input name="albumId" id="album-id" value={formAlbumId} type="hidden" />
<div className="row">
<div className="six columns">
<label htmlFor="song-title">Song Title</label><input type="text" name="title" id="song-title" defaultValue={formSongTitle} />
</div>
<div className="six columns">
<label htmlFor="song-duration">Duration (seconds)</label><input type="text" name="duration" id="song-duration" defaultValue={formSongDuration} />
</div>
</div>
<div className="row">
<div className="six columns">
<label htmlFor="song-trackNumber">Track Number</label><input type="text" name="trackNumber" id="song-trackNumber" defaultValue={formSongTrackNumber} />
</div>
</div>
<Button variant="primary" type="submit">{formModalButtonLabel}</Button>
</form>
</div>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
</Modal.Footer>
</Modal>
</>
);
}