<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Banda di Spilamberto 1834</title>
<!-- Tailwind CSS CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- React & ReactDOM CDN -->
<script src="https://unpkg.com/react@18/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" crossorigin></script>
<!-- Babel per la compilazione JSX al volo nel browser -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<!-- Lucide Icons -->
<script src="https://unpkg.com/lucide@latest"></script>
</head>
<body class="bg-slate-50 text-slate-800 font-sans pb-12">
<div id="root"></div>
<script type="text/babel">
const { useState, useEffect } = React;
// ==========================================
// CONFIGURAZIONE FIREBASE DALLA TUA CONSOLE
// ==========================================
const firebaseConfig = {
apiKey: "AlzaSyBWNdxhqD0UqN0pL-iC6f9oBOm18401Sns",
authDomain: "app-banda-spilamberto.firebaseapp.com",
projectId: "app-banda-spilamberto",
storageBucket: "app-banda-spilamberto.firebasestorage.app",
messagingSenderId: "384654785456",
appId: "1:384654785456:web:f8e847bcf0ffc9a78b7475",
measurementId: "G-GGBMT0P8QE"
};
function App() {
const [user, setUser] = useState(null);
const [userProfile, setUserProfile] = useState(null);
const [activeTab, setActiveTab] = useState('events');
const [events, setEvents] = useState([
{
id: 'demo-1',
title: 'Prova Generale di Sezione',
date: '2026-10-15',
timeMeet: '20:30',
timeStart: '20:45',
location: 'Sede Banda - Via Roncati, Spilamberto',
mapUrl: 'https://maps.google.com/?q=Spilamberto',
notes: 'Ripasso brani per il concerto d\'autunno. Massima puntualità.',
repertoire: '1. Florentiner March\n2. Cassiopeia\n3. Abba Gold',
attendance: {}
}
]);
const [announcements, setAnnouncements] = useState([
{
id: 'ann-1',
title: 'Aggiornamento Divisa',
content: 'Per il prossimo concerto è richiesta la divisa estiva (pantaloni scuri e polo ufficiale).',
target: 'Tutti',
date: '2026-10-01'
}
]);
// Form Stati
const [isRegistering, setIsRegistering] = useState(false);
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [fullName, setFullName] = useState('');
const [section, setSection] = useState('Legni');
const [instrument, setInstrument] = useState('Clarinetto');
const logoUrl = "https://i.ibb.co/68vDfZ1/banda-spilamberto-logo.png";
useEffect(() => {
if (window.lucide) {
window.lucide.createIcons();
}
}, [activeTab, user, isRegistering]);
const handleAuth = (e) => {
e.preventDefault();
const mockUser = {
email,
displayName: fullName || email.split('@')[0],
role: email.includes('admin') ? 'Amministratore' : 'Musicista',
section,
instrument
};
setUser(mockUser);
setUserProfile(mockUser);
};
const handleLogout = () => {
setUser(null);
setUserProfile(null);
};
const handleRsvp = (eventId, status) => {
const updatedEvents = events.map(ev => {
if (ev.id === eventId) {
const currentUserId = userProfile?.email || 'local-user';
return {
...ev,
attendance: {
...ev.attendance,
[currentUserId]: {
status,
name: userProfile?.fullName || userProfile?.displayName || 'Musicista',
instrument: userProfile?.instrument || 'Strumento',
section: userProfile?.section || 'Legni'
}
}
};
}
return ev;
});
setEvents(updatedEvents);
};
return (
<div className="min-h-screen bg-slate-50 text-slate-800 font-sans pb-12">
{/* HEADER BANDA */}
<header className="bg-white border-b border-slate-200 sticky top-0 z-50 shadow-sm">
<div className="max-w-4xl mx-auto px-4 py-3 flex items-center justify-between">
<div className="flex items-center space-x-3">
<div className="w-12 h-12 rounded-full border-2 border-blue-600 p-0.5 bg-white flex items-center justify-center overflow-hidden shadow-sm">
<img src={logoUrl} alt="Logo Banda di Spilamberto" className="w-full h-full object-cover" />
</div>
<div>
<h1 className="font-bold text-lg text-slate-900 leading-tight">Banda di Spilamberto 1834</h1>
<p className="text-xs text-blue-700 font-medium">Gestione Organico e Impegni</p>
</div>
</div>
{user && (
<div className="flex items-center space-x-2">
<span className="hidden sm:inline text-xs bg-emerald-100 text-emerald-800 px-2.5 py-1 rounded-full font-semibold">
{userProfile?.role || 'Musicista'}
</span>
<button
onClick={handleLogout}
className="p-2 text-slate-500 hover:text-red-600 rounded-lg hover:bg-slate-100 transition"
title="Disconnetti"
>
Logout
</button>
</div>
)}
</div>
</header>
{/* SCHERMATA LOGIN SE NON AUTENTICATO */}
{!user ? (
<main className="max-w-md mx-auto px-4 py-8">
<div className="bg-white p-6 rounded-2xl shadow-md border border-slate-100">
<div className="text-center mb-6">
<div className="w-20 h-20 mx-auto mb-3 rounded-full border-4 border-blue-600/20 p-1 bg-white overflow-hidden">
<img src={logoUrl} alt="Logo" className="w-full h-full object-cover rounded-full" />
</div>
<h2 className="text-xl font-bold text-slate-900">Accesso Musicisti</h2>
<p className="text-xs text-slate-500 mt-1">Accedi per consultare gli impegni e le presenze</p>
</div>
<form onSubmit={handleAuth} className="space-y-4">
{isRegistering && (
<>
<div>
<label className="block text-xs font-semibold text-slate-600 mb-1">Nome e Cognome</label>
<input
type="text"
required
value={fullName}
onChange={e => setFullName(e.target.value)}
className="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-600 focus:outline-none text-sm"
placeholder="Mario Rossi"
/>
</div>
<div className="grid grid-cols-2 gap-2">
<div>
<label className="block text-xs font-semibold text-slate-600 mb-1">Sezione</label>
<select
value={section}
onChange={e => setSection(e.target.value)}
className="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-600 focus:outline-none text-sm bg-white"
>
<option value="Legni">Legni</option>
<option value="Ottoni">Ottoni</option>
<option value="Percussioni">Percussioni</option>
</select>
</div>
<div>
<label className="block text-xs font-semibold text-slate-600 mb-1">Strumento</label>
<input
type="text"
required
value={instrument}
onChange={e => setInstrument(e.target.value)}
className="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-600 focus:outline-none text-sm"
placeholder="es. Clarinetto"
/>
</div>
</div>
</>
)}
<div>
<label className="block text-xs font-semibold text-slate-600 mb-1">Email</label>
<input
type="email"
required
value={email}
onChange={e => setEmail(e.target.value)}
className="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-600 focus:outline-none text-sm"
placeholder="nome@bandaspilamberto.it"
/>
</div>
<div>
<label className="block text-xs font-semibold text-slate-600 mb-1">Password</label>
<input
type="password"
required
value={password}
onChange={e => setPassword(e.target.value)}
className="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-600 focus:outline-none text-sm"
placeholder="••••••••"
/>
</div>
<button
type="submit"
className="w-full bg-blue-700 hover:bg-blue-800 text-white font-semibold py-2.5 rounded-lg shadow-sm transition duration-150 text-sm"
>
{isRegistering ? 'Registrati all\'App' : 'Accedi'}
</button>
</form>
<div className="mt-4 text-center">
<button
onClick={() => setIsRegistering(!isRegistering)}
className="text-xs text-blue-700 hover:underline font-medium"
>
{isRegistering ? 'Hai già un account? Accedi' : 'Nuovo musicista? Registrati qui'}
</button>
</div>
</div>
</main>
) : (
/* CONTENUTO PRINCIPALE APP LOGGATO */
<main className="max-w-4xl mx-auto px-4 py-6">
{/* MENU NAVIGAZIONE SCHEDE */}
<div className="flex border-b border-slate-200 mb-6 bg-white rounded-xl p-1 shadow-sm">
<button
onClick={() => setActiveTab('events')}
className={`flex-1 py-2.5 text-xs sm:text-sm font-semibold rounded-lg flex items-center justify-center space-x-2 transition ${activeTab === 'events' ? 'bg-blue-700 text-white shadow-sm' : 'text-slate-600 hover:bg-slate-100'}`}
>
<span>Impegni e Prove</span>
</button>
<button
onClick={() => setActiveTab('announcements')}
className={`flex-1 py-2.5 text-xs sm:text-sm font-semibold rounded-lg flex items-center justify-center space-x-2 transition ${activeTab === 'announcements' ? 'bg-blue-700 text-white shadow-sm' : 'text-slate-600 hover:bg-slate-100'}`}
>
<span>Bacheca</span>
</button>
<button
onClick={() => setActiveTab('info')}
className={`flex-1 py-2.5 text-xs sm:text-sm font-semibold rounded-lg flex items-center justify-center space-x-2 transition ${activeTab === 'info' ? 'bg-blue-700 text-white shadow-sm' : 'text-slate-600 hover:bg-slate-100'}`}
>
<span>Info & App</span>
</button>
</div>
{/* SCHEDA EVENTI */}
{activeTab === 'events' && (
<div className="space-y-6">
{events.map(ev => (
<div key={ev.id} className="bg-white border border-slate-200 rounded-2xl overflow-hidden shadow-sm hover:shadow-md transition">
<div className="bg-blue-900 text-white p-4 flex justify-between items-start">
<div>
<span className="inline-block bg-blue-700/60 text-blue-100 text-[10px] font-bold px-2 py-0.5 rounded uppercase tracking-wider mb-1">
Evento Programmato
</span>
<h3 className="text-lg font-bold">{ev.title}</h3>
<p className="text-xs text-blue-200 flex items-center mt-1">
{ev.date} — Ritrovo ore {ev.timeMeet} (Inizio ore {ev.timeStart})
</p>
</div>
</div>
<div className="p-4 space-y-4">
{/* Luogo & Mappa */}
<div className="flex items-start justify-between bg-slate-50 p-3 rounded-xl border border-slate-100">
<div>
<p className="text-xs font-semibold text-slate-800">{ev.location}</p>
<p className="text-[11px] text-slate-500">{ev.notes}</p>
</div>
<a
href={ev.mapUrl}
target="_blank"
rel="noreferrer"
className="text-xs bg-emerald-600 text-white px-3 py-1.5 rounded-lg font-medium hover:bg-emerald-700 shrink-0"
>
Mappa
</a>
</div>
{/* Modulo Sondaggio Presenza */}
<div className="border-t border-slate-100 pt-3">
<p className="text-xs font-bold text-slate-700 mb-2">Conferma la tua presenza:</p>
<div className="grid grid-cols-3 gap-2">
<button
onClick={() => handleRsvp(ev.id, 'Presente')}
className="py-2 bg-emerald-50 text-emerald-700 border border-emerald-200 rounded-xl hover:bg-emerald-100 font-semibold text-xs"
>
Presente
</button>
<button
onClick={() => handleRsvp(ev.id, 'In forse')}
className="py-2 bg-amber-50 text-amber-700 border border-amber-200 rounded-xl hover:bg-amber-100 font-semibold text-xs"
>
In forse
</button>
<button
onClick={() => handleRsvp(ev.id, 'Assente')}
className="py-2 bg-rose-50 text-rose-700 border border-rose-200 rounded-xl hover:bg-rose-100 font-semibold text-xs"
>
Assente
</button>
</div>
</div>
</div>
</div>
))}
</div>
)}
{/* SCHEDA BACHECA */}
{activeTab === 'announcements' && (
<div className="space-y-4">
{announcements.map(ann => (
<div key={ann.id} className="bg-white border border-slate-200 p-4 rounded-xl shadow-sm">
<div className="flex justify-between items-start mb-2">
<h3 className="font-bold text-slate-900 text-sm">{ann.title}</h3>
<span className="text-[10px] bg-blue-100 text-blue-800 font-semibold px-2 py-0.5 rounded">
{ann.target}
</span>
</div>
<p className="text-xs text-slate-600 leading-relaxed">{ann.content}</p>
<p className="text-[10px] text-slate-400 mt-2">{ann.date}</p>
</div>
))}
</div>
)}
{/* SCHEDA INFO & DOMINIO */}
{activeTab === 'info' && (
<div className="bg-white p-6 rounded-2xl border border-slate-200 shadow-sm space-y-4">
<h3 className="font-bold text-slate-900 text-base">Applicazione Ufficiale</h3>
<p className="text-xs text-slate-600">
Questa Web App è collegata direttamente al dominio ufficiale della banda:
<a href="https://www.bandaspilamberto.it" target="_blank" rel="noreferrer" className="text-blue-700 font-semibold underline ml-1">
www.bandaspilamberto.it
</a>
</p>
<div className="bg-slate-50 p-4 rounded-xl border border-slate-100 text-xs space-y-2">
<p className="font-bold text-slate-800">Come installarla sullo smartphone:</p>
<p className="text-slate-600">
• <strong>Android:</strong> Apri il link su Chrome, tocca i tre pallini in alto a destra e seleziona <em>"Aggiungi a schermata Home"</em>.
</p>
<p className="text-slate-600">
• <strong>iPhone / iOS:</strong> Apri il link su Safari, tocca il tasto Condividi (icona in basso con la freccia) e seleziona <em>"Aggiungi alla schermata Home"</em>.
</p>
</div>
</div>
)}
</main>
)}
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
</script>
</body>
</html>