quackscape/assets/js/userarea.js
Kumi d921c2dcad
feat: add media resolution updates & API endpoints
Introduced a new API endpoint to retrieve media for a given category,
enhancing the user experience by dynamically updating thumbnails
post-upload based on available resolutions. This connects the frontend
to the backend efficiently, ensuring users can see the immediate impact
of their uploads. Additionally, updated serializers and views in the
backend to support this functionality, alongside improving code comments
for future development clarity.

- Implemented `getCategoryMedia` in the JS API for fetching media
resolutions.
- Enabled dynamic thumbnail updates in the user area post file upload,
improving visual feedback.
- Extended the Django REST framework routers to include the new media
endpoint, facilitating easier access to media items.
- Updated the `OriginalMediaSerializer` to include `category` for more
detailed media information.
- Enriched task and views files with necessary TODO comments to guide
future enhancements and exception handling.

This change significantly improves the content management workflow,
making it more interactive and user-friendly.
2024-03-17 08:35:40 +01:00

151 lines
4.6 KiB
JavaScript

import "../scss/frontend.scss";
import "../css/userarea.css";
import { getCategoryMedia, getCookie, getElementById } from "./api";
import { Tab } from "bootstrap";
import DataTable from "datatables.net-dt";
let mediaTable = new DataTable("#mediaTable");
let scenesTable = new DataTable("#scenesTable");
let permissionsTable = new DataTable("#permissionsTable");
/* Uploads */
document.querySelectorAll(".drop-zone__input").forEach((inputElement) => {
const dropZoneElement = inputElement.closest(".drop-zone");
dropZoneElement.addEventListener("click", (e) => {
inputElement.click();
});
dropZoneElement.addEventListener("dragover", (e) => {
e.preventDefault();
dropZoneElement.classList.add("drop-zone--over");
});
["dragleave", "dragend", "drop"].forEach((type) => {
dropZoneElement.addEventListener(type, (e) => {
dropZoneElement.classList.remove("drop-zone--over");
});
});
dropZoneElement.addEventListener("drop", (e) => {
e.preventDefault();
if (e.dataTransfer.files.length) {
inputElement.files = e.dataTransfer.files;
handleFiles(inputElement.files);
}
});
inputElement.addEventListener("change", (e) => {
if (inputElement.files.length) {
handleFiles(inputElement.files);
}
});
});
function handleFiles(files) {
const uploadStatus = document.getElementById("uploadStatus");
Array.from(files).forEach((file) => {
const fileRow = document.createElement("div");
fileRow.classList.add(
"row",
"align-items-center",
"mb-2",
"file-upload-wrapper"
);
const thumbnailCol = document.createElement("div");
thumbnailCol.classList.add("col-2");
const thumbnail = document.createElement("img");
thumbnail.classList.add("img-fluid", "thumbnail");
thumbnail.src = ""; // TODO: Add a loading spinner or something here
thumbnailCol.appendChild(thumbnail);
const fileNameCol = document.createElement("div");
fileNameCol.classList.add("col-7");
const fileName = document.createElement("span");
fileName.classList.add("file-name");
fileName.textContent = file.name;
fileNameCol.appendChild(fileName);
const progressCol = document.createElement("div");
progressCol.classList.add("col-3");
const progressBar = document.createElement("div");
progressBar.classList.add("progress");
const progressBarInner = document.createElement("div");
progressBarInner.classList.add("progress-bar");
progressBarInner.setAttribute("role", "progressbar");
progressBarInner.setAttribute("aria-valuemin", "0");
progressBarInner.setAttribute("aria-valuemax", "100");
progressBarInner.style.width = "0%";
progressBar.appendChild(progressBarInner);
progressCol.appendChild(progressBar);
fileRow.appendChild(thumbnailCol);
fileRow.appendChild(fileNameCol);
fileRow.appendChild(progressCol);
uploadStatus.prepend(fileRow);
uploadFile(file, progressBarInner, thumbnail);
});
}
function uploadFile(file, progressBar, thumbnail) {
const xhr = new XMLHttpRequest();
const formData = new FormData();
formData.append("file", file);
formData.append("csrfmiddlewaretoken", getCookie("csrftoken"));
if (file.type.startsWith("image")) {
formData.append("media_type", "image");
} else if (file.type.startsWith("video")) {
formData.append("media_type", "video");
} else {
formData.append("media_type", "other");
}
formData.append("title", file.name);
xhr.upload.addEventListener("progress", (e) => {
if (e.lengthComputable) {
if (e.loaded == e.total) {
progressBar.style.width = "100%";
progressBar.textContent = "Processing...";
} else {
const percentComplete = (e.loaded / e.total) * 100;
progressBar.style.width = `${percentComplete}%`;
progressBar.textContent = `${Math.round(percentComplete)}%`;
}
}
});
xhr.open("POST", document.location.href, true);
xhr.onload = () => {
if (xhr.status === 201) {
const response = JSON.parse(xhr.responseText);
progressBar.textContent = "Converting...";
let thumbnailCheck = setInterval(() => {
getCategoryMedia(response.category, response.id).then((media) => {
if (media.obj.resolutions.length > 0) {
clearInterval(thumbnailCheck);
thumbnail.src = media.obj.resolutions[0].file;
progressBar.classList.add("bg-success");
progressBar.textContent = "Done!";
}
});
}, 2000);
} else {
progressBar.classList.add("bg-danger");
progressBar.textContent = "Error!";
}
};
xhr.send(formData);
}