This commit is contained in:
2026-04-13 15:18:37 +02:00
parent a30a1f3a14
commit d19d6ab3d9
10 changed files with 601 additions and 113 deletions

View File

@@ -1,5 +1,6 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flux/core/blocs/session/session_bloc.dart';
import 'package:flux/features/store/data/store_repository.dart';
import 'package:flux/features/store/models/store_model.dart';
import 'package:get_it/get_it.dart';
@@ -9,9 +10,11 @@ part 'store_state.dart';
class StoreBloc extends Bloc<StoreEvent, StoreState> {
final StoreRepository _repository = GetIt.I<StoreRepository>();
final SessionBloc _sessionBloc;
StoreBloc() : super(const StoreState()) {
StoreBloc(this._sessionBloc) : super(const StoreState(stores: [])) {
on<CreateStoreRequested>(_onCreateStore);
on<LoadStoresRequested>(_onLoadStores);
}
Future<void> _onCreateStore(
@@ -28,4 +31,26 @@ class StoreBloc extends Bloc<StoreEvent, StoreState> {
);
}
}
Future<void> _onLoadStores(
LoadStoresRequested event,
Emitter<StoreState> emit,
) async {
emit(state.copyWith(status: StoreStatus.loading));
try {
final stores = await _repository.getStoresByCompany(
_sessionBloc.state.company!.id,
);
emit(
state.copyWith(
status: StoreStatus.success,
stores: stores, // Assicurati di avere 'stores' nello StoreState
),
);
} catch (e) {
emit(
state.copyWith(status: StoreStatus.failure, errorMessage: e.toString()),
);
}
}
}

View File

@@ -14,3 +14,5 @@ class CreateStoreRequested extends StoreEvent {
@override
List<Object?> get props => [store];
}
class LoadStoresRequested extends StoreEvent {}

View File

@@ -6,25 +6,29 @@ class StoreState extends Equatable {
final StoreStatus status;
final StoreModel? store;
final String? errorMessage;
final List<StoreModel> stores;
const StoreState({
this.status = StoreStatus.initial,
this.store,
this.errorMessage,
required this.stores,
});
StoreState copyWith({
StoreStatus? status,
StoreModel? store,
String? errorMessage,
List<StoreModel>? stores,
}) {
return StoreState(
status: status ?? this.status,
store: store ?? this.store,
errorMessage: errorMessage ?? this.errorMessage,
stores: stores ?? this.stores,
);
}
@override
List<Object?> get props => [status, store, errorMessage];
List<Object?> get props => [status, store, errorMessage, stores];
}

View File

@@ -82,115 +82,110 @@ class _CreateStoreScreenState extends State<CreateStoreScreen> {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => StoreBloc(),
child: Scaffold(
appBar: AppBar(title: const Text('Il tuo primo Negozio')),
body: BlocConsumer<StoreBloc, StoreState>(
listener: (context, state) {
if (state.status == StoreStatus.success) {
context.read<SessionBloc>().add(AppStarted());
}
if (state.status == StoreStatus.failure) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.errorMessage ?? 'Errore salvataggio'),
),
);
}
},
builder: (context, state) {
return SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(24.0),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildHeader(context),
const SizedBox(height: 32),
// Nome del Negozio (Icona obbligatoria)
FluxTextField(
label: 'Nome del Negozio',
icon: Icons.storefront_rounded,
controller: _nomeController,
),
const SizedBox(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_SectionTitle(title: 'LOCALIZZAZIONE'),
TextButton.icon(
onPressed: _useCompanyAddress,
icon: const Icon(Icons.copy_rounded, size: 16),
label: const Text(
'Copia da Azienda',
style: TextStyle(fontSize: 12),
),
),
],
),
const SizedBox(height: 12),
// Indirizzo (Icona obbligatoria)
FluxTextField(
label: 'Indirizzo e n. civico',
icon: Icons.map_outlined,
controller: _indirizzoController,
),
const SizedBox(height: 16),
// RIGA TRIPLA: Comune, CAP, PR
Row(
crossAxisAlignment: CrossAxisAlignment
.start, // Allinea in alto in caso di errori
children: [
Expanded(
flex: 3,
child: FluxTextField(
label: 'Comune',
icon:
Icons.location_city_rounded, // Icona aggiunta
controller: _comuneController,
),
),
const SizedBox(width: 12),
Expanded(
flex: 2,
child: FluxTextField(
label: 'CAP',
icon: Icons.post_add_rounded, // Icona aggiunta
controller: _capController,
keyboardType: TextInputType.number,
),
),
const SizedBox(width: 12),
Expanded(
flex:
2, // Aumentato leggermente per ospitare l'icona
child: FluxTextField(
label: 'PR',
icon: Icons.explore_outlined, // Icona aggiunta
controller: _provinciaController,
),
),
],
),
const SizedBox(height: 48),
_buildSubmitButton(context, state),
],
),
),
return Scaffold(
appBar: AppBar(title: const Text('Il tuo primo Negozio')),
body: BlocConsumer<StoreBloc, StoreState>(
listener: (context, state) {
if (state.status == StoreStatus.success) {
context.read<SessionBloc>().add(AppStarted());
}
if (state.status == StoreStatus.failure) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.errorMessage ?? 'Errore salvataggio'),
),
);
},
),
}
},
builder: (context, state) {
return SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(24.0),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildHeader(context),
const SizedBox(height: 32),
// Nome del Negozio (Icona obbligatoria)
FluxTextField(
label: 'Nome del Negozio',
icon: Icons.storefront_rounded,
controller: _nomeController,
),
const SizedBox(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_SectionTitle(title: 'LOCALIZZAZIONE'),
TextButton.icon(
onPressed: _useCompanyAddress,
icon: const Icon(Icons.copy_rounded, size: 16),
label: const Text(
'Copia da Azienda',
style: TextStyle(fontSize: 12),
),
),
],
),
const SizedBox(height: 12),
// Indirizzo (Icona obbligatoria)
FluxTextField(
label: 'Indirizzo e n. civico',
icon: Icons.map_outlined,
controller: _indirizzoController,
),
const SizedBox(height: 16),
// RIGA TRIPLA: Comune, CAP, PR
Row(
crossAxisAlignment: CrossAxisAlignment
.start, // Allinea in alto in caso di errori
children: [
Expanded(
flex: 3,
child: FluxTextField(
label: 'Comune',
icon: Icons.location_city_rounded, // Icona aggiunta
controller: _comuneController,
),
),
const SizedBox(width: 12),
Expanded(
flex: 2,
child: FluxTextField(
label: 'CAP',
icon: Icons.post_add_rounded, // Icona aggiunta
controller: _capController,
keyboardType: TextInputType.number,
),
),
const SizedBox(width: 12),
Expanded(
flex: 2, // Aumentato leggermente per ospitare l'icona
child: FluxTextField(
label: 'PR',
icon: Icons.explore_outlined, // Icona aggiunta
controller: _provinciaController,
),
),
],
),
const SizedBox(height: 48),
_buildSubmitButton(context, state),
],
),
),
),
);
},
),
);
}