413 lines
16 KiB
Plaintext
413 lines
16 KiB
Plaintext
@model Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models.EditShippingModel
|
|
@{
|
|
// Layout = "_AdminLayout";
|
|
ViewBag.PageTitle = "Edit Shipping";
|
|
NopHtml.SetActiveMenuItemSystemName("Shippings.Edit");
|
|
}
|
|
|
|
<form asp-action="Edit" method="post">
|
|
<input asp-for="Id" type="hidden" />
|
|
|
|
<div class="content-header clearfix">
|
|
<h1 class="float-left">
|
|
<i class="fas fa-edit"></i>
|
|
Edit Shipping: @Model.LicencePlate - @(Model.ShippingDate.ToString("yyyy-MM-dd"))
|
|
</h1>
|
|
<div class="float-right">
|
|
<button type="submit" name="save" class="btn btn-primary">
|
|
<i class="far fa-save"></i>
|
|
Update Shipping
|
|
</button>
|
|
<a asp-action="List" class="btn btn-default">
|
|
<i class="fas fa-arrow-left"></i>
|
|
Back to List
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<section class="content">
|
|
<div class="container-fluid">
|
|
<div class="form-horizontal">
|
|
<div class="cards-group">
|
|
<!-- Basic Information -->
|
|
<div class="card card-default">
|
|
<div class="card-header">
|
|
<div class="card-title">Shipping Information</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="ShippingDate" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<nop-editor asp-for="ShippingDate" required="true" />
|
|
<span asp-validation-for="ShippingDate"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<div class="col-md-3">
|
|
<nop-label asp-for="LicencePlate" />
|
|
</div>
|
|
<div class="col-md-9">
|
|
<nop-editor asp-for="LicencePlate" required="true" />
|
|
<span asp-validation-for="LicencePlate"></span>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- File Upload Section - Only shown when editing existing Shipping -->
|
|
<div class="card card-default">
|
|
<div class="card-header">
|
|
<div class="card-title">
|
|
<i class="fas fa-file-pdf"></i>
|
|
Upload Documents (PDF only)
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<!-- Drag & Drop Zone -->
|
|
<div id="dropZone" class="drop-zone">
|
|
<div class="drop-zone-content">
|
|
<i class="fas fa-cloud-upload-alt fa-3x text-muted"></i>
|
|
<h4>Drag & Drop PDF files here</h4>
|
|
<p class="text-muted">or click to select files</p>
|
|
<input type="file" id="fileInput" multiple accept=".pdf" style="display: none;">
|
|
<button type="button" id="selectFilesBtn" class="btn btn-outline-primary">
|
|
<i class="fas fa-folder-open"></i>
|
|
Select Files
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Upload Progress -->
|
|
<div id="uploadProgress" style="display: none;">
|
|
<div class="progress mb-3">
|
|
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 0%"></div>
|
|
</div>
|
|
<p id="uploadStatus" class="text-center"></p>
|
|
</div>
|
|
|
|
<!-- Existing Documents -->
|
|
<div class="mt-3">
|
|
<h5>Existing Documents:</h5>
|
|
<div id="documentsGridContainer">
|
|
@await Html.PartialAsync("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Components/_DocumentsGridPartial.cshtml", Model.ExistingDocuments)
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Newly Uploaded Files List -->
|
|
<div id="uploadedFiles" class="mt-3" style="display: none;">
|
|
<h5>Newly Uploaded Files:</h5>
|
|
<div id="filesList" class="list-group">
|
|
<!-- Uploaded files will appear here -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</form>
|
|
|
|
<style>
|
|
.drop-zone {
|
|
border: 2px dashed #dee2e6;
|
|
border-radius: 10px;
|
|
padding: 40px;
|
|
text-align: center;
|
|
transition: all 0.3s ease;
|
|
background-color: #f8f9fa;
|
|
min-height: 200px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.drop-zone:hover,
|
|
.drop-zone.drag-over {
|
|
border-color: #007bff;
|
|
background-color: rgba(0, 123, 255, 0.05);
|
|
}
|
|
|
|
.drop-zone-content {
|
|
pointer-events: none;
|
|
}
|
|
|
|
.file-item {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 10px 15px;
|
|
margin-bottom: 5px;
|
|
border: 1px solid #dee2e6;
|
|
border-radius: 5px;
|
|
background-color: #fff;
|
|
}
|
|
|
|
.file-item .file-info {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.file-item .file-info i {
|
|
margin-right: 10px;
|
|
color: #dc3545;
|
|
}
|
|
|
|
.file-item .file-actions button {
|
|
margin-left: 5px;
|
|
}
|
|
|
|
.upload-error {
|
|
border-color: #dc3545;
|
|
background-color: rgba(220, 53, 69, 0.05);
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
|
|
let grid;
|
|
|
|
function onGridInitialized(e) {
|
|
grid = e.component; // save instance
|
|
}
|
|
|
|
|
|
$(document).ready(function() {
|
|
let uploadedFiles = [];
|
|
const ShippingId = @Model.Id;
|
|
|
|
// File input and drop zone elements
|
|
const dropZone = document.getElementById('dropZone');
|
|
const fileInput = document.getElementById('fileInput');
|
|
const selectFilesBtn = document.getElementById('selectFilesBtn');
|
|
|
|
|
|
|
|
function addDocumentToGrid(doc) {
|
|
grid.getDataSource().store().insert(doc).done(() => grid.refresh());
|
|
}
|
|
|
|
// Click to select files
|
|
selectFilesBtn.addEventListener('click', () => fileInput.click());
|
|
dropZone.addEventListener('click', (e) => {
|
|
if (e.target === dropZone || e.target.closest('.drop-zone-content')) {
|
|
fileInput.click();
|
|
}
|
|
});
|
|
|
|
// File input change
|
|
fileInput.addEventListener('change', handleFiles);
|
|
|
|
// Drag and drop events
|
|
dropZone.addEventListener('dragover', handleDragOver);
|
|
dropZone.addEventListener('dragenter', handleDragEnter);
|
|
dropZone.addEventListener('dragleave', handleDragLeave);
|
|
dropZone.addEventListener('drop', handleDrop);
|
|
|
|
function handleDragOver(e) {
|
|
e.preventDefault();
|
|
dropZone.classList.add('drag-over');
|
|
}
|
|
|
|
function handleDragEnter(e) {
|
|
e.preventDefault();
|
|
dropZone.classList.add('drag-over');
|
|
}
|
|
|
|
function handleDragLeave(e) {
|
|
e.preventDefault();
|
|
if (!dropZone.contains(e.relatedTarget)) {
|
|
dropZone.classList.remove('drag-over');
|
|
}
|
|
}
|
|
|
|
function handleDrop(e) {
|
|
e.preventDefault();
|
|
dropZone.classList.remove('drag-over');
|
|
|
|
const files = e.dataTransfer.files;
|
|
processFiles(files);
|
|
}
|
|
|
|
function handleFiles(e) {
|
|
const files = e.target.files;
|
|
processFiles(files);
|
|
}
|
|
|
|
function processFiles(files) {
|
|
Array.from(files).forEach(file => {
|
|
if (file.type === 'application/pdf') {
|
|
uploadFile(file);
|
|
} else {
|
|
showError(`"${file.name}" is not a PDF file. Only PDF files are allowed.`);
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
function uploadFile(file) {
|
|
const formData = new FormData();
|
|
formData.append('file', file);
|
|
formData.append('ShippingId', ShippingId);
|
|
formData.append('__RequestVerificationToken', $('input[name="__RequestVerificationToken"]').val());
|
|
|
|
showUploadProgress(`Uploading and processing ${file.name}...`);
|
|
|
|
$.ajax({
|
|
url: '@Url.Action("UploadFile", "Shipping")',
|
|
type: 'POST',
|
|
data: formData,
|
|
processData: false,
|
|
contentType: false,
|
|
success: function(result) {
|
|
hideUploadProgress();
|
|
|
|
console.log('Upload result:', result); // Debug log
|
|
|
|
if (result.success) {
|
|
showSuccess(`"${result.document.FileName}" uploaded and processed successfully`);
|
|
addDocumentToExistingList(result.document);
|
|
// Call a new endpoint to get the updated partial view
|
|
reloadPartialView();
|
|
|
|
} else {
|
|
showError(`Upload failed: ${result.errorMessage}`);
|
|
}
|
|
},
|
|
error: function(xhr, status, error) {
|
|
hideUploadProgress();
|
|
showError(`An error occurred during the upload: ${error}`);
|
|
}
|
|
});
|
|
}
|
|
|
|
// New function to reload the partial view
|
|
function reloadPartialView() {
|
|
// You'll need to create a new controller action for this endpoint
|
|
// that returns the partial view with the updated list of documents.
|
|
$.ajax({
|
|
url: '@Url.Action("ReloadPartialView", "Shipping")',
|
|
type: 'GET',
|
|
success: function(html) {
|
|
// Replace the content of the container holding the partial view
|
|
$('#documentsGridContainer').html(html);
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('Error reloading documents partial view:', error);
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
function addDocumentToExistingList(doc) {
|
|
const existingList = document.getElementById('existingFilesList');
|
|
|
|
const fileItem = document.createElement('div');
|
|
fileItem.className = 'file-item';
|
|
|
|
// Use PascalCase to match C# model properties
|
|
fileItem.innerHTML = `
|
|
<div class="file-info">
|
|
<i class="fas fa-file-pdf"></i>
|
|
<div>
|
|
<div><strong>${doc.FileName || 'Unnamed'}</strong> <small class="text-muted">(${doc.FileSize || 0} KB)</small></div>
|
|
${doc.DocumentDate ? `<small>Date: ${new Date(doc.DocumentDate).toLocaleDateString()}</small><br>` : ''}
|
|
${doc.RecipientName ? `<small>Recipient: ${doc.RecipientName}</small><br>` : ''}
|
|
${doc.SenderName ? `<small>Sender: ${doc.SenderName}</small><br>` : ''}
|
|
${doc.InvoiceNumber ? `<small>Invoice: ${doc.InvoiceNumber}</small><br>` : ''}
|
|
${doc.TotalAmount ? `<small>Amount: $${doc.TotalAmount}</small><br>` : ''}
|
|
${doc.ItemCount ? `<small>Items: ${doc.ItemCount}</small>` : ''}
|
|
</div>
|
|
</div>
|
|
<div class="file-actions">
|
|
<button type="button" class="btn btn-sm btn-outline-primary" onclick="viewFile('${doc.FilePath}')">
|
|
<i class="fas fa-eye"></i> View
|
|
</button>
|
|
<button type="button" class="btn btn-sm btn-outline-danger" onclick="deleteExistingFile(${doc.Id}, this)">
|
|
<i class="fas fa-trash"></i> Delete
|
|
</button>
|
|
</div>
|
|
`;
|
|
existingList.appendChild(fileItem);
|
|
}
|
|
|
|
function showUploadProgress(message) {
|
|
const progressDiv = document.getElementById('uploadProgress');
|
|
const statusText = document.getElementById('uploadStatus');
|
|
|
|
statusText.textContent = message;
|
|
progressDiv.style.display = 'block';
|
|
|
|
// Animate progress bar
|
|
const progressBar = progressDiv.querySelector('.progress-bar');
|
|
progressBar.style.width = '100%';
|
|
}
|
|
|
|
function hideUploadProgress() {
|
|
document.getElementById('uploadProgress').style.display = 'none';
|
|
const progressBar = document.querySelector('#uploadProgress .progress-bar');
|
|
progressBar.style.width = '0%';
|
|
}
|
|
|
|
function showError(message) {
|
|
displayBarNotification(message, 'error', 5000);
|
|
}
|
|
|
|
function showSuccess(message) {
|
|
displayBarNotification(message, 'success', 3000);
|
|
}
|
|
|
|
// Global functions for file actions
|
|
window.viewFile = function(filePath) {
|
|
window.open(filePath, '_blank');
|
|
};
|
|
|
|
window.deleteFile = function(filePath, button) {
|
|
if (confirm('Are you sure you want to delete this file?')) {
|
|
$.post('@Url.Action("DeleteUploadedFile")', { filePath: filePath })
|
|
.done(function(result) {
|
|
if (result.success) {
|
|
uploadedFiles = uploadedFiles.filter(f => f.filePath !== filePath);
|
|
const fileItem = button.closest('.file-item');
|
|
fileItem.remove();
|
|
|
|
if (uploadedFiles.length === 0) {
|
|
document.getElementById('uploadedFiles').style.display = 'none';
|
|
}
|
|
|
|
showSuccess('File deleted successfully');
|
|
} else {
|
|
showError('Failed to delete file: ' + result.message);
|
|
}
|
|
})
|
|
.fail(function() {
|
|
showError('Failed to delete file');
|
|
});
|
|
}
|
|
};
|
|
|
|
window.deleteExistingFile = function(documentId, button) {
|
|
if (confirm('Are you sure you want to delete this document?')) {
|
|
$.post('@Url.Action("DeleteDocument")', { documentId: documentId })
|
|
.done(function(result) {
|
|
if (result.success) {
|
|
const fileItem = button.closest('.file-item');
|
|
fileItem.remove();
|
|
showSuccess('Document deleted successfully');
|
|
} else {
|
|
showError('Failed to delete document: ' + result.message);
|
|
}
|
|
})
|
|
.fail(function() {
|
|
showError('Failed to delete document');
|
|
});
|
|
}
|
|
};
|
|
});
|
|
</script> |