Files
elixforms-web-pages/php/recupero-proposta-cct-da-contratti/index.php
T

440 lines
18 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/../common/ElixFormsComponent.php';
require_once __DIR__ . '/../common/QueryParamHelper.php';
use ElixForms\Common\ElixFormsComponent;
use ElixForms\Common\QueryParamHelper;
/**
* Pagina custom "Recupero Proposta CCT da Contratti" per elixForms.
* Equivalente PHP del componente React RecuperoPropostaCctDaContrattiComponent.
*/
class RecuperoPropostaCctDaContrattiPage extends ElixFormsComponent
{
private string $codiceFiscale;
private array $fieldKeys;
private int $minCharsForSearch;
public function __construct(array $properties, array $fieldKeys, int $minCharsForSearch = 3)
{
parent::__construct($properties);
$this->fieldKeys = $fieldKeys;
$this->minCharsForSearch = $minCharsForSearch;
// Recupera il codice fiscale dalla query string
$this->codiceFiscale = QueryParamHelper::getDecodedTextFromQuery($fieldKeys['codiceFiscale']) ?? '';
}
/**
* Genera l'HTML e CSS del componente Autocomplete e i relativi campi nascosti.
*/
protected function createCustomFormFields(): string
{
$escapedCodFis = htmlspecialchars($this->codiceFiscale, ENT_QUOTES, 'UTF-8');
$minChars = $this->minCharsForSearch;
// Campi di output definiti nella configurazione
$outCodiceContratto = htmlspecialchars($this->fieldKeys['codiceContratto']);
$outTitoloContratto = htmlspecialchars($this->fieldKeys['titoloContratto']);
$outIdDomanda = htmlspecialchars($this->fieldKeys['idDomanda']);
$outIdRicevuta = htmlspecialchars($this->fieldKeys['idRicevuta']);
// Recupero di eventuali valori correnti dal GET per precompilazione iniziale
$currCodice = htmlspecialchars(QueryParamHelper::getDecodedTextFromQuery($this->fieldKeys['codiceContratto']) ?? '', ENT_QUOTES, 'UTF-8');
$currTitolo = htmlspecialchars(QueryParamHelper::getDecodedTextFromQuery($this->fieldKeys['titoloContratto']) ?? '', ENT_QUOTES, 'UTF-8');
$currDomanda = htmlspecialchars(QueryParamHelper::getDecodedTextFromQuery($this->fieldKeys['idDomanda']) ?? '', ENT_QUOTES, 'UTF-8');
$currRicevuta = htmlspecialchars(QueryParamHelper::getDecodedTextFromQuery($this->fieldKeys['idRicevuta']) ?? '', ENT_QUOTES, 'UTF-8');
$initialSearchText = '';
if ($currCodice !== '' && $currTitolo !== '') {
$initialSearchText = "[{$currCodice}] {$currTitolo}";
}
// Layout del campo di ricerca
$autocompleteInputHtml = <<<HTML
<div class="autocomplete-wrapper" id="autocomplete-container">
<input
id="autocomplete-search"
name="autocomplete-search"
className="form-control"
class="form-control"
type="text"
placeholder="Digita almeno {$minChars} caratteri per cercare..."
value="{$initialSearchText}"
autoComplete="off"
/>
<div id="autocomplete-dropdown" class="autocomplete-dropdown d-none"></div>
<div id="selected-contract-card" class="card mt-3 d-none">
<div class="card-body">
<div class="row g-2">
<div class="col-12 col-md-6"><strong>ID Contratto:</strong> <span id="summary-id"></span></div>
<div class="col-12 col-md-6"><strong>Titolo:</strong> <span id="summary-title"></span></div>
<div class="col-12 col-md-6"><strong>ID Domanda:</strong> <span id="summary-domanda"></span></div>
<div class="col-12 col-md-6"><strong>ID Ricevuta:</strong> <span id="summary-ricevuta"></span></div>
</div>
</div>
</div>
</div>
<!-- Input Nascosti per elixForms -->
<input type="hidden" id="codiceContratto_hidden" name="{$outCodiceContratto}" value="{$currCodice}" />
<input type="hidden" id="titoloContratto_hidden" name="{$outTitoloContratto}" value="{$currTitolo}" />
<input type="hidden" id="idDomanda_hidden" name="{$outIdDomanda}" value="{$currDomanda}" />
<input type="hidden" id="idRicevuta_hidden" name="{$outIdRicevuta}" value="{$currRicevuta}" />
HTML;
$labelHtml = '<label class="form-label fw-semibold" htmlFor="autocomplete-search">Cerca Contratto</label>';
return (new \ElixForms\Common\ElixFormsElement($labelHtml, $autocompleteInputHtml))->render();
}
/**
* Inietta i CSS specifici per l'autocomplete e la card.
*/
protected function renderExtraContentPre(): string
{
ob_start();
?>
<style>
.autocomplete-wrapper {
position: relative;
width: 100%;
}
.autocomplete-dropdown {
position: absolute;
top: 100%;
left: 0;
right: 0;
z-index: 1000;
background: #ffffff;
border: 1px solid #a19f9d;
border-top: none;
border-radius: 0 0 2px 2px;
max-height: 250px;
overflow-y: auto;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.autocomplete-dropdown-item {
padding: 8px 12px;
cursor: pointer;
font-size: 14px;
line-height: 1.4;
border-bottom: 1px solid #f3f2f1;
transition: background-color 0.1s ease;
}
.autocomplete-dropdown-item:last-child {
border-bottom: none;
}
.autocomplete-dropdown-item:hover,
.autocomplete-dropdown-item.highlighted {
background-color: #edebe9;
}
.autocomplete-dropdown-item .contract-id {
font-weight: 600;
color: #323130;
}
.autocomplete-dropdown-item .contract-title {
color: #605e5c;
}
.autocomplete-loading {
padding: 12px;
text-align: center;
color: #605e5c;
font-size: 14px;
font-style: italic;
}
.autocomplete-no-results {
padding: 12px;
text-align: center;
color: #a19f9d;
font-size: 14px;
}
.autocomplete-error {
padding: 12px;
text-align: center;
color: #a4262c;
font-size: 14px;
}
</style>
<?php
return ob_get_clean();
}
/**
* Inietta il codice JavaScript per gestire le chiamate AJAX al proxy ed il comportamento dell'interfaccia.
*/
protected function renderExtraContentPost(): string
{
$escapedCodFis = htmlspecialchars($this->codiceFiscale, ENT_QUOTES, 'UTF-8');
$minChars = $this->minCharsForSearch;
ob_start();
?>
<script>
document.addEventListener('DOMContentLoaded', function() {
var searchInput = document.getElementById('autocomplete-search');
var dropdown = document.getElementById('autocomplete-dropdown');
var container = document.getElementById('autocomplete-container');
var card = document.getElementById('selected-contract-card');
var summaryId = document.getElementById('summary-id');
var summaryTitle = document.getElementById('summary-title');
var summaryDomanda = document.getElementById('summary-domanda');
var summaryRicevuta = document.getElementById('summary-ricevuta');
var hiddenCodice = document.getElementById('codiceContratto_hidden');
var hiddenTitolo = document.getElementById('titoloContratto_hidden');
var hiddenDomanda = document.getElementById('idDomanda_hidden');
var hiddenRicevuta = document.getElementById('idRicevuta_hidden');
var codFis = <?= json_encode($escapedCodFis) ?>;
var minChars = <?= $minChars ?>;
var searchResults = [];
var highlightedIndex = -1;
var debounceTimer = null;
// Se i campi hidden sono precompilati all'avvio, mostra la card di riepilogo
if (hiddenCodice.value && hiddenTitolo.value) {
showSummaryCard({
idContratto: hiddenCodice.value,
titoloContratto: hiddenTitolo.value,
idDomanda: hiddenDomanda.value,
idRicevuta: hiddenRicevuta.value
});
}
// Input event listener (con debounce)
searchInput.addEventListener('input', function() {
var text = this.value;
if (text.length === 0) {
clearSelection();
hideDropdown();
return;
}
if (debounceTimer) {
clearTimeout(debounceTimer);
}
if (text.length >= minChars) {
// Controlla se l'utente ha solo modificato il testo del contratto selezionato
if (hiddenCodice.value && text !== "[" + hiddenCodice.value + "] " + hiddenTitolo.value) {
clearSelection();
}
debounceTimer = setTimeout(function() {
fetchResults(text);
}, 300);
} else {
hideDropdown();
}
});
// Gestione eventi da tastiera
searchInput.addEventListener('keydown', function(event) {
if (dropdown.classList.contains('d-none')) return;
var items = dropdown.querySelectorAll('.autocomplete-dropdown-item');
if (items.length === 0) return;
switch (event.key) {
case 'ArrowDown':
event.preventDefault();
highlightedIndex = Math.min(highlightedIndex + 1, items.length - 1);
updateHighlight(items);
break;
case 'ArrowUp':
event.preventDefault();
highlightedIndex = Math.max(highlightedIndex - 1, 0);
updateHighlight(items);
break;
case 'Enter':
event.preventDefault();
if (highlightedIndex >= 0 && highlightedIndex < searchResults.length) {
selectContract(searchResults[highlightedIndex]);
}
break;
case 'Escape':
event.preventDefault();
hideDropdown();
break;
}
});
// Chiudi il menu a discesa se si clicca all'esterno
document.addEventListener('mousedown', function(event) {
if (!container.contains(event.target)) {
hideDropdown();
}
});
function fetchResults(term) {
showDropdown();
dropdown.innerHTML = '<div class="autocomplete-loading">Ricerca in corso...</div>';
highlightedIndex = -1;
// Calcolo dinamico della base directory per supportare URL con o senza slash finale
var baseDir = window.location.pathname;
if (!baseDir.endsWith('/') && !baseDir.endsWith('.php')) {
baseDir += '/';
}
var lastSlash = baseDir.lastIndexOf('/');
var dir = baseDir.substring(0, lastSlash + 1);
var url = dir + 'search-contratti.php?term=' + encodeURIComponent(term) + '&cod_fis=' + encodeURIComponent(codFis);
fetch(url)
.then(function(response) {
return response.text().then(function(text) {
var data = null;
try {
data = JSON.parse(text);
} catch (e) {
// Risposta non JSON
}
if (!response.ok) {
var errMsg = (data && data.message) ? data.message :
(data && data.error) ? data.error :
('Errore API: ' + response.status + ' ' + response.statusText);
throw new Error(errMsg);
}
if (data === null) {
throw new Error('Risposta del server non in formato JSON.');
}
return data;
});
})
.then(function(data) {
searchResults = data;
renderResults(data);
})
.catch(function(error) {
console.error('Errore durante la ricerca contratti:', error);
dropdown.innerHTML = '<div class="autocomplete-error">' + error.message + '</div>';
});
}
function renderResults(results) {
if (results.length === 0) {
dropdown.innerHTML = '<div class="autocomplete-no-results">Nessun risultato trovato</div>';
return;
}
dropdown.innerHTML = '';
results.forEach(function(contract, index) {
var item = document.createElement('div');
item.className = 'autocomplete-dropdown-item';
item.innerHTML = '<span class="contract-id">[' + contract.idContratto + ']</span> ' +
'<span class="contract-title">' + contract.titoloContratto + '</span>';
// Mouse interactions
item.addEventListener('mousedown', function(event) {
event.preventDefault();
selectContract(contract);
});
item.addEventListener('mouseenter', function() {
highlightedIndex = index;
var items = dropdown.querySelectorAll('.autocomplete-dropdown-item');
updateHighlight(items);
});
dropdown.appendChild(item);
});
}
function updateHighlight(items) {
items.forEach(function(item, index) {
if (index === highlightedIndex) {
item.classList.add('highlighted');
// Scorri il menu se l'elemento evidenziato è fuori vista
item.scrollIntoView({ block: 'nearest' });
} else {
item.classList.remove('highlighted');
}
});
}
function selectContract(contract) {
searchInput.value = '[' + contract.idContratto + '] ' + contract.titoloContratto;
hiddenCodice.value = contract.idContratto;
hiddenTitolo.value = contract.titoloContratto;
hiddenDomanda.value = contract.idDomanda;
hiddenRicevuta.value = contract.idRicevuta;
showSummaryCard(contract);
hideDropdown();
}
function showSummaryCard(contract) {
summaryId.textContent = contract.idContratto;
summaryTitle.textContent = contract.titoloContratto;
summaryDomanda.textContent = contract.idDomanda;
summaryRicevuta.textContent = contract.idRicevuta;
card.classList.remove('d-none');
}
function clearSelection() {
hiddenCodice.value = '';
hiddenTitolo.value = '';
hiddenDomanda.value = '';
hiddenRicevuta.value = '';
card.classList.add('d-none');
}
function showDropdown() {
dropdown.classList.remove('d-none');
}
function hideDropdown() {
dropdown.classList.add('d-none');
highlightedIndex = -1;
}
});
</script>
<?php
return ob_get_clean();
}
}
// =============================================================================
// Entry Point della Pagina
// =============================================================================
// Lettura e validazione della configurazione
$configFile = __DIR__ . '/config.json';
if (!file_exists($configFile)) {
die("File di configurazione config.json non trovato.");
}
$config = json_decode(file_get_contents($configFile), true);
if (json_last_error() !== JSON_ERROR_NONE) {
die("Errore di sintassi nel file config.json.");
}
// Istanziazione ed esecuzione del rendering
$page = new RecuperoPropostaCctDaContrattiPage(
$config['component'],
[
'codiceFiscale' => $config['elixForms']['inputs']['codiceFiscale'],
'idDomanda' => $config['elixForms']['outputs']['idDomanda'],
'idRicevuta' => $config['elixForms']['outputs']['idRicevuta'],
'codiceContratto'=> $config['elixForms']['outputs']['codiceContratto'],
'titoloContratto'=> $config['elixForms']['outputs']['titoloContratto'],
],
$config['component']['minCharsForSearch'] ?? 3
);
echo $page->render();