diff --git a/lib/core/routes/app_router.dart b/lib/core/routes/app_router.dart index 552ad08..1bbe5d4 100644 --- a/lib/core/routes/app_router.dart +++ b/lib/core/routes/app_router.dart @@ -9,6 +9,7 @@ import 'package:flux/core/widgets/set_password_screen.dart'; import 'package:flux/core/widgets/shared_forms/mobile_upload_screen.dart'; import 'package:flux/core/widgets/shared_forms/upload_success_screen.dart'; import 'package:flux/features/auth/ui/auth_screen.dart'; +import 'package:flux/features/company/bloc/company_settings_cubit.dart'; import 'package:flux/features/company/ui/company_settings_screen.dart'; import 'package:flux/features/customers/blocs/customers_cubit.dart'; import 'package:flux/features/customers/models/customer_model.dart'; @@ -30,6 +31,8 @@ import 'package:flux/features/operations/blocs/operation_form_cubit.dart'; import 'package:flux/features/operations/models/operation_model.dart'; import 'package:flux/features/operations/ui/operation_form_screen.dart'; import 'package:flux/features/operations/ui/operation_list_screen.dart'; +import 'package:flux/features/settings/settings_view.dart'; +import 'package:flux/features/settings/theme_settings_view.dart'; import 'package:flux/features/tickets/blocs/ticket_form_cubit.dart'; import 'package:flux/features/tickets/blocs/ticket_list_cubit.dart'; import 'package:flux/features/tickets/models/ticket_model.dart'; @@ -131,8 +134,11 @@ class AppRouter { }, ), GoRoute( - path: 'company_settings', - builder: (context, state) => const CompanySettingsScreen(), + path: 'company-settings', + builder: (context, state) => BlocProvider( + create: (context) => CompanySettingsCubit(), + child: const CompanySettingsScreen(), + ), ), GoRoute( path: 'staff', // Diventa /master-data/staff @@ -153,16 +159,13 @@ class AppRouter { // 3. IMPOSTAZIONI GoRoute( path: '/settings', - builder: (context, state) => Scaffold( - appBar: AppBar(title: Text(context.l10n.commonSettings)), - body: Center( - child: ElevatedButton.icon( - onPressed: () => context.read().signOut(), - icon: const Icon(Icons.logout), - label: const Text("Esci da FLUX"), - ), + builder: (context, state) => const SettingsView(), + routes: [ + GoRoute( + path: 'theme', + builder: (context, state) => const ThemeSettingsView(), ), - ), + ], ), GoRoute( path: '/operations', diff --git a/lib/features/company/bloc/company_settings_cubit.dart b/lib/features/company/bloc/company_settings_cubit.dart index 1cbf4ab..2adf083 100644 --- a/lib/features/company/bloc/company_settings_cubit.dart +++ b/lib/features/company/bloc/company_settings_cubit.dart @@ -1,4 +1,3 @@ -import 'dart:io'; import 'package:equatable/equatable.dart'; import 'package:flutter/foundation.dart'; // Per kIsWeb import 'package:flutter_bloc/flutter_bloc.dart'; @@ -6,7 +5,6 @@ import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/features/company/data/company_repository.dart'; import 'package:flux/features/company/models/company_model.dart'; import 'package:get_it/get_it.dart'; -import 'package:image_picker/image_picker.dart'; part 'company_settings_state.dart'; @@ -30,9 +28,12 @@ class CompanySettingsCubit extends Cubit { void updateFields({ String? name, - String? vatId, + String? vatId, // Modificato da vatNumber a vatId + String? fiscalCode, // Aggiunto + String? sdi, // Aggiunto String? address, String? city, + String? province, // Aggiunto String? zipCode, String? phone, String? email, @@ -42,8 +43,11 @@ class CompanySettingsCubit extends Cubit { final updated = state.company!.copyWith( name: name ?? state.company!.name, vatId: vatId ?? state.company!.vatId, + fiscalCode: fiscalCode ?? state.company!.fiscalCode, + sdi: sdi ?? state.company!.sdi, address: address ?? state.company!.address, city: city ?? state.company!.city, + province: province ?? state.company!.province, zipCode: zipCode ?? state.company!.zipCode, phone: phone ?? state.company!.phone, email: email ?? state.company!.email, diff --git a/lib/features/company/bloc/company_settings_state.dart b/lib/features/company/bloc/company_settings_state.dart index c6eee74..5c01581 100644 --- a/lib/features/company/bloc/company_settings_state.dart +++ b/lib/features/company/bloc/company_settings_state.dart @@ -1,6 +1,6 @@ part of 'company_settings_cubit.dart'; -class CompanySettingsState { +class CompanySettingsState extends Equatable { final CompanySettingsStatus status; final CompanyModel? company; final String? errorMessage; @@ -22,6 +22,9 @@ class CompanySettingsState { errorMessage: errorMessage, ); } + + @override + List get props => [status, company, errorMessage]; } enum CompanySettingsStatus { diff --git a/lib/features/company/models/company_model.dart b/lib/features/company/models/company_model.dart index 29cea37..419cee6 100644 --- a/lib/features/company/models/company_model.dart +++ b/lib/features/company/models/company_model.dart @@ -205,7 +205,7 @@ class CompanyModel extends Equatable { 'sdi': sdi, 'company_logo': logoUrl, 'phone': phone, - 'email': 'email', + 'email': email, 'is_paid': isPaid, if (paymentExpiration != null) 'payment_expiration': paymentExpiration!.toIso8601String(), diff --git a/lib/features/company/ui/company_settings_screen.dart b/lib/features/company/ui/company_settings_screen.dart index 178ca5c..62bcefd 100644 --- a/lib/features/company/ui/company_settings_screen.dart +++ b/lib/features/company/ui/company_settings_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flux/features/company/bloc/company_settings_cubit.dart'; +import 'package:flux/features/company/models/company_model.dart'; import 'package:image_picker/image_picker.dart'; class CompanySettingsScreen extends StatefulWidget { @@ -15,8 +16,11 @@ class _CompanySettingsScreenState extends State { final _nameCtrl = TextEditingController(); final _vatCtrl = TextEditingController(); + final _fiscalCodeCtrl = TextEditingController(); // Nuovo + final _sdiCtrl = TextEditingController(); // Nuovo final _addressCtrl = TextEditingController(); final _cityCtrl = TextEditingController(); + final _provinceCtrl = TextEditingController(); // Nuovo final _zipCtrl = TextEditingController(); final _phoneCtrl = TextEditingController(); final _emailCtrl = TextEditingController(); @@ -26,27 +30,42 @@ class _CompanySettingsScreenState extends State { @override void initState() { super.initState(); - context.read().initSettings(); + final cubit = context.read(); + cubit.initSettings(); + if (cubit.state.status == CompanySettingsStatus.ready && + cubit.state.company != null) { + _syncControllers(cubit.state.company!); + } } @override void dispose() { _nameCtrl.dispose(); _vatCtrl.dispose(); + _fiscalCodeCtrl.dispose(); // Nuovo + _sdiCtrl.dispose(); // Nuovo _addressCtrl.dispose(); _cityCtrl.dispose(); + _provinceCtrl.dispose(); // Nuovo _zipCtrl.dispose(); _phoneCtrl.dispose(); _emailCtrl.dispose(); super.dispose(); } - void _syncControllers(company) { - if (_nameCtrl.text.isEmpty) _nameCtrl.text = company.name ?? ''; - if (_vatCtrl.text.isEmpty) _vatCtrl.text = company.vatNumber ?? ''; - if (_addressCtrl.text.isEmpty) _addressCtrl.text = company.address ?? ''; - if (_cityCtrl.text.isEmpty) _cityCtrl.text = company.city ?? ''; - if (_zipCtrl.text.isEmpty) _zipCtrl.text = company.zipCode ?? ''; + void _syncControllers(CompanyModel company) { + if (_nameCtrl.text.isEmpty) _nameCtrl.text = company.name; + if (_vatCtrl.text.isEmpty) _vatCtrl.text = company.vatId; + if (_fiscalCodeCtrl.text.isEmpty) { + _fiscalCodeCtrl.text = company.fiscalCode; // Nuovo + } + if (_sdiCtrl.text.isEmpty) _sdiCtrl.text = company.sdi; // Nuovo + if (_provinceCtrl.text.isEmpty) { + _provinceCtrl.text = company.province; // Nuovo + } + if (_addressCtrl.text.isEmpty) _addressCtrl.text = company.address; + if (_cityCtrl.text.isEmpty) _cityCtrl.text = company.city; + if (_zipCtrl.text.isEmpty) _zipCtrl.text = company.zipCode; if (_phoneCtrl.text.isEmpty) _phoneCtrl.text = company.phone ?? ''; if (_emailCtrl.text.isEmpty) _emailCtrl.text = company.email ?? ''; _isInitialized = true; @@ -56,6 +75,9 @@ class _CompanySettingsScreenState extends State { context.read().updateFields( name: _nameCtrl.text, vatId: _vatCtrl.text, + fiscalCode: _fiscalCodeCtrl.text, // Nuovo + sdi: _sdiCtrl.text, // Nuovo + province: _provinceCtrl.text, address: _addressCtrl.text, city: _cityCtrl.text, zipCode: _zipCtrl.text, @@ -174,29 +196,43 @@ class _CompanySettingsScreenState extends State { ), const Divider(), const SizedBox(height: 16), + TextFormField( + controller: _nameCtrl, + decoration: const InputDecoration( + labelText: 'Ragione Sociale', + prefixIcon: Icon(Icons.badge), + ), + validator: (val) => val == null || val.isEmpty + ? 'Campo obbligatorio' + : null, + ), + const SizedBox(height: 16), Row( children: [ Expanded( - flex: 2, child: TextFormField( - controller: _nameCtrl, + controller: _vatCtrl, decoration: const InputDecoration( - labelText: 'Ragione Sociale', - prefixIcon: Icon(Icons.badge), + labelText: 'Partita IVA', + prefixIcon: Icon(Icons.receipt_long), ), - validator: (val) => val == null || val.isEmpty - ? 'Campo obbligatorio' - : null, ), ), const SizedBox(width: 16), Expanded( - flex: 1, child: TextFormField( - controller: _vatCtrl, + controller: _fiscalCodeCtrl, decoration: const InputDecoration( - labelText: 'Partita IVA / C.F.', - prefixIcon: Icon(Icons.receipt_long), + labelText: 'Codice Fiscale', + ), + ), + ), + const SizedBox(width: 16), + Expanded( + child: TextFormField( + controller: _sdiCtrl, + decoration: const InputDecoration( + labelText: 'Codice SDI', ), ), ), @@ -233,6 +269,16 @@ class _CompanySettingsScreenState extends State { ), ), const SizedBox(width: 16), + Expanded( + flex: 1, + child: TextFormField( + controller: _provinceCtrl, + decoration: const InputDecoration( + labelText: 'Provincia (es. MI)', + ), + ), + ), + const SizedBox(width: 16), Expanded( flex: 1, child: TextFormField( diff --git a/lib/features/settings/settings_view.dart b/lib/features/settings/settings_view.dart index 264c159..fd2c59c 100644 --- a/lib/features/settings/settings_view.dart +++ b/lib/features/settings/settings_view.dart @@ -1,7 +1,9 @@ // lib/ui/impostazioni/impostazioni_view.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/theme/theme.dart'; -import 'package:flux/features/settings/theme_settings_view.dart'; +import 'package:go_router/go_router.dart'; class SettingsView extends StatelessWidget { const SettingsView({super.key}); @@ -15,48 +17,33 @@ class SettingsView extends StatelessWidget { children: [ _settingsSection('Account', [ _settingsTile( - Icons.person, - 'Profilo Utente', - 'Configura i tuoi dati', - context, - MaterialPageRoute( - builder: (context) => const ThemeSettingsView(), - ), + icon: Icons.person, + title: 'Profilo Utente', + subtitle: 'Configura i tuoi dati', + context: context, + onTap: () {}, ), _settingsTile( - Icons.store, - 'Mio Negozio', - 'Piacenza Centro', - context, - MaterialPageRoute( - builder: (context) => const ThemeSettingsView(), - ), + title: 'Impostazioni Azienda', + icon: Icons.business, + subtitle: 'Configura i dati aziendali', + context: context, + onTap: () => context.push('/master-data/company-settings'), ), ]), const SizedBox(height: 16), _settingsSection('Applicazione', [ _settingsTile( - Icons.sync, - 'Sincronizzazione', - 'Ultima: 5 min fa', - context, - MaterialPageRoute( - builder: (context) => const ThemeSettingsView(), - ), - ), - _settingsTile( - Icons.dark_mode, - 'Tema (FLUX Dark)', - 'Configurazione visiva', - context, - MaterialPageRoute( - builder: (context) => const ThemeSettingsView(), - ), + icon: Icons.dark_mode, + title: 'Tema (FLUX Dark)', + subtitle: 'Configurazione visiva', + context: context, + onTap: () => context.push('/settings/theme'), ), ]), const SizedBox(height: 24), TextButton.icon( - onPressed: () {}, + onPressed: () => context.read().signOut(), icon: const Icon(Icons.exit_to_app, color: Colors.red), label: const Text('Logout', style: TextStyle(color: Colors.red)), ), @@ -83,22 +70,22 @@ class SettingsView extends StatelessWidget { ); } - Widget _settingsTile( - IconData icon, - String title, - String subtitle, - BuildContext context, - MaterialPageRoute route, - ) { + Widget _settingsTile({ + required BuildContext context, + required IconData icon, + required String title, + String? subtitle, + required VoidCallback onTap, + }) { return ListTile( leading: Icon(icon, color: FluxColors.primaryBlue), title: Text(title, style: Theme.of(context).textTheme.titleLarge), - subtitle: Text(subtitle), + subtitle: Text(subtitle ?? ''), trailing: Icon( Icons.chevron_right, color: Theme.of(context).textTheme.bodyMedium?.color, ), - onTap: () => Navigator.of(context).push(route), + onTap: onTap, ); } } diff --git a/lib/main.dart b/lib/main.dart index b567e8d..d5ff658 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,6 +6,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flux/features/attachments/data/attachments_repository.dart'; import 'package:flux/features/auth/bloc/auth_cubit.dart'; +import 'package:flux/features/company/data/company_repository.dart'; import 'package:flux/features/operations/blocs/operation_list_cubit.dart'; import 'package:flux/features/operations/data/operations_repository.dart'; import 'package:flux/features/tickets/data/ticket_repository.dart'; @@ -106,6 +107,7 @@ Future setupLocator() async { getIt.registerSingleton( SessionCubit(getIt(), getIt()), ); + getIt.registerLazySingleton(() => CompanyRepository()); } class FluxApp extends StatefulWidget {