Debut gestion playlist dans api + creation playlist front

This commit is contained in:
Heloise BOUSSON 2024-06-27 19:40:54 +02:00
parent 35a6e4266f
commit 286e660f63
5 changed files with 261 additions and 20 deletions

41
api/index.php Normal file → Executable file
View File

@ -8,6 +8,9 @@ MusicAPI::init();
Flight::route('GET /songs(/@id)', 'findSong'); Flight::route('GET /songs(/@id)', 'findSong');
Flight::route('GET /albums(/@id)', 'findAlbum'); Flight::route('GET /albums(/@id)', 'findAlbum');
Flight::route('GET /artists(/@id)', 'findArtist'); Flight::route('GET /artists(/@id)', 'findArtist');
Flight::route('GET /playlists(/@id)', 'findPlaylist');
Flight::route('POST /playlists', 'createPlaylist');
Flight::route('DELETE /playlists/@id', 'deletePlaylist');
function findSong($id = null) function findSong($id = null)
{ {
@ -74,6 +77,44 @@ function findArtist($id = null)
} }
} }
function findPlaylist($id = null)
{
if ($id === null) {
$res = MusicAPI::findAllPlaylists();
Flight::json(["results" => $res]);
} else {
$res = MusicAPI::findPlaylistById($id);
if ($res) {
Flight::json($res);
} else {
Flight::halt(404);
}
}
}
function createPlaylist()
{
$data = Flight::request()->data;
$name = $data->name ?? null;
if ($name) {
$id = MusicAPI::createPlaylist($name);
Flight::json(["id" => $id], 201);
} else {
Flight::halt(400, "Missing name parameter");
}
}
function deletePlaylist($id)
{
$res = MusicAPI::deletePlaylist($id);
if ($res) {
Flight::json(["status" => "success"]);
} else {
Flight::halt(404);
}
}
Flight::start(); Flight::start();
?> ?>

33
api/model/model.php Normal file → Executable file
View File

@ -3,10 +3,10 @@
class Database class Database
{ {
private $host; private $host;
private $user; private $user;
private $pass; private $pass;
private $dbname; private $dbname;
private $pdo; private $pdo;
public function __construct($host, $user, $pass, $dbname) { public function __construct($host, $user, $pass, $dbname) {
$this->host = $host; $this->host = $host;
@ -127,5 +127,32 @@ class MusicAPI
return $stmt->fetchAll(); return $stmt->fetchAll();
} }
// Fonctions gestion des playlists
public static function findAllPlaylists()
{
$sql = "SELECT * FROM Playlist;";
$stmt = self::$db->query($sql);
return $stmt->fetchAll();
}
public static function findPlaylistById($id)
{
$sql = "SELECT * FROM Playlist WHERE Playlist.id=?;";
$stmt = self::$db->query($sql, [$id]);
return $stmt->fetchAll();
}
public static function createPlaylist($name)
{
$sql = "INSERT INTO Playlist (name) VALUES (?);";
self::$db->query($sql, [$name]);
return self::$db->lastInsertId();
}
public static function deletePlaylist($id)
{
$sql = "DELETE FROM Playlist WHERE id=?;";
return self::$db->query($sql, [$id]);
}
} }
?> ?>

View File

@ -1,11 +1,13 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Riot App</title> <title>Riot App</title>
<script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.tailwindcss.com"></script>
</head> </head>
<body class="bg-neutral-50">
<body class="bg-neutral-50">
<onzer></onzer> <onzer></onzer>
@ -16,16 +18,20 @@
<script type="javascript" src="./onzer.riot"></script> <script type="javascript" src="./onzer.riot"></script>
<script type="text/javascript"> <script type="text/javascript">
function fetch_data(){ function fetch_data() {
return fetch("https://dwarves.iut-fbleau.fr/~fauvet/api/albums").then(response => { return fetch("https://dwarves.iut-fbleau.fr/~fauvet/api/albums").then(response => {
return response.json(); return response.json();
} ) })
} }
riot.compile().then(() => { riot.compile().then(() => {
riot.mount('onzer', {items: fetch_data()}); riot.mount('onzer', { items: fetch_data() });
}) })
</script> </script>
</body> <script src="./navigation.riot" type="riot"></script>
<script src="./playlist-form.riot" type="riot"></script>
</body>
</html> </html>

View File

@ -14,35 +14,56 @@
<input class="flex-grow-1 border-solid border bg-emerald-100 w-half rounded-lg border-emerald-300 border h-20 pl-6 grow" <input class="flex-grow-1 border-solid border bg-emerald-100 w-half rounded-lg border-emerald-300 border h-20 pl-6 grow"
placeholder={ state.placeholder } onkeyup={ edit } /> placeholder={ state.placeholder } onkeyup={ edit } />
<input type="button" value="Playlists" <input type="button" value="Playlists"
class="ml-2 border-solid bg-emerald-300 border rounded-lg border-emerald-600 mb-4 h-20 w-48 mt-2"/> class="ml-2 border-solid bg-emerald-300 border rounded-lg border-emerald-600 mb-4 h-20 w-48 mt-2"/>
</div> </div>
</form> </form>
</div> </div>
<div class="flex flex-wrap px-12 justify-between mt-8"> <div if={ state.items && state.items.length > 0 } class="flex flex-wrap px-12 justify-between mt-8">
<div each={ album in state.items.slice((state.page - 1) * 9, state.page * 9) } class="item mb-4 border border-solid rounded-lg h-64 flex justify-center items-center"> <div each={ item in state.items.slice((state.page - 1) * 9, state.page * 9) } class="item mb-4 border border-solid rounded-lg h-64 flex justify-center items-center"
<p> { album.name } </p> style={ state.search === 'songs' ? 'width: 100%;' : '' }>
<div class="text-center">
<p>{ item.name }</p>
<button if={ state.search === 'songs' } onclick={ () => addSong(item) } class="add-button">Ajouter</button>
</div>
</div> </div>
</div> </div>
<div if={ !state.items || state.items.length === 0 } class="no-results">
<p>Aucun résultat trouvé.</p>
</div>
<div class="pagination"> <div class="pagination">
<button onclick={prevPage} disabled={state.page === 1}>Previous</button> <button onclick={prevPage} disabled={state.page === 1}>Previous</button>
<span>Page {state.page} of {state.totalPages}</span> <span>Page {state.page} of {state.totalPages}</span>
<button onclick={nextPage} disabled={state.page === state.totalPages}>Next</button> <button onclick={nextPage} disabled={state.page === state.totalPages}>Next</button>
</div> </div>
<!-- Modal pour le formulaire de création de playlist -->
<div class="modal" if={ state.showModal }>
<div class="modal-content">
<span class="close" onclick={ closeModal }>&times;</span>
<playlist-form></playlist-form>
</div>
</div>
<script> <script>
riot.compile().then(() => {
riot.mount('playlist-form');
})
export default { export default {
async onBeforeMount(props){ async onBeforeMount(props) {
let data = await props.items; let data = await props.items;
this.state = { this.state = {
placeholder: "Rechercher dans les albums", placeholder: "Rechercher dans les albums",
items: data.results, items: data.results || [],
search: "albums", search: "albums",
filter: undefined, filter: undefined,
id: undefined, id: undefined,
page: 1, page: 1,
totalPages: Math.ceil(data.results.length / 9), totalPages: Math.ceil((data.results || []).length / 9),
showModal: false,
}; };
this.paintButton(); this.paintButton();
this.album_style = "isActivate"; this.album_style = "isActivate";
@ -79,16 +100,29 @@
}, },
async fetchData(){ async fetchData(){
let data = await this.execQuery(this.state.search, this.state.filter, this.state.id); let data = await this.execQuery(this.state.search, this.state.filter, this.state.id);
this.state.items = data.results; this.state.items = data.results || [];
this.state.totalPages = Math.ceil(data.results.length / 9); this.state.totalPages = Math.ceil((data.results || []).length / 9);
this.update(); this.update();
}, },
async fetchPlaylists() {
try {
const response = await fetch('https://dwarves.iut-fbleau.fr/~fauvet/api/playlists');
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
console.log('Playlists:', data);
// Utilisez les données des playlists comme nécessaire ici
} catch (error) {
console.error('Error fetching playlists:', error);
}
},
paintButton(){ paintButton(){
this.album_style = "isDeactivate"; this.album_style = "isDeactivate";
this.artist_style = "isDeactivate"; this.artist_style = "isDeactivate";
this.song_style = "isDeactivate"; this.song_style = "isDeactivate";
}, },
execQuery(table, filter = undefined, id = undefined){ execQuery(table, filter = undefined, id = undefined){
let baseHttpRequest = "https://dwarves.iut-fbleau.fr/~fauvet/api/"; let baseHttpRequest = "https://dwarves.iut-fbleau.fr/~fauvet/api/";
let computeHttpRequest; let computeHttpRequest;
if(filter !== undefined){ if(filter !== undefined){
@ -106,6 +140,19 @@
} }
return fetch(computeHttpRequest).then(response => response.json()); return fetch(computeHttpRequest).then(response => response.json());
}, },
openModal() {
this.state.showModal = true;
this.update();
},
closeModal() {
this.state.showModal = false;
this.update();
},
addSong(item) {
console.log("Ajouter le titre:", item);
// Ajoutez ici le code pour gérer l'ajout du titre à une playlist ou une autre action
this.openModal(); // Appel à openModal pour ouvrir le modal
},
prevPage() { prevPage() {
if (this.state.page > 1) { if (this.state.page > 1) {
this.state.page -= 1; this.state.page -= 1;
@ -134,6 +181,9 @@
border-color: #6EE7B7; border-color: #6EE7B7;
width: 32%; width: 32%;
} }
.item[song] {
width: 100%;
}
.pagination { .pagination {
display: flex; display: flex;
justify-content: center; justify-content: center;
@ -152,5 +202,59 @@
background-color: #D1FAE5; background-color: #D1FAE5;
cursor: not-allowed; cursor: not-allowed;
} }
.add-button {
background-color: #34D399;
border: none;
border-radius: 4px;
padding: 8px 16px;
margin-top: 8px;
cursor: pointer;
color: white;
}
.no-results {
text-align: center;
margin-top: 16px;
font-size: 18px;
color: #6B7280;
}
/* Modal */
.modal {
/*display: none; /* Par défaut, le modal est caché */
position: fixed;
z-index: 10;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0,0,0,0.4); /* Fond semi-transparent pour le modal */
}
.modal-content {
background-color: #fefefe;
margin: 10% auto; /* Centre le modal à l'écran */
padding: 20px;
border: 1px solid #888;
width: 80%;
max-width: 600px;
border-radius: 8px;
position: relative;
}
.close {
position: absolute;
top: 10px;
right: 10px;
font-size: 24px;
font-weight: bold;
cursor: pointer;
color: #888;
}
.close:hover,
.close:focus {
color: #000;
}
</style> </style>
</onzer> </onzer>

63
playlist-form.riot Normal file
View File

@ -0,0 +1,63 @@
<playlist-form>
<form onsubmit={handleSubmit}>
<label for="playlist-name">Nom de la playlist</label>
<input type="text" id="playlist-name" name="playlist-name"/>
<button>Créer la playlist</button>
</form>
<script>
this.handleSubmit = async (event) => {
event.preventDefault();
const formData = new FormData(event.target);
const playlistName = formData.get('playlist-name');
try {
const response = await fetch('https://dwarves.iut-fbleau.fr/~fauvet/api/playlists', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({name: playlistName})
});
if(!response.ok) {
throw new Error('Erreur lors de la création de la playlist');
}
event.target.reset();
alert('Playlist créée avec succès !');
} catch(error) {
console.error('Erreur : ', error);
alert('Une erreur est survenue lors de la création de la playlist');
}
}
</script>
<style>
form {
display: flex;
flex-direction: column;
max-width: 300px;
margin: 20px auto;
z-index: 15;
}
label, input {
margin-bottom: 10px;
}
button {
padding: 10px;
background-color: #6EE7B7;
border: none;
color: white;
cursor: pointer;
}
button:hover {
background-color: #059669;
}
</style>
</playlist-form>