212 lines
6.9 KiB
Dart
212 lines
6.9 KiB
Dart
|
|
import 'package:flutter/material.dart';
|
||
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||
|
|
import 'package:flux/core/blocs/session/session_cubit.dart';
|
||
|
|
import 'package:flux/core/widgets/flux_text_field.dart';
|
||
|
|
import 'package:flux/features/onboarding/blocs/onboarding_cubit.dart';
|
||
|
|
import 'package:flux/features/onboarding/blocs/onboarding_state.dart';
|
||
|
|
// Importa i tuoi file (cubit, modelli, ecc.)
|
||
|
|
|
||
|
|
class OnboardingScreen extends StatefulWidget {
|
||
|
|
const OnboardingScreen({super.key});
|
||
|
|
|
||
|
|
@override
|
||
|
|
State<OnboardingScreen> createState() => _OnboardingScreenState();
|
||
|
|
}
|
||
|
|
|
||
|
|
class _OnboardingScreenState extends State<OnboardingScreen> {
|
||
|
|
late PageController _pageController;
|
||
|
|
|
||
|
|
@override
|
||
|
|
void initState() {
|
||
|
|
super.initState();
|
||
|
|
// Inizializziamo il controller sulla pagina giusta.
|
||
|
|
// L'indice parte da 0. company=0, store=1, staff=2.
|
||
|
|
final initialStep = context.read<OnboardingCubit>().state.step;
|
||
|
|
_pageController = PageController(initialPage: _getPageIndex(initialStep));
|
||
|
|
}
|
||
|
|
|
||
|
|
@override
|
||
|
|
void dispose() {
|
||
|
|
_pageController.dispose();
|
||
|
|
super.dispose();
|
||
|
|
}
|
||
|
|
|
||
|
|
int _getPageIndex(OnboardingStep step) {
|
||
|
|
switch (step) {
|
||
|
|
case OnboardingStep.company:
|
||
|
|
return 0;
|
||
|
|
case OnboardingStep.store:
|
||
|
|
return 1;
|
||
|
|
case OnboardingStep.staff:
|
||
|
|
return 2;
|
||
|
|
default:
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget build(BuildContext context) {
|
||
|
|
return BlocConsumer<OnboardingCubit, OnboardingState>(
|
||
|
|
// Ascoltiamo solo quando cambia lo step per animare la pagina
|
||
|
|
listenWhen: (previous, current) => previous.step != current.step,
|
||
|
|
listener: (context, state) {
|
||
|
|
if (state.step == OnboardingStep.completed) {
|
||
|
|
// Il SessionCubit prenderà il controllo e farà il redirect,
|
||
|
|
// qui potremmo mostrare un bel toast di successo.
|
||
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
||
|
|
const SnackBar(content: Text("Configurazione completata! 🚀")),
|
||
|
|
);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
final targetPage = _getPageIndex(state.step);
|
||
|
|
_pageController.animateToPage(
|
||
|
|
targetPage,
|
||
|
|
duration: const Duration(milliseconds: 500),
|
||
|
|
curve: Curves.easeInOut,
|
||
|
|
);
|
||
|
|
},
|
||
|
|
builder: (context, state) {
|
||
|
|
return Scaffold(
|
||
|
|
body: SafeArea(
|
||
|
|
child: Stack(
|
||
|
|
children: [
|
||
|
|
// Il PageView disabilita lo scorrimento manuale con NeverScrollableScrollPhysics
|
||
|
|
PageView(
|
||
|
|
controller: _pageController,
|
||
|
|
physics: const NeverScrollableScrollPhysics(),
|
||
|
|
children: [
|
||
|
|
_buildCompanyForm(context, state),
|
||
|
|
_buildStoreForm(context, state),
|
||
|
|
_buildStaffForm(
|
||
|
|
context,
|
||
|
|
state,
|
||
|
|
), // Qui c'è la magia paranoica
|
||
|
|
],
|
||
|
|
),
|
||
|
|
|
||
|
|
// Overlay di caricamento universale
|
||
|
|
if (state.isLoading)
|
||
|
|
Container(
|
||
|
|
color: Colors.black.withValues(alpha: 0.5),
|
||
|
|
child: const Center(child: CircularProgressIndicator()),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
},
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- I METODI DEI FORM ---
|
||
|
|
// (Nella realtà li metterai in file separati o widget custom per pulizia)
|
||
|
|
|
||
|
|
Widget _buildCompanyForm(BuildContext context, OnboardingState state) {
|
||
|
|
// Controller e chiavi del form...
|
||
|
|
return Padding(
|
||
|
|
padding: const EdgeInsets.all(24.0),
|
||
|
|
child: Column(
|
||
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
||
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||
|
|
children: [
|
||
|
|
const Text(
|
||
|
|
"Step 1: La tua Azienda",
|
||
|
|
style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
|
||
|
|
),
|
||
|
|
const SizedBox(height: 8),
|
||
|
|
const Text("Inserisci i dati della tua attività."),
|
||
|
|
const SizedBox(height: 32),
|
||
|
|
|
||
|
|
// Esempio usando la tua FluxTextField
|
||
|
|
FluxTextField(label: 'Ragione Sociale / Nome Azienda'),
|
||
|
|
const SizedBox(height: 16),
|
||
|
|
FluxTextField(label: 'Partita IVA'),
|
||
|
|
|
||
|
|
const Spacer(),
|
||
|
|
ElevatedButton(
|
||
|
|
onPressed: () {
|
||
|
|
// 1. Valida il form
|
||
|
|
// 2. Crea il CompanyModel
|
||
|
|
// 3. Chiama il Cubit:
|
||
|
|
// context.read<OnboardingCubit>().saveCompany(newCompany);
|
||
|
|
},
|
||
|
|
child: const Text("Salva e prosegui"),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
Widget _buildStoreForm(BuildContext context, OnboardingState state) {
|
||
|
|
return Padding(
|
||
|
|
padding: const EdgeInsets.all(24.0),
|
||
|
|
child: Column(
|
||
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
||
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||
|
|
children: [
|
||
|
|
const Text(
|
||
|
|
"Step 2: Il primo Negozio",
|
||
|
|
style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
|
||
|
|
),
|
||
|
|
const SizedBox(height: 8),
|
||
|
|
const Text("Dove si trova il tuo punto vendita principale?"),
|
||
|
|
const SizedBox(height: 32),
|
||
|
|
|
||
|
|
FluxTextField(label: 'Nome Negozio (es. Sede Centrale)'),
|
||
|
|
const SizedBox(height: 16),
|
||
|
|
FluxTextField(label: 'Indirizzo'),
|
||
|
|
|
||
|
|
const Spacer(),
|
||
|
|
ElevatedButton(
|
||
|
|
onPressed: () {
|
||
|
|
// context.read<OnboardingCubit>().saveStore(newStore);
|
||
|
|
},
|
||
|
|
child: const Text("Salva Negozio"),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
Widget _buildStaffForm(BuildContext context, OnboardingState state) {
|
||
|
|
// NOTA PARANOICA: Qui chiediamo jobTitle (Testo libero),
|
||
|
|
// ma NON diamo modo di scegliere il system_role!
|
||
|
|
return Padding(
|
||
|
|
padding: const EdgeInsets.all(24.0),
|
||
|
|
child: Column(
|
||
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
||
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||
|
|
children: [
|
||
|
|
const Text(
|
||
|
|
"Step 3: Il tuo Profilo",
|
||
|
|
style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
|
||
|
|
),
|
||
|
|
const SizedBox(height: 8),
|
||
|
|
const Text("Crea il tuo profilo operativo per iniziare a lavorare."),
|
||
|
|
const SizedBox(height: 32),
|
||
|
|
|
||
|
|
FluxTextField(label: 'Nome'),
|
||
|
|
const SizedBox(height: 16),
|
||
|
|
FluxTextField(label: 'Cognome'),
|
||
|
|
const SizedBox(height: 16),
|
||
|
|
|
||
|
|
// TESTO LIBERO! Il cliente ci scrive quello che vuole ("CEO", "Boss", "Stagista")
|
||
|
|
FluxTextField(label: 'Ruolo / Etichetta (es. Titolare)'),
|
||
|
|
|
||
|
|
const Spacer(),
|
||
|
|
ElevatedButton(
|
||
|
|
onPressed: () {
|
||
|
|
// Quando chiami il Cubit, passi i dati della UI.
|
||
|
|
// Ti ricordi? L'OnboardingCubit forzerà `system_role = SystemRole.admin`
|
||
|
|
// dietro le quinte!
|
||
|
|
// context.read<OnboardingCubit>().saveStaff(newStaff);
|
||
|
|
},
|
||
|
|
child: const Text("Inizia a usare Flux!"),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|