fixed user setting

This commit is contained in:
2026-05-18 13:31:34 +02:00
parent e6a805f1f7
commit 955a7ed9e9
4 changed files with 946 additions and 35 deletions
+1 -1
View File
@@ -86,7 +86,7 @@
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a class="dropdown-item d-flex align-items-center" href="../users">
<a class="dropdown-item d-flex align-items-center" href="user_settings.php">
<i class="bx bx-user fs-5"></i><span>Utente</span>
</a>
</li>
+3 -3
View File
@@ -51,7 +51,7 @@ $dashboardSections = [
'permission' => 'warehouse.dashboard.view',
],
[
'label' => 'Scadenziario',
'label' => 'Smart-Alert',
'icon' => '⏰',
'class' => 'btn-scadenziario',
'url' => 'scadenzario/index.php',
@@ -187,7 +187,7 @@ $dashboardSections = [
<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>Dashboard Produzione - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
<title>Dashboard <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
<!-- Bootstrap + jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
@@ -490,7 +490,7 @@ $dashboardSections = [
include(__DIR__ . '/scadenzario/include/my_deadlines_widget.php');
?>
<h3 class="dashboard-title">Dashboard Produzione</h3>
<h3 class="dashboard-title">Dashboard</h3>
<!-- ===== STATISTICHE PRINCIPALI ===== -->
<div class="stats-row">
@@ -1,4 +1,5 @@
<?php
/**
* Renders two status banners for the current user:
* - red -> overdue deadlines (scaduta)
@@ -43,49 +44,91 @@ if (!$_emp || ($_overdue === 0 && $_approaching === 0)) {
}
?>
<style>
.my-deadlines-widgets { display: flex; gap: 0.75rem; margin-bottom: 1rem; flex-wrap: wrap; }
.my-deadlines-widgets {
display: flex;
gap: 0.75rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.my-deadlines-widgets .mdw {
flex: 1 1 260px;
display: flex; align-items: center; gap: 0.9rem;
display: flex;
align-items: center;
gap: 0.9rem;
padding: 0.85rem 1rem;
border-radius: 0.6rem;
text-decoration: none;
color: #fff;
box-shadow: 0 2px 6px rgba(0,0,0,0.08);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
transition: transform 0.15s, box-shadow 0.15s;
}
.my-deadlines-widgets .mdw:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0,0,0,0.15); color: #fff; }
.my-deadlines-widgets .mdw-red { background: linear-gradient(135deg, #dc3545 0%, #b02a37 100%); }
.my-deadlines-widgets .mdw-orange { background: linear-gradient(135deg, #e8930c 0%, #c77a00 100%); }
.my-deadlines-widgets .mdw-icon {
width: 42px; height: 42px; border-radius: 50%;
display: flex; align-items: center; justify-content: center;
background: rgba(255,255,255,0.22); font-size: 1.2rem; flex-shrink: 0;
.my-deadlines-widgets .mdw:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
color: #fff;
}
.my-deadlines-widgets .mdw-red {
background: linear-gradient(135deg, #dc3545 0%, #b02a37 100%);
}
.my-deadlines-widgets .mdw-orange {
background: linear-gradient(135deg, #e8930c 0%, #c77a00 100%);
}
.my-deadlines-widgets .mdw-icon {
width: 42px;
height: 42px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255, 0.22);
font-size: 1.2rem;
flex-shrink: 0;
}
.my-deadlines-widgets .mdw-body {
flex: 1;
line-height: 1.2;
}
.my-deadlines-widgets .mdw-count {
font-size: 1.6rem;
font-weight: 700;
}
.my-deadlines-widgets .mdw-label {
font-size: 0.8rem;
opacity: 0.95;
}
.my-deadlines-widgets .mdw-arrow {
opacity: 0.7;
font-size: 0.9rem;
}
.my-deadlines-widgets .mdw-body { flex: 1; line-height: 1.2; }
.my-deadlines-widgets .mdw-count { font-size: 1.6rem; font-weight: 700; }
.my-deadlines-widgets .mdw-label { font-size: 0.8rem; opacity: 0.95; }
.my-deadlines-widgets .mdw-arrow { opacity: 0.7; font-size: 0.9rem; }
</style>
<div class="my-deadlines-widgets">
<?php if ($_overdue > 0): ?>
<a class="mdw mdw-red" href="scadenzario/index.php?filter_my=1&filter_status=scaduta">
<span class="mdw-icon"><i class="fa-solid fa-triangle-exclamation"></i></span>
<span class="mdw-body">
<span class="mdw-count"><?= $_overdue ?></span>
<span class="mdw-label d-block">Scadenz<?= $_overdue === 1 ? 'a' : 'e' ?> scadut<?= $_overdue === 1 ? 'a' : 'e' ?> — <?= $_dept !== '' ? htmlspecialchars($_dept, ENT_QUOTES, 'UTF-8') : 'personali' ?></span>
</span>
<span class="mdw-arrow"><i class="fa-solid fa-arrow-right"></i></span>
</a>
<a class="mdw mdw-red" href="scadenzario/index.php?filter_my=1&filter_status=scaduta">
<span class="mdw-icon"><i class="fa-solid fa-triangle-exclamation"></i></span>
<span class="mdw-body">
<span class="mdw-count"><?= $_overdue ?></span>
<span class="mdw-label d-block">Task<?= $_overdue === 1 ? '' : 's' ?> scadut<?= $_overdue === 1 ? 'o' : 'i' ?> — <?= $_dept !== '' ? htmlspecialchars($_dept, ENT_QUOTES, 'UTF-8') : 'personali' ?></span>
</span>
<span class="mdw-arrow"><i class="fa-solid fa-arrow-right"></i></span>
</a>
<?php endif; ?>
<?php if ($_approaching > 0): ?>
<a class="mdw mdw-orange" href="scadenzario/index.php?filter_my=1&filter_status=in-scadenza">
<span class="mdw-icon"><i class="fa-solid fa-clock"></i></span>
<span class="mdw-body">
<span class="mdw-count"><?= $_approaching ?></span>
<span class="mdw-label d-block">In scadenza a breve <?= $_dept !== '' ? htmlspecialchars($_dept, ENT_QUOTES, 'UTF-8') : 'personali' ?></span>
</span>
<span class="mdw-arrow"><i class="fa-solid fa-arrow-right"></i></span>
</a>
<a class="mdw mdw-orange" href="scadenzario/index.php?filter_my=1&filter_status=in-scadenza">
<span class="mdw-icon"><i class="fa-solid fa-clock"></i></span>
<span class="mdw-body">
<span class="mdw-count"><?= $_approaching ?></span>
<span class="mdw-label d-block">In scadenza a breve <?= $_dept !== '' ? htmlspecialchars($_dept, ENT_QUOTES, 'UTF-8') : 'personali' ?></span>
</span>
<span class="mdw-arrow"><i class="fa-solid fa-arrow-right"></i></span>
</a>
<?php endif; ?>
</div>
</div>
+868
View File
@@ -0,0 +1,868 @@
<?php include('include/headscript.php'); ?>
<?php
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection();
$userId = (int)($iduserlogin ?? 0);
if ($userId <= 0) {
die('Utente non valido.');
}
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
if (empty($_SESSION['user_settings_csrf'])) {
$_SESSION['user_settings_csrf'] = bin2hex(random_bytes(32));
}
$csrfToken = $_SESSION['user_settings_csrf'];
$successMessage = '';
$errorMessage = '';
// Load countries.
$countries = [];
try {
$stmtCountries = $pdo->query("
SELECT id, name, iso_3166_2
FROM auth_countries
ORDER BY name ASC
");
$countries = $stmtCountries->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {
$countries = [];
}
// Load current user.
$stmtProfileUser = $pdo->prepare("
SELECT
id,
email,
password,
first_name,
last_name,
phone,
avatar,
address,
country_id,
birthday,
role_id,
status,
last_login
FROM auth_users
WHERE id = ?
LIMIT 1
");
$stmtProfileUser->execute([$userId]);
$profileUser = $stmtProfileUser->fetch(PDO::FETCH_ASSOC);
if (!$profileUser) {
die('Utente non trovato.');
}
function e($value)
{
return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
}
function normalizeAvatarPath($avatar)
{
$avatar = trim((string)$avatar);
if ($avatar === '') {
return '';
}
// If the database already contains a complete relative path, use it as it is.
if (
str_starts_with($avatar, '../') ||
str_starts_with($avatar, './') ||
str_starts_with($avatar, '/') ||
str_starts_with($avatar, 'http://') ||
str_starts_with($avatar, 'https://')
) {
return $avatar;
}
// If the database contains only the filename, build the expected user upload path.
return '../upload/users/' . $avatar;
}
function getAvatarInitials($profileUser)
{
$first = trim((string)($profileUser['first_name'] ?? ''));
$last = trim((string)($profileUser['last_name'] ?? ''));
$email = trim((string)($profileUser['email'] ?? ''));
$initials = '';
if ($first !== '') {
$initials .= mb_substr($first, 0, 1);
}
if ($last !== '') {
$initials .= mb_substr($last, 0, 1);
}
if ($initials === '' && $email !== '') {
$initials = mb_substr($email, 0, 1);
}
return strtoupper($initials ?: 'U');
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$postedToken = $_POST['csrf_token'] ?? '';
if (!hash_equals($csrfToken, $postedToken)) {
$errorMessage = 'Sessione non valida. Ricarica la pagina e riprova.';
} else {
$email = trim($_POST['email'] ?? '');
$firstName = trim($_POST['first_name'] ?? '');
$lastName = trim($_POST['last_name'] ?? '');
$phone = trim($_POST['phone'] ?? '');
$address = trim($_POST['address'] ?? '');
$countryId = $_POST['country_id'] !== '' ? (int)$_POST['country_id'] : null;
$birthday = trim($_POST['birthday'] ?? '');
$currentPassword = $_POST['current_password'] ?? '';
$newPassword = $_POST['new_password'] ?? '';
$confirmPassword = $_POST['confirm_password'] ?? '';
$birthdayValue = null;
$avatarToSave = $profileUser['avatar'];
if ($birthday !== '') {
$dateObj = DateTime::createFromFormat('Y-m-d', $birthday);
if (!$dateObj || $dateObj->format('Y-m-d') !== $birthday) {
$errorMessage = 'La data di nascita non è valida.';
} else {
$birthdayValue = $birthday;
}
}
if (!$errorMessage && $email === '') {
$errorMessage = 'Lemail è obbligatoria.';
}
if (!$errorMessage && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errorMessage = 'Lemail inserita non è valida.';
}
// Check unique email.
if (!$errorMessage) {
$stmtCheckEmail = $pdo->prepare("
SELECT id
FROM auth_users
WHERE email = ? AND id <> ?
LIMIT 1
");
$stmtCheckEmail->execute([$email, $userId]);
if ($stmtCheckEmail->fetchColumn()) {
$errorMessage = 'Questa email è già utilizzata da un altro utente.';
}
}
// Avatar upload.
if (!$errorMessage && isset($_FILES['avatar']) && $_FILES['avatar']['error'] !== UPLOAD_ERR_NO_FILE) {
if ($_FILES['avatar']['error'] !== UPLOAD_ERR_OK) {
$errorMessage = 'Errore durante il caricamento dellavatar.';
} else {
$maxFileSize = 2 * 1024 * 1024; // 2 MB
if ($_FILES['avatar']['size'] > $maxFileSize) {
$errorMessage = 'Lavatar non può superare 2 MB.';
} else {
$tmpFile = $_FILES['avatar']['tmp_name'];
$originalName = $_FILES['avatar']['name'];
$allowedMimeTypes = [
'image/jpeg' => 'jpg',
'image/png' => 'png',
'image/webp' => 'webp',
'image/gif' => 'gif',
];
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->file($tmpFile);
if (!array_key_exists($mimeType, $allowedMimeTypes)) {
$errorMessage = 'Formato avatar non valido. Sono consentiti JPG, PNG, WEBP o GIF.';
} else {
$uploadDir = __DIR__ . '/../upload/users/';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$extension = $allowedMimeTypes[$mimeType];
$safeOriginalName = preg_replace('/[^A-Za-z0-9_\-\.]/', '_', pathinfo($originalName, PATHINFO_FILENAME));
$fileName = time() . '_' . $userId . '_' . $safeOriginalName . '.' . $extension;
$destination = $uploadDir . $fileName;
if (!move_uploaded_file($tmpFile, $destination)) {
$errorMessage = 'Impossibile salvare il file avatar.';
} else {
// Path used by pages inside userarea, for example:
// <img src="../upload/users/file.jpg">
$avatarToSave = $fileName;
}
}
}
}
}
$passwordToSave = null;
$wantsPasswordChange = ($currentPassword !== '' || $newPassword !== '' || $confirmPassword !== '');
if (!$errorMessage && $wantsPasswordChange) {
if ($currentPassword === '') {
$errorMessage = 'Inserisci la password attuale.';
} elseif ($newPassword === '') {
$errorMessage = 'Inserisci la nuova password.';
} elseif (strlen($newPassword) < 8) {
$errorMessage = 'La nuova password deve contenere almeno 8 caratteri.';
} elseif ($newPassword !== $confirmPassword) {
$errorMessage = 'La conferma password non corrisponde.';
} elseif (!password_verify($currentPassword, $profileUser['password'])) {
$errorMessage = 'La password attuale non è corretta.';
} else {
// Password is encrypted before saving.
$passwordToSave = password_hash($newPassword, PASSWORD_DEFAULT);
}
}
if (!$errorMessage) {
try {
$pdo->beginTransaction();
$stmtUpdate = $pdo->prepare("
UPDATE auth_users
SET
email = :email,
first_name = :first_name,
last_name = :last_name,
phone = :phone,
avatar = :avatar,
address = :address,
country_id = :country_id,
birthday = :birthday,
updated_at = NOW()
WHERE id = :id
LIMIT 1
");
$stmtUpdate->execute([
':email' => $email,
':first_name' => $firstName !== '' ? $firstName : null,
':last_name' => $lastName !== '' ? $lastName : null,
':phone' => $phone !== '' ? $phone : null,
':avatar' => $avatarToSave !== '' ? $avatarToSave : null,
':address' => $address !== '' ? $address : null,
':country_id' => $countryId,
':birthday' => $birthdayValue,
':id' => $userId,
]);
if ($passwordToSave !== null) {
$stmtPassword = $pdo->prepare("
UPDATE auth_users
SET password = ?, updated_at = NOW()
WHERE id = ?
LIMIT 1
");
$stmtPassword->execute([$passwordToSave, $userId]);
}
$pdo->commit();
$successMessage = $passwordToSave !== null
? 'Profilo, avatar e password aggiornati correttamente.'
: 'Profilo aggiornato correttamente.';
// Reload updated user.
$stmtProfileUser->execute([$userId]);
$profileUser = $stmtProfileUser->fetch(PDO::FETCH_ASSOC);
$_SESSION['user_settings_csrf'] = bin2hex(random_bytes(32));
$csrfToken = $_SESSION['user_settings_csrf'];
} catch (Exception $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
$errorMessage = 'Errore durante il salvataggio delle impostazioni.';
}
}
}
}
$avatarPath = normalizeAvatarPath($profileUser['avatar'] ?? '');
?>
<!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>Impostazioni Utente <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
<style>
body {
background: linear-gradient(135deg, #f3f6f8, #e8eef3);
font-family: 'Segoe UI', sans-serif;
color: #2b3e50;
}
.page-content {
padding: 1.4rem 1rem;
display: flex;
flex-direction: column;
align-items: center;
}
.settings-wrap {
width: 100%;
max-width: 1280px;
}
h3.settings-title {
text-align: center;
font-weight: 800;
color: #2b3e50;
margin-bottom: 1.2rem;
letter-spacing: 0.3px;
}
.settings-card {
background: #fff;
border-radius: 16px;
box-shadow: 0 5px 12px rgba(0, 0, 0, 0.08);
margin-bottom: 16px;
overflow: hidden;
}
.settings-header {
padding: 16px 18px;
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
display: flex;
align-items: center;
gap: 12px;
}
.settings-icon {
font-size: 1.8rem;
line-height: 1;
}
.settings-heading {
margin: 0;
font-weight: 800;
font-size: 1.1rem;
}
.settings-subtitle {
margin: 0;
color: #6b7a89;
font-size: 0.92rem;
}
.settings-body {
padding: 20px;
}
.profile-layout {
display: grid;
grid-template-columns: 280px 1fr;
gap: 24px;
align-items: flex-start;
}
.avatar-panel {
background: linear-gradient(135deg, #f7fbff, #edf5ff);
border: 1px solid #dbeafe;
border-radius: 18px;
padding: 20px;
text-align: center;
}
.avatar-box {
width: 132px;
height: 132px;
border-radius: 34px;
background: linear-gradient(135deg, #cde5ff, #dff0ff);
display: flex;
align-items: center;
justify-content: center;
font-size: 3rem;
font-weight: 800;
color: #2b3e50;
box-shadow: 0 5px 12px rgba(0, 0, 0, 0.08);
overflow: hidden;
margin: 0 auto 14px auto;
}
.avatar-box img {
width: 100%;
height: 100%;
object-fit: cover;
}
.avatar-name {
font-size: 1.1rem;
font-weight: 800;
margin: 0;
color: #2b3e50;
}
.avatar-email {
color: #6b7a89;
margin: 4px 0 14px 0;
font-size: 0.92rem;
word-break: break-word;
}
.avatar-upload-label {
display: inline-flex;
align-items: center;
justify-content: center;
width: 100%;
border-radius: 14px;
padding: 11px 14px;
cursor: pointer;
font-weight: 800;
color: #2b3e50;
background: linear-gradient(135deg, #e5e7eb, #f3f4f6);
box-shadow: 0 5px 12px rgba(0, 0, 0, 0.08);
transition: all 0.2s ease;
margin-top: 8px;
}
.avatar-upload-label:hover {
transform: translateY(-2px);
box-shadow: 0 8px 18px rgba(0, 0, 0, 0.13);
}
.avatar-upload-input {
display: none;
}
.avatar-help {
font-size: 0.82rem;
color: #6b7a89;
margin-top: 10px;
line-height: 1.35;
}
.profile-meta {
color: #6b7a89;
font-size: 0.88rem;
margin-top: 14px;
}
.form-label {
font-weight: 700;
color: #2b3e50;
margin-bottom: 6px;
}
.form-control,
.form-select {
border-radius: 12px;
border: 1px solid #d8e0e7;
padding: 10px 12px;
font-size: 0.95rem;
}
.form-control:focus,
.form-select:focus {
border-color: #8bbcf7;
box-shadow: 0 0 0 0.18rem rgba(139, 188, 247, 0.25);
}
.help-text {
font-size: 0.86rem;
color: #6b7a89;
margin-top: 6px;
}
.password-box {
background: linear-gradient(135deg, #fff7e6, #fffaf0);
border-radius: 16px;
padding: 16px;
border: 1px solid rgba(255, 184, 107, 0.45);
}
.btn-save-settings {
border: 0;
border-radius: 16px;
padding: 13px 24px;
font-size: 1rem;
font-weight: 800;
color: #fff;
background: linear-gradient(135deg, #61ce5dff, #61ce5dff);
box-shadow: 0 5px 12px rgba(0, 0, 0, 0.08);
transition: all 0.2s ease;
}
.btn-save-settings:hover {
transform: translateY(-2px);
box-shadow: 0 8px 18px rgba(0, 0, 0, 0.13);
color: #fff;
}
.btn-back {
border: 0;
border-radius: 16px;
padding: 13px 20px;
font-size: 1rem;
font-weight: 800;
color: #2b3e50;
background: linear-gradient(135deg, #e5e7eb, #f3f4f6);
box-shadow: 0 5px 12px rgba(0, 0, 0, 0.08);
transition: all 0.2s ease;
text-decoration: none;
display: inline-flex;
align-items: center;
}
.btn-back:hover {
transform: translateY(-2px);
box-shadow: 0 8px 18px rgba(0, 0, 0, 0.13);
color: #2b3e50;
}
.alert {
border-radius: 16px;
border: 0;
font-weight: 600;
}
.readonly-note {
background: linear-gradient(135deg, #cde5ff, #dff0ff);
border-radius: 16px;
padding: 14px 16px;
color: #2b3e50;
font-weight: 600;
margin-bottom: 18px;
}
.actions-row {
display: flex;
justify-content: space-between;
gap: 12px;
flex-wrap: wrap;
margin-top: 18px;
}
.selected-file-name {
font-size: 0.84rem;
color: #2b3e50;
margin-top: 8px;
font-weight: 600;
word-break: break-word;
}
@media (max-width: 992px) {
.profile-layout {
grid-template-columns: 1fr;
}
.avatar-panel {
max-width: 420px;
margin: 0 auto;
width: 100%;
}
}
@media (max-width: 768px) {
.settings-body {
padding: 16px;
}
.actions-row {
flex-direction: column;
}
.btn-save-settings,
.btn-back {
width: 100%;
justify-content: center;
}
}
</style>
</head>
<body>
<div class="wrapper toggled">
<?php include('include/navbar.php'); ?>
<?php include('include/topbar.php'); ?>
<div class="page-wrapper">
<div class="page-content">
<div class="settings-wrap">
<h3 class="settings-title">Impostazioni Utente</h3>
<?php if ($successMessage): ?>
<div class="alert alert-success">
<?= e($successMessage); ?>
</div>
<?php endif; ?>
<?php if ($errorMessage): ?>
<div class="alert alert-danger">
<?= e($errorMessage); ?>
</div>
<?php endif; ?>
<form method="post" enctype="multipart/form-data" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?= e($csrfToken); ?>">
<div class="settings-card">
<div class="settings-header">
<div class="settings-icon">👤</div>
<div>
<p class="settings-heading">Profilo personale</p>
<p class="settings-subtitle">Dati anagrafici, contatti e avatar utente</p>
</div>
</div>
<div class="settings-body">
<div class="readonly-note">
Ruolo, stato account e impostazioni di sicurezza avanzate non sono modificabili da questa pagina.
</div>
<div class="profile-layout">
<div class="avatar-panel">
<div class="avatar-box" id="avatarPreviewBox">
<?php if (!empty($avatarPath)): ?>
<img src="<?= e($avatarPath); ?>" class="user-img" alt="user avatar" id="avatarPreviewImage">
<?php else: ?>
<span id="avatarInitials"><?= e(getAvatarInitials($profileUser)); ?></span>
<?php endif; ?>
</div>
<p class="avatar-name">
<?= e(trim(($profileUser['first_name'] ?? '') . ' ' . ($profileUser['last_name'] ?? '')) ?: 'Utente'); ?>
</p>
<p class="avatar-email">
<?= e($profileUser['email']); ?>
</p>
<label for="avatar" class="avatar-upload-label">
Carica avatar
</label>
<input type="file"
class="avatar-upload-input"
id="avatar"
name="avatar"
accept="image/jpeg,image/png,image/webp,image/gif">
<div id="selectedFileName" class="selected-file-name"></div>
<div class="avatar-help">
Formati consentiti: JPG, PNG, WEBP, GIF.<br>
Dimensione massima: 2 MB.
</div>
<div class="profile-meta">
Stato account: <?= e($profileUser['status']); ?>
<?php if (!empty($profileUser['last_login'])): ?>
<br>Ultimo accesso: <?= e(date('d/m/Y H:i', strtotime($profileUser['last_login']))); ?>
<?php endif; ?>
</div>
</div>
<div>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label" for="first_name">Nome</label>
<input type="text"
class="form-control"
id="first_name"
name="first_name"
value="<?= e($profileUser['first_name']); ?>">
</div>
<div class="col-md-6">
<label class="form-label" for="last_name">Cognome</label>
<input type="text"
class="form-control"
id="last_name"
name="last_name"
value="<?= e($profileUser['last_name']); ?>">
</div>
<div class="col-md-6">
<label class="form-label" for="email">Email</label>
<input type="email"
class="form-control"
id="email"
name="email"
value="<?= e($profileUser['email']); ?>"
required>
</div>
<div class="col-md-6">
<label class="form-label" for="phone">Telefono</label>
<input type="text"
class="form-control"
id="phone"
name="phone"
value="<?= e($profileUser['phone']); ?>">
</div>
<div class="col-md-6">
<label class="form-label" for="birthday">Data di nascita</label>
<input type="date"
class="form-control"
id="birthday"
name="birthday"
value="<?= e($profileUser['birthday']); ?>">
</div>
<div class="col-md-6">
<label class="form-label" for="country_id">Paese</label>
<select class="form-select" id="country_id" name="country_id">
<option value="">Seleziona...</option>
<?php foreach ($countries as $country): ?>
<option value="<?= (int)$country['id']; ?>"
<?= ((int)$profileUser['country_id'] === (int)$country['id']) ? 'selected' : ''; ?>>
<?= e($country['name'] . (!empty($country['iso_3166_2']) ? ' (' . $country['iso_3166_2'] . ')' : '')); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-12">
<label class="form-label" for="address">Indirizzo</label>
<input type="text"
class="form-control"
id="address"
name="address"
value="<?= e($profileUser['address']); ?>">
</div>
</div>
</div>
</div>
</div>
</div>
<div class="settings-card">
<div class="settings-header">
<div class="settings-icon">🔐</div>
<div>
<p class="settings-heading">Cambio password</p>
<p class="settings-subtitle">Compila questa sezione solo se vuoi modificare la password</p>
</div>
</div>
<div class="settings-body">
<div class="password-box">
<div class="row g-3">
<div class="col-md-4">
<label class="form-label" for="current_password">Password attuale</label>
<input type="password"
class="form-control"
id="current_password"
name="current_password"
autocomplete="current-password">
</div>
<div class="col-md-4">
<label class="form-label" for="new_password">Nuova password</label>
<input type="password"
class="form-control"
id="new_password"
name="new_password"
autocomplete="new-password">
</div>
<div class="col-md-4">
<label class="form-label" for="confirm_password">Conferma nuova password</label>
<input type="password"
class="form-control"
id="confirm_password"
name="confirm_password"
autocomplete="new-password">
</div>
</div>
<div class="help-text">
Se lasci questi campi vuoti, la password attuale rimane invariata.
La nuova password deve avere almeno 8 caratteri.
</div>
</div>
<div class="actions-row">
<a href="production_dashboard.php" class="btn-back"> Torna alla dashboard</a>
<button type="submit" class="btn-save-settings">Salva impostazioni</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<?php include('jsinclude.php'); ?>
<?php include('include/footer.php'); ?>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const avatarInput = document.getElementById('avatar');
const previewBox = document.getElementById('avatarPreviewBox');
const selectedFileName = document.getElementById('selectedFileName');
if (!avatarInput || !previewBox) {
return;
}
avatarInput.addEventListener('change', function() {
const file = this.files && this.files[0] ? this.files[0] : null;
if (!file) {
selectedFileName.textContent = '';
return;
}
selectedFileName.textContent = file.name;
if (!file.type.startsWith('image/')) {
return;
}
const reader = new FileReader();
reader.onload = function(event) {
previewBox.innerHTML = '';
const img = document.createElement('img');
img.src = event.target.result;
img.className = 'user-img';
img.alt = 'user avatar';
previewBox.appendChild(img);
};
reader.readAsDataURL(file);
});
});
</script>
</body>
</html>