2025-10-23 13:19:05 +00:00
< ? php
session_start ();
$roleName = isset ( $_SESSION [ 'role_name' ]) ? $_SESSION [ 'role_name' ] : null ;
$isLogged = isset ( $_SESSION [ 'user_id' ]);
$username = isset ( $_SESSION [ 'username' ]) ? $_SESSION [ 'username' ] : null ;
2025-11-07 18:03:44 +00:00
// Flag di sessione: mostra l'effetto solo una volta per sessione
$alessioCandidate = $isLogged && $username && stripos ( $username , 'alessio' ) !== false ;
$showBlessingOnce = false ;
if ( $alessioCandidate && empty ( $_SESSION [ 'alessio_blessed' ])) {
$showBlessingOnce = true ;
$_SESSION [ 'alessio_blessed' ] = true ;
}
2025-10-23 13:19:05 +00:00
?>
2025-10-21 10:37:08 +00:00
<! DOCTYPE html >
< html lang = " it " >
2025-10-23 13:19:05 +00:00
< head >
< meta charset = " UTF-8 " >
< meta name = " viewport " content = " width=device-width, initial-scale=1.0 " >
< title > Biblioteca | Home </ title >
< script src = " https://cdn.tailwindcss.com " ></ script >
< script src = " https://code.jquery.com/jquery-3.7.1.min.js " ></ script >
2025-11-07 18:03:44 +00:00
< style >
#alessioBlessing{position:fixed;left:50%;transform:translateX(-50%);top:-300px;width:220px;height:220px;pointer-events:none;z-index:9999;opacity:0;}
#alessioBlessing .halo{position:absolute;top:-20px;left:50%;transform:translateX(-50%);width:150px;height:150px;border-radius:50%;box-shadow:0 0 30px 15px rgba(255,215,0,0.7) inset,0 0 25px 10px rgba(255,215,0,0.6);background:radial-gradient(circle, rgba(255,238,169,0.7) 0%, rgba(255,204,0,0.4) 60%, rgba(255,204,0,0.1) 100%);}
#alessioBlessing .photo{position:absolute;bottom:0;left:50%;transform:translateX(-50%);width:120px;height:160px;border-radius:10px;object-fit:cover;box-shadow:0 10px 25px rgba(0,0,0,0.15);}
#alessioBlessing .sparkles{position:absolute;inset:0;}
#alessioBlessing .sparkles span{position:absolute;width:6px;height:6px;background:#ffd700;border-radius:50%;box-shadow:0 0 10px #ffd700;opacity:.9;animation:twinkle 1.2s infinite ease-in-out;}
@ keyframes twinkle { 0 % , 100 % { transform : translateY ( 0 ) scale ( 1 ); opacity :. 3 ;} 50 % { transform : translateY ( - 6 px ) scale ( 1.2 ); opacity : 1 ;}}
@ keyframes descendTop { 0 % { top :- 300 px ; opacity : 0 ;} 30 % { top : 18 % ; opacity : 1 ;} 60 % { top : 35 % ; opacity : 1 ;} 85 % { top : 60 % ; opacity :. 9 ;} 100 % { top : 110 % ; opacity : 0 ;}}
#alessioBlessing.run{animation:descendTop 4.8s ease-in-out forwards;}
</ style >
2025-10-23 13:19:05 +00:00
</ head >
< body class = " bg-[#f8fafc] text-[#545454] " >
< nav class = " w-full bg-[#545454] text-white shadow " >
< div class = " max-w-7xl mx-auto px-4 " >
< div class = " flex justify-between items-center h-16 " >
< div class = " flex items-center gap-6 " >
2025-10-23 13:26:03 +00:00
< a href = " # " class = " font-semibold text-lg " > Biblioteca Online </ a >
2025-10-23 13:19:05 +00:00
< div class = " hidden md:flex items-center gap-4 " >
< a href = " # " class = " hover:text-[#cbff4d] " > Catalogo </ a >
< a href = " # " class = " hover:text-[#cbff4d] " > Recensioni </ a >
</ div >
</ div >
<!-- Menu basato sul ruolo -->
< div class = " hidden md:flex items-center gap-4 " >
< ? php if ( $isLogged && $roleName === 'admin' ) : ?>
< a href = " # " class = " hover:text-[#cbff4d] " > Gestione Utenti </ a >
< a href = " # " class = " hover:text-[#cbff4d] " > Ruoli & Permessi </ a >
< a href = " # " class = " hover:text-[#cbff4d] " > Gestione Bibliotecari </ a >
< ? php elseif ( $isLogged && $roleName === 'bibliotecario' ) : ?>
< a href = " # " class = " hover:text-[#cbff4d] " > Elenco Libri </ a >
< a href = " # " class = " hover:text-[#cbff4d] " > Elenco Film </ a >
< a href = " # " class = " hover:text-[#cbff4d] " > Elenco Documentari </ a >
< a href = " # " class = " hover:text-[#cbff4d] " > Prenotazioni </ a >
< a href = " # " class = " hover:text-[#cbff4d] " > Utenti Registrati </ a >
< ? php elseif ( $isLogged && $roleName === 'utente' ) : ?>
< a href = " # " class = " hover:text-[#cbff4d] " > Prenota </ a >
< a href = " # " class = " hover:text-[#cbff4d] " > Le mie Prenotazioni </ a >
< ? php endif ; ?>
</ div >
< div class = " flex items-center gap-3 " >
< ? php if ( $isLogged ) : ?>
< span class = " hidden md:inline text-sm " > Ciao , < ? php echo htmlspecialchars ( $username ); ?> </span>
2025-10-23 13:26:03 +00:00
< a href = " ./php/auth/logout.php " class = " px-4 py-2 bg-[#84dd63] text-[#1f2937] rounded hover:bg-[#cbff4d] " > Logout </ a >
2025-10-23 13:19:05 +00:00
< ? php else : ?>
< button id = " openLogin " class = " px-4 py-2 bg-[#84dd63] text-[#1f2937] rounded hover:bg-[#cbff4d] " > Login </ button >
2025-10-30 14:53:18 +00:00
< button id = " openRegister " class = " px-4 py-2 bg-[#69747c] text-white rounded hover:bg-[#545454] " > Registrati </ button >
2025-10-23 13:19:05 +00:00
< ? php endif ; ?>
</ div >
</ div >
</ div >
</ nav >
<!-- Hero / Intro -->
< section class = " max-w-7xl mx-auto px-4 py-10 " >
< div class = " grid md:grid-cols-2 gap-8 items-center " >
< div >
< h1 class = " text-3xl md:text-4xl font-bold text-[#6baa75] " > Benvenuto nella Biblioteca Online </ h1 >
< p class = " mt-3 text-[#69747c] " > Esplora libri , film e documentari . Prenota facilmente e gestisci le tue recensioni . In base al tuo ruolo vedrai azioni diverse .</ p >
< div class = " mt-6 flex gap-3 " >
< a href = " # " class = " px-5 py-2 bg-[#6baa75] text-white rounded hover:bg-[#84dd63] " > Sfoglia Catalogo </ a >
< ? php if ( ! $isLogged ) : ?>
< button id = " openLogin2 " class = " px-5 py-2 bg-[#545454] text-white rounded hover:bg-[#69747c] " > Accedi </ button >
2025-10-30 14:53:18 +00:00
< button id = " openRegister2 " class = " px-5 py-2 bg-[#69747c] text-white rounded hover:bg-[#545454] " > Registrati </ button >
2025-10-23 13:19:05 +00:00
< ? php endif ; ?>
</ div >
</ div >
< div class = " bg-white rounded-lg shadow p-6 border border-[#e5e7eb] " >
< h2 class = " text-xl font-semibold text-[#545454] " > Cosa puoi fare </ h2 >
< ul class = " mt-3 space-y-2 text-[#69747c] list-disc list-inside " >
< li > Utente : prenotare e gestire le tue prenotazioni </ li >
< li > Bibliotecario : gestire catalogo , prenotazioni e recensioni </ li >
< li > Admin : gestire utenti , ruoli e permessi </ li >
</ ul >
</ div >
</ div >
</ section >
<!-- Modal Login -->
< div id = " loginModal " class = " fixed inset-0 bg-black/40 hidden items-center justify-center " >
< div class = " bg-white w-full max-w-md rounded-lg shadow-lg p-6 " >
< div class = " flex justify-between items-center mb-4 " >
< h3 class = " text-lg font-semibold text-[#545454] " > Accedi </ h3 >
< button id = " closeLogin " class = " text-[#69747c] hover:text-[#545454] " > ✕ </ button >
</ div >
< form id = " loginForm " class = " space-y-4 " >
< div >
2025-10-24 06:12:04 +00:00
< label class = " block text-sm text-[#69747c] " > Username </ label >
< input type = " text " name = " username " required class = " mt-1 w-full border rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[#84dd63] " placeholder = " username " >
2025-10-23 13:19:05 +00:00
</ div >
< div >
< label class = " block text-sm text-[#69747c] " > Password </ label >
< input type = " password " name = " password " required class = " mt-1 w-full border rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[#84dd63] " placeholder = " •••••••• " >
</ div >
< div id = " loginError " class = " hidden text-red-600 text-sm " ></ div >
< button type = " submit " class = " w-full bg-[#6baa75] text-white rounded py-2 hover:bg-[#84dd63] " > Login </ button >
</ form >
</ div >
</ div >
2025-10-30 14:53:18 +00:00
<!-- Modal Registrazione -->
< div id = " registerModal " class = " fixed inset-0 bg-black/40 hidden items-center justify-center " >
< div class = " bg-white w-full max-w-2xl rounded-lg shadow-lg p-6 " >
< div class = " flex justify-between items-center mb-4 " >
< h3 class = " text-lg font-semibold text-[#545454] " > Registrazione Utente </ h3 >
< button id = " closeRegister " class = " text-[#69747c] hover:text-[#545454] " > ✕ </ button >
</ div >
< form id = " registerForm " class = " grid grid-cols-1 md:grid-cols-2 gap-4 " >
< div >
< label class = " block text-sm text-[#69747c] " > Nome </ label >
< input type = " text " name = " nome " required class = " mt-1 w-full border rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[#84dd63] " >
</ div >
< div >
< label class = " block text-sm text-[#69747c] " > Cognome </ label >
< input type = " text " name = " cognome " required class = " mt-1 w-full border rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[#84dd63] " >
</ div >
< div >
< label class = " block text-sm text-[#69747c] " > Data di nascita </ label >
< input type = " date " name = " data_nascita " required class = " mt-1 w-full border rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[#84dd63] " >
</ div >
< div >
< label class = " block text-sm text-[#69747c] " > Luogo di nascita </ label >
< input type = " text " name = " luogo_nascita " required class = " mt-1 w-full border rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[#84dd63] " >
</ div >
< div >
< label class = " block text-sm text-[#69747c] " > Codice Fiscale </ label >
< input type = " text " name = " cod_fiscale " maxlength = " 16 " required class = " mt-1 w-full border rounded px-3 py-2 uppercase focus:outline-none focus:ring-2 focus:ring-[#84dd63] " >
</ div >
< div >
< label class = " block text-sm text-[#69747c] " > Telefono </ label >
< input type = " tel " name = " telefono " maxlength = " 10 " required class = " mt-1 w-full border rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[#84dd63] " >
</ div >
< div class = " md:col-span-2 mt-2 border-t pt-4 " >
< h2 class = " text-lg font-semibold text-[#545454] " > Credenziali di accesso </ h2 >
</ div >
< div >
< label class = " block text-sm text-[#69747c] " > Username </ label >
2025-10-30 15:13:56 +00:00
< input type = " text " name = " username " required class = " mt-1 w-full border rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[#84dd63] " placeholder = " username " >
2025-10-30 14:53:18 +00:00
</ div >
< div >
< label class = " block text-sm text-[#69747c] " > Password </ label >
< input type = " password " name = " password " required class = " mt-1 w-full border rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[#84dd63] " placeholder = " Almeno 8 caratteri, maiuscola, minuscola, speciale " >
</ div >
< div id = " registerError " class = " md:col-span-2 hidden text-red-600 text-sm " ></ div >
< div id = " registerOk " class = " md:col-span-2 hidden text-green-700 text-sm " ></ div >
< div class = " md:col-span-2 mt-2 " >
< button type = " submit " class = " w-full bg-[#6baa75] text-white rounded py-2 hover:bg-[#84dd63] " > Registrati </ button >
</ div >
</ form >
</ div >
</ div >
2025-10-23 13:19:05 +00:00
< script >
$ ( function () {
const $modal = $ ( '#loginModal' );
$ ( '#openLogin, #openLogin2' ) . on ( 'click' , function () { $modal . removeClass ( 'hidden' ) . addClass ( 'flex' ); });
$ ( '#closeLogin' ) . on ( 'click' , function () { $modal . addClass ( 'hidden' ) . removeClass ( 'flex' ); $ ( '#loginError' ) . addClass ( 'hidden' ) . text ( '' ); });
$ ( document ) . on ( 'keydown' , function ( e ){ if ( e . key === 'Escape' ){ $ ( '#closeLogin' ) . click (); } });
$ ( '#loginForm' ) . on ( 'submit' , function ( e ) {
e . preventDefault ();
const formData = $ ( this ) . serialize ();
$ . ajax ({
2025-10-23 13:26:03 +00:00
url : './php/auth/login.php' ,
2025-10-23 13:19:05 +00:00
method : 'POST' ,
data : formData ,
headers : { 'X-Requested-With' : 'XMLHttpRequest' },
success : function ( resp ) {
try { resp = typeof resp === 'string' ? JSON . parse ( resp ) : resp ; } catch ( _ ) {}
if ( resp && resp . status === 'ok' ) {
location . reload ();
} else {
$ ( '#loginError' ) . removeClass ( 'hidden' ) . text ( resp && resp . message ? resp . message : 'Accesso non riuscito.' );
}
},
error : function () {
$ ( '#loginError' ) . removeClass ( 'hidden' ) . text ( 'Errore di rete. Riprovare.' );
}
});
});
2025-10-30 14:53:18 +00:00
const $regModal = $ ( '#registerModal' );
$ ( '#openRegister, #openRegister2' ) . on ( 'click' , function (){ $regModal . removeClass ( 'hidden' ) . addClass ( 'flex' ); });
$ ( '#closeRegister' ) . on ( 'click' , function (){ $regModal . addClass ( 'hidden' ) . removeClass ( 'flex' ); $ ( '#registerError' ) . addClass ( 'hidden' ) . text ( '' ); $ ( '#registerOk' ) . addClass ( 'hidden' ) . text ( '' ); });
function clientValidate ( pwd ){
if ( / \s /. test ( pwd )) return 'La password non deve contenere spazi' ;
if ( pwd . length < 8 ) return 'La password deve avere almeno 8 caratteri' ;
if ( !/ [ a - z ] /. test ( pwd )) return 'La password deve contenere almeno una minuscola' ;
if ( !/ [ A - Z ] /. test ( pwd )) return 'La password deve contenere almeno una maiuscola' ;
if ( !/ [ ^ a - zA - Z0 - 9 ] /. test ( pwd )) return 'La password deve contenere almeno un carattere speciale' ;
return null ;
}
$ ( '#registerForm' ) . on ( 'submit' , function ( e ){
e . preventDefault ();
const $err = $ ( '#registerError' );
const $ok = $ ( '#registerOk' );
$err . addClass ( 'hidden' ) . text ( '' );
$ok . addClass ( 'hidden' ) . text ( '' );
const pwd = $ ( this ) . find ( 'input[name="password"]' ) . val ();
const v = clientValidate ( pwd );
if ( v ) { $err . removeClass ( 'hidden' ) . text ( v ); return ; }
$ . ajax ({
url : './php/auth/register.php' ,
method : 'POST' ,
data : $ ( this ) . serialize (),
headers : { 'X-Requested-With' : 'XMLHttpRequest' },
success : function ( resp ){
try { resp = typeof resp === 'string' ? JSON . parse ( resp ) : resp ; } catch ( _ ) {}
if ( resp && resp . status === 'ok' ) {
$ok . removeClass ( 'hidden' ) . text ( 'Registrazione completata. Reindirizzamento...' );
setTimeout ( function (){ window . location . reload (); }, 800 );
} else {
const msg = resp && resp . errors ? resp . errors . join ( ' | ' ) : 'Registrazione non riuscita' ;
$err . removeClass ( 'hidden' ) . text ( msg );
}
},
error : function (){
$err . removeClass ( 'hidden' ) . text ( 'Errore di rete. Riprovare.' );
}
});
});
2025-11-07 18:03:44 +00:00
const isAlessioOnce = < ? php echo ( $showBlessingOnce ? 'true' : 'false' ); ?> ;
if ( isAlessioOnce ) {
const $b = $ (
' < div id = " alessioBlessing " > \
< div class = " halo " ></ div > \
< img class = " photo " src = " ./assets/santino.png " alt = " Santino " onerror = " this.style.display= \ 'none \ ' " /> \
< div class = " sparkles " ></ div > \
</ div > '
);
$ ( 'body' ) . append ( $b );
$b . find ( '.photo' ) . attr ( 'src' , './assets/img/santino.png' ) . attr ( 'alt' , 'Santino Alessio' );
const $s = $b . find ( '.sparkles' );
for ( let i = 0 ; i < 18 ; i ++ ) {
const $sp = $ ( '<span/>' );
$sp . css ({
left : ( Math . random () * 200 ) + 'px' ,
top : ( Math . random () * 200 ) + 'px' ,
animationDelay : ( Math . random () * 1.2 ) + 's'
});
$s . append ( $sp );
}
// Avvia animazione, riproduce l'MP3 celestiale e rimuove
function playHeavenly (){
try {
const audio = new Audio ( './assets/sound/heavenly.mp3' );
audio . volume = 0.7 ;
audio . play () . catch (() => {
const once = function (){
audio . play () . catch (() => {});
document . removeEventListener ( 'click' , once );
document . removeEventListener ( 'keydown' , once );
document . removeEventListener ( 'touchstart' , once );
};
document . addEventListener ( 'click' , once , { once : true });
document . addEventListener ( 'keydown' , once , { once : true });
document . addEventListener ( 'touchstart' , once , { once : true });
});
} catch ( e ){}
}
setTimeout ( function (){ $b . addClass ( 'run' ); playHeavenly (); }, 150 );
setTimeout ( function (){ $b . remove (); }, 5200 );
}
2025-10-23 13:19:05 +00:00
});
</ script >
</ body >
2025-10-21 10:37:08 +00:00
</ html >