YogiBook_App/lib/screens/select_school_page.dart
2025-12-27 20:46:49 +01:00

508 lines
14 KiB
Dart

import 'package:flutter/material.dart';
import '../models/school.dart';
import '../services/vanguard_api.dart';
import 'lessons_page.dart';
import 'home_page.dart';
import 'meditation_page.dart';
import 'login_page.dart';
class SelectSchoolPage extends StatefulWidget {
final String token;
const SelectSchoolPage({super.key, required this.token});
@override
State<SelectSchoolPage> createState() => _SelectSchoolPageState();
}
class _SelectSchoolPageState extends State<SelectSchoolPage> {
static const Color kBg = Color(0xFFF6F6FB);
static const Color kGreen = Color(0xFF10B981);
bool loading = true;
String error = '';
String? firstName;
List<School> schools = [];
int bottomIndex = 1; // 0=Home, 1=Lezioni, 2=Account (qui siamo in "Lezioni")
@override
void initState() {
super.initState();
_load();
}
Future<void> _load() async {
setState(() {
loading = true;
error = '';
});
try {
final data = await VanguardApi.getUserSchools(token: widget.token);
final user = (data['user'] as Map<String, dynamic>? ?? {});
firstName = user['first_name']?.toString();
final list = (data['schools'] as List<dynamic>? ?? [])
.map((e) => School.fromJson(e as Map<String, dynamic>))
.toList();
setState(() => schools = list);
// Auto-select if API says so
final autoSelect = data['auto_select'] == true;
final selectedId = data['selected_school_id'];
if (autoSelect && selectedId != null && schools.isNotEmpty) {
final id = (selectedId as num).toInt();
final s = schools.firstWhere((x) => x.id == id);
_enterSchool(s);
}
} catch (e) {
setState(() => error = 'Errore: $e');
} finally {
setState(() => loading = false);
}
}
void _enterSchool(School s) {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (_) =>
HomePage(token: widget.token, school: s, userFirstName: firstName),
),
);
}
String get _name => (firstName ?? '').trim();
String get _avatarLetter => _name.isNotEmpty ? _name[0].toUpperCase() : 'U';
Future<void> _logout() async {
final ok = await showDialog<bool>(
context: context,
builder: (_) => AlertDialog(
title: const Text('Conferma logout'),
content: const Text('Vuoi uscire dal tuo account?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text('Annulla'),
),
ElevatedButton(
onPressed: () => Navigator.pop(context, true),
child: const Text('Logout'),
),
],
),
);
if (ok != true) return;
// chiude il drawer se aperto
Navigator.of(context).pop();
// chiama API logout (se fallisce usciamo lo stesso)
try {
await VanguardApi.logout(token: widget.token);
} catch (_) {}
if (!mounted) return;
// torna a Login e cancella tutta la stack
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (_) => const LoginPage()),
(route) => false,
);
}
void _handleBottomNav(int i) {
setState(() => bottomIndex = i);
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('Prima seleziona la scuola')));
}
@override
Widget build(BuildContext context) {
return Scaffold(
drawer: _AppDrawer(token: widget.token, onLogout: _logout),
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
centerTitle: true,
title: const Text(
'Cambia scuola',
style: TextStyle(fontWeight: FontWeight.w800, fontSize: 18),
),
actions: [
Padding(
padding: const EdgeInsets.only(right: 12),
child: CircleAvatar(
radius: 16,
backgroundColor: kGreen,
child: Text(
_avatarLetter,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w900,
fontSize: 12,
),
),
),
),
],
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed, // con 4 icone serve
backgroundColor: Colors.white,
selectedItemColor: const Color(0xFF10B981),
unselectedItemColor: Colors.black54,
currentIndex: bottomIndex,
onTap: _handleBottomNav,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home_rounded),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.event_note_rounded),
label: 'Lezioni',
),
BottomNavigationBarItem(
icon: Icon(Icons.person_rounded),
label: 'Account',
),
BottomNavigationBarItem(
icon: Icon(Icons.self_improvement_rounded),
label: 'Meditazione',
),
],
),
body: Stack(
children: [
// --- SFONDO (gradient)
Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFFF4F6FA),
Color(0xFFEFF7F3),
Color(0xFFF4F6FA),
],
),
),
),
// --- BOLLE decorative
const _BgBlob(
color: Color(0x3310B981),
size: 280,
top: -70,
left: -90,
),
const _BgBlob(
color: Color(0x22F59E0B),
size: 230,
bottom: 80,
right: -70,
),
const _BgBlob(
color: Color(0x227C3AED),
size: 190,
bottom: -55,
left: 35,
),
// --- CONTENUTO della pagina (quello che avevi prima)
SafeArea(
top: false,
child: loading
? const Center(child: CircularProgressIndicator())
: error.isNotEmpty
? _ErrorBox(message: error, onRetry: _load)
: _SchoolsList(
firstName: firstName,
schools: schools,
onSelect: _enterSchool,
),
),
],
),
);
}
}
class _AppDrawer extends StatelessWidget {
final String token;
final VoidCallback onLogout;
const _AppDrawer({required this.token, required this.onLogout});
@override
Widget build(BuildContext context) {
return Drawer(
child: SafeArea(
child: ListView(
padding: EdgeInsets.zero,
children: [
const DrawerHeader(
child: Align(
alignment: Alignment.bottomLeft,
child: Text(
'Menu',
style: TextStyle(fontSize: 22, fontWeight: FontWeight.w900),
),
),
),
ListTile(
leading: const Icon(Icons.swap_horiz),
title: const Text('Cambia scuola'),
onTap: () => Navigator.of(context).pop(), // sei già qui
),
const Divider(height: 1),
ListTile(
leading: const Icon(Icons.logout),
title: const Text('Logout'),
onTap: onLogout,
),
],
),
),
);
}
}
class _SchoolsList extends StatelessWidget {
static const Color kGreen = Color(0xFF10B981);
final String? firstName;
final List<School> schools;
final void Function(School) onSelect;
const _SchoolsList({
required this.firstName,
required this.schools,
required this.onSelect,
});
@override
Widget build(BuildContext context) {
final name = (firstName ?? '').trim();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// header compatto (stesso stile “soft” delle lezioni)
Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name.isNotEmpty
? 'Seleziona una scuola, $name'
: 'Seleziona una scuola',
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w900,
color: Color(0xFF2B2B2B),
),
),
const SizedBox(height: 6),
const Text(
'Scegli la scuola di yoga.',
style: TextStyle(
color: Colors.black45,
fontWeight: FontWeight.w600,
),
),
],
),
),
Expanded(
child: ListView.builder(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
itemCount: schools.length,
itemBuilder: (_, i) {
final s = schools[i];
return _SchoolCard(school: s, onTap: () => onSelect(s));
},
),
),
const SizedBox(height: 8),
Center(
child: Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Image.asset('assets/images/yogibook_logo.png', height: 56),
),
),
],
);
}
}
class _SchoolCard extends StatelessWidget {
static const Color kGreen = Color(0xFF10B981);
final School school;
final VoidCallback onTap;
const _SchoolCard({required this.school, required this.onTap});
@override
Widget build(BuildContext context) {
final address = (school.addressFull ?? '').trim();
return Container(
margin: const EdgeInsets.only(bottom: 12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(18),
boxShadow: const [
BoxShadow(
blurRadius: 18,
color: Color(0x12000000),
offset: Offset(0, 10),
),
],
),
child: InkWell(
borderRadius: BorderRadius.circular(18),
onTap: onTap,
child: Padding(
padding: const EdgeInsets.fromLTRB(12, 12, 12, 12),
child: Row(
children: [
Container(
width: 44,
height: 44,
decoration: BoxDecoration(
color: const Color(0xFFE7F8F1),
borderRadius: BorderRadius.circular(14),
),
child: const Icon(Icons.school, color: kGreen),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
school.name,
style: const TextStyle(
fontWeight: FontWeight.w900,
fontSize: 15,
color: Color(0xFF1F1F1F),
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
if (address.isNotEmpty) ...[
const SizedBox(height: 4),
Text(
address,
style: const TextStyle(
fontSize: 12,
color: Colors.black54,
fontWeight: FontWeight.w600,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
],
],
),
),
const SizedBox(width: 10),
Container(
width: 34,
height: 34,
decoration: const BoxDecoration(
color: kGreen,
shape: BoxShape.circle,
),
child: const Icon(Icons.chevron_right, color: Colors.white),
),
],
),
),
),
);
}
}
class _ErrorBox extends StatelessWidget {
final String message;
final VoidCallback onRetry;
const _ErrorBox({required this.message, required this.onRetry});
@override
Widget build(BuildContext context) {
return Center(
child: Padding(
padding: const EdgeInsets.all(18),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.error_outline, size: 58, color: Colors.redAccent),
const SizedBox(height: 10),
Text(message, textAlign: TextAlign.center),
const SizedBox(height: 12),
ElevatedButton(onPressed: onRetry, child: const Text('Riprova')),
],
),
),
);
}
}
class _BgBlob extends StatelessWidget {
final Color color;
final double size;
final double? top;
final double? left;
final double? right;
final double? bottom;
const _BgBlob({
required this.color,
required this.size,
this.top,
this.left,
this.right,
this.bottom,
});
@override
Widget build(BuildContext context) {
return Positioned(
top: top,
left: left,
right: right,
bottom: bottom,
child: IgnorePointer(
child: Container(
width: size,
height: size,
decoration: BoxDecoration(
color: color,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
blurRadius: 70,
color: color,
offset: const Offset(0, 18),
),
],
),
),
),
);
}
}