theloftstore/public/userarea/import_list.php
2025-11-17 15:05:10 +01:00

424 lines
18 KiB
PHP

<?php
include('include/headscript.php');
require_once(__DIR__ . '/class/db-functions.php'); // usa la tua classe PDO
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Imported Data Management</title>
<?php include('cssinclude.php'); ?>
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css">
<style>
.editable {
cursor: pointer;
background-color: #fff8e1;
}
.action-btn {
padding: 4px 8px;
font-size: 0.85rem;
}
td.editable:hover {
background-color: #fff5cc;
cursor: text;
}
td.modified {
background-color: #ff9c9cff !important;
/* evidenzia celle modificate */
}
td.noedit {
background-color: #f8f9fa;
color: #888;
}
</style>
</head>
<body>
<div class="wrapper">
<?php include('include/navbar.php'); ?>
<div class="dashboard-main-wrapper wrapper">
<?php include('include/topbar.php'); ?>
<div class="dashboard-body">
<div class="card shadow-sm">
<div class="card-body">
<div class="d-flex flex-wrap justify-content-between align-items-center mb-3">
<h4 class="mb-0">Imported Data</h4>
<div class="d-flex align-items-center gap-2">
<label for="clientFilter" class="form-label mb-0 me-2">Filter by Client:</label>
<select id="clientFilter" class="form-select form-select-sm" style="width: 220px;">
<option value="">All Clients</option>
<?php
// carichiamo i clienti dal DB
$clients = $pdo->query("SELECT idclient, client_name FROM clients ORDER BY client_name")->fetchAll(PDO::FETCH_ASSOC);
foreach ($clients as $cl) {
echo '<option value="' . htmlspecialchars($cl['idclient']) . '">' . htmlspecialchars($cl['client_name']) . '</option>';
}
?>
</select>
</div>
</div>
<div class="d-flex justify-content-between align-items-center mb-2">
<div>
<button id="updatePricesBtn" class="btn btn-warning btn-sm" style="display:none;">
<i class="fas fa-sync-alt"></i> Aggiorna Prezzi
</button>
</div>
</div>
<div class="table-responsive">
<table id="importTable" class="table table-striped table-bordered w-100">
<thead>
<tr>
<th></th> <!-- Checkbox column -->
<th>ID</th>
<th>Collection</th>
<th>Category</th>
<th>Model</th>
<th>Model Description</th>
<th>Mod.Code</th>
<th>Description</th>
<th>Finish.Code</th>
<th>Finishing Description</th>
<th>Available Qty</th>
<th>WH</th>
<th>Price</th>
<th>Actions</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
<?php include('include/footer.php'); ?>
</div>
<?php include('jsinclude.php'); ?>
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script>
<script>
$(document).ready(function() {
let table = $('#importTable').DataTable({
ajax: {
url: 'import_list_data.php',
dataSrc: ''
},
columns: [{
data: null,
orderable: false,
searchable: false,
className: 'text-center',
render: function() {
return '<input type="checkbox" class="row-check" />';
}
},
{
data: 'id'
},
{
data: 'collection',
className: 'editable'
},
{
data: 'category',
className: 'noedit text-muted'
},
{
data: 'model',
className: 'editable'
},
{
data: 'model_description',
className: 'editable'
},
{
data: 'mod_code',
className: 'text-muted'
},
{
data: 'description',
className: 'editable'
},
{
data: 'finish_code',
className: 'editable'
},
{
data: 'finishing_description',
className: 'editable'
},
{
data: 'available_qty',
className: 'editable'
},
{
data: 'wh',
className: 'editable'
},
{
data: 'price',
className: 'editable'
},
{
data: null,
orderable: false,
render: function(data, type, row) {
return `
<button class="btn btn-success btn-sm action-btn save-row" data-id="${row.id}">
<i class="fas fa-save"></i>
</button>
<button class="btn btn-danger btn-sm action-btn delete-row" data-id="${row.id}">
<i class="fas fa-trash"></i>
</button>
`;
}
}
],
pageLength: 25,
order: [
[1, 'desc']
],
responsive: true,
autoWidth: false
});
// === Filtro per Client ===
$('#clientFilter').on('change', function() {
const selectedClient = $(this).val();
// Ricarica i dati passando il parametro idclient
table.ajax.url('import_list_data.php' + (selectedClient ? '?idclient=' + selectedClient : '')).load();
});
// === Inline Editing ===
$('#importTable tbody').on('click', 'td.editable', function() {
const cell = table.cell(this);
const rowData = table.row(cell.index().row).data();
const colName = table.column(cell.index().column).dataSrc();
const originalValue = rowData[colName] ?? '';
// Evita doppia apertura
if ($(this).find('input').length > 0) return;
const input = $('<input type="text" class="form-control form-control-sm"/>')
.val(originalValue)
.css({
'min-width': '120px',
'height': '24px',
'padding': '0 4px'
});
$(this).html(input);
input.focus();
// Gestione conferma o uscita
input.on('blur keydown', function(e) {
if (e.type === 'blur' || e.key === 'Enter') {
const newValue = $(this).val();
// Aggiorna in memoria e interfaccia
rowData[colName] = newValue;
table.row(cell.index().row).data(rowData).draw(false);
const td = $(table.cell(cell.index()).node());
if (newValue !== originalValue) {
td.addClass('modified'); // evidenzia modificato
} else {
td.removeClass('modified');
}
}
});
});
// === Salvataggio singola riga ===
$('#importTable').on('click', '.save-row', function() {
const rowData = table.row($(this).closest('tr')).data();
$.ajax({
url: 'import_list_save.php',
type: 'POST',
data: {
row: JSON.stringify(rowData)
},
success: function(res) {
Swal.close();
// Se il server restituisce già JSON, non serve JSON.parse()
let json = (typeof res === 'object') ? res : null;
if (!json) {
try {
json = JSON.parse(res);
} catch (e) {
console.error("Invalid JSON from server:", res);
Swal.fire('Errore', 'Risposta non valida dal server.', 'error');
return;
}
}
if (json.status === 'ok') {
Swal.fire({
title: 'Successo',
text: `Aggiornati ${json.updated} prezzi.`,
icon: 'success',
timer: 2000,
showConfirmButton: false
});
table.ajax.reload(null, false); // 🔁 aggiorna tabella
} else {
console.error("Errore backend:", json);
Swal.fire('Errore', json.message || 'Errore sconosciuto.', 'error');
}
},
error: function(xhr, status, err) {
Swal.fire('Errore', 'Errore di rete o server non raggiungibile.', 'error');
console.error("AJAX error:", status, err, xhr.responseText);
}
});
});
// === Eliminazione con conferma ===
$('#importTable').on('click', '.delete-row', function() {
const id = $(this).data('id');
Swal.fire({
title: 'Are you sure?',
text: 'This record will be permanently deleted.',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Yes, delete it',
cancelButtonText: 'Cancel'
}).then(result => {
if (result.isConfirmed) {
$.ajax({
url: 'import_list_delete.php',
type: 'POST',
data: {
id: id
},
success: function(res) {
let json;
try {
json = JSON.parse(res);
} catch (e) {
Swal.fire('Error', res, 'error');
return;
}
if (json.status === 'ok') {
Swal.fire('Deleted', 'Row removed successfully.', 'success');
table.ajax.reload(null, false);
} else {
Swal.fire('Error', json.message, 'error');
}
},
error: function() {
Swal.fire('Error', 'Request failed.', 'error');
}
});
}
});
});
// === Gestione selezione righe e pulsante Aggiorna Prezzi ===
$('#importTable').on('change', '.row-check', function() {
const checkedCount = $('#importTable .row-check:checked').length;
$('#updatePricesBtn').toggle(checkedCount > 0);
});
// === Aggiornamento prezzi con ChatPDF ===
$('#updatePricesBtn').on('click', function() {
const selectedRows = [];
$('#importTable .row-check:checked').each(function() {
const row = table.row($(this).closest('tr')).data();
if (row) selectedRows.push(row);
});
if (selectedRows.length === 0) {
Swal.fire('Notice', 'Seleziona almeno una riga.', 'info');
return;
}
const clientId = $('#clientFilter').val();
if (!clientId) {
Swal.fire('Notice', 'Seleziona prima un cliente.', 'info');
return;
}
Swal.fire({
title: 'Aggiornare i prezzi?',
text: `Verranno interrogati i prezzi per ${selectedRows.length} prodotti.`,
icon: 'question',
showCancelButton: true,
confirmButtonText: 'Procedi',
cancelButtonText: 'Annulla'
}).then(result => {
if (result.isConfirmed) {
Swal.fire({
title: 'Aggiornamento in corso...',
allowOutsideClick: false,
didOpen: () => Swal.showLoading()
});
$.ajax({
url: 'update_prices_chatpdf.php',
type: 'POST',
data: {
rows: JSON.stringify(selectedRows),
idclient: clientId
},
success: function(res) {
Swal.close();
// Se il server ha già restituito un oggetto JSON, usiamolo direttamente
let json = (typeof res === "object") ? res : null;
// Se invece è una stringa JSON, parse
if (!json) {
try {
json = JSON.parse(res);
} catch (e) {
console.error("JSON parse error:", res);
Swal.fire('Errore', 'Risposta non valida dal server.', 'error');
return;
}
}
// Ora siamo sicuri che json è un oggetto valido
if (json.status === 'ok') {
Swal.fire('Successo', `Aggiornati ${json.updated} prezzi.`, 'success');
table.ajax.reload(null, false);
} else {
Swal.fire('Errore', json.message || 'Errore sconosciuto.', 'error');
}
},
error: function() {
Swal.fire('Errore', 'Aggiornamento fallito.', 'error');
}
});
}
});
});
});
</script>
</div> <!-- end wrapper -->
</body>
</html>