2169 lines
83 KiB
JavaScript
2169 lines
83 KiB
JavaScript
document.addEventListener('DOMContentLoaded', function() {
|
|
document.querySelectorAll('.file-size').forEach(function(element) {
|
|
const size = parseInt(element.getAttribute('data-size'));
|
|
element.textContent = formatFileSize(size);
|
|
});
|
|
|
|
document.getElementById('searchButton').addEventListener('click', searchFiles);
|
|
document.getElementById('newFolderBtn').addEventListener('click', showNewFolderModal);
|
|
|
|
document.querySelectorAll('.delete-folder-button').forEach(button => {
|
|
button.addEventListener('click', function() {
|
|
const folderName = this.getAttribute('data-folder-name');
|
|
confirmDeleteFolder(folderName);
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll('.delete-file-button').forEach(button => {
|
|
button.addEventListener('click', function() {
|
|
const fileName = this.getAttribute('data-file-name');
|
|
confirmDelete(fileName);
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll('.copy-button').forEach(button => {
|
|
button.addEventListener('click', function() {
|
|
const fileUrl = this.getAttribute('data-file-url');
|
|
copyFileLink(fileUrl);
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll('.rename-file-btn').forEach(button => {
|
|
button.addEventListener('click', function() {
|
|
const fileName = this.getAttribute('data-file-name');
|
|
const folderName = this.getAttribute('data-folder-name');
|
|
renameFile(folderName, fileName);
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll('.move-file-btn').forEach(button => {
|
|
button.addEventListener('click', function() {
|
|
const fileName = this.getAttribute('data-file-name');
|
|
showMoveFileModal(fileName);
|
|
});
|
|
});
|
|
|
|
document.getElementById('confirmMoveFile').addEventListener('click', moveFile);
|
|
document.getElementById('themeSwitcher').addEventListener('click', toggleDarkMode);
|
|
|
|
initTheme();
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
const accountDropdownBtn = document.getElementById('accountDropdownBtn');
|
|
const accountDropdownMenu = document.getElementById('accountDropdownMenu');
|
|
|
|
accountDropdownBtn.addEventListener('click', function (e) {
|
|
e.stopPropagation();
|
|
accountDropdownMenu.classList.toggle('show');
|
|
});
|
|
|
|
document.addEventListener('click', function (e) {
|
|
if (!accountDropdownBtn.contains(e.target) && !accountDropdownMenu.contains(e.target)) {
|
|
accountDropdownMenu.classList.remove('show');
|
|
}
|
|
});
|
|
});
|
|
|
|
$('.modal').modal({
|
|
show: false
|
|
});
|
|
|
|
const metadataLink = document.querySelector('a[onclick="displayMetadata()"]');
|
|
if (metadataLink) {
|
|
metadataLink.addEventListener('click', function(event) {
|
|
event.preventDefault();
|
|
displayMetadata();
|
|
});
|
|
}
|
|
|
|
document.querySelectorAll('[onclick^="showFileInfo"]').forEach(link => {
|
|
link.addEventListener('click', function(event) {
|
|
event.preventDefault();
|
|
const fileName = this.getAttribute('onclick').match(/'([^']+)'/)[1];
|
|
showFileInfo(fileName);
|
|
});
|
|
});
|
|
});
|
|
|
|
function formatFileSize(fileSizeInBytes) {
|
|
if (fileSizeInBytes < 1024) return fileSizeInBytes + ' octets';
|
|
else if (fileSizeInBytes < 1048576) return (fileSizeInBytes / 1024).toFixed(2) + ' Ko';
|
|
else if (fileSizeInBytes < 1073741824) return (fileSizeInBytes / 1048576).toFixed(2) + ' Mo';
|
|
else return (fileSizeInBytes / 1073741824).toFixed(2) + ' Go';
|
|
}
|
|
|
|
function searchFiles() {
|
|
const input = document.getElementById('searchInput');
|
|
const filter = input.value.toUpperCase();
|
|
const table = document.getElementById('fileTable');
|
|
const tr = table.getElementsByTagName('tr');
|
|
|
|
for (let i = 1; i < tr.length; i++) {
|
|
const td = tr[i].getElementsByTagName('td')[0];
|
|
if (td) {
|
|
const txtValue = td.textContent || td.innerText;
|
|
if (txtValue.toUpperCase().indexOf(filter) > -1) {
|
|
tr[i].style.display = "";
|
|
} else {
|
|
tr[i].style.display = "none";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function showNewFolderModal() {
|
|
Swal.fire({
|
|
title: 'Nouveau dossier',
|
|
input: 'text',
|
|
inputPlaceholder: 'Entrer le nom du nouveau dossier',
|
|
confirmButtonText: 'Créer',
|
|
showCancelButton: true,
|
|
cancelButtonText: 'Annuler',
|
|
preConfirm: (folderName) => {
|
|
if (!folderName) {
|
|
Swal.showValidationMessage('Le nom du dossier ne peut pas être vide.');
|
|
}
|
|
return folderName;
|
|
}
|
|
}).then(result => {
|
|
if (result.isConfirmed) {
|
|
createNewFolder(result.value);
|
|
}
|
|
});
|
|
}
|
|
|
|
function createNewFolder(folderName) {
|
|
fetch('/api/dpanel/dashboard/newfolder', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ folderName }),
|
|
})
|
|
.then(response => {
|
|
if (response.ok) {
|
|
return response.json();
|
|
} else {
|
|
return response.json().then(error => Promise.reject(error));
|
|
}
|
|
})
|
|
.then(result => {
|
|
Swal.fire({
|
|
position: 'top',
|
|
icon: 'success',
|
|
title: 'Le dossier a été créé avec succès.',
|
|
showConfirmButton: false,
|
|
timer: 2000,
|
|
toast: true
|
|
}).then(() => {
|
|
location.reload();
|
|
});
|
|
})
|
|
.catch(error => {
|
|
Swal.fire({
|
|
position: 'top',
|
|
icon: 'error',
|
|
title: 'Erreur lors de la création du dossier.',
|
|
text: error.message,
|
|
showConfirmButton: false,
|
|
timer: 2350,
|
|
toast: true
|
|
});
|
|
});
|
|
}
|
|
|
|
function confirmDeleteFolder(folderName) {
|
|
Swal.fire({
|
|
title: 'Êtes-vous sûr?',
|
|
text: `La suppression du dossier "${folderName}" est irréversible!`,
|
|
icon: 'warning',
|
|
showCancelButton: true,
|
|
confirmButtonColor: '#d33',
|
|
cancelButtonColor: '#3085d6',
|
|
confirmButtonText: 'Supprimer',
|
|
cancelButtonText: 'Annuler',
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
deleteFolder(folderName);
|
|
}
|
|
});
|
|
}
|
|
|
|
function deleteFolder(folderName) {
|
|
fetch(`/api/dpanel/dashboard/deletefolder/${folderName}`, {
|
|
method: 'DELETE',
|
|
})
|
|
.then(response => {
|
|
if (response.ok) {
|
|
Swal.fire({
|
|
position: 'top',
|
|
icon: 'success',
|
|
title: 'Le dossier a été supprimé avec succès.',
|
|
showConfirmButton: false,
|
|
timer: 1800,
|
|
toast: true
|
|
}).then(() => {
|
|
location.reload();
|
|
});
|
|
} else {
|
|
throw new Error('La suppression du dossier a échoué');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
Swal.fire({
|
|
position: 'top',
|
|
icon: 'error',
|
|
title: error.message,
|
|
showConfirmButton: false,
|
|
timer: 1800,
|
|
toast: true
|
|
});
|
|
});
|
|
}
|
|
|
|
function confirmDelete(filename) {
|
|
Swal.fire({
|
|
title: 'Êtes-vous sûr de vouloir supprimer ce fichier?',
|
|
text: 'Cette action est irréversible!',
|
|
icon: 'warning',
|
|
showCancelButton: true,
|
|
confirmButtonColor: '#d33',
|
|
cancelButtonColor: '#3085d6',
|
|
confirmButtonText: 'Supprimer'
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
deleteFile(filename);
|
|
}
|
|
});
|
|
}
|
|
|
|
function deleteFile(filename) {
|
|
fetch('/api/dpanel/dashboard/delete', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
filename: filename,
|
|
}),
|
|
})
|
|
.then(response => {
|
|
if (response.ok) {
|
|
Swal.fire({
|
|
position: 'top',
|
|
icon: 'success',
|
|
title: 'Le fichier a été supprimé avec succès.',
|
|
showConfirmButton: false,
|
|
timer: 1800,
|
|
toast: true
|
|
}).then(() => {
|
|
location.reload();
|
|
});
|
|
} else {
|
|
throw new Error('La suppression du fichier a échoué');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
Swal.fire({
|
|
position: 'top',
|
|
icon: 'error',
|
|
title: error.message,
|
|
showConfirmButton: false,
|
|
timer: 1800,
|
|
toast: true
|
|
});
|
|
});
|
|
}
|
|
|
|
function copyFileLink(fileUrl) {
|
|
navigator.clipboard.writeText(fileUrl).then(() => {
|
|
Swal.fire({
|
|
position: 'top',
|
|
icon: 'success',
|
|
title: 'Lien copié !',
|
|
showConfirmButton: false,
|
|
timer: 1500,
|
|
toast: true
|
|
});
|
|
}, (err) => {
|
|
console.error('Erreur lors de la copie: ', err);
|
|
});
|
|
}
|
|
|
|
function renameFile(folderName, currentName) {
|
|
Swal.fire({
|
|
title: 'Entrez le nouveau nom',
|
|
input: 'text',
|
|
inputValue: currentName,
|
|
inputPlaceholder: 'Nouveau nom',
|
|
showCancelButton: true,
|
|
confirmButtonText: 'Renommer',
|
|
cancelButtonText: 'Annuler',
|
|
inputValidator: (value) => {
|
|
if (!value) {
|
|
return 'Vous devez entrer un nom de fichier';
|
|
}
|
|
}
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
const newName = result.value;
|
|
fetch(`/api/dpanel/dashboard/rename/${folderName}`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ currentName: currentName, newName: newName }),
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network response was not ok');
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
Swal.fire({
|
|
position: 'top',
|
|
icon: 'success',
|
|
title: 'Le fichier a été renommé avec succès.',
|
|
showConfirmButton: false,
|
|
timer: 1800,
|
|
toast: true,
|
|
}).then(() => {
|
|
location.reload();
|
|
});
|
|
})
|
|
.catch((error) => {
|
|
Swal.fire({
|
|
position: 'top',
|
|
icon: 'error',
|
|
title: 'Erreur lors du renommage du fichier.',
|
|
text: error.message,
|
|
showConfirmButton: false,
|
|
timer: 1800,
|
|
toast: true,
|
|
});
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
function showMoveFileModal(fileName) {
|
|
// Récupérer les dossiers depuis le tableau
|
|
const folders = Array.from(document.querySelectorAll('tr[data-type="folder"]'))
|
|
.map(folderRow => ({
|
|
name: folderRow.dataset.name,
|
|
value: folderRow.dataset.name // On s'assure d'avoir une valeur correcte
|
|
}));
|
|
|
|
Swal.fire({
|
|
title: 'Déplacer le fichier',
|
|
html: `
|
|
<select id="moveFolderSelect" class="folder-select w-full p-2 border rounded">
|
|
<option value="">Choisir un dossier...</option>
|
|
${folders.map(folder => `
|
|
<option value="${folder.value}">${folder.name}</option>
|
|
`).join('')}
|
|
</select>
|
|
`,
|
|
showCancelButton: true,
|
|
confirmButtonText: 'Déplacer',
|
|
cancelButtonText: 'Annuler',
|
|
preConfirm: () => {
|
|
const select = document.getElementById('moveFolderSelect');
|
|
const folderName = select.value;
|
|
if (!folderName) {
|
|
Swal.showValidationMessage('Veuillez sélectionner un dossier');
|
|
return false;
|
|
}
|
|
return folderName; // On retourne directement la valeur du dossier
|
|
}
|
|
}).then((result) => {
|
|
if (result.isConfirmed && result.value) {
|
|
moveFile(fileName, result.value);
|
|
}
|
|
});
|
|
}
|
|
|
|
function moveFile(fileName, folderName) {
|
|
// Log pour debug
|
|
console.log('Moving file:', { fileName, folderName });
|
|
|
|
fetch('/api/dpanel/dashboard/movefile', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
fileName: fileName,
|
|
folderName: folderName // Maintenant c'est une chaîne de caractères valide
|
|
}),
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network response was not ok');
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
if (data.message === "File moved successfully") {
|
|
Swal.fire({
|
|
position: 'top',
|
|
icon: 'success',
|
|
title: 'Le fichier a été déplacé avec succès.',
|
|
showConfirmButton: false,
|
|
timer: 1800,
|
|
toast: true,
|
|
}).then(() => {
|
|
location.reload();
|
|
});
|
|
} else {
|
|
throw new Error(data.error || 'Une erreur est survenue');
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
Swal.fire({
|
|
position: 'top',
|
|
icon: 'error',
|
|
title: 'Erreur lors du déplacement du fichier.',
|
|
text: error.message,
|
|
showConfirmButton: false,
|
|
timer: 1800,
|
|
toast: true,
|
|
});
|
|
});
|
|
}
|
|
|
|
const body = document.body;
|
|
const themeSwitcher = document.getElementById('themeSwitcher');
|
|
|
|
function setTheme(theme) {
|
|
if (theme === 'dark') {
|
|
body.classList.add('dark');
|
|
} else {
|
|
body.classList.remove('dark');
|
|
}
|
|
localStorage.setItem('theme', theme);
|
|
}
|
|
|
|
const savedTheme = localStorage.getItem('theme');
|
|
if (savedTheme) {
|
|
setTheme(savedTheme);
|
|
} else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
|
setTheme('dark');
|
|
}
|
|
|
|
themeSwitcher.addEventListener('click', function() {
|
|
if (body.classList.contains('dark')) {
|
|
setTheme('light');
|
|
} else {
|
|
setTheme('dark');
|
|
}
|
|
});
|
|
|
|
async function showFileInfo(fileName) {
|
|
try {
|
|
const response = await fetch('/api/dpanel/dashboard/getmetadatafile/file_info', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
fileLink: fileName,
|
|
})
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
const fileInfo = data.find(file => file.fileName === fileName);
|
|
|
|
if (!fileInfo) {
|
|
throw new Error(`No information found for the file ${fileName}.`);
|
|
}
|
|
|
|
let html = `<p>Nom du fichier : ${fileInfo.fileName}</p>`;
|
|
if (fileInfo.expiryDate) {
|
|
html += `<p>Date d'expiration : ${fileInfo.expiryDate}</p>`;
|
|
}
|
|
if (fileInfo.password) {
|
|
html += `<p>Mot de passe : Oui</p>`;
|
|
}
|
|
if (fileInfo.userId) {
|
|
html += `<p>Utilisateur : <a href="/api/dpanel/dashboard/getuser/${fileInfo.userId}" target="_blank">${fileInfo.userId}</a></p>`;
|
|
}
|
|
|
|
Swal.fire({
|
|
title: 'Informations sur le fichier',
|
|
html: html,
|
|
confirmButtonText: 'Fermer'
|
|
});
|
|
} catch (error) {
|
|
console.error('Error in showFileInfo:', error);
|
|
Swal.fire({
|
|
position: 'top',
|
|
icon: 'error',
|
|
title: 'Les informations sur le fichier ne sont pas disponibles pour le moment.',
|
|
text: `Erreur : ${error.message}`,
|
|
showConfirmButton: false,
|
|
timer: 1800,
|
|
toast: true,
|
|
});
|
|
}
|
|
}
|
|
|
|
function displayMetadata() {
|
|
fetch('/build-metadata')
|
|
.then(response => response.json())
|
|
.then(metadata => {
|
|
document.getElementById('buildVersion').textContent = metadata.build_version;
|
|
document.getElementById('nodeVersion').textContent = metadata.node_version;
|
|
document.getElementById('expressVersion').textContent = metadata.express_version;
|
|
document.getElementById('buildSha').textContent = metadata.build_sha;
|
|
document.getElementById('osType').textContent = metadata.os_type;
|
|
document.getElementById('osRelease').textContent = metadata.os_release;
|
|
|
|
$('#metadataModal').modal('show');
|
|
})
|
|
.catch(error => {
|
|
console.error('Failed to fetch metadata:', error);
|
|
Swal.fire({
|
|
icon: 'error',
|
|
title: 'Erreur',
|
|
text: 'Impossible de récupérer les métadonnées'
|
|
});
|
|
});
|
|
}
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
// Recherche avec debounce
|
|
const searchInput = document.getElementById('searchInput');
|
|
if (searchInput) {
|
|
let timeout;
|
|
searchInput.addEventListener('input', (e) => {
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(() => {
|
|
const term = e.target.value.toLowerCase();
|
|
document.querySelectorAll('#fileTable tbody tr').forEach(row => {
|
|
const text = row.querySelector('td:first-child').textContent.toLowerCase();
|
|
row.style.display = text.includes(term) ? '' : 'none';
|
|
});
|
|
}, 150);
|
|
});
|
|
}
|
|
|
|
// Gestion des modales
|
|
document.querySelectorAll('[data-toggle="modal"]').forEach(trigger => {
|
|
trigger.addEventListener('click', () => {
|
|
const modal = document.querySelector(trigger.dataset.target);
|
|
if (modal) modal.classList.add('show');
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll('.modal .close, .modal .btn-secondary').forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
const modal = btn.closest('.modal');
|
|
if (modal) modal.classList.remove('show');
|
|
});
|
|
});
|
|
|
|
// Dropdowns
|
|
document.querySelectorAll('.dropdown-toggle').forEach(toggle => {
|
|
toggle.addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
const menu = toggle.nextElementSibling;
|
|
if (!menu) return;
|
|
|
|
// Fermer les autres dropdowns
|
|
document.querySelectorAll('.dropdown-menu.show').forEach(m => {
|
|
if (m !== menu) m.classList.remove('show');
|
|
});
|
|
|
|
menu.classList.toggle('show');
|
|
});
|
|
});
|
|
|
|
// Fermer les dropdowns au clic extérieur
|
|
document.addEventListener('click', () => {
|
|
document.querySelectorAll('.dropdown-menu.show').forEach(menu => {
|
|
menu.classList.remove('show');
|
|
});
|
|
});
|
|
});
|
|
|
|
// Loading overlay
|
|
window.showLoadingState = () => {
|
|
const overlay = document.createElement('div');
|
|
overlay.className = 'loading-overlay animate';
|
|
overlay.innerHTML = '<div class="loading-spinner"></div>';
|
|
document.body.appendChild(overlay);
|
|
};
|
|
|
|
window.hideLoadingState = () => {
|
|
const overlay = document.querySelector('.loading-overlay');
|
|
if (overlay) overlay.remove();
|
|
};
|
|
|
|
// Gestion améliorée de l'état de chargement
|
|
window.showLoadingState = () => {
|
|
const overlay = document.createElement('div');
|
|
overlay.className = 'loading-overlay';
|
|
|
|
const wrapper = document.createElement('div');
|
|
wrapper.className = 'spinner-wrapper';
|
|
|
|
const spinner = document.createElement('div');
|
|
spinner.className = 'loading-spinner';
|
|
|
|
wrapper.appendChild(spinner);
|
|
overlay.appendChild(wrapper);
|
|
document.body.appendChild(overlay);
|
|
|
|
// Force le reflow pour démarrer l'animation
|
|
overlay.offsetHeight;
|
|
overlay.classList.add('show');
|
|
};
|
|
|
|
window.hideLoadingState = () => {
|
|
const overlay = document.querySelector('.loading-overlay');
|
|
if (overlay) {
|
|
overlay.classList.remove('show');
|
|
overlay.addEventListener('transitionend', () => overlay.remove(), { once: true });
|
|
}
|
|
};
|
|
|
|
// Animation des lignes du tableau
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const tableRows = document.querySelectorAll('.table tr');
|
|
tableRows.forEach((row, index) => {
|
|
row.style.setProperty('--row-index', index);
|
|
requestAnimationFrame(() => row.classList.add('show'));
|
|
});
|
|
|
|
// Animation du conteneur principal
|
|
const mainContainer = document.querySelector('.form-container');
|
|
if (mainContainer) {
|
|
requestAnimationFrame(() => mainContainer.classList.add('show'));
|
|
}
|
|
});
|
|
|
|
// Fonction pour les transitions de page
|
|
function transitionToPage(url) {
|
|
document.body.classList.add('page-transition');
|
|
showLoadingState();
|
|
|
|
setTimeout(() => {
|
|
window.location.href = url;
|
|
}, 300);
|
|
}
|
|
|
|
// Amélioration des modales
|
|
function showModal(modalId) {
|
|
const modal = document.querySelector(modalId);
|
|
if (!modal) return;
|
|
|
|
modal.style.display = 'flex';
|
|
requestAnimationFrame(() => {
|
|
modal.classList.add('show');
|
|
modal.querySelector('.modal-content')?.classList.add('show');
|
|
});
|
|
}
|
|
|
|
function hideModal(modalId) {
|
|
const modal = document.querySelector(modalId);
|
|
if (!modal) return;
|
|
|
|
modal.querySelector('.modal-content')?.classList.remove('show');
|
|
modal.classList.remove('show');
|
|
|
|
modal.addEventListener('transitionend', () => {
|
|
modal.style.display = 'none';
|
|
}, { once: true });
|
|
}
|
|
|
|
// État de chargement des boutons
|
|
function setButtonLoading(button, isLoading) {
|
|
if (isLoading) {
|
|
button.classList.add('loading');
|
|
button.dataset.originalText = button.innerHTML;
|
|
button.innerHTML = '';
|
|
} else {
|
|
button.classList.remove('loading');
|
|
if (button.dataset.originalText) {
|
|
button.innerHTML = button.dataset.originalText;
|
|
}
|
|
}
|
|
}
|
|
|
|
function createLoadingScreen() {
|
|
const container = document.createElement('div');
|
|
container.className = 'initial-loading';
|
|
const content = `
|
|
<div class="success-animation">
|
|
<div class="success-icon">
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z" />
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
|
</svg>
|
|
</div>
|
|
<div class="success-text">
|
|
<h2>Vous y êtes presque !</h2>
|
|
<p>Préparation de votre espace de travail...</p>
|
|
<p class="loading-message">Chargement des données</p>
|
|
</div>
|
|
<div class="progress-bar"></div>
|
|
</div>
|
|
`;
|
|
container.innerHTML = content;
|
|
document.body.appendChild(container);
|
|
return container;
|
|
}
|
|
|
|
function initializeLoadingScreen() {
|
|
// Vérifier si c'est la première visite de la session
|
|
const hasSeenAnimation = sessionStorage.getItem('hasSeenLoadingAnimation');
|
|
|
|
if (hasSeenAnimation) {
|
|
// Si l'animation a déjà été vue, initialiser directement le contenu
|
|
const contentWrapper = document.querySelector('.content-wrapper');
|
|
if (contentWrapper) {
|
|
contentWrapper.classList.add('loaded');
|
|
}
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return new Promise((resolve) => {
|
|
const loadingScreen = createLoadingScreen();
|
|
|
|
setTimeout(() => {
|
|
loadingScreen.classList.add('fade-out');
|
|
loadingScreen.addEventListener('animationend', () => {
|
|
loadingScreen.remove();
|
|
// Marquer l'animation comme vue pour cette session
|
|
sessionStorage.setItem('hasSeenLoadingAnimation', 'true');
|
|
resolve();
|
|
}, { once: true });
|
|
}, 2000);
|
|
});
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', async function() {
|
|
try {
|
|
await initializeLoadingScreen();
|
|
const contentWrapper = document.querySelector('.content-wrapper');
|
|
if (contentWrapper) {
|
|
contentWrapper.classList.add('loaded');
|
|
}
|
|
} catch (error) {
|
|
console.error('Erreur lors du chargement:', error);
|
|
}
|
|
});
|
|
|
|
fetch('/build-metadata')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
document.getElementById('version-number').textContent = data.build_version;
|
|
})
|
|
.catch(error => {
|
|
console.error('Error fetching version:', error);
|
|
document.getElementById('version-number').textContent = 'Version indisponible';
|
|
});
|
|
|
|
// Fonction pour afficher les détails de collaboration
|
|
function showCollaborationDetails(itemName, itemType) {
|
|
const modal = $('#collaborationModal');
|
|
const usersContainer = modal.find('.collaboration-users');
|
|
const currentItem = { name: itemName, type: itemType };
|
|
|
|
// Stockage des informations de l'item actuel
|
|
modal.data('currentItem', currentItem);
|
|
|
|
fetch(`/api/dpanel/collaboration/details/${itemType}/${itemName}`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
let userList = '';
|
|
if (data.activeUsers && data.activeUsers.length > 0) {
|
|
userList = data.activeUsers.map(user => {
|
|
const avatarUrl = user.profilePicture || getDefaultAvatar(user.name);
|
|
return `
|
|
<div class="collaboration-user-item">
|
|
<img
|
|
src="${avatarUrl}"
|
|
alt="${user.name}"
|
|
class="collaboration-user-avatar"
|
|
onerror="this.src='${getDefaultAvatar(user.name)}'"
|
|
>
|
|
<div class="collaboration-user-info">
|
|
<div class="collaboration-user-name">${user.name}</div>
|
|
<div class="collaboration-user-status">En ligne</div>
|
|
</div>
|
|
<button class="btn btn-sm btn-outline-danger remove-collab-btn" data-user-id="${user.id}">
|
|
<i class="fas fa-user-minus"></i>
|
|
</button>
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
} else {
|
|
userList = '<div class="text-muted text-center">Aucun utilisateur actif</div>';
|
|
}
|
|
usersContainer.html(userList);
|
|
modal.modal('show');
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
Swal.fire({
|
|
icon: 'error',
|
|
title: 'Erreur',
|
|
text: 'Impossible de charger les détails de la collaboration'
|
|
});
|
|
});
|
|
}
|
|
|
|
// Gestionnaire de recherche d'utilisateurs
|
|
function searchCollabUser(username) {
|
|
if (!username) return;
|
|
|
|
const resultsDiv = $('#searchCollabResults');
|
|
|
|
fetch(`/api/dpanel/collaboration/searchuser?username=${encodeURIComponent(username)}`)
|
|
.then(response => response.json())
|
|
.then(result => {
|
|
if (result.found) {
|
|
const avatarUrl = result.user.profilePicture || getDefaultAvatar(result.user.name);
|
|
resultsDiv.html(`
|
|
<div class="user-result p-2 border rounded d-flex align-items-center justify-content-between">
|
|
<div class="d-flex align-items-center">
|
|
<img
|
|
src="${avatarUrl}"
|
|
alt="${result.user.name}"
|
|
class="user-avatar mr-2"
|
|
style="width: 32px; height: 32px;"
|
|
onerror="this.src='${getDefaultAvatar(result.user.name)}'"
|
|
>
|
|
<span>${result.user.name}</span>
|
|
</div>
|
|
<button class="btn btn-sm btn-primary add-collab-btn" data-user-id="${result.user.id}">
|
|
<i class="fas fa-user-plus"></i> Ajouter
|
|
</button>
|
|
</div>
|
|
`);
|
|
} else {
|
|
resultsDiv.html('<div class="text-danger">Utilisateur non trouvé</div>');
|
|
}
|
|
});
|
|
}
|
|
|
|
// Initialisation des événements de collaboration
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const modal = $('#collaborationModal');
|
|
|
|
// Recherche d'utilisateurs
|
|
$('#searchCollabBtn').on('click', () => {
|
|
const username = $('#searchCollabUser').val().trim();
|
|
searchCollabUser(username);
|
|
});
|
|
|
|
$('#searchCollabUser').on('keypress', (e) => {
|
|
if (e.key === 'Enter') {
|
|
const username = e.target.value.trim();
|
|
searchCollabUser(username);
|
|
}
|
|
});
|
|
|
|
// Gestion de l'ajout de collaborateurs
|
|
$(document).on('click', '.add-collab-btn', function() {
|
|
const userId = $(this).data('user-id');
|
|
const currentItem = modal.data('currentItem');
|
|
|
|
addCollaborator(currentItem.name, currentItem.type, userId);
|
|
});
|
|
|
|
// Gestion de la suppression de collaborateurs
|
|
$(document).on('click', '.remove-collab-btn', function() {
|
|
const userId = $(this).data('user-id');
|
|
const currentItem = modal.data('currentItem');
|
|
|
|
removeCollaborator(currentItem.name, currentItem.type, userId);
|
|
});
|
|
|
|
// Désactivation de la collaboration
|
|
$('#disableCollabBtn').on('click', function() {
|
|
const currentItem = modal.data('currentItem');
|
|
modal.modal('hide');
|
|
toggleCollaboration(currentItem.name, currentItem.type, false);
|
|
});
|
|
});
|
|
|
|
function addCollaborator(itemName, itemType, userId) {
|
|
fetch('/api/dpanel/collaboration/add', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ itemName, itemType, userId })
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
showCollaborationDetails(itemName, itemType); // Rafraîchir la liste
|
|
Swal.fire({
|
|
position: 'top-end',
|
|
icon: 'success',
|
|
title: 'Collaborateur ajouté',
|
|
showConfirmButton: false,
|
|
timer: 1500,
|
|
toast: true
|
|
});
|
|
}
|
|
})
|
|
.catch(error => console.error('Error:', error));
|
|
}
|
|
|
|
function removeCollaborator(itemName, itemType, userId) {
|
|
fetch('/api/dpanel/collaboration/remove', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ itemName, itemType, userId })
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
showCollaborationDetails(itemName, itemType); // Rafraîchir la liste
|
|
Swal.fire({
|
|
position: 'top-end',
|
|
icon: 'success',
|
|
title: 'Collaborateur retiré',
|
|
showConfirmButton: false,
|
|
timer: 1500,
|
|
toast: true
|
|
});
|
|
}
|
|
})
|
|
.catch(error => console.error('Error:', error));
|
|
}
|
|
|
|
// Fonction pour afficher les détails de collaboration
|
|
function showCollaborationDetails(itemName, itemType) {
|
|
// Récupérer le modal
|
|
const modal = $('#collaborationModal');
|
|
const usersContainer = modal.find('.collaboration-users');
|
|
|
|
fetch(`/api/dpanel/collaboration/details/${itemType}/${itemName}`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
let userList = '';
|
|
if (data.activeUsers && data.activeUsers.length > 0) {
|
|
userList = data.activeUsers.map(user => {
|
|
const avatarUrl = user.profilePicture || getDefaultAvatar(user.name);
|
|
return `
|
|
<div class="collaboration-user-item">
|
|
<img
|
|
src="${avatarUrl}"
|
|
alt="${user.name}"
|
|
class="collaboration-user-avatar"
|
|
onerror="this.src='${getDefaultAvatar(user.name)}'"
|
|
>
|
|
<div class="collaboration-user-info">
|
|
<div class="collaboration-user-name">${user.name}</div>
|
|
<div class="collaboration-user-status">En ligne</div>
|
|
</div>
|
|
<button class="btn btn-sm btn-outline-danger remove-collab-btn" data-user-id="${user.id}">
|
|
<i class="fas fa-user-minus"></i>
|
|
</button>
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
} else {
|
|
userList = '<div class="text-muted text-center p-3">Aucun utilisateur actif</div>';
|
|
}
|
|
|
|
usersContainer.html(userList);
|
|
|
|
// Gestionnaire pour la recherche d'utilisateurs
|
|
const searchInput = $('#searchCollabUser');
|
|
const searchBtn = $('#searchCollabBtn');
|
|
const resultsDiv = $('#searchCollabResults');
|
|
|
|
searchBtn.off('click').on('click', () => searchCollabUser(searchInput.val().trim()));
|
|
searchInput.off('keypress').on('keypress', (e) => {
|
|
if (e.key === 'Enter') {
|
|
searchCollabUser(searchInput.val().trim());
|
|
}
|
|
});
|
|
|
|
// Gestionnaire pour la désactivation de la collaboration
|
|
$('#disableCollaborationBtn').off('click').on('click', () => {
|
|
modal.modal('hide');
|
|
toggleCollaboration(itemName, itemType, false);
|
|
});
|
|
|
|
// Afficher le modal
|
|
modal.modal('show');
|
|
})
|
|
.catch(error => {
|
|
console.error('Error fetching collaboration details:', error);
|
|
Swal.fire({
|
|
icon: 'error',
|
|
title: 'Erreur',
|
|
text: 'Impossible de charger les détails de la collaboration'
|
|
});
|
|
});
|
|
}
|
|
|
|
function searchCollabUser(username) {
|
|
if (!username) return;
|
|
|
|
fetch(`/api/dpanel/collaboration/searchuser?username=${encodeURIComponent(username)}`)
|
|
.then(response => response.json())
|
|
.then(result => {
|
|
const resultsDiv = $('#searchCollabResults');
|
|
if (result.found) {
|
|
const avatarUrl = result.user.profilePicture || getDefaultAvatar(result.user.name);
|
|
resultsDiv.html(`
|
|
<div class="user-result p-2 border rounded d-flex align-items-center justify-content-between">
|
|
<div class="d-flex align-items-center">
|
|
<img
|
|
src="${avatarUrl}"
|
|
alt="${result.user.name}"
|
|
class="user-avatar mr-2"
|
|
style="width: 32px; height: 32px;"
|
|
onerror="this.src='${getDefaultAvatar(result.user.name)}'"
|
|
>
|
|
<span>${result.user.name}</span>
|
|
</div>
|
|
<button class="btn btn-sm btn-primary add-collab-btn" data-user-id="${result.user.id}">
|
|
<i class="fas fa-user-plus"></i> Ajouter
|
|
</button>
|
|
</div>
|
|
`);
|
|
} else {
|
|
resultsDiv.html('<div class="text-danger text-center">Utilisateur non trouvé</div>');
|
|
}
|
|
});
|
|
}
|
|
|
|
// Fonction pour gérer l'activation/désactivation de la collaboration
|
|
function toggleCollaboration(itemName, itemType, enable) {
|
|
const itemLabel = itemType === 'folder' ? 'dossier' : 'fichier';
|
|
|
|
const performToggle = () => {
|
|
fetch('/api/dpanel/collaboration/toggle', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
itemName,
|
|
itemType,
|
|
enable
|
|
})
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
updateCollaborationUI({
|
|
itemName,
|
|
itemType,
|
|
isCollaborative: enable,
|
|
activeUsers: data.activeUsers || []
|
|
});
|
|
|
|
Swal.fire({
|
|
position: 'top',
|
|
icon: 'success',
|
|
title: `Collaboration ${enable ? 'activée' : 'désactivée'}`,
|
|
showConfirmButton: false,
|
|
timer: 1500,
|
|
toast: true
|
|
});
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
Swal.fire({
|
|
position: 'top',
|
|
icon: 'error',
|
|
title: 'Erreur lors de la modification de la collaboration',
|
|
showConfirmButton: false,
|
|
timer: 1500,
|
|
toast: true
|
|
});
|
|
});
|
|
};
|
|
|
|
if (!enable) {
|
|
performToggle();
|
|
} else {
|
|
Swal.fire({
|
|
title: 'Activer la collaboration ?',
|
|
text: `D'autres utilisateurs pourront accéder à ce ${itemLabel} en temps réel.`,
|
|
icon: 'question',
|
|
showCancelButton: true,
|
|
confirmButtonText: 'Activer',
|
|
cancelButtonText: 'Annuler'
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
performToggle();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// Fonction pour mettre à jour l'interface utilisateur
|
|
function updateCollaborationUI(data) {
|
|
const row = document.querySelector(`tr[data-name="${data.itemName}"]`);
|
|
if (!row) return;
|
|
|
|
const button = row.querySelector('.toggle-collaboration-btn');
|
|
const nameCell = row.querySelector('td:first-child');
|
|
|
|
if (button) {
|
|
button.setAttribute('data-is-collaborative', data.isCollaborative);
|
|
button.title = data.isCollaborative ? 'Voir les collaborateurs' : 'Activer la collaboration';
|
|
button.classList.toggle('active', data.isCollaborative);
|
|
}
|
|
|
|
let badge = nameCell.querySelector('.collaboration-badge');
|
|
if (data.isCollaborative) {
|
|
if (!badge) {
|
|
badge = document.createElement('span');
|
|
badge.className = 'ml-2 badge badge-info collaboration-badge';
|
|
badge.innerHTML = '<i class="fas fa-users"></i> <span class="active-users-count"></span>';
|
|
nameCell.querySelector('div').appendChild(badge);
|
|
}
|
|
|
|
const countSpan = badge.querySelector('.active-users-count');
|
|
if (data.activeUsers && data.activeUsers.length > 0) {
|
|
badge.classList.remove('badge-secondary');
|
|
badge.classList.add('badge-info');
|
|
countSpan.textContent = ` ${data.activeUsers.length}`;
|
|
badge.title = `Collaborateurs actifs : ${data.activeUsers.map(u => u.name).join(', ')}`;
|
|
} else {
|
|
badge.classList.remove('badge-info');
|
|
badge.classList.add('badge-secondary');
|
|
countSpan.textContent = '';
|
|
badge.title = 'Aucun collaborateur actif';
|
|
}
|
|
} else if (badge) {
|
|
badge.remove();
|
|
}
|
|
}
|
|
|
|
// Initialisation au chargement de la page
|
|
document.addEventListener('DOMContentLoaded', async function() {
|
|
// Initialiser WebSocket
|
|
const ws = new WebSocket(`ws://${window.location.host}`);
|
|
|
|
ws.onmessage = function(event) {
|
|
const data = JSON.parse(event.data);
|
|
if (data.type === 'collaborationStatus') {
|
|
updateCollaborationUI(data);
|
|
}
|
|
};
|
|
|
|
// Charger le statut initial de collaboration pour tous les éléments
|
|
try {
|
|
const response = await fetch('/api/dpanel/collaboration/status');
|
|
const data = await response.json();
|
|
if (data.items) {
|
|
Object.entries(data.items).forEach(([itemId, status]) => {
|
|
// Pour chaque élément dans le fichier collaboration.json
|
|
const [type, name] = itemId.split('-');
|
|
updateCollaborationUI({
|
|
itemName: name,
|
|
itemType: type,
|
|
isCollaborative: status.isCollaborative,
|
|
activeUsers: status.activeUsers
|
|
});
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading collaboration status:', error);
|
|
}
|
|
|
|
// Gestionnaire pour les boutons de collaboration
|
|
document.querySelectorAll('.toggle-collaboration-btn').forEach(button => {
|
|
button.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
const itemName = this.getAttribute('data-item-name');
|
|
const itemType = this.getAttribute('data-item-type');
|
|
const isCollaborative = this.getAttribute('data-is-collaborative') === 'true';
|
|
|
|
if (isCollaborative) {
|
|
showCollaborationDetails(itemName, itemType);
|
|
} else {
|
|
toggleCollaboration(itemName, itemType, !isCollaborative);
|
|
}
|
|
});
|
|
});
|
|
|
|
// Joindre automatiquement si on est sur un élément collaboratif
|
|
const currentPath = window.location.pathname;
|
|
const matches = currentPath.match(/\/folder\/(.+)$/);
|
|
if (matches) {
|
|
const folderName = decodeURIComponent(matches[1]);
|
|
joinCollaboration(folderName, 'folder');
|
|
}
|
|
});
|
|
|
|
// Initialisation au chargement de la page
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Initialiser WebSocket
|
|
const ws = new WebSocket(`ws://${window.location.host}`);
|
|
|
|
ws.onmessage = function(event) {
|
|
const data = JSON.parse(event.data);
|
|
if (data.type === 'collaborationStatus') {
|
|
updateCollaborationUI(data);
|
|
}
|
|
};
|
|
|
|
// Gestionnaire pour les boutons de collaboration
|
|
document.querySelectorAll('.toggle-collaboration-btn').forEach(button => {
|
|
button.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
const itemName = this.getAttribute('data-item-name');
|
|
const itemType = this.getAttribute('data-item-type');
|
|
const isCollaborative = this.getAttribute('data-is-collaborative') === 'true';
|
|
|
|
if (isCollaborative) {
|
|
showCollaborationDetails(itemName, itemType);
|
|
} else {
|
|
toggleCollaboration(itemName, itemType, !isCollaborative);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const contextMenu = document.querySelector('.context-menu');
|
|
let selectedItem = null;
|
|
|
|
// Activer le menu contextuel sur les lignes du tableau
|
|
document.querySelectorAll('#fileTable tbody tr').forEach(row => {
|
|
row.addEventListener('contextmenu', function(e) {
|
|
e.preventDefault(); // Empêcher le menu contextuel par défaut
|
|
|
|
selectedItem = {
|
|
type: this.dataset.type,
|
|
name: this.dataset.name,
|
|
isCollaborative: this.querySelector('.toggle-collaboration-btn')?.dataset.isCollaborative === 'true'
|
|
};
|
|
|
|
// Ajuster la visibilité des options du menu en fonction du type
|
|
adjustMenuOptions(selectedItem);
|
|
|
|
// Positionner le menu contextuel
|
|
showContextMenu(e.pageX, e.pageY);
|
|
});
|
|
});
|
|
|
|
// Fermer le menu au clic en dehors
|
|
document.addEventListener('click', function(e) {
|
|
if (!contextMenu.contains(e.target)) {
|
|
hideContextMenu();
|
|
}
|
|
});
|
|
|
|
// Gérer les actions du menu contextuel
|
|
document.querySelectorAll('.context-menu .menu-item').forEach(item => {
|
|
item.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
const action = this.dataset.action;
|
|
|
|
if (selectedItem) {
|
|
handleMenuAction(action, selectedItem);
|
|
}
|
|
|
|
hideContextMenu();
|
|
});
|
|
});
|
|
|
|
// Fonction pour ajuster les options du menu selon le type d'élément
|
|
function adjustMenuOptions(item) {
|
|
const menuItems = contextMenu.querySelectorAll('.menu-item');
|
|
|
|
menuItems.forEach(menuItem => {
|
|
const action = menuItem.dataset.action;
|
|
|
|
// Gérer la visibilité des options selon le type
|
|
switch(action) {
|
|
case 'open':
|
|
menuItem.style.display = item.type.includes('folder') ? 'flex' : 'none';
|
|
break;
|
|
case 'collaborate':
|
|
menuItem.style.display = item.type === 'folder' ? 'flex' : 'none';
|
|
menuItem.querySelector('span').textContent =
|
|
item.isCollaborative ? 'Gérer la collaboration' : 'Activer la collaboration';
|
|
break;
|
|
case 'share':
|
|
menuItem.style.display = item.type === 'file' ? 'flex' : 'none';
|
|
break;
|
|
// Vous pouvez ajouter d'autres cas selon vos besoins
|
|
}
|
|
});
|
|
}
|
|
|
|
// Fonction pour afficher le menu contextuel
|
|
function showContextMenu(x, y) {
|
|
const menu = contextMenu;
|
|
menu.style.display = 'block';
|
|
|
|
// Ajuster la position si le menu dépasse de la fenêtre
|
|
const menuRect = menu.getBoundingClientRect();
|
|
const windowWidth = window.innerWidth;
|
|
const windowHeight = window.innerHeight;
|
|
|
|
if (x + menuRect.width > windowWidth) {
|
|
x = windowWidth - menuRect.width;
|
|
}
|
|
|
|
if (y + menuRect.height > windowHeight) {
|
|
y = windowHeight - menuRect.height;
|
|
}
|
|
|
|
menu.style.left = `${x}px`;
|
|
menu.style.top = `${y}px`;
|
|
}
|
|
|
|
// Fonction pour cacher le menu contextuel
|
|
function hideContextMenu() {
|
|
contextMenu.style.display = 'none';
|
|
}
|
|
|
|
// Fonction pour gérer les actions du menu
|
|
function handleMenuAction(action, item) {
|
|
switch(action) {
|
|
case 'open':
|
|
if (item.type === 'folder') {
|
|
window.location.href = `/dpanel/dashboard/folder/${encodeURIComponent(item.name)}`;
|
|
}
|
|
break;
|
|
|
|
case 'rename':
|
|
Swal.fire({
|
|
title: 'Renommer',
|
|
input: 'text',
|
|
inputValue: item.name,
|
|
showCancelButton: true,
|
|
confirmButtonText: 'Renommer',
|
|
cancelButtonText: 'Annuler',
|
|
inputValidator: (value) => {
|
|
if (!value) {
|
|
return 'Le nom ne peut pas être vide';
|
|
}
|
|
}
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
// Appeler votre API de renommage ici
|
|
console.log(`Renommer ${item.name} en ${result.value}`);
|
|
}
|
|
});
|
|
break;
|
|
|
|
case 'delete':
|
|
Swal.fire({
|
|
title: 'Êtes-vous sûr ?',
|
|
text: `Voulez-vous vraiment supprimer "${item.name}" ?`,
|
|
icon: 'warning',
|
|
showCancelButton: true,
|
|
confirmButtonColor: 'hsl(var(--destructive))',
|
|
confirmButtonText: 'Supprimer',
|
|
cancelButtonText: 'Annuler'
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
// Appeler votre API de suppression ici
|
|
console.log(`Supprimer ${item.name}`);
|
|
}
|
|
});
|
|
break;
|
|
|
|
case 'collaborate':
|
|
if (item.isCollaborative) {
|
|
showCollaborationDetails(item.name, item.type);
|
|
} else {
|
|
toggleCollaboration(item.name, item.type, true);
|
|
}
|
|
break;
|
|
|
|
case 'move':
|
|
// Implémenter la logique de déplacement
|
|
console.log(`Déplacer ${item.name}`);
|
|
break;
|
|
|
|
case 'share':
|
|
if (item.type === 'file') {
|
|
// Copier le lien de partage dans le presse-papier
|
|
const shareButton = document.querySelector(`[data-file-name="${item.name}"] .copy-button`);
|
|
const fileUrl = shareButton?.dataset.fileUrl;
|
|
if (fileUrl) {
|
|
navigator.clipboard.writeText(fileUrl)
|
|
.then(() => {
|
|
Swal.fire({
|
|
position: 'top-end',
|
|
icon: 'success',
|
|
title: 'Lien copié !',
|
|
showConfirmButton: false,
|
|
timer: 1500,
|
|
toast: true
|
|
});
|
|
});
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Gestion de la suppression des dossiers
|
|
document.querySelectorAll('.delete-folder-btn').forEach(button => {
|
|
button.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
const folderName = this.dataset.folderName;
|
|
|
|
Swal.fire({
|
|
title: 'Êtes-vous sûr ?',
|
|
text: `Voulez-vous vraiment supprimer le dossier "${folderName}" ?`,
|
|
icon: 'warning',
|
|
showCancelButton: true,
|
|
confirmButtonColor: '#dc3545',
|
|
confirmButtonText: 'Supprimer',
|
|
cancelButtonText: 'Annuler'
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
// Appel à votre API pour supprimer le dossier
|
|
fetch(`/api/dpanel/folders/delete/${encodeURIComponent(folderName)}`, {
|
|
method: 'DELETE'
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
// Supprimer la ligne du tableau
|
|
const row = button.closest('tr');
|
|
row.remove();
|
|
|
|
// Afficher une notification de succès
|
|
Swal.fire({
|
|
position: 'top-end',
|
|
icon: 'success',
|
|
title: 'Dossier supprimé !',
|
|
showConfirmButton: false,
|
|
timer: 1500,
|
|
toast: true
|
|
});
|
|
} else {
|
|
throw new Error(data.message || 'Erreur lors de la suppression');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
Swal.fire({
|
|
position: 'top-end',
|
|
icon: 'error',
|
|
title: 'Erreur lors de la suppression',
|
|
text: error.message,
|
|
showConfirmButton: false,
|
|
timer: 3000,
|
|
toast: true
|
|
});
|
|
});
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
// Gestion du renommage des dossiers
|
|
document.querySelectorAll('.rename-folder-btn').forEach(button => {
|
|
button.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
const folderName = this.dataset.folderName;
|
|
|
|
Swal.fire({
|
|
title: 'Renommer le dossier',
|
|
input: 'text',
|
|
inputValue: folderName,
|
|
showCancelButton: true,
|
|
confirmButtonText: 'Renommer',
|
|
cancelButtonText: 'Annuler',
|
|
inputValidator: (value) => {
|
|
if (!value) {
|
|
return 'Veuillez entrer un nom de dossier';
|
|
}
|
|
}
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
const newName = result.value;
|
|
// Appel à votre API pour renommer le dossier
|
|
fetch('/api/dpanel/folders/rename', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
oldName: folderName,
|
|
newName: newName
|
|
})
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
// Mettre à jour l'affichage
|
|
const row = button.closest('tr');
|
|
row.querySelector('td:first-child').textContent = newName;
|
|
|
|
// Mettre à jour les attributs data
|
|
row.dataset.name = newName;
|
|
button.dataset.folderName = newName;
|
|
button.dataset.itemName = newName;
|
|
|
|
// Mettre à jour le lien d'ouverture
|
|
const openLink = row.querySelector('a.dropdown-item');
|
|
if (openLink) {
|
|
openLink.href = `/dpanel/dashboard/folder/${encodeURIComponent(newName)}`;
|
|
}
|
|
|
|
Swal.fire({
|
|
position: 'top-end',
|
|
icon: 'success',
|
|
title: 'Dossier renommé !',
|
|
showConfirmButton: false,
|
|
timer: 1500,
|
|
toast: true
|
|
});
|
|
} else {
|
|
throw new Error(data.message || 'Erreur lors du renommage');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
Swal.fire({
|
|
position: 'top-end',
|
|
icon: 'error',
|
|
title: 'Erreur lors du renommage',
|
|
text: error.message,
|
|
showConfirmButton: false,
|
|
timer: 3000,
|
|
toast: true
|
|
});
|
|
});
|
|
}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll('tr[data-type="folder"] td:first-child, tr[data-type="shared-folder"] td:first-child').forEach(cell => {
|
|
cell.addEventListener('dblclick', (e) => {
|
|
e.preventDefault(); // Prevent text selection
|
|
const row = cell.closest('tr');
|
|
const url = row.dataset.url;
|
|
if (url) {
|
|
window.location.href = url;
|
|
}
|
|
});
|
|
});
|
|
|
|
// Disable text selection on double-click for folder names
|
|
document.querySelectorAll('tr[data-type="folder"] td:first-child, tr[data-type="shared-folder"] td:first-child').forEach(cell => {
|
|
cell.style.userSelect = 'none';
|
|
});
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const searchContainer = document.querySelector('.flex.justify-between.items-center');
|
|
const button = document.createElement('button');
|
|
button.className = 'btn btn-secondary ml-2';
|
|
button.innerHTML = '<i class="fas fa-th-large"></i>';
|
|
searchContainer.appendChild(button);
|
|
|
|
const table = document.querySelector('#fileTable tbody');
|
|
let isGridView = localStorage.getItem('isGridView') === 'true';
|
|
|
|
function buildGridLayout(tr) {
|
|
const firstCell = tr.querySelector('td:first-child');
|
|
const name = firstCell.querySelector('div').innerText.trim();
|
|
const icon = firstCell.querySelector('i').cloneNode(true);
|
|
const type = tr.querySelector('td:nth-child(2)').innerText.trim();
|
|
const owner = tr.querySelector('td:nth-child(3)').innerText.trim();
|
|
const size = tr.querySelector('td:nth-child(4)').innerText.trim();
|
|
const collab = firstCell.querySelector('.collaboration-badge');
|
|
|
|
const content = document.createElement('div');
|
|
content.className = 'icon-container';
|
|
content.innerHTML = `
|
|
<div class="icon">${icon.outerHTML}</div>
|
|
<div class="label">${name}</div>
|
|
<div class="details">${type} • ${size}</div>
|
|
`;
|
|
|
|
firstCell.innerHTML = '';
|
|
firstCell.appendChild(content);
|
|
if (collab) {
|
|
firstCell.appendChild(collab);
|
|
}
|
|
}
|
|
|
|
function toggleView(e) {
|
|
e?.preventDefault();
|
|
isGridView = !table.classList.contains('grid-view');
|
|
|
|
if (isGridView) {
|
|
table.classList.add('grid-view');
|
|
table.querySelectorAll('tr').forEach(buildGridLayout);
|
|
button.innerHTML = '<i class="fas fa-list"></i>';
|
|
} else {
|
|
table.classList.remove('grid-view');
|
|
location.reload();
|
|
button.innerHTML = '<i class="fas fa-th-large"></i>';
|
|
}
|
|
|
|
localStorage.setItem('isGridView', isGridView);
|
|
}
|
|
|
|
button.addEventListener('click', toggleView);
|
|
|
|
if (isGridView) {
|
|
table.classList.add('grid-view');
|
|
table.querySelectorAll('tr').forEach(buildGridLayout);
|
|
button.innerHTML = '<i class="fas fa-list"></i>';
|
|
}
|
|
});
|
|
|
|
// Améliorations de la vue grille
|
|
function toggleGridView() {
|
|
const table = document.querySelector('#fileTable tbody');
|
|
const isGridView = table.classList.contains('grid-view');
|
|
|
|
if (!isGridView) {
|
|
table.classList.add('grid-view');
|
|
document.querySelectorAll('#fileTable tbody tr').forEach(tr => {
|
|
const firstCell = tr.querySelector('td:first-child');
|
|
const icon = firstCell.querySelector('i').cloneNode(true);
|
|
const name = firstCell.textContent.trim();
|
|
const type = tr.querySelector('td:nth-child(2)').textContent.trim();
|
|
|
|
const container = document.createElement('div');
|
|
container.className = 'icon-container';
|
|
container.innerHTML = `
|
|
<div class="icon">${icon.outerHTML}</div>
|
|
<div class="name">${name}</div>
|
|
<div class="type">${type}</div>
|
|
`;
|
|
|
|
firstCell.innerHTML = '';
|
|
firstCell.appendChild(container);
|
|
});
|
|
} else {
|
|
table.classList.remove('grid-view');
|
|
location.reload(); // Recharger pour restaurer la vue liste
|
|
}
|
|
|
|
localStorage.setItem('viewMode', isGridView ? 'list' : 'grid');
|
|
}
|
|
|
|
// Gestionnaire du menu contextuel amélioré
|
|
function handleContextMenu(e) {
|
|
e.preventDefault();
|
|
|
|
const target = e.target.closest('tr');
|
|
if (!target) return;
|
|
|
|
const contextMenu = document.querySelector('.context-menu');
|
|
contextMenu.style.display = 'block';
|
|
|
|
// Positionnement intelligent du menu
|
|
const x = e.pageX;
|
|
const y = e.pageY;
|
|
const winWidth = window.innerWidth;
|
|
const winHeight = window.innerHeight;
|
|
const menuWidth = contextMenu.offsetWidth;
|
|
const menuHeight = contextMenu.offsetHeight;
|
|
|
|
contextMenu.style.left = (x + menuWidth > winWidth ? winWidth - menuWidth : x) + 'px';
|
|
contextMenu.style.top = (y + menuHeight > winHeight ? winHeight - menuHeight : y) + 'px';
|
|
|
|
// Stockage de la référence à l'élément
|
|
contextMenu.dataset.targetName = target.dataset.name;
|
|
contextMenu.dataset.targetType = target.dataset.type;
|
|
|
|
// Mise à jour des actions du menu
|
|
updateContextMenuActions(target);
|
|
}
|
|
|
|
function updateContextMenuActions(target) {
|
|
const contextMenu = document.querySelector('.context-menu');
|
|
const actions = contextMenu.querySelectorAll('.menu-item');
|
|
|
|
actions.forEach(action => {
|
|
action.onclick = (e) => {
|
|
e.preventDefault();
|
|
const name = contextMenu.dataset.targetName;
|
|
const type = contextMenu.dataset.targetType;
|
|
|
|
switch(action.dataset.action) {
|
|
case 'open':
|
|
if (type === 'folder') {
|
|
window.location.href = `/dpanel/dashboard/folder/${encodeURIComponent(name)}`;
|
|
}
|
|
break;
|
|
case 'rename':
|
|
if (type === 'folder') {
|
|
renameFolder(name);
|
|
} else {
|
|
renameFile(name);
|
|
}
|
|
break;
|
|
case 'delete':
|
|
if (type === 'folder') {
|
|
confirmDeleteFolder(name);
|
|
} else {
|
|
confirmDelete(name);
|
|
}
|
|
break;
|
|
case 'share':
|
|
if (type === 'file') {
|
|
const url = target.dataset.url;
|
|
copyFileLink(url);
|
|
}
|
|
break;
|
|
}
|
|
|
|
contextMenu.style.display = 'none';
|
|
};
|
|
});
|
|
}
|
|
|
|
// Initialisation
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
// Restaurer la vue précédente
|
|
const viewMode = localStorage.getItem('viewMode');
|
|
if (viewMode === 'grid') {
|
|
toggleGridView();
|
|
}
|
|
|
|
// Gestionnaire du bouton de vue
|
|
document.querySelector('.view-toggle').addEventListener('click', toggleGridView);
|
|
|
|
// Gestionnaire du menu contextuel
|
|
document.addEventListener('contextmenu', handleContextMenu);
|
|
document.addEventListener('click', (e) => {
|
|
if (!e.target.closest('.context-menu')) {
|
|
document.querySelector('.context-menu').style.display = 'none';
|
|
}
|
|
});
|
|
});
|
|
|
|
function getDefaultAvatar(username) {
|
|
const encodedName = encodeURIComponent(username);
|
|
return `https://api.dicebear.com/7.x/initials/svg?seed=${encodedName}&background=%234e54c8&radius=50`;
|
|
}
|
|
|
|
// Modifiez la fonction qui affiche les détails de collaboration
|
|
function showCollaborationDetails(itemName, itemType) {
|
|
fetch(`/api/dpanel/collaboration/details/${itemType}/${itemName}`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
let userList = '';
|
|
if (data.activeUsers && data.activeUsers.length > 0) {
|
|
userList = data.activeUsers.map(user => {
|
|
const avatarUrl = user.profilePicture || getDefaultAvatar(user.name);
|
|
return `
|
|
<div class="user-item">
|
|
<img
|
|
src="${avatarUrl}"
|
|
alt="${user.name}"
|
|
class="user-avatar"
|
|
onerror="this.onerror=null; this.src='${getDefaultAvatar(user.name)}'"
|
|
>
|
|
<span>${user.name}</span>
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
} else {
|
|
userList = '<div class="text-muted">Aucun utilisateur actif</div>';
|
|
}
|
|
});
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
// Récupération des éléments nécessaires
|
|
const tableBody = document.querySelector('#fileTable tbody');
|
|
const searchContainer = document.querySelector('.flex.justify-between.items-center');
|
|
|
|
if (!tableBody || !searchContainer) return; // Protection contre les éléments manquants
|
|
|
|
// Création du bouton de basculement
|
|
const viewToggleBtn = document.createElement('button');
|
|
viewToggleBtn.className = 'btn btn-secondary ml-2 view-toggle-btn';
|
|
viewToggleBtn.innerHTML = '<i class="fas fa-th-large"></i>';
|
|
searchContainer.appendChild(viewToggleBtn);
|
|
|
|
// Récupération du mode de vue sauvegardé
|
|
let isGridView = localStorage.getItem('isGridView') === 'true';
|
|
|
|
function buildGridLayout(tr) {
|
|
if (!tr) return;
|
|
|
|
const firstCell = tr.querySelector('td:first-child');
|
|
if (!firstCell) return;
|
|
|
|
const name = firstCell.innerText.trim();
|
|
const icon = firstCell.querySelector('i')?.cloneNode(true);
|
|
const type = tr.querySelector('td:nth-child(2)')?.innerText.trim() || '';
|
|
const owner = tr.querySelector('td:nth-child(3)')?.innerText.trim() || '';
|
|
const size = tr.querySelector('td:nth-child(4)')?.innerText.trim() || '';
|
|
const collab = firstCell.querySelector('.collaboration-badge');
|
|
|
|
if (!icon) return;
|
|
|
|
const content = document.createElement('div');
|
|
content.className = 'icon-container';
|
|
content.innerHTML = `
|
|
<div class="icon">${icon.outerHTML}</div>
|
|
<div class="label">${name}</div>
|
|
<div class="details">${type} • ${size}</div>
|
|
`;
|
|
|
|
firstCell.innerHTML = '';
|
|
firstCell.appendChild(content);
|
|
if (collab) {
|
|
firstCell.appendChild(collab);
|
|
}
|
|
}
|
|
|
|
function toggleView() {
|
|
isGridView = !tableBody.classList.contains('grid-view');
|
|
|
|
if (isGridView) {
|
|
tableBody.classList.add('grid-view');
|
|
document.querySelectorAll('#fileTable tbody tr').forEach(buildGridLayout);
|
|
viewToggleBtn.innerHTML = '<i class="fas fa-list"></i>';
|
|
} else {
|
|
tableBody.classList.remove('grid-view');
|
|
location.reload(); // Recharge la page pour restaurer la vue liste
|
|
viewToggleBtn.innerHTML = '<i class="fas fa-th-large"></i>';
|
|
}
|
|
|
|
localStorage.setItem('isGridView', isGridView);
|
|
}
|
|
|
|
// Ajout du gestionnaire d'événements
|
|
viewToggleBtn.addEventListener('click', toggleView);
|
|
|
|
// Initialisation de la vue au chargement
|
|
if (isGridView) {
|
|
tableBody.classList.add('grid-view');
|
|
document.querySelectorAll('#fileTable tbody tr').forEach(buildGridLayout);
|
|
viewToggleBtn.innerHTML = '<i class="fas fa-list"></i>';
|
|
}
|
|
});
|
|
|
|
// ...existing code...
|
|
|
|
// Gestion des collaborations (remplacez ou ajoutez cette partie)
|
|
function showCollaborationModal(itemName, itemType) {
|
|
const modalHtml = `
|
|
<div class="collaboration-content">
|
|
<div class="active-users mb-4">
|
|
<h6 class="mb-2">Collaborateurs actifs</h6>
|
|
<div id="activeUsersList" class="user-list">
|
|
<div class="text-center">
|
|
<i class="fas fa-spinner fa-spin"></i> Chargement...
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="add-collaborator">
|
|
<h6 class="mb-2">Ajouter un collaborateur</h6>
|
|
<div class="input-group mb-3">
|
|
<input type="text" id="searchUserInput" class="form-control" placeholder="Rechercher un utilisateur">
|
|
<div class="input-group-append">
|
|
<button class="btn btn-outline-secondary" type="button" id="searchUserBtn">
|
|
<i class="fas fa-search"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div id="searchResults" class="search-results"></div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
Swal.fire({
|
|
title: 'Gestion de la collaboration',
|
|
html: modalHtml,
|
|
showCancelButton: true,
|
|
showDenyButton: true,
|
|
confirmButtonText: 'Fermer',
|
|
denyButtonText: 'Désactiver la collaboration',
|
|
denyButtonColor: '#dc3545',
|
|
width: '600px',
|
|
didOpen: () => {
|
|
// Charger les utilisateurs actifs
|
|
loadActiveUsers(itemName, itemType);
|
|
|
|
// Configuration de la recherche
|
|
const searchInput = Swal.getPopup().querySelector('#searchUserInput');
|
|
const searchBtn = Swal.getPopup().querySelector('#searchUserBtn');
|
|
|
|
searchBtn.addEventListener('click', () => searchUsers(searchInput.value, itemName, itemType));
|
|
searchInput.addEventListener('keypress', (e) => {
|
|
if (e.key === 'Enter') {
|
|
searchUsers(searchInput.value, itemName, itemType);
|
|
}
|
|
});
|
|
}
|
|
}).then((result) => {
|
|
if (result.isDenied) {
|
|
disableCollaboration(itemName, itemType);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Fonction de chargement des utilisateurs actifs
|
|
function loadActiveUsers(itemName, itemType) {
|
|
fetch(`/api/dpanel/collaboration/users/${itemType}/${itemName}`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
const usersList = Swal.getPopup().querySelector('#activeUsersList');
|
|
if (!usersList) return;
|
|
|
|
if (data.users && data.users.length > 0) {
|
|
const usersHtml = data.users.map(user => `
|
|
<div class="collaboration-user-item">
|
|
<div class="d-flex align-items-center">
|
|
<img src="${user.profilePicture || getDefaultAvatar(user.name)}"
|
|
alt="${user.name}"
|
|
class="user-avatar mr-2"
|
|
onerror="this.src='${getDefaultAvatar(user.name)}'"
|
|
>
|
|
<div>
|
|
<div class="user-name">${user.name}</div>
|
|
<div class="user-status">En ligne</div>
|
|
</div>
|
|
</div>
|
|
<button class="btn btn-sm btn-outline-danger" onclick="removeCollaborator('${itemName}', '${itemType}', '${user.id}')">
|
|
<i class="fas fa-user-minus"></i>
|
|
</button>
|
|
</div>
|
|
`).join('');
|
|
usersList.innerHTML = usersHtml;
|
|
} else {
|
|
usersList.innerHTML = '<div class="text-muted text-center">Aucun collaborateur actif</div>';
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Erreur lors du chargement des utilisateurs:', error);
|
|
});
|
|
}
|
|
|
|
// Fonction de recherche d'utilisateurs
|
|
function searchUsers(searchTerm, itemName, itemType) {
|
|
if (!searchTerm.trim()) return;
|
|
|
|
const resultsDiv = Swal.getPopup().querySelector('#searchResults');
|
|
if (!resultsDiv) return;
|
|
|
|
resultsDiv.innerHTML = '<div class="text-center"><i class="fas fa-spinner fa-spin"></i> Recherche...</div>';
|
|
|
|
fetch(`/api/dpanel/users/search?term=${encodeURIComponent(searchTerm)}`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.users && data.users.length > 0) {
|
|
const resultsHtml = data.users.map(user => `
|
|
<div class="search-result-item">
|
|
<div class="d-flex align-items-center justify-content-between">
|
|
<div class="d-flex align-items-center">
|
|
<img src="${user.profilePicture || getDefaultAvatar(user.name)}"
|
|
alt="${user.name}"
|
|
class="user-avatar mr-2"
|
|
onerror="this.src='${getDefaultAvatar(user.name)}'">
|
|
<span>${user.name}</span>
|
|
</div>
|
|
<button class="btn btn-sm btn-primary" onclick="addCollaborator('${itemName}', '${itemType}', '${user.id}')">
|
|
<i class="fas fa-user-plus"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
`).join('');
|
|
resultsDiv.innerHTML = resultsHtml;
|
|
} else {
|
|
resultsDiv.innerHTML = '<div class="text-muted text-center">Aucun utilisateur trouvé</div>';
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Erreur lors de la recherche:', error);
|
|
resultsDiv.innerHTML = '<div class="text-danger text-center">Erreur lors de la recherche</div>';
|
|
});
|
|
}
|
|
|
|
// Ajoutez cet écouteur d'événements pour le bouton de collaboration
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
document.querySelectorAll('.toggle-collaboration-btn').forEach(button => {
|
|
button.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
const itemName = this.getAttribute('data-item-name');
|
|
const itemType = this.getAttribute('data-item-type');
|
|
const isCollaborative = this.getAttribute('data-is-collaborative') === 'true';
|
|
|
|
if (isCollaborative) {
|
|
showCollaborationModal(itemName, itemType);
|
|
} else {
|
|
toggleCollaboration(itemName, itemType, true);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
// Remplacez ou ajoutez cette fonction dans votre fichier dashboard.js
|
|
function showCollaborationModal(itemName, itemType) {
|
|
Swal.fire({
|
|
title: 'Gestion de la collaboration',
|
|
html: `
|
|
<div class="collaboration-content">
|
|
<div class="active-users mb-4">
|
|
<h6 class="mb-2">Collaborateurs actifs</h6>
|
|
<div id="activeUsersList" class="user-list">
|
|
<div class="text-center">
|
|
<i class="fas fa-spinner fa-spin"></i> Chargement...
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="add-collaborator">
|
|
<h6 class="mb-2">Ajouter un collaborateur</h6>
|
|
<div class="input-group mb-3">
|
|
<input type="text" id="searchUserInput" class="form-control" placeholder="Rechercher un utilisateur">
|
|
<div class="input-group-append">
|
|
<button class="btn btn-outline-secondary" type="button" id="searchUserBtn">
|
|
<i class="fas fa-search"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div id="searchResults" class="search-results"></div>
|
|
</div>
|
|
</div>
|
|
`,
|
|
showCancelButton: true,
|
|
showDenyButton: true,
|
|
confirmButtonText: 'Fermer',
|
|
denyButtonText: 'Désactiver la collaboration',
|
|
denyButtonColor: '#dc3545',
|
|
width: '600px',
|
|
customClass: {
|
|
container: 'collaboration-modal',
|
|
popup: 'collaboration-popup',
|
|
content: 'collaboration-content'
|
|
},
|
|
didOpen: () => {
|
|
loadActiveUsers(itemName, itemType);
|
|
setupSearchHandlers(itemName, itemType);
|
|
}
|
|
}).then((result) => {
|
|
if (result.isDenied) {
|
|
disableCollaboration(itemName, itemType);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Modifier l'événement click des boutons de collaboration
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
document.querySelectorAll('.toggle-collaboration-btn').forEach(button => {
|
|
button.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
const itemName = this.getAttribute('data-item-name');
|
|
const itemType = this.getAttribute('data-item-type');
|
|
const isCollaborative = this.getAttribute('data-is-collaborative') === 'true';
|
|
|
|
if (isCollaborative) {
|
|
showCollaborationModal(itemName, itemType);
|
|
} else {
|
|
toggleCollaboration(itemName, itemType, true);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
function loadActiveUsers(itemName, itemType) {
|
|
const usersList = Swal.getPopup().querySelector('#activeUsersList');
|
|
|
|
fetch(`/api/dpanel/collaboration/users/${itemType}/${itemName}`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (!usersList) return;
|
|
|
|
if (data.users && data.users.length > 0) {
|
|
usersList.innerHTML = data.users.map(user => `
|
|
<div class="collaboration-user-item">
|
|
<div class="d-flex align-items-center">
|
|
<img src="${user.profilePicture || getDefaultAvatar(user.name)}"
|
|
alt="${user.name}"
|
|
class="user-avatar mr-2"
|
|
onerror="this.src='${getDefaultAvatar(user.name)}'"
|
|
>
|
|
<div>
|
|
<div class="user-name">${user.name}</div>
|
|
<div class="user-status">En ligne</div>
|
|
</div>
|
|
</div>
|
|
<button class="btn btn-sm btn-outline-danger" onclick="removeCollaborator('${itemName}', '${itemType}', '${user.id}')">
|
|
<i class="fas fa-user-minus"></i>
|
|
</button>
|
|
</div>
|
|
`).join('');
|
|
} else {
|
|
usersList.innerHTML = '<div class="text-muted text-center">Aucun collaborateur actif</div>';
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Erreur:', error);
|
|
usersList.innerHTML = '<div class="text-danger text-center">Erreur lors du chargement</div>';
|
|
});
|
|
}
|
|
|
|
function setupSearchHandlers(itemName, itemType) {
|
|
const searchInput = Swal.getPopup().querySelector('#searchUserInput');
|
|
const searchBtn = Swal.getPopup().querySelector('#searchUserBtn');
|
|
|
|
if (!searchInput || !searchBtn) return;
|
|
|
|
searchBtn.onclick = () => searchUsers(searchInput.value, itemName, itemType);
|
|
searchInput.onkeypress = (e) => {
|
|
if (e.key === 'Enter') {
|
|
searchUsers(searchInput.value, itemName, itemType);
|
|
}
|
|
};
|
|
}
|
|
|
|
function searchUsers(searchTerm, itemName, itemType) {
|
|
if (!searchTerm.trim()) return;
|
|
|
|
const resultsDiv = Swal.getPopup().querySelector('#searchResults');
|
|
if (!resultsDiv) return;
|
|
|
|
resultsDiv.innerHTML = '<div class="text-center"><i class="fas fa-spinner fa-spin"></i> Recherche...</div>';
|
|
|
|
fetch(`/api/dpanel/users/search?term=${encodeURIComponent(searchTerm)}`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.users && data.users.length > 0) {
|
|
resultsDiv.innerHTML = data.users.map(user => `
|
|
<div class="search-result-item">
|
|
<div class="d-flex align-items-center justify-content-between">
|
|
<div class="d-flex align-items-center">
|
|
<img src="${user.profilePicture || getDefaultAvatar(user.name)}"
|
|
alt="${user.name}"
|
|
class="user-avatar mr-2"
|
|
onerror="this.src='${getDefaultAvatar(user.name)}'"
|
|
>
|
|
<span>${user.name}</span>
|
|
</div>
|
|
<button class="btn btn-sm btn-primary" onclick="addCollaborator('${itemName}', '${itemType}', '${user.id}')">
|
|
<i class="fas fa-user-plus"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
`).join('');
|
|
} else {
|
|
resultsDiv.innerHTML = '<div class="text-muted text-center">Aucun utilisateur trouvé</div>';
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Erreur:', error);
|
|
resultsDiv.innerHTML = '<div class="text-danger text-center">Erreur lors de la recherche</div>';
|
|
});
|
|
} |