feat(setting): added profile data apdating for sttings screen, added validation for general info form

This commit is contained in:
misha
2026-04-14 09:28:02 +03:00
parent 631ceb2b7a
commit 684415ef5b
7 changed files with 291 additions and 189 deletions

View File

@@ -7,7 +7,19 @@ import 'package:eatvio_app/core/error_reporting/report_from.dart';
class MenuCubit extends Cubit<MenuState> {
final ProfileRepository profileRepository;
MenuCubit(this.profileRepository) : super(MenuState());
MenuCubit(this.profileRepository) : super(const MenuState.initial());
Future<void> getMyProfile() async {
emit(const MenuState.loading());
try {
final profile = await profileRepository.getMyProfile();
emit(MenuState.loaded(profileModel: profile));
} catch (e, st) {
await reportFrom(e, st, this);
log(e.toString());
emit(const MenuState.error());
}
}
Future<String?> makePassKey() async {
try {

View File

@@ -1 +1,17 @@
class MenuState {}
import 'package:eatvio_app/features/profile/models/profile_model.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'menu_state.freezed.dart';
@freezed
abstract class MenuState with _$MenuState {
const factory MenuState.initial() = MenuStateInitial;
const factory MenuState.loading() = MenuStateLoading;
const factory MenuState.loaded({
required ProfileModel profileModel,
}) = MenuStateLoaded;
const factory MenuState.error() = MenuStateError;
}

View File

@@ -6,6 +6,8 @@ import 'package:eatvio_app/core/theme/custom_text_style.dart';
import 'package:eatvio_app/core/token_storage.dart';
import 'package:eatvio_app/core/utils/image_constant.dart';
import 'package:eatvio_app/core/utils/date_time_utils.dart';
import 'package:eatvio_app/core/widgets/data_error_widget.dart';
import 'package:eatvio_app/core/widgets/loader.dart';
import 'package:eatvio_app/core/locator_service.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/core/websockets/ws_manager.dart';
@@ -13,9 +15,9 @@ import 'package:eatvio_app/features/consultant_rating/presentation/consultant_ra
import 'package:eatvio_app/features/finances_and_consultations_archive/presentation/consultant_finances_screen.dart';
import 'package:eatvio_app/features/finances_and_consultations_archive/presentation/user_purchases_screen.dart';
import 'package:eatvio_app/features/menu/presentation/bloc/menu_cubit/menu_cubit.dart';
import 'package:eatvio_app/features/menu/presentation/bloc/menu_cubit/menu_state.dart';
import 'package:eatvio_app/features/my_diets/presentation/my_diets_screen.dart';
import 'package:eatvio_app/features/my_plans/presentation/my_plans_screen.dart';
import 'package:eatvio_app/features/profile/models/profile_model.dart';
import 'package:eatvio_app/features/recipe/presentation/pages/my_recipes_screen.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@@ -25,90 +27,107 @@ import 'package:go_router/go_router.dart';
import 'package:package_info_plus/package_info_plus.dart';
class MenuScreen extends StatelessWidget {
final ProfileModel profileModel;
const MenuScreen({super.key, required this.profileModel});
const MenuScreen({super.key});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => sl<MenuCubit>(),
create: (context) => sl<MenuCubit>()..getMyProfile(),
child: Builder(
builder: (context) {
return Scaffold(
appBar: AppBar(centerTitle: false, title: const Text('Меню')),
body: SingleChildScrollView(
child: Column(
children: [
_tile(title: 'Настройки профиля', leading: ImageConstant.icnProfileSettings, onTap: () => GoRouter.of(context).push('/settings-screen')),
if (profileModel.roles.contains('consultant')) _divider(context),
if (profileModel.roles.contains('consultant'))
_tile(leading: ImageConstant.icnRecipes, title: 'Мои рецепты', onTap: () => GoRouter.of(context).push(MyRecipesScreen.path)),
if (profileModel.roles.contains('consultant')) _divider(context),
if (profileModel.roles.contains('consultant'))
_tile(leading: 'assets/icons/diets.svg', title: 'Мои диеты', onTap: () => GoRouter.of(context).push(MyDietsScreen.path)),
if (profileModel.roles.contains('consultant')) _divider(context),
if (profileModel.roles.contains('consultant'))
_tile(leading: ImageConstant.icnPlans, title: 'Мои планы', onTap: () => GoRouter.of(context).push(MyPlansScreen.path)),
if (!hidePlans) ...[
_divider(context),
_tile(
leading: 'assets/icons/finance.svg',
title: 'Мои финансы',
onTap: () {
if (profileModel.roles.contains('consultant')) {
GoRouter.of(context).push(ConsultantFinancesScreen.path);
return;
}
GoRouter.of(context).push(UserPurchasesScreen.path);
},
return BlocBuilder<MenuCubit, MenuState>(
builder: (BuildContext context, MenuState state) {
if (state is MenuStateLoaded) {
final profileModel = state.profileModel;
return Scaffold(
appBar: AppBar(centerTitle: false, title: const Text('Меню')),
body: SingleChildScrollView(
child: Column(
children: [
_tile(title: 'Настройки профиля', leading: ImageConstant.icnProfileSettings, onTap: () => GoRouter.of(context).push('/settings-screen')),
if (profileModel.roles.contains('consultant')) _divider(context),
if (profileModel.roles.contains('consultant'))
_tile(leading: ImageConstant.icnRecipes, title: 'Мои рецепты', onTap: () => GoRouter.of(context).push(MyRecipesScreen.path)),
if (profileModel.roles.contains('consultant')) _divider(context),
if (profileModel.roles.contains('consultant'))
_tile(leading: 'assets/icons/diets.svg', title: 'Мои диеты', onTap: () => GoRouter.of(context).push(MyDietsScreen.path)),
if (profileModel.roles.contains('consultant')) _divider(context),
if (profileModel.roles.contains('consultant'))
_tile(leading: ImageConstant.icnPlans, title: 'Мои планы', onTap: () => GoRouter.of(context).push(MyPlansScreen.path)),
if (!hidePlans) ...[
_divider(context),
_tile(
leading: 'assets/icons/finance.svg',
title: 'Мои финансы',
onTap: () {
if (profileModel.roles.contains('consultant')) {
GoRouter.of(context).push(ConsultantFinancesScreen.path);
return;
}
GoRouter.of(context).push(UserPurchasesScreen.path);
},
),
],
if (profileModel.roles.contains('consultant')) _divider(context),
if (profileModel.roles.contains('consultant'))
_tile(
leading: 'assets/icons/consultant_rating_icon.svg',
title: 'Мой рейтинг',
onTap: () {
GoRouter.of(context).push(ConsultantRatingScreen.path);
},
),
_divider(context),
_tile(
leading: ImageConstant.icnGlossary,
title: 'Глоссарий',
onTap: () async {
final passKey = await context.read<MenuCubit>().makePassKey();
if (passKey != null && context.mounted) {
GoRouter.of(context).push('/glossary-screen', extra: passKey);
}
},
),
_divider(context),
_tile(
leading: 'assets/icons/notifications.svg',
title: 'Уведомления',
onTap: () => GoRouter.of(context).pushNamed('notificationsSettingsScreen'),
),
_divider(context),
_tile(leading: ImageConstant.icnSupport, title: 'Поддержка', onTap: () => GoRouter.of(context).push('/support-screen')),
_divider(context),
_tile(leading: 'assets/icons/blocked_users.svg', title: 'Чёрный список', onTap: () => GoRouter.of(context).pushNamed('blockedUsersScreen')),
// _divider(context),
// _tile(
// leading: ImageConstant.icnDevTools,
// title: 'Для разработчиков',
// onTap: () {
// GoRouter.of(context).pushNamed(DevToolsScreen.name);
// },
// ),
_divider(context),
_tile(leading: ImageConstant.icnExit, title: 'Выход', onTap: _onTapLogout(context)),
const SizedBox(height: 10),
const AppInfo(),
],
),
],
if (profileModel.roles.contains('consultant')) _divider(context),
if (profileModel.roles.contains('consultant'))
_tile(
leading: 'assets/icons/consultant_rating_icon.svg',
title: 'Мой рейтинг',
onTap: () {
GoRouter.of(context).push(ConsultantRatingScreen.path);
},
),
_divider(context),
_tile(
leading: ImageConstant.icnGlossary,
title: 'Глоссарий',
onTap: () async {
final passKey = await context.read<MenuCubit>().makePassKey();
if (passKey != null && context.mounted) {
GoRouter.of(context).push('/glossary-screen', extra: passKey);
}
},
),
_divider(context),
_tile(
leading: 'assets/icons/notifications.svg',
title: 'Уведомления',
onTap: () => GoRouter.of(context).pushNamed('notificationsSettingsScreen'),
),
_divider(context),
_tile(leading: ImageConstant.icnSupport, title: 'Поддержка', onTap: () => GoRouter.of(context).push('/support-screen')),
_divider(context),
_tile(leading: 'assets/icons/blocked_users.svg', title: 'Чёрный список', onTap: () => GoRouter.of(context).pushNamed('blockedUsersScreen')),
// _divider(context),
// _tile(
// leading: ImageConstant.icnDevTools,
// title: 'Для разработчиков',
// onTap: () {
// GoRouter.of(context).pushNamed(DevToolsScreen.name);
// },
// ),
_divider(context),
_tile(leading: ImageConstant.icnExit, title: 'Выход', onTap: _onTapLogout(context)),
const SizedBox(height: 10),
const AppInfo(),
],
),
),
);
}
if (state is MenuStateError) {
return Scaffold(
appBar: AppBar(centerTitle: false, title: const Text('Меню')),
body: DataErrorWidget(onReload: () async => context.read<MenuCubit>().getMyProfile()),
);
}
return Scaffold(
appBar: AppBar(centerTitle: false, title: const Text('Меню')),
body: const Loader(),
);
},
);
},
),