Version 1.0.0 - Frontend
This commit is contained in:
257
src/components/Widget/View/UploadFiles.vue
Normal file
257
src/components/Widget/View/UploadFiles.vue
Normal file
@@ -0,0 +1,257 @@
|
||||
<template>
|
||||
<section class="upload-files">
|
||||
<div class="files-header">
|
||||
<h2><Icon icon="fa-folder"/> Mes fichiers</h2>
|
||||
<Box box-class="area-container" padding="close" level="second">
|
||||
<div class="upload-area">
|
||||
<Button :color-lower="status === 'download'" :disabled="status === 'download'" class="upload-button" @click="uploadFile()"><Icon icon="fa-upload"/> Ajouter un fichier</Button>
|
||||
<p v-if="status === 'download'" class="upload-file-name" ref="uploadStatus"><Icon icon='fa-spinner' spin-pulse/> Téléchargement en cours...</p>
|
||||
<p v-else-if="status === 'error'" class="upload-status" ref="uploadStatus"><Error>Erreur lors du téléchargement</Error></p>
|
||||
<p v-else-if="status === 'toohigh'" class="upload-status" ref="uploadStatus"><Error>Le fichier est trop volumineux</Error></p>
|
||||
<p v-else-if="status === 'success'" class="upload-status" ref="uploadStatus"><Success>Fichier téléchargé avec succès</Success></p>
|
||||
<p v-else class="upload-status" ref="uploadStatus">Aucun fichier séléctionné</p>
|
||||
</div>
|
||||
<p class="text-secondary infosup"><Icon icon="fa-circle-info"/> Ce système n'est pas un stockage permanent de données car il dépend du CDN de Discord. Vos fichiers peuvent exprirer à tout moment.</p>
|
||||
</Box>
|
||||
</div>
|
||||
<div v-if="myFiles && myFiles.length > 0" class="uploaded-files">
|
||||
<span v-for="file in myFiles" :key="file.id"><VideoComposable :video="file" delete/></span>
|
||||
</div>
|
||||
<p v-else-if="isLoading" class="none"><Icon icon="fa-spinner" spin-pulse/> Chargement des fichiers...</p>
|
||||
<p v-else class="none"><Icon icon="fa-circle-xmark"/> Aucun fichier enregistré</p>
|
||||
<Modal icon="fa-upload" title="Uploader un fichier" ref="uploadModal">
|
||||
<p>Etes-vous sûr de vouloir uploader ce fichier ?</p>
|
||||
<p class="text-secondary">Ce fichier sera stocké sur le CDN de Discord et sera à jamais accessible. Ne diffusez rien de sensible.</p>
|
||||
<p v-if="fileSelected" class="upload-modal-name"><Icon icon="fa-file"/> {{ fileSelected.name }}</p>
|
||||
<div class="upload-actions">
|
||||
<Button @click="closeModal()">Annuler</Button>
|
||||
<Button @click="confirmUpload()">Confirmer</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</section>
|
||||
</template>
|
||||
<script setup>
|
||||
import Box from '@/components/UI/Box.vue';
|
||||
import Button from '@/components/UI/Button.vue';
|
||||
import Modal from '@/components/UI/Modal.vue';
|
||||
import Success from '@/components/UI/Success.vue';
|
||||
import Error from '@/components/UI/Error.vue';
|
||||
import VideoComposable from '@/components/Widget/VideoComposable.vue';
|
||||
import { IORequest } from '@/utils/IORequest';
|
||||
import { onMounted, onUnmounted, ref } from 'vue';
|
||||
import Events from '@/utils/Events';
|
||||
|
||||
const fileSelected = ref(null);
|
||||
const status = ref(false);
|
||||
const uploadModal = ref(null);
|
||||
const myFiles = ref([]);
|
||||
const isLoading = ref(true);
|
||||
|
||||
onMounted(() => {
|
||||
refreshUploadedFiles();
|
||||
Events.on("video:delete", deleteFile);
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
Events.off("video:delete", deleteFile);
|
||||
});
|
||||
|
||||
function deleteFile(data) {
|
||||
IORequest('/UPLOAD/FILE/DELETE', (response) => {
|
||||
refreshUploadedFiles();
|
||||
}, data.video);
|
||||
}
|
||||
|
||||
function uploadFile() {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'file';
|
||||
input.accept = '.mp3,.wav,.ogg'; // Accept audio files
|
||||
input.onchange = (event) => {
|
||||
const file = event.target.files[0];
|
||||
if (file) {
|
||||
fileSelected.value = file;
|
||||
// Here you would typically handle the file upload to the server
|
||||
console.log(`File selected: ${file.name}`);
|
||||
// Reset the input for future uploads
|
||||
input.value = '';
|
||||
// destroy input
|
||||
input.remove();
|
||||
uploadModal.value.open();
|
||||
} else {
|
||||
fileSelected.value = null;
|
||||
}
|
||||
};
|
||||
input.click();
|
||||
}
|
||||
|
||||
function confirmUpload() {
|
||||
console.log(`Uploading file: ${fileSelected.value.name}`);
|
||||
status.value = 'download';
|
||||
uploadModal.value.close();
|
||||
if(fileSelected.value) {
|
||||
// Send the file to the server
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
const fileBuffer = reader.result;
|
||||
// If it's higher than 300mb
|
||||
if (fileBuffer.byteLength > 300 * 1024 * 1024) {
|
||||
status.value = 'toohigh';
|
||||
console.error('File is too large');
|
||||
return;
|
||||
}
|
||||
IORequest('/UPLOAD/FILE', (response) => {
|
||||
if(!response) {
|
||||
status.value = 'error';
|
||||
} else if(response === "TOOHIGH") {
|
||||
status.value = 'toohigh';
|
||||
} else {
|
||||
status.value = 'success';
|
||||
}
|
||||
refreshUploadedFiles();
|
||||
}, {name: fileSelected.value.name, file: fileBuffer})
|
||||
fileSelected.value = null;
|
||||
};
|
||||
reader.readAsArrayBuffer(fileSelected.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function closeModal() {
|
||||
uploadModal.value.close();
|
||||
fileSelected.value = null;
|
||||
status.value = false;
|
||||
}
|
||||
|
||||
function refreshUploadedFiles() {
|
||||
myFiles.value = [];
|
||||
isLoading.value = true;
|
||||
IORequest('/UPLOAD/FILES', (response) => {
|
||||
if (response) {
|
||||
myFiles.value = response;
|
||||
} else {
|
||||
myFiles.value = [];
|
||||
}
|
||||
isLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
<style scoped>
|
||||
|
||||
.infosup {
|
||||
margin: 0 10px 10px 10px;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
.uploaded-files {
|
||||
flex: 1;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.none {
|
||||
text-align: center;
|
||||
font-size: 1.5em;
|
||||
color: var(--text-secondary);
|
||||
opacity: 0.8;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.files-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.text-secondary {
|
||||
font-size: 0.8em;
|
||||
color: var(--text-secondary);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.upload-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.upload-actions Button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.upload-status {
|
||||
font-size: 0.9em;
|
||||
color: var(--text-secondary);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.upload-file-name {
|
||||
font-size: 1em;
|
||||
color: var(--text-primary);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.upload-modal-name {
|
||||
font-size: 0.8em;
|
||||
color: var(--text-primary);
|
||||
background-color: var(--tertiary);
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 10px;
|
||||
padding: 10px 10px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.upload-files {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px),
|
||||
screen and (max-height: 607px) {
|
||||
.upload-area {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.upload-button {
|
||||
order: 1;
|
||||
}
|
||||
|
||||
.area-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.upload-button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.upload-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.files-header h2 {
|
||||
margin: 0;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user