diff --git a/public/userarea/add_part_quick.php b/public/userarea/add_part_quick.php new file mode 100644 index 0000000..400ec2b --- /dev/null +++ b/public/userarea/add_part_quick.php @@ -0,0 +1,52 @@ + 255) { + $part_description = mb_substr($part_description, 0, 255); + } + + $db = DBHandlerSelect::getInstance(); + $pdo = $db->getConnection(); + + // Insert minimal + $stmt = $pdo->prepare(" + INSERT INTO identification_parts (iddatadb, part_number, part_description) + VALUES (?, 1, ?) + "); + $ok = $stmt->execute([$iddatadb, $part_description]); + + if (!$ok) { + throw new Exception('Insert failed'); + } + + echo json_encode([ + 'success' => true, + 'message' => 'Part added', + 'id' => $pdo->lastInsertId() + ]); +} catch (Exception $e) { + echo json_encode(['success' => false, 'message' => $e->getMessage()]); +} +exit; diff --git a/public/userarea/import_edit2.php b/public/userarea/import_edit2.php index 0f3b21d..766145d 100644 --- a/public/userarea/import_edit2.php +++ b/public/userarea/import_edit2.php @@ -278,8 +278,8 @@ function fixedDefaultValue(array $f): string } /* Sticky columns - first column (Actions) */ - .grid-top .grid-cell.save-all-cell, - .grid-header.button-header, + .grid-top .grid-cell.save-all-cell, + .grid-header.button-header, .grid-cell.button-cell { position: sticky !important; left: 0; @@ -301,7 +301,7 @@ function fixedDefaultValue(array $f): string background-color: #e9ecef; } - .grid-top .grid-cell:nth-child(2), + .grid-top .grid-cell:nth-child(2), .grid-row .grid-header:nth-child(2), .grid-row .grid-cell:nth-child(2) { position: sticky !important; @@ -323,7 +323,7 @@ function fixedDefaultValue(array $f): string .grid-row:hover .grid-cell:nth-child(2) { background-color: #e9ecef; } - + .grid-row { position: relative; } @@ -336,7 +336,7 @@ function fixedDefaultValue(array $f): string background-color: #e0f7fa !important; flex: 0 0 500px !important; } - + .grid-header.expanded { background-color: #e0f7fa !important; } @@ -748,8 +748,8 @@ function fixedDefaultValue(array $f): string $topColIndex++; } } - - echo "
"; + + echo ""; $topColIndex++; echo ""; $topColIndex++; @@ -1125,9 +1125,9 @@ function fixedDefaultValue(array $f): string function expandColumn(cell, expand) { const columnIndex = cell.getAttribute('data-index'); if (!columnIndex) return; - + const allColumnCells = document.querySelectorAll(`.grid-cell[data-index="${columnIndex}"], .grid-header[data-index="${columnIndex}"], .grid-top-cell[data-index="${columnIndex}"]`); - + allColumnCells.forEach(colCell => { if (expand) { colCell.classList.add('expanded'); @@ -1511,8 +1511,8 @@ function fixedDefaultValue(array $f): string // Gestione degli input inputs.forEach(input => { - if (input.tagName === 'SELECT' || - input.classList.contains('date-picker') || + if (input.tagName === 'SELECT' || + input.classList.contains('date-picker') || input.type === 'number' || input.type === 'date') { input.addEventListener('focus', function() { @@ -1532,7 +1532,7 @@ function fixedDefaultValue(array $f): string expandColumn(cell, true); cell.dataset.convertingToTextarea = 'true'; - + const textarea = document.createElement('textarea'); textarea.value = this.value; @@ -1546,9 +1546,9 @@ function fixedDefaultValue(array $f): string textarea.setAttribute('data-current-value', this.getAttribute('data-current-value') || ''); textarea.setAttribute('data-fixed-key', this.getAttribute('data-fixed-key') || ''); textarea.dataset.originalInput = 'true'; - + this.parentNode.replaceChild(textarea, this); - + setTimeout(() => { textarea.focus(); delete cell.dataset.convertingToTextarea; @@ -1566,7 +1566,7 @@ function fixedDefaultValue(array $f): string const element = e.target; if (element.tagName === 'TEXTAREA' && element.dataset.originalInput === 'true') { const cell = element.closest('.grid-cell'); - + const input = document.createElement('input'); input.type = 'text'; input.value = element.value; @@ -1578,16 +1578,16 @@ function fixedDefaultValue(array $f): string input.setAttribute('data-selected-value', element.getAttribute('data-selected-value') || ''); input.setAttribute('data-current-value', element.getAttribute('data-current-value') || ''); input.setAttribute('data-fixed-key', element.getAttribute('data-fixed-key') || ''); - + element.parentNode.replaceChild(input, element); - + expandColumn(cell, false); - + input.addEventListener('focus', function() { const cell = this.closest('.grid-cell'); expandColumn(cell, true); cell.dataset.convertingToTextarea = 'true'; - + const textarea = document.createElement('textarea'); textarea.value = this.value; textarea.name = this.name; @@ -1600,15 +1600,17 @@ function fixedDefaultValue(array $f): string textarea.setAttribute('data-current-value', this.getAttribute('data-current-value') || ''); textarea.setAttribute('data-fixed-key', this.getAttribute('data-fixed-key') || ''); textarea.dataset.originalInput = 'true'; - + this.parentNode.replaceChild(textarea, this); setTimeout(() => { textarea.focus(); delete cell.dataset.convertingToTextarea; }, 0); }); - - const changeEvent = new Event('change', { bubbles: true }); + + const changeEvent = new Event('change', { + bubbles: true + }); input.dispatchEvent(changeEvent); } else if (element.tagName === 'INPUT' && element.type === 'text') { const cell = element.closest('.grid-cell'); @@ -1952,6 +1954,80 @@ function fixedDefaultValue(array $f): string }); }); + // Quick add part from "Tested Component" (+ button) + $(document).on('click', '.add-part-btn', async function() { + const rowIndex = $(this).data('row'); + const $row = $(this).closest('.grid-row'); + const iddatadb = $row.data('id'); + + // Input inside the same cell + const $cell = $(this).closest('.grid-cell'); + const $input = $cell.find('input[name^="rows["][name$="[tested_component]"]'); + + const partDescription = ($input.val() || '').trim(); + + if (!iddatadb) { + alert('❌ iddatadb not found on row'); + return; + } + + if (!partDescription) { + alert('⚠️ Inserisci prima una descrizione nel campo Tested Component.'); + $input.focus(); + return; + } + + try { + const formData = new FormData(); + formData.append('iddatadb', iddatadb); + formData.append('part_description', partDescription); + + const resp = await fetch('add_part_quick.php', { + method: 'POST', + body: formData + }); + + const data = await resp.json(); + + if (!resp.ok || !data.success) { + throw new Error(data.message || ('HTTP ' + resp.status)); + } + + // ✅ Do NOT clear tested_component: keep it as a warning/notice + $input.addClass('cell-changed'); + setTimeout(() => $input.removeClass('cell-changed'), 1200); + + // opzionale: se vuoi comunque “registrare” il cambiamento nel tracker unsaved + $input.trigger('change'); + + + showQuickPartModal('✅ Parte aggiunta con successo!'); + + + } catch (err) { + alert('❌ Errore aggiunta parte: ' + err.message); + console.error(err); + } + }); + + function showQuickPartModal(message) { + const modalEl = document.getElementById('quickPartModal'); + if (!modalEl) { + alert(message); // fallback se il modal non esiste + return; + } + + document.getElementById('quickPartModalMessage').textContent = message; + + let modal = bootstrap.Modal.getInstance(modalEl); + if (!modal) modal = new bootstrap.Modal(modalEl, { + backdrop: true, + keyboard: true + }); + modal.show(); + } + + $(document).on('click', '.parts-btn', function() { const iddatadb = $(this).data('iddatadb') || null; const idquotations = $(this).data('idquotations') || null; @@ -2256,7 +2332,7 @@ function fixedDefaultValue(array $f): string }); } }); - + // Fix for sticky columns const gridContainer = document.querySelector('.grid-container'); if (gridContainer) { @@ -2266,16 +2342,16 @@ function fixedDefaultValue(array $f): string row.style.minWidth = 'max-content'; } }); - + const gridTop = document.querySelector('.grid-top'); if (gridTop && !gridTop.style.minWidth) { gridTop.style.minWidth = 'max-content'; } - + const stickyTopCells = document.querySelectorAll('.grid-top .grid-cell.save-all-cell, .grid-top .grid-cell:nth-child(2)'); stickyTopCells.forEach(cell => { if (!cell.style.minWidth && !cell.style.flex) { - + const computedStyle = window.getComputedStyle(cell); if (computedStyle.flex === '0 0 auto' || !computedStyle.flex.includes('0 0')) { cell.style.minWidth = cell.offsetWidth + 'px';