Mango.Nop.Plugins/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Shipping/Edit.cshtml

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>