first commit theloftstore

This commit is contained in:
2025-11-12 18:43:50 +01:00
parent e75be99e43
commit 6b65b31932
480 changed files with 9352 additions and 57951 deletions
+216 -261
View File
@@ -1,303 +1,258 @@
<?php
include('include/headscript.php');
// Controlla se è stato passato un ID valido
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
header("Location: xlstemplates_grid.php?status=error&message=" . urlencode("Invalid ID"));
exit;
}
$id = intval($_GET['id']); // Sanifica l'ID
// Recupera il template dal database
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection();
$stmt = $pdo->prepare("SELECT * FROM excel_templates WHERE id = ?");
$stmt->execute([$id]);
$template = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$template) {
header("Location: template_dashboard.php?status=error&message=" . urlencode("Template not found"));
exit;
}
// Debug del template
error_log("Loaded template: " . print_r($template, true));
// Recupera lista clienti
$clients = $pdo->query("SELECT idclient, client_name FROM clients ORDER BY client_name")->fetchAll(PDO::FETCH_ASSOC);
?>
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Import XLS - Cassina Products</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>
.table-container {
overflow-x: auto;
max-width: 100%;
margin-bottom: 20px;
}
.table {
width: 100%;
border-collapse: collapse;
}
.table th,
.table td {
padding: 10px;
text-align: left;
border: 1px solid #dee2e6;
min-width: 100px;
max-width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.table th:first-child,
.table td:first-child {
min-width: 50px;
max-width: 50px;
.select2-container {
width: 100% !important;
}
.table td,
.table th {
background-color: #f8f9fa;
position: relative;
cursor: col-resize;
user-select: none;
}
.table th .resize-handle {
position: absolute;
top: 0;
right: 0;
width: 5px;
height: 100%;
cursor: col-resize;
background: transparent;
}
.table th .resize-handle:hover {
background: #007bff;
}
.search-container {
margin-bottom: 20px;
}
.search-container input {
width: 300px;
padding: 8px;
border: 1px solid #ced4da;
border-radius: 5px;
}
.loader {
display: none;
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
width: 30px;
height: 30px;
animation: spin 1s linear infinite;
margin: 10px auto;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
vertical-align: middle;
}
</style>
<title><?= htmlspecialchars($template['name']) ?> - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
</head>
<body>
<div class="wrapper">
<?php include('include/navbar.php'); ?>
<?php include('include/navbar.php'); ?>
<div class="dashboard-main-wrapper">
<?php include('include/topbar.php'); ?>
<div class="page-wrapper">
<div class="page-content">
<?php include('top_stat_widget.php'); ?>
<div class="card radius-10">
<div class="card-header">
<div class="d-flex align-items-center">
<div>
<h6 class="mb-0"><?= htmlspecialchars($template['name']) ?></h6>
<small>Template ID: <?= $id ?>, Start Row: <?= $template['header_row'] ?>, Start Column: <?= $template['start_column'] ?></small>
<div class="dashboard-body">
<div class="card shadow-sm">
<div class="card-body">
<h4 class="mb-4">Import Excel File</h4>
<!-- Upload Form -->
<form id="uploadForm" enctype="multipart/form-data" method="POST">
<div class="row g-3 align-items-end">
<div class="col-md-3">
<label for="xlsFile" class="form-label">Excel file (.xls / .xlsx)</label>
<input type="file" name="xlsFile" id="xlsFile" accept=".xls,.xlsx" class="form-control" required>
</div>
<div class="col-md-2">
<label for="headerRow" class="form-label">Header row</label>
<input type="number" name="headerRow" id="headerRow" value="4" min="1" class="form-control" required>
</div>
<div class="col-md-3">
<label for="idclient" class="form-label">Client</label>
<select name="idclient" id="idclient" class="form-select select2" required>
<option value="">Select client...</option>
<?php foreach ($clients as $cl): ?>
<option value="<?= htmlspecialchars($cl['idclient']) ?>">
<?= htmlspecialchars($cl['client_name']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-primary w-100">
<i class="fas fa-upload"></i> Upload
</button>
</div>
</div>
</div>
<div class="card-body">
<!-- Form per caricare il file -->
<form id="uploadForm" enctype="multipart/form-data" class="mb-4">
<div class="mb-3">
<label for="excel_file" class="form-label">Upload XLS File</label>
<input type="file" class="form-control" id="excel_file" name="excel_file" accept=".xls,.xlsx" required>
</div>
<button type="submit" class="btn btn-primary">Upload</button>
<div class="loader" id="loader"></div>
</form>
</form>
<!-- Contenitore per messaggi di errore -->
<div id="errorContainer" class="alert alert-danger mt-3" style="display: none;"></div>
<hr class="my-4">
<!-- Contenitore per la tabella -->
<div id="tableContainer"></div>
<!-- Filter + Table Section -->
<div id="tableSection" class="d-none">
<div class="mb-3">
<label class="form-label">Filter by Categories</label>
<select id="categorySelect" class="form-select select2" multiple></select>
</div>
<table id="dataTable" class="table table-striped table-bordered w-100">
<thead></thead>
<tbody></tbody>
</table>
<button id="saveData" class="btn btn-success mt-3">
<i class="fas fa-save"></i> Save to Database
</button>
</div>
</div>
</div>
</div>
<!--end page wrapper -->
<div class="overlay toggle-icon"></div>
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
<?php include('include/footer.php'); ?>
</div>
<!--end wrapper-->
<!-- search modal -->
<?php //include('include/searchmodal.php');
?>
<!-- end search modal -->
<!--start switcher-->
<?php //include('include/themeswitcher.php');
?>
<!--end switcher-->
<?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 src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
const form = document.getElementById('uploadForm');
const loader = document.getElementById('loader');
const errorContainer = document.getElementById('errorContainer');
const tableContainer = document.getElementById('tableContainer');
$(document).ready(function() {
form.addEventListener('submit', function(e) {
$('.select2').select2();
let fullData = [];
let table;
// === Upload Excel ===
$('#uploadForm').on('submit', function(e) {
e.preventDefault();
loader.style.display = 'block';
errorContainer.style.display = 'none';
tableContainer.innerHTML = '';
let formData = new FormData(this);
const formData = new FormData(this);
formData.append('template_id', <?= $id ?>);
formData.append('header_row', <?= $template['header_row'] ?>);
formData.append('start_column', <?= $template['start_column'] ?>);
fetch('process_import_xls.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
loader.style.display = 'none';
if (data.error) {
errorContainer.textContent = data.error;
errorContainer.style.display = 'block';
} else {
let html = `
<form id="selectRowsForm" action="import_edit.php" method="POST">
<input type="hidden" name="template_id" value="${data.template_id}">
<input type="hidden" name="columns" value='${JSON.stringify(data.columns)}'>
<input type="hidden" name="rows" value='${JSON.stringify(data.rows)}'>
<input type="hidden" name="filename" value="${data.filename}">
<div class="search-container">
<input type="text" id="searchInput" class="form-control" placeholder="Cerca nelle righe...">
</div>
<div class="table-container">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Seleziona</th>
${data.columns.map(col => `<th>${col || 'Colonna senza nome'}<div class="resize-handle"></div></th>`).join('')}
</tr>
</thead>
<tbody>
${data.rows.map((row, index) => `
<tr>
<td><input type="checkbox" class="row-checkbox" name="selected_rows[]" value="${index}"></td>
${row.map(cell => `<td>${cell}</td>`).join('')}
</tr>
`).join('')}
</tbody>
</table>
</div>
<button type="submit" class="btn btn-primary mt-3" id="proceedButton" disabled>Prosegui</button>
</form>
`;
tableContainer.innerHTML = html;
// Aggiungi logica per il ridimensionamento delle colonne
const thElements = document.querySelectorAll('.table th');
thElements.forEach((th, index) => {
if (index === 0) return; // Escludi la colonna "Seleziona" dal ridimensionamento
const resizeHandle = th.querySelector('.resize-handle');
if (resizeHandle) {
resizeHandle.addEventListener('mousedown', (e) => {
e.preventDefault();
const startX = e.clientX;
const startWidth = th.offsetWidth;
const onMouseMove = (e) => {
const newWidth = Math.max(50, startWidth + (e.clientX - startX));
th.style.width = `${newWidth}px`;
th.style.minWidth = `${newWidth}px`;
th.style.maxWidth = `${newWidth}px`;
const cells = document.querySelectorAll(`.table td:nth-child(${index + 1})`);
cells.forEach(cell => {
cell.style.width = `${newWidth}px`;
cell.style.minWidth = `${newWidth}px`;
cell.style.maxWidth = `${newWidth}px`;
});
};
const onMouseUp = () => {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
};
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
});
}
});
// Aggiungi event listener per la ricerca
const searchInput = document.getElementById('searchInput');
const rows = document.querySelectorAll('.table tbody tr');
const checkboxes = document.querySelectorAll('.row-checkbox');
const proceedButton = document.getElementById('proceedButton');
searchInput.addEventListener('input', function() {
const searchTerm = this.value.toLowerCase();
rows.forEach(row => {
const text = Array.from(row.cells).slice(1).map(cell => cell.textContent.toLowerCase()).join(' ');
row.style.display = text.includes(searchTerm) ? '' : 'none';
});
});
// Aggiungi event listener per i checkbox
checkboxes.forEach(checkbox => {
checkbox.addEventListener('change', function() {
proceedButton.disabled = !Array.from(checkboxes).some(cb => cb.checked);
});
});
$.ajax({
url: 'import_xls_process.php',
type: 'POST',
data: formData,
processData: false,
contentType: false,
beforeSend: () => Swal.fire({
title: 'Processing...',
allowOutsideClick: false,
didOpen: () => Swal.showLoading()
}),
success: function(res) {
Swal.close();
let json;
try {
json = JSON.parse(res);
} catch (e) {
Swal.fire('Error', 'Invalid JSON:' + res, 'error');
return;
}
})
.catch(error => {
loader.style.display = 'none';
errorContainer.textContent = 'Errore durante il caricamento del file: ' + error.message;
errorContainer.style.display = 'block';
});
if (json.status === 'ok') {
fullData = json.data;
$('#tableSection').removeClass('d-none');
// Popola Select categorie
$('#categorySelect').empty();
json.categories.forEach(cat => {
$('#categorySelect').append(`<option value="${cat}">${cat}</option>`);
});
// Mostra tabella vuota inizialmente (nessuna categoria selezionata)
renderTable([], json.columns);
Swal.fire('Success', 'File uploaded successfully! Select categories to view data.', 'success');
} else {
Swal.fire('Error', json.message, 'error');
}
},
error: function() {
Swal.fire('Error', 'Upload failed.', 'error');
}
});
});
// === Filtro dinamico categorie ===
$('#categorySelect').on('change', function() {
const selected = $(this).val();
let filtered = [];
if (selected && selected.length) {
filtered = fullData.filter(r => selected.includes(r['category']));
}
renderTable(filtered, fullData.length ? Object.keys(fullData[0]) : []);
});
// === Funzione per DataTable ===
function renderTable(data, columns) {
if ($.fn.DataTable.isDataTable('#dataTable')) {
$('#dataTable').DataTable().destroy();
}
// Aggiungiamo una colonna "Select"
const cols = [{
title: '<input type="checkbox" id="selectAllRows" />',
data: null,
orderable: false,
searchable: false,
className: 'text-center',
render: function() {
return '<input type="checkbox" class="row-select" />';
}
},
...columns.map(c => ({
title: c.replace(/_/g, ' ').toUpperCase(),
data: c
}))
];
table = $('#dataTable').DataTable({
destroy: true,
data: data,
columns: cols,
pageLength: 25,
order: [],
createdRow: function(row, rowData) {
const selectedCats = $('#categorySelect').val() || [];
const cat = (rowData['category'] || '').trim();
if (selectedCats.includes(cat)) {
$(row).find('input.row-select').prop('checked', true);
}
$(row).find('input.row-select').data('row', rowData);
}
});
// --- Gestione "Select All" ---
$('#selectAllRows').off('click').on('click', function() {
const isChecked = this.checked;
$('#dataTable input.row-select').prop('checked', isChecked);
});
}
// === Salvataggio selezione ===
$('#saveData').on('click', function() {
const selectedRows = [];
$('#dataTable input.row-select:checked').each(function() {
const rowData = $(this).data('row');
if (rowData) selectedRows.push(rowData);
});
if (selectedRows.length === 0) {
Swal.fire('Notice', 'No rows selected for import.', 'info');
return;
}
$.ajax({
url: 'import_save.php',
type: 'POST',
data: {
rows: JSON.stringify(selectedRows),
idclient: $('#idclient').val(),
source_file: $('#xlsFile')[0].files[0]?.name || ''
},
success: function(res) {
let json;
try {
json = JSON.parse(res);
} catch (e) {
Swal.fire('Error', res, 'error');
return;
}
if (json.status === 'ok') Swal.fire('Success', 'Rows imported successfully!', 'success');
else Swal.fire('Error', json.message, 'error');
},
error: function() {
Swal.fire('Error', 'Failed to import data.', 'error');
}
});
});
});
</script>
</body>