<section class="film-table-container">
<h1>Manage Films</h1>
<table id="film-table">
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Duration (min)</th>
<th>Age Limit</th>
<th>Uploaded</th>
<th>Serial Number</th>
<th>Image Path</th>
<th>Release Year</th>
<th>Overview</th>
<th>Issued Date</th>
<th>Languages</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<!-- rows will be loaded with js -->
</tbody>
</table>
</section>
<script>
document.addEventListener('DOMContentLoaded', async () => {
const tbody = document.querySelector('#film-table tbody');
try {
const langRes = await fetch('Functions/Languages/getLanguages.php');
if (!langRes.ok) {
showMessage('error', `Failed to fetch languages: ${langRes.status} ${langRes.statusText}`);
return;
}
let langJson;
try {
langJson = await langRes.json();
} catch {
showMessage('error', 'Invalid JSON received for languages.');
return;
}
const languages = langJson.languages;
const filmRes = await fetch('Functions/Films/getFilms.php');
if (!filmRes.ok) {
showMessage('error', `Failed to fetch films: ${filmRes.status} ${filmRes.statusText}`);
return;
}
let filmJson;
try {
filmJson = await filmRes.json();
} catch {
showMessage('error', 'Invalid JSON received for films.');
return;
}
const filmData = filmJson.movies;
function createLanguageSelect(selectedLangs = []) {
const select = document.createElement('select');
select.classList.add('film-languages');
select.multiple = true;
select.disabled = true;
select.style.width = '150px';
select.size = 3;
languages.forEach(lang => {
const option = document.createElement('option');
option.value = lang.pk_availableLanguage;
option.textContent = lang.languageName;
if (selectedLangs.includes(Number(lang.pk_availableLanguage))) {
option.selected = true;
}
select.appendChild(option);
});
return select;
}
filmData.forEach(film => {
const tr = document.createElement('tr');
tr.dataset.id = film.pk_filmID;
const langSelect = createLanguageSelect(film.languages || []);
tr.innerHTML = `
<td>${film.pk_filmID}</td>
<td><input class="film-title" type="text" value="${film.title}" disabled></td>
<td><input class="film-duration" type="number" value="${film.duration}" disabled></td>
<td><input class="film-ageLimit" type="number" value="${film.ageLimit}" disabled></td>
<td><input class="film-uploaded" type="checkbox" ${film.uploaded == 1 ? 'checked' : ''} disabled></td>
<td><input class="film-serial" type="text" value="${film.serialNumber}" disabled></td>
<td><input class="film-imagePath" type="text" value="${film.imagePath}" disabled></td>
<td><input class="film-releaseYear" type="number" value="${film.releaseYear || ''}" disabled></td>
<td><textarea class="film-overview" rows="3" disabled>${film.overview || ''}</textarea></td>
<td><input class="film-issuedDate" type="datetime-local" value="${new Date(film.issuedDate).toISOString().slice(0, 16)}" disabled></td>
<td></td>
<td>
<button class="btn-edit">Edit</button>
<button class="btn-save" style="display:none;">Save</button>
<button class="btn-delete">Delete</button>
</td>
`;
tr.children[10].appendChild(langSelect);
tbody.appendChild(tr);
});
tbody.addEventListener('click', async (e) => {
const tr = e.target.closest('tr');
if (!tr) return;
const inputs = tr.querySelectorAll('input, select, textarea');
if (e.target.classList.contains('btn-edit')) {
inputs.forEach(input => input.disabled = false);
tr.querySelector('.btn-edit').style.display = 'none';
tr.querySelector('.btn-save').style.display = 'inline-block';
}
else if (e.target.classList.contains('btn-save')) {
const langSelect = tr.querySelector('select.film-languages');
// get selected options from langSelect and return their values as integers
const selectedLanguages = Array.from(langSelect.selectedOptions).map(opt => parseInt(opt.value));
/* console.log(selectedLanguages); */
const data = {
id: tr.dataset.id,
title: tr.querySelector('.film-title').value,
duration: tr.querySelector('.film-duration').value,
ageLimit: tr.querySelector('.film-ageLimit').value,
uploaded: tr.querySelector('.film-uploaded').checked ? 1 : 0,
serialNumber: tr.querySelector('.film-serial').value,
imagePath: tr.querySelector('.film-imagePath').value,
releaseYear: tr.querySelector('.film-releaseYear').value,
overview: tr.querySelector('.film-overview').value,
issuedDate: tr.querySelector('.film-issuedDate').value,
languages: selectedLanguages
};
try {
const res = await fetch('Functions/Films/updateFilm.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!res.ok) {
showMessage('error', `Update failed: ${res.status} ${res.statusText}`);
return;
}
const json = await res.json();
if (json.status !== 'success') {
showMessage('error', json.message || 'Unknown error updating film.');
return;
}
inputs.forEach(input => input.disabled = true);
tr.querySelector('.btn-edit').style.display = 'inline-block';
tr.querySelector('.btn-save').style.display = 'none';
showMessage('success', 'Film updated successfully.');
} catch {
showMessage('error', 'Error communicating with server.');
}
}
else if (e.target.classList.contains('btn-delete')) {
const filmTitle = tr.querySelector('.film-title').value;
if (!confirm(`Are you sure you want to delete the film "${filmTitle}"?`)) return;
try {
const res = await fetch('Functions/Films/deleteFilm.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: tr.dataset.id })
});
const json = await res.json();
if (json.status === 'error') {
// server returned error with message
showMessage('error', json.message || 'Unknown error deleting film.');
return;
}
if (!res.ok) {
// HTTP error but no JSON error message
showMessage('error', `Delete failed: ${res.status} ${res.statusText}`);
return;
}
tr.remove();
showMessage('success', 'Film deleted successfully.');
} catch {
showMessage('error', 'Error communicating with server.');
}
}
});
} catch (err) {
showMessage('error', 'Unexpected error: ' + err.message);
}
});
</script>