{% extends 'base.html' %} {% block title %}File Upload{% endblock %} {% block content %} <div class="bg-white p-10 rounded-lg shadow-lg w-11/12 md:w-1/2 lg:w-1/3 mx-auto"> <h2 class="text-2xl font-bold mb-6 text-gray-800 text-center">Upload CSV File</h2> <form id="uploadForm" enctype="multipart/form-data" class="space-y-6"> <div> <label for="fileInput" class="block text-sm font-medium text-gray-700 mb-2">Choose CSV File</label> <input type="file" name="file" id="fileInput" accept=".csv" class="w-full border border-gray-300 p-3 rounded-lg focus:outline-none focus:ring focus:ring-blue-400"> </div> <button type="submit" class="w-full bg-blue-600 text-white py-3 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring focus:ring-blue-400"> Upload </button> </form> <!-- Error Display --> <div id="errorSection" class="hidden mt-4 bg-red-100 border border-red-400 text-red-700 p-4 rounded-lg"> <strong class="font-bold">Error:</strong> <ul id="errorList" class="mt-2 list-disc list-inside"></ul> </div> <!-- Success Message --> <div id="successSection" class="hidden mt-4 mb-8 bg-green-100 border border-green-400 text-green-700 p-4 rounded-lg text-center"> <strong class="font-bold text-lg">Success!</strong> <p id="successMessage" class="block mt-2 text-md"></p> </div> <div id="downloadSection" class="hidden mt-16 flex justify-center"> <a id="downloadLink" href="#" class="w-full max-w-xs text-center bg-blue-600 text-white py-4 px-12 rounded-lg shadow-lg hover:bg-blue-700 focus:outline-none focus:ring focus:ring-blue-400 transition text-lg font-semibold block"> 📥 Download Updated CSV </a> </div> </div> <script> document.getElementById('uploadForm').addEventListener('submit', async function (e) { e.preventDefault(); const fileInput = document.getElementById('fileInput'); const errorSection = document.getElementById('errorSection'); const errorList = document.getElementById('errorList'); const successSection = document.getElementById('successSection'); const successMessage = document.getElementById('successMessage'); const downloadSection = document.getElementById('downloadSection'); const downloadLink = document.getElementById('downloadLink'); errorList.innerHTML = ''; successMessage.innerHTML = ''; errorSection.classList.add('hidden'); successSection.classList.add('hidden'); downloadSection.classList.add('hidden'); const formData = new FormData(); formData.append('file', fileInput.files[0]); try { const response = await fetch("{% url 'upload-file' %}", { method: 'POST', body: formData, headers: { 'X-CSRFToken': '{{ csrf_token }}', } }); const result = await response.json(); if (response.ok && result.status === 'success') { successMessage.innerText = result.message; successSection.classList.remove('hidden'); downloadLink.href = result.download_url; downloadSection.classList.remove('hidden'); } else { errorList.innerHTML = ''; if (response.status === 403) { const li = document.createElement('li'); li.textContent = 'You are not authorized to perform this action.'; errorList.appendChild(li); } else if (response.status === 400 && result.status === 'error') { for (const [field, messages] of Object.entries(result.errors)) { messages.forEach(message => { const li = document.createElement('li'); li.textContent = `${field}: ${message}`; errorList.appendChild(li); }); } } else { const li = document.createElement('li'); li.textContent = 'An unexpected error occurred. Please try again.'; errorList.appendChild(li); } errorSection.classList.remove('hidden'); } } catch (error) { const li = document.createElement('li'); li.textContent = 'Failed to connect to the server. Please check your internet connection.'; errorList.appendChild(li); errorSection.classList.remove('hidden'); } }); </script> {% endblock %}