Files
zibo-dashboard/public/userarea/company-functions.php
T
2026-06-05 14:35:19 +02:00

618 lines
27 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
include('include/headscript.php');
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection();
function jsonResponse(array $data): void
{
header('Content-Type: application/json; charset=utf-8');
echo json_encode($data);
exit;
}
function normalizeNullableInt($value): ?int
{
return (isset($value) && $value !== '') ? (int)$value : null;
}
function normalizeBoolValue($value): int
{
return ((string)$value === '0') ? 0 : 1;
}
function cleanString(?string $value): string
{
return trim((string)$value);
}
/* ==========================================
AJAX HANDLERS
========================================== */
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['ajax'] == '1') {
$action = $_POST['action'] ?? '';
try {
if ($action === 'add') {
$functionName = cleanString($_POST['function_name'] ?? '');
$personFullName = cleanString($_POST['person_full_name'] ?? '');
$phone = cleanString($_POST['phone'] ?? '');
$email = cleanString($_POST['email'] ?? '');
$notes = cleanString($_POST['notes'] ?? '');
$sortOrder = normalizeNullableInt($_POST['sort_order'] ?? '0') ?? 0;
$isActive = normalizeBoolValue($_POST['is_active'] ?? '1');
if ($functionName === '') {
jsonResponse(['success' => false, 'message' => 'Il nome funzione è obbligatorio.']);
}
if ($email !== '' && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
jsonResponse(['success' => false, 'message' => 'Email non valida.']);
}
$stmt = $pdo->prepare("\n INSERT INTO company_functions\n (function_name, person_full_name, phone, email, notes, sort_order, is_active, created_at, updated_at)\n VALUES\n (:function_name, :person_full_name, :phone, :email, :notes, :sort_order, :is_active, NOW(), NOW())\n ");
$stmt->execute([
'function_name' => $functionName,
'person_full_name' => $personFullName !== '' ? $personFullName : '',
'phone' => $phone !== '' ? $phone : null,
'email' => $email !== '' ? $email : null,
'notes' => $notes !== '' ? $notes : null,
'sort_order' => $sortOrder,
'is_active' => $isActive,
]);
jsonResponse(['success' => true, 'message' => 'Funzione salvata correttamente.']);
}
if ($action === 'edit') {
$id = (int)($_POST['id'] ?? 0);
$functionName = cleanString($_POST['function_name'] ?? '');
$personFullName = cleanString($_POST['person_full_name'] ?? '');
$phone = cleanString($_POST['phone'] ?? '');
$email = cleanString($_POST['email'] ?? '');
$notes = cleanString($_POST['notes'] ?? '');
$sortOrder = normalizeNullableInt($_POST['sort_order'] ?? '0') ?? 0;
$isActive = normalizeBoolValue($_POST['is_active'] ?? '1');
if ($id <= 0) {
jsonResponse(['success' => false, 'message' => 'ID funzione non valido.']);
}
if ($functionName === '') {
jsonResponse(['success' => false, 'message' => 'Il nome funzione è obbligatorio.']);
}
if ($email !== '' && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
jsonResponse(['success' => false, 'message' => 'Email non valida.']);
}
$stmt = $pdo->prepare("\n UPDATE company_functions\n SET function_name = :function_name,\n person_full_name = :person_full_name,\n phone = :phone,\n email = :email,\n notes = :notes,\n sort_order = :sort_order,\n is_active = :is_active,\n updated_at = NOW()\n WHERE id = :id\n ");
$stmt->execute([
'function_name' => $functionName,
'person_full_name' => $personFullName !== '' ? $personFullName : '',
'phone' => $phone !== '' ? $phone : null,
'email' => $email !== '' ? $email : null,
'notes' => $notes !== '' ? $notes : null,
'sort_order' => $sortOrder,
'is_active' => $isActive,
'id' => $id,
]);
jsonResponse(['success' => true, 'message' => 'Funzione aggiornata correttamente.']);
}
if ($action === 'delete') {
$id = (int)($_POST['id'] ?? 0);
if ($id <= 0) {
jsonResponse(['success' => false, 'message' => 'ID funzione non valido.']);
}
$stmt = $pdo->prepare("DELETE FROM company_functions WHERE id = :id");
$stmt->execute(['id' => $id]);
jsonResponse(['success' => true, 'message' => 'Funzione cancellata correttamente.']);
}
jsonResponse(['success' => false, 'message' => 'Azione non riconosciuta.']);
} catch (Exception $e) {
jsonResponse(['success' => false, 'message' => $e->getMessage()]);
}
}
/* ==========================================
PAGE DATA
========================================== */
$stmtFunctions = $pdo->query("\n SELECT id, function_name, person_full_name, phone, email, notes, sort_order, is_active, created_at, updated_at\n FROM company_functions\n ORDER BY is_active DESC, sort_order ASC, function_name ASC, person_full_name ASC\n");
$functions = $stmtFunctions->fetchAll(PDO::FETCH_ASSOC);
?>
<!doctype html>
<html lang="it">
<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" />
<?php include('cssinclude.php'); ?>
<title>Funzioni Aziendali - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css">
<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>
<style>
body {
font-size: 1.05rem;
background: #f8fafc;
}
.card {
border-radius: 16px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.back-dashboard {
background-color: #cfe3ff !important;
color: #1f2d3d !important;
border: 1px solid #bcd4f4 !important;
border-radius: 10px;
font-weight: 600;
font-size: 1rem;
padding: 10px 18px;
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
transition: all 0.2s ease-in-out;
}
.back-dashboard:hover {
background-color: #b9d3ff !important;
transform: translateY(-2px);
}
.btn-main-action,
.btn-add {
background-color: #0d6efd;
color: #fff;
border-radius: 8px;
padding: 10px 20px;
font-weight: 500;
transition: all 0.2s ease-in-out;
}
.btn-main-action:hover,
.btn-add:hover {
background-color: #0b5ed7;
color: #fff;
transform: scale(1.02);
}
.table thead {
background-color: #cfe3ff;
color: #1f2d3d;
}
#tabCompanyFunctions thead th {
text-align: center;
vertical-align: middle;
}
.modal-content {
border-radius: 16px;
}
.function-name {
font-weight: 700;
color: #1f2937;
}
.person-name {
font-weight: 600;
color: #334155;
}
.contact-line {
display: block;
font-size: 0.9rem;
text-decoration: none;
}
.notes-small {
color: #64748b;
font-size: 0.9rem;
max-width: 420px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.badge-status {
padding: 0.25rem 0.65rem;
border-radius: 999px;
font-size: 0.82rem;
font-weight: 700;
}
.badge-status.active {
background-color: #d1fae5;
color: #065f46;
}
.badge-status.inactive {
background-color: #e5e7eb;
color: #374151;
}
.empty-text {
color: #94a3b8;
font-style: italic;
}
@media (max-width: 767.98px) {
.card-header {
flex-direction: column;
align-items: flex-start !important;
gap: .5rem;
}
.back-dashboard,
.btn-main-action {
width: 100%;
}
}
</style>
</head>
<body>
<div class="wrapper" id="appWrapper">
<?php include('include/navbar.php'); ?>
<?php include('include/topbar.php'); ?>
<div class="page-wrapper">
<div class="page-content">
<div class="card p-3">
<div class="card-header d-flex justify-content-between align-items-center flex-wrap gap-2">
<h5 class="mb-0">Funzioni Aziendali</h5>
<button type="button" class="btn back-dashboard" onclick="location.href='production_dashboard.php'">
↩️ Torna alla Dashboard
</button>
</div>
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3 flex-wrap gap-2">
<div>
<h6 class="fw-semibold mb-1">Elenco Funzioni</h6>
<div class="text-muted small">Gestione di RSPP, medico del lavoro, RLS e altre funzioni aziendali.</div>
</div>
<button class="btn btn-main-action" data-bs-toggle="modal" data-bs-target="#companyFunctionModal" onclick="openCompanyFunctionModal()">
Aggiungi Funzione
</button>
</div>
<div class="table-responsive">
<table id="tabCompanyFunctions" class="table table-striped align-middle text-center" style="width:100%;">
<thead>
<tr>
<th>Funzione</th>
<th>Nominativo</th>
<th>Contatti</th>
<th>Note</th>
<th>Ordine</th>
<th>Stato</th>
<th>Azioni</th>
</tr>
</thead>
<tbody>
<?php foreach ($functions as $row): ?>
<?php
$id = (int)$row['id'];
$functionName = (string)($row['function_name'] ?? '');
$personFullName = (string)($row['person_full_name'] ?? '');
$phone = (string)($row['phone'] ?? '');
$email = (string)($row['email'] ?? '');
$notes = (string)($row['notes'] ?? '');
$sortOrder = (int)($row['sort_order'] ?? 0);
$isActive = (int)($row['is_active'] ?? 1);
?>
<tr>
<td class="text-start">
<div class="function-name"><?= htmlspecialchars($functionName, ENT_QUOTES, 'UTF-8') ?></div>
</td>
<td class="text-start">
<?php if ($personFullName !== ''): ?>
<div class="person-name"><?= htmlspecialchars($personFullName, ENT_QUOTES, 'UTF-8') ?></div>
<?php else: ?>
<span class="empty-text">Da definire</span>
<?php endif; ?>
</td>
<td class="text-start">
<?php if ($phone !== ''): ?>
<a class="contact-line" href="tel:<?= htmlspecialchars($phone, ENT_QUOTES, 'UTF-8') ?>">
📞 <?= htmlspecialchars($phone, ENT_QUOTES, 'UTF-8') ?>
</a>
<?php endif; ?>
<?php if ($email !== ''): ?>
<a class="contact-line" href="mailto:<?= htmlspecialchars($email, ENT_QUOTES, 'UTF-8') ?>">
✉️ <?= htmlspecialchars($email, ENT_QUOTES, 'UTF-8') ?>
</a>
<?php endif; ?>
<?php if ($phone === '' && $email === ''): ?>
<span class="empty-text">Nessun contatto</span>
<?php endif; ?>
</td>
<td class="text-start">
<?php if ($notes !== ''): ?>
<div class="notes-small" title="<?= htmlspecialchars($notes, ENT_QUOTES, 'UTF-8') ?>">
<?= htmlspecialchars($notes, ENT_QUOTES, 'UTF-8') ?>
</div>
<?php else: ?>
<span class="empty-text">—</span>
<?php endif; ?>
</td>
<td><?= $sortOrder ?></td>
<td>
<?php if ($isActive === 1): ?>
<span class="badge-status active">Attiva</span>
<?php else: ?>
<span class="badge-status inactive">Non attiva</span>
<?php endif; ?>
</td>
<td>
<button
type="button"
class="btn btn-sm btn-outline-secondary edit-function mb-1"
data-id="<?= $id ?>"
data-function_name="<?= htmlspecialchars($functionName, ENT_QUOTES, 'UTF-8') ?>"
data-person_full_name="<?= htmlspecialchars($personFullName, ENT_QUOTES, 'UTF-8') ?>"
data-phone="<?= htmlspecialchars($phone, ENT_QUOTES, 'UTF-8') ?>"
data-email="<?= htmlspecialchars($email, ENT_QUOTES, 'UTF-8') ?>"
data-notes="<?= htmlspecialchars($notes, ENT_QUOTES, 'UTF-8') ?>"
data-sort_order="<?= $sortOrder ?>"
data-is_active="<?= $isActive ?>">
✏️ Modifica
</button>
<button
type="button"
class="btn btn-sm btn-outline-danger delete-function mb-1"
data-id="<?= $id ?>"
data-name="<?= htmlspecialchars($functionName, ENT_QUOTES, 'UTF-8') ?>">
🗑️ Cancella
</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<?php include('include/footer.php'); ?>
</div>
<!-- MODALE ADD / EDIT FUNZIONE -->
<div class="modal fade" id="companyFunctionModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header" style="background-color:#cfe3ff;">
<h5 class="modal-title" id="companyFunctionModalTitle">Aggiungi Funzione</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="companyFunctionForm">
<input type="hidden" id="functionId">
<div class="mb-3">
<label class="form-label fw-semibold">Nome funzione <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="functionName" placeholder="Es. RSPP, Medico del lavoro, RLS" required>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Nome e Cognome persona</label>
<input type="text" class="form-control" id="personFullName" placeholder="Es. Mario Rossi">
</div>
<div class="row">
<div class="col-12 col-md-6 mb-3">
<label class="form-label fw-semibold">Telefono</label>
<input type="text" class="form-control" id="phone" placeholder="Es. +39 333 1234567">
</div>
<div class="col-12 col-md-6 mb-3">
<label class="form-label fw-semibold">Email</label>
<input type="email" class="form-control" id="email" placeholder="nome@azienda.it">
</div>
</div>
<div class="row">
<div class="col-12 col-md-6 mb-3">
<label class="form-label fw-semibold">Ordine</label>
<input type="number" class="form-control" id="sortOrder" value="0" min="0" step="1">
<small class="text-muted">Serve solo per ordinare la visualizzazione.</small>
</div>
<div class="col-12 col-md-6 mb-3">
<label class="form-label fw-semibold">Stato</label>
<select class="form-select" id="isActive">
<option value="1">Attiva</option>
<option value="0">Non attiva</option>
</select>
</div>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Note</label>
<textarea class="form-control" id="notes" rows="3" placeholder="Note interne, riferimenti, disponibilità, ecc."></textarea>
</div>
<div class="text-center">
<button type="submit" class="btn btn-add">💾 Salva</button>
</div>
</form>
</div>
</div>
</div>
</div>
<?php include('jsinclude.php'); ?>
<script>
function escapeHtml(value) {
return $('<div>').text(value || '').html();
}
function openCompanyFunctionModal() {
$('#functionId').val('');
$('#functionName').val('');
$('#personFullName').val('');
$('#phone').val('');
$('#email').val('');
$('#notes').val('');
$('#sortOrder').val('0');
$('#isActive').val('1');
$('#companyFunctionModalTitle').text('Aggiungi Funzione');
}
$(document).ready(function() {
$('#tabCompanyFunctions').DataTable({
order: [
[5, 'asc'],
[4, 'asc'],
[0, 'asc']
],
pageLength: 25,
language: {
url: 'https://cdn.datatables.net/plug-ins/1.13.6/i18n/it-IT.json',
emptyTable: 'Nessuna funzione presente'
},
columnDefs: [{
targets: -1,
orderable: false,
searchable: false
}]
});
$(document).on('click', '.edit-function', function() {
const btn = $(this);
$('#functionId').val(btn.data('id'));
$('#functionName').val(btn.data('function_name'));
$('#personFullName').val(btn.data('person_full_name'));
$('#phone').val(btn.data('phone'));
$('#email').val(btn.data('email'));
$('#notes').val(btn.data('notes'));
$('#sortOrder').val(btn.data('sort_order'));
$('#isActive').val(String(btn.data('is_active')));
$('#companyFunctionModalTitle').text('Modifica Funzione');
$('#companyFunctionModal').modal('show');
});
$('#companyFunctionForm').on('submit', function(e) {
e.preventDefault();
const id = $('#functionId').val();
const payload = new URLSearchParams();
payload.append('ajax', '1');
payload.append('action', id ? 'edit' : 'add');
payload.append('id', id);
payload.append('function_name', $('#functionName').val().trim());
payload.append('person_full_name', $('#personFullName').val().trim());
payload.append('phone', $('#phone').val().trim());
payload.append('email', $('#email').val().trim());
payload.append('notes', $('#notes').val().trim());
payload.append('sort_order', $('#sortOrder').val() || '0');
payload.append('is_active', $('#isActive').val());
fetch('', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: payload.toString()
})
.then(r => r.json())
.then(data => {
if (data.success) {
Swal.fire({
icon: 'success',
title: 'Salvato!',
text: data.message || 'Operazione completata.',
confirmButtonColor: '#3085d6'
}).then(() => location.reload());
} else {
Swal.fire('Errore', data.message || 'Impossibile salvare.', 'error');
}
})
.catch(err => {
console.error(err);
Swal.fire('Errore', 'Errore di comunicazione.', 'error');
});
});
$(document).on('click', '.delete-function', function() {
const id = $(this).data('id');
const name = $(this).data('name');
Swal.fire({
title: 'Confermi la cancellazione?',
text: name ? ('Funzione: ' + name) : 'La funzione verrà cancellata.',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#6c757d',
confirmButtonText: 'Sì, cancella',
cancelButtonText: 'Annulla'
}).then((result) => {
if (!result.isConfirmed) return;
const payload = new URLSearchParams();
payload.append('ajax', '1');
payload.append('action', 'delete');
payload.append('id', id);
fetch('', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: payload.toString()
})
.then(r => r.json())
.then(data => {
if (data.success) {
Swal.fire({
icon: 'success',
title: 'Cancellato!',
text: data.message || 'Funzione cancellata.',
confirmButtonColor: '#3085d6'
}).then(() => location.reload());
} else {
Swal.fire('Errore', data.message || 'Impossibile cancellare.', 'error');
}
})
.catch(err => {
console.error(err);
Swal.fire('Errore', 'Errore di comunicazione.', 'error');
});
});
});
});
</script>
</body>
</html>