feat: Add quotation modal and iddatadb update for quotation parts/images
- Add quotation modal for selecting quotation - Load quotation parts and photos - Update iddatadb with quotation parts and photo references
This commit is contained in:
parent
f6ea17388c
commit
03771e3ca8
32
public/userarea/load_quotations.php
Normal file
32
public/userarea/load_quotations.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
header('Content-Type: application/json');
|
||||
|
||||
include('include/headscript.php');
|
||||
|
||||
$dbHandler = DBHandlerSelect::getInstance();
|
||||
$pdo = $dbHandler->getConnection();
|
||||
|
||||
// Recupera l'ID dell'utente loggato
|
||||
$user_id = $iduserlogin ?? 1;
|
||||
|
||||
if (!$user_id) {
|
||||
echo json_encode(['success' => false, 'message' => "ID dell'utente autenticato mancante"]);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare(
|
||||
"SELECT DISTINCT q.*
|
||||
FROM quotations q
|
||||
INNER JOIN identification_parts ip
|
||||
ON ip.idquotations = q.id
|
||||
AND ip.iddatadb IS NULL
|
||||
WHERE q.iduser = :iduser"
|
||||
);
|
||||
$stmt->execute([':iduser' => $user_id]);
|
||||
$quotations = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
echo json_encode(['success' => true, 'quotations' => $quotations]);
|
||||
} catch (PDOException $e) {
|
||||
echo json_encode(['success' => false, 'message' => 'Errore nel caricamento delle quotations: ' . $e->getMessage()]);
|
||||
}
|
||||
@ -14,6 +14,7 @@
|
||||
<div style="display: flex; align-items: center;">
|
||||
<button type="button" class="btn btn-info btn-sm" id="renumberPartsBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Rinumera Parti</button>
|
||||
<button type="button" class="btn btn-secondary btn-sm ms-2" id="toggleVoiceBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;"><i class="fas fa-microphone"></i> Voce</button>
|
||||
<button type="button" class="btn btn-info btn-sm ms-2 d-none" id="quotationeBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Add Quotation</button>
|
||||
<button type="button" class="btn btn-primary btn-sm ms-2" id="showHideImageBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">
|
||||
<i class="fas fa-eye-slash" style="font-size: 0.8rem;"></i>
|
||||
<i class="fas fa-image ms-1" style="font-size: 0.8rem;"></i>
|
||||
@ -145,6 +146,24 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Finestra modale "Aggiungi preventivo" -->
|
||||
<div class="modal fade" id="addQuotationModal" tabindex="-1" aria-labelledby="addQuotationModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-md">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addQuotationModalLabel">Choose a quotation</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<select id="addQuotationSelect" class="form-control form-control-sm" style="width: 100% !important; min-width: 100% !important"></select>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Annulla</button>
|
||||
<button type="button" class="btn btn-primary btn-sm" id="addQuotationBtn">Confirm</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* --- Base --- */
|
||||
@ -161,6 +180,14 @@
|
||||
max-width: 100% !important
|
||||
}
|
||||
|
||||
#addQuotationModal {
|
||||
z-index: 1060 !important
|
||||
}
|
||||
|
||||
#addQuotationModal .modal-backdrop {
|
||||
z-index: 1055 !important
|
||||
}
|
||||
|
||||
/* Tabelle */
|
||||
#partsTable tr {
|
||||
display: table-row !important
|
||||
|
||||
@ -6,6 +6,7 @@ $(document).ready(function () {
|
||||
let unsavedChanges = false;
|
||||
let matrici = [];
|
||||
let macroMatrici = [];
|
||||
let quotations = [];
|
||||
|
||||
// --- ROW ID helpers: niente più cache impazzita di jQuery .data() ---
|
||||
function getPartId($row) {
|
||||
@ -141,7 +142,7 @@ $(document).ready(function () {
|
||||
// ===================
|
||||
// MODAL HANDLING
|
||||
// ===================
|
||||
function loadParts(iddatadb, idquotations) {
|
||||
function loadParts(iddatadb, idquotations, callback = null) {
|
||||
if (iddatadb) {
|
||||
if (matrici.length === 0) {
|
||||
$.ajax({
|
||||
@ -153,14 +154,14 @@ $(document).ready(function () {
|
||||
loadMacroMatrici();
|
||||
initializeGlobalSelect2();
|
||||
loadPhoto(iddatadb, idquotations);
|
||||
loadExistingParts(iddatadb, idquotations);
|
||||
loadExistingParts(iddatadb, idquotations, callback);
|
||||
},
|
||||
error: function (xhr, status, error) {
|
||||
matrici = [];
|
||||
loadMacroMatrici();
|
||||
initializeGlobalSelect2();
|
||||
loadPhoto(iddatadb, idquotations);
|
||||
loadExistingParts(iddatadb, idquotations);
|
||||
loadExistingParts(iddatadb, idquotations, callback);
|
||||
const errorMsg = $(
|
||||
'<div class="alert alert-danger temp-alert" role="alert">Errore nel caricamento delle matrici: ' +
|
||||
error +
|
||||
@ -180,11 +181,11 @@ $(document).ready(function () {
|
||||
loadMacroMatrici();
|
||||
initializeGlobalSelect2();
|
||||
loadPhoto(iddatadb, idquotations);
|
||||
loadExistingParts(iddatadb, idquotations);
|
||||
loadExistingParts(iddatadb, idquotations, callback);
|
||||
}
|
||||
} else {
|
||||
loadPhoto(iddatadb, idquotations);
|
||||
loadExistingParts(iddatadb, idquotations);
|
||||
loadExistingParts(iddatadb, idquotations, callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -589,6 +590,8 @@ $(document).ready(function () {
|
||||
if (response.success) {
|
||||
$saveStatus.show();
|
||||
setTimeout(() => $saveStatus.hide(), 2000);
|
||||
|
||||
if (!$("#quotationeBtn").hasClass('d-none')) $("#quotationeBtn").addClass("d-none");
|
||||
} else {
|
||||
const errorMsg = $(
|
||||
'<div class="alert alert-danger temp-alert" role="alert">Errore nel salvataggio: ' +
|
||||
@ -1155,7 +1158,7 @@ $(document).ready(function () {
|
||||
saveRow($(this).closest("tr"));
|
||||
});
|
||||
|
||||
function loadExistingParts(iddatadb, idquotations) {
|
||||
function loadExistingParts(iddatadb, idquotations, callback = null) {
|
||||
const endpoint = idquotations
|
||||
? "load_parts_quotation.php"
|
||||
: "load_parts.php";
|
||||
@ -1233,8 +1236,11 @@ $(document).ready(function () {
|
||||
});
|
||||
} else {
|
||||
addNewRow(1, false); // Riga iniziale normale
|
||||
$("#quotationeBtn").removeClass("d-none");
|
||||
}
|
||||
updateRowButtons();
|
||||
|
||||
if (callback) callback();
|
||||
},
|
||||
error: function (xhr, status, error) {
|
||||
const errorMsg = $(
|
||||
@ -1787,6 +1793,114 @@ $(document).ready(function () {
|
||||
|
||||
// Esporta la funzione loadParts per essere usata da import_Edit2.php
|
||||
window.loadParts = loadParts;
|
||||
|
||||
$(document).on("click", "#quotationeBtn", function () {
|
||||
$("#addQuotationModal").modal("show");
|
||||
|
||||
if (quotations.length > 0) {
|
||||
reloadQuotations();
|
||||
} else {
|
||||
$.ajax({
|
||||
url: "load_quotations.php",
|
||||
method: "GET",
|
||||
success: function (response) {
|
||||
quotations = response?.quotations || [];
|
||||
|
||||
reloadQuotations();
|
||||
},
|
||||
error: function (xhr, status, error) {
|
||||
console.error("Errore AJAX caricamento quotations:", error, xhr.responseText);
|
||||
let message = `
|
||||
<div class="alert alert-danger temp-alert" role="alert">
|
||||
Errore nel caricamento delle quotations: ${error} (${xhr.status})
|
||||
</div>
|
||||
`;
|
||||
|
||||
$("#partsModal .modal-body").prepend(errorMsg);
|
||||
|
||||
setTimeout(function () {
|
||||
message.fadeOut(500, function () {
|
||||
$(this).remove();
|
||||
});
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on("click", "#addQuotationBtn", function () {
|
||||
const quotationId = $("#addQuotationSelect").val();
|
||||
|
||||
if (quotationId && confirm("Confermo di collegare la quotazione al campione?")) {
|
||||
$("#addQuotationModal").modal("hide");
|
||||
|
||||
loadParts(null, quotationId, () => {
|
||||
$("#quotationeBtn").addClass("d-none");
|
||||
|
||||
setTimeout(() => {
|
||||
$("#partsTableBody tr").each(function () {
|
||||
$(this).find(".save-loading").show();
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
url: "save_parts_photo_iddatadb.php",
|
||||
method: "POST",
|
||||
data: JSON.stringify({
|
||||
iddatadb: $("#partsModal").data("iddatadb"),
|
||||
photoList: $('#photoSelector option').map(function () {
|
||||
return this.value?.split('/')?.pop();
|
||||
}).get(),
|
||||
partIds: $('#partsTableBody tr').map(function () {
|
||||
return $(this).data("part-id");
|
||||
}).get(),
|
||||
}),
|
||||
success: function () {
|
||||
$("#partsTableBody tr").each(function () {
|
||||
let $row = $(this);
|
||||
let $saveStatus = $row.find(".save-status");
|
||||
let $saveLoading = $row.find(".save-loading");
|
||||
|
||||
$saveLoading.hide();
|
||||
$saveStatus.show();
|
||||
|
||||
setTimeout(() => $saveStatus.hide(), 2000);
|
||||
});
|
||||
}, error: function (xhr, status, error) {
|
||||
let message = `
|
||||
<div class="alert alert-danger temp-alert" role="alert">
|
||||
Errore di salvataggio: ${error} (${xhr.status})
|
||||
</div>
|
||||
`;
|
||||
|
||||
$("#partsModal .modal-body").prepend(message);
|
||||
|
||||
setTimeout(function () {
|
||||
message.fadeOut(500, function () {
|
||||
$(this).remove();
|
||||
});
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function reloadQuotations() {
|
||||
if (quotations.length > 0) {
|
||||
$("#addQuotationSelect").empty();
|
||||
|
||||
$("#addQuotationSelect").append("<option value=''>Seleziona Quotation</option>");
|
||||
|
||||
quotations.forEach(quotation => {
|
||||
if (quotation?.description) {
|
||||
$("#addQuotationSelect").append(`<option value='${quotation?.id}'>${quotation?.description}</option>`);
|
||||
}
|
||||
});
|
||||
|
||||
$("#addQuotationSelect").select2();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on("change", ".propagate-date-input", function () {
|
||||
|
||||
48
public/userarea/save_parts_photo_iddatadb.php
Normal file
48
public/userarea/save_parts_photo_iddatadb.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
header('Content-Type: application/json');
|
||||
include('include/headscript.php');
|
||||
|
||||
$dbHandler = DBHandlerSelect::getInstance();
|
||||
$pdo = $dbHandler->getConnection();
|
||||
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
$iddatadb = $data['iddatadb'] ?? null;
|
||||
$partIds = $data['partIds'] ?? [];
|
||||
$photoList = $data['photoList'] ?? null;
|
||||
|
||||
if ($iddatadb) {
|
||||
if (count($partIds) != 0) {
|
||||
$idList = array_values(array_map('intval', $partIds));
|
||||
$placeholders = [];
|
||||
$parameters = [':iddatadb' => $iddatadb];
|
||||
|
||||
foreach ($idList as $index => $id) {
|
||||
$paramName = ":id{$index}";
|
||||
$placeholders[] = $paramName;
|
||||
$parameters[$paramName] = $id;
|
||||
}
|
||||
|
||||
$sql = 'UPDATE identification_parts SET iddatadb = :iddatadb WHERE id IN (' . implode(',', $placeholders) . ')';
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($parameters);
|
||||
}
|
||||
|
||||
if (count($photoList) != 0) {
|
||||
$placeholders = [];
|
||||
$parameters = [':iddatadb' => $iddatadb];
|
||||
|
||||
foreach ($photoList as $index => $photo) {
|
||||
$paramName = ":photo{$index}";
|
||||
$placeholders[] = $paramName;
|
||||
$parameters[$paramName] = $photo;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare('UPDATE datadb_photos SET iddatadb = :iddatadb WHERE file_path IN (' . implode(',', $placeholders) . ')');
|
||||
$stmt->execute($parameters);
|
||||
}
|
||||
|
||||
echo json_encode(['success' => true, 'message' => '']);
|
||||
} else {
|
||||
echo json_encode(['success' => false, 'message' => 'Dati mancanti']);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user