diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index d535af69..2ee97ce4 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -388,7 +388,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 21; + CURRENT_PROJECT_VERSION = 24; DEVELOPMENT_TEAM = VL68C36HYS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -538,7 +538,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 21; + CURRENT_PROJECT_VERSION = 24; DEVELOPMENT_TEAM = VL68C36HYS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -576,7 +576,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 21; + CURRENT_PROJECT_VERSION = 24; DEVELOPMENT_TEAM = VL68C36HYS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 498d4b70..a88158e2 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -21,7 +21,7 @@ CFBundleSignature ???? CFBundleVersion - 21 + 24 ITSAppUsesNonExemptEncryption LSRequiresIPhoneOS diff --git a/lib/core/app_router.dart b/lib/core/app_router.dart index da7e1220..c849628d 100644 --- a/lib/core/app_router.dart +++ b/lib/core/app_router.dart @@ -100,9 +100,6 @@ class AppRouter { GoRoute( path: '/my-profile-screen', name: 'myProfileScreen', - redirect: (context, state) async { - return null; - }, pageBuilder: (context, state) { return const NoTransitionPage(child: ProfileScreen()); }, @@ -112,15 +109,21 @@ class AppRouter { name: 'feedScreen', pageBuilder: (context, state) => const NoTransitionPage(child: FeedScreen()), redirect: (context, state) async { - final data = state.extra as Map?; - if (data?['needToInitializeWebSocket'] == false) { - return null; + try { + await sl().initialize(); + } catch (e) { + rethrow; } - await sl().initialize(); - return null; + return '/feed-screen'; }, ), - GoRoute(path: '/diary-screen', name: 'diaryScreen', pageBuilder: (context, state) => const NoTransitionPage(child: DiaryScreen())), + GoRoute( + path: '/diary-screen', + name: 'diaryScreen', + pageBuilder: (context, state) => const NoTransitionPage( + child: DiaryScreen(), + ), + ), GoRoute( path: ConsultationsScreen.path, name: ConsultationsScreen.name, @@ -296,7 +299,12 @@ class AppRouter { ), GoRoute(path: '/become-consultant-screen', name: 'becomeConsultantScreen', builder: (context, state) => const BecomeConsultantScreen()), GoRoute( - path: '/stepper-become-consultant-screen', name: 'stepperBecomeConsultantScreen', builder: (context, state) => const StepperBecomeConsultantScreen()), + path: '/stepper-become-consultant-screen', + name: 'stepperBecomeConsultantScreen', + builder: (context, state) => StepperBecomeConsultantScreen( + slug: state.extra == null ? null : state.extra as String, + ), + ), GoRoute(path: '/calendar-screen', name: 'calendarScreen', builder: (context, state) => const CalendarScreen()), GoRoute(path: '/support-screen', name: 'supportScreen', builder: (context, state) => const SupportScreen()), GoRoute( diff --git a/lib/core/locator_service.dart b/lib/core/locator_service.dart index 9ee53c7c..cd8731a3 100644 --- a/lib/core/locator_service.dart +++ b/lib/core/locator_service.dart @@ -120,7 +120,7 @@ Future init() async { sl.registerFactory(() => DietsCubit(feedRepository: sl(), dietsRepository: sl())); sl.registerFactory(() => CommentsCubit(feedRepository: sl())); sl.registerFactory(() => PlansCubit(feedRepository: sl(), planRepository: sl())); - sl.registerFactory(() => SettingsCubit(profileRepository: sl(), settingsRepository: sl())); + sl.registerFactory(() => SettingsCubit(profileRepository: sl(), settingsRepository: sl(), consultantRepository: sl())); sl.registerFactory(() => RegisterConsultantCubit(consultantRepository: sl())); sl.registerFactory( () => DiaryCubit(chatRepository: sl(), diaryRepository: sl(), glossaryRepository: sl(), profileRepository: sl(), dietRepository: sl())); diff --git a/lib/core/widgets/custom_popup.dart b/lib/core/widgets/custom_popup.dart index 47081135..dbe04ec4 100644 --- a/lib/core/widgets/custom_popup.dart +++ b/lib/core/widgets/custom_popup.dart @@ -6,7 +6,6 @@ import 'package:eatvio_app/core/utils/toasts.dart'; import 'package:eatvio_app/core/widgets/show_error_dialog.dart'; import 'package:eatvio_app/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_cubit.dart'; import 'package:eatvio_app/features/complaining/presentation/complaining_bottom_sheet.dart'; -import 'package:eatvio_app/features/create_recipe/presentation/pages/recipe_create_screen.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart'; import 'package:eatvio_app/features/feed/models/recipes_model.dart'; @@ -98,12 +97,10 @@ class CustomPopup extends StatelessWidget { ), ); }); - if (complainedContentType == ComplainedContent.posts || complainedContentType == ComplainedContent.recipe) { + if (complainedContentType == ComplainedContent.posts) { addItem('assets/icons/edit_paint.svg', 'Редактировать', () async { if (complainedContentType == ComplainedContent.posts) { GoRouter.of(context).pushNamed('blogPostCreateScreen', extra: feedBlogPostModel); - } else if (complainedContentType == ComplainedContent.recipe) { - GoRouter.of(context).pushNamed(RecipeCreateScreen.name, extra: recipe); } }); } diff --git a/lib/features/consultant/become_consultant/models/consultation_request_model.dart b/lib/features/consultant/become_consultant/models/consultation_request_model.dart index 1579fab5..13cc0e77 100644 --- a/lib/features/consultant/become_consultant/models/consultation_request_model.dart +++ b/lib/features/consultant/become_consultant/models/consultation_request_model.dart @@ -8,9 +8,10 @@ part 'consultation_request_model.g.dart'; @freezed abstract class ConsultationRequestModel with _$ConsultationRequestModel { const factory ConsultationRequestModel({ - @JsonKey(name: 'rating_place') required int ratingPlace, + @JsonKey(name: 'rating_place') int? ratingPlace, @JsonKey(name: 'education_resource') required EducationModel educationModel, @JsonKey(name: 'cert_photos') required List photos, + @JsonKey(name: 'canceled_moderation') CanceledModerationModel? canceledModeration, }) = _ConsultationRequestModel; factory ConsultationRequestModel.fromJson(Map json) => _$ConsultationRequestModelFromJson(json); @@ -24,3 +25,20 @@ abstract class CertPhotosModel with _$CertPhotosModel { factory CertPhotosModel.fromJson(Map json) => _$CertPhotosModelFromJson(json); } + +enum ModerationStatus { + approved, + created, + canceled +} + +@freezed +abstract class CanceledModerationModel with _$CanceledModerationModel { + const factory CanceledModerationModel({ + required String title, + required ModerationStatus status, + required List? additional, + }) = _CanceledModerationModel; + + factory CanceledModerationModel.fromJson(Map json) => _$CanceledModerationModelFromJson(json); +} diff --git a/lib/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_cubit.dart b/lib/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_cubit.dart index a7171f89..05bfd52a 100644 --- a/lib/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_cubit.dart +++ b/lib/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_cubit.dart @@ -1,13 +1,15 @@ import 'dart:io'; - import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart'; import 'package:eatvio_app/features/consultant/become_consultant/models/consultant_profile_model.dart'; import 'package:eatvio_app/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_state.dart'; import 'package:eatvio_app/features/consultant/become_consultant/repositories/consultant_repository.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:http/http.dart' as http; +import 'package:path_provider/path_provider.dart'; class RegisterConsultantCubit extends Cubit { final ConsultantRepository consultantRepository; + bool _update = false; RegisterConsultantCubit({ required this.consultantRepository, @@ -17,12 +19,80 @@ class RegisterConsultantCubit extends Cubit { socialLinks: SocialLinksModel(), hasMedicalEducation: true, ), + loading: true, acceptOffer: false, ), ); + Future downloadImageAsFile(String imageUrl) async { + final response = await http.get(Uri.parse(imageUrl)); + + if (response.statusCode == 200) { + final tempDir = await getTemporaryDirectory(); + final filePath = '${tempDir.path}/${imageUrl.split('/').last}'; + final file = File(filePath); + return await file.writeAsBytes(response.bodyBytes); + } else { + throw Exception('Не удалось загрузить изображение'); + } + } + + getMyRequestStatus(String slug) async { + _update = true; + final myRequestStatus = await consultantRepository.getMyRequestStatus(slug); + + final List photos = await Future.wait( + myRequestStatus.photos.map( + (e) async => (await downloadImageAsFile(e.url)).path, + ), + ); + + List? certificates = myRequestStatus.educationModel.completedCourses?.map((courseMap) { + final course = courseMap.values.first; + + return CertificatesModel( + title: course.title, + date: course.date, + ); + }).toList(); + + String? sanitizeLink(String? link) { + return (link != null && link.isNotEmpty) ? link : null; + } + + emit( + RegisterConsultantState( + consultant: ConsultantProfileModel( + photos: photos, + certificates: certificates, + socialLinks: SocialLinksModel( + vkLink: sanitizeLink(myRequestStatus.educationModel.vkLink), + tgLink: sanitizeLink(myRequestStatus.educationModel.tgLink), + fbLink: sanitizeLink(myRequestStatus.educationModel.fbLink), + instaLink: sanitizeLink(myRequestStatus.educationModel.instaLink), + personalSiteLink: sanitizeLink(myRequestStatus.educationModel.personalSiteLink), + ), + hasMedicalEducation: myRequestStatus.educationModel.hasMedicalEducation == 1, + ), + acceptOffer: false, + loading: false, + requestModel: myRequestStatus, + ), + ); + } + + disableLoading() { + emit(state.copyWith(loading: false)); + } + updateConsultantProfileModel(ConsultantProfileModel consultant, [bool acceptOffer = false]) { - emit(RegisterConsultantState(consultant: consultant, acceptOffer: acceptOffer)); + emit( + state.copyWith( + consultant: consultant, + acceptOffer: acceptOffer, + loading: false, + ), + ); } registerConsultant() async { @@ -35,7 +105,7 @@ class RegisterConsultantCubit extends Cubit { ), ); } - await consultantRepository.registerConsultant(consultant: state.consultant); + await consultantRepository.registerConsultant(consultant: state.consultant, update: _update); } Future> uploadPhotos(List files) async { diff --git a/lib/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_state.dart b/lib/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_state.dart index 5f318efe..5f613821 100644 --- a/lib/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_state.dart +++ b/lib/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_state.dart @@ -1,4 +1,5 @@ import 'package:eatvio_app/features/consultant/become_consultant/models/consultant_profile_model.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/models/consultation_request_model.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'register_consultant_state.freezed.dart'; @@ -8,5 +9,7 @@ abstract class RegisterConsultantState with _$RegisterConsultantState { const factory RegisterConsultantState({ required ConsultantProfileModel consultant, required bool acceptOffer, + required bool loading, + ConsultationRequestModel? requestModel, }) = _RegisterConsultantState; } diff --git a/lib/features/consultant/become_consultant/presentation/pages/certificates_and_diplomas_screen.dart b/lib/features/consultant/become_consultant/presentation/pages/certificates_and_diplomas_screen.dart index 6e49d3b3..3b877c4d 100644 --- a/lib/features/consultant/become_consultant/presentation/pages/certificates_and_diplomas_screen.dart +++ b/lib/features/consultant/become_consultant/presentation/pages/certificates_and_diplomas_screen.dart @@ -30,19 +30,20 @@ class _CertificatesAndDiplomasScreenState extends State().state.consultant.certificates != null) { - diplomasList = context - .read() - .state - .consultant - .certificates! - .map( - (e) => DiplomaEntity( - date: DateTime.tryParse(e.date), - textEditingController: TextEditingController(text: e.title), - enableDeleteButton: true, + diplomasList = [ + ...context.read().state.consultant.certificates!.map( + (e) => DiplomaEntity( + date: DateTime.tryParse(e.date), + textEditingController: TextEditingController(text: e.title), + enableDeleteButton: true, + ), ), - ) - .toList(); + DiplomaEntity( + textEditingController: TextEditingController(), + enableDeleteButton: false, + date: null, + ), + ]; diplomasList.last.enableDeleteButton = false; } } diff --git a/lib/features/consultant/become_consultant/presentation/pages/stepper_become_consultant_screen.dart b/lib/features/consultant/become_consultant/presentation/pages/stepper_become_consultant_screen.dart index 28692a4c..494ffc36 100644 --- a/lib/features/consultant/become_consultant/presentation/pages/stepper_become_consultant_screen.dart +++ b/lib/features/consultant/become_consultant/presentation/pages/stepper_become_consultant_screen.dart @@ -1,5 +1,8 @@ import 'package:eatvio_app/core/utils/image_constant.dart'; +import 'package:eatvio_app/core/widgets/loader.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/models/consultation_request_model.dart'; import 'package:eatvio_app/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_cubit.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_state.dart'; import 'package:eatvio_app/features/consultant/become_consultant/presentation/pages/additional_settings_screen.dart'; import 'package:eatvio_app/features/consultant/become_consultant/presentation/pages/certificates_and_diplomas_screen.dart'; import 'package:eatvio_app/features/consultant/become_consultant/presentation/pages/last_step_screen.dart'; @@ -15,7 +18,9 @@ import 'package:go_router/go_router.dart'; import 'package:lottie/lottie.dart'; class StepperBecomeConsultantScreen extends StatefulWidget { - const StepperBecomeConsultantScreen({super.key}); + final String? slug; + + const StepperBecomeConsultantScreen({super.key, this.slug}); @override State createState() => _StepperBecomeConsultantScreenState(); @@ -25,249 +30,328 @@ class _StepperBecomeConsultantScreenState extends State(); + late final RegisterConsultantCubit registrationConsultantCubit; bool isLoading = false; + @override + void initState() { + super.initState(); + if (widget.slug == null) { + registrationConsultantCubit = sl()..disableLoading(); + } else { + registrationConsultantCubit = sl()..getMyRequestStatus(widget.slug!); + } + } + @override Widget build(BuildContext context) { return BlocProvider( create: (context) => registrationConsultantCubit, - child: Scaffold( - floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, - floatingActionButton: Row( - children: [ - Container( - height: 48, - width: MediaQuery.of(context).size.width * 0.2, - padding: const EdgeInsets.only(left: 16, right: 4), - child: FloatingActionButton.extended( - heroTag: 'backButtonRegistration', - highlightElevation: 0, - focusElevation: 0, - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(20), - ), - backgroundColor: const Color(0xFFEAF2FD), - onPressed: () async { - setState(() { - pageController.previousPage( - duration: const Duration(milliseconds: 350), - curve: Curves.easeInOut, - ); - }); - }, - label: Icon( - Icons.arrow_back_ios_new_rounded, - color: appTheme.blueA400, - ), - ), - ), - Container( - height: 48, - width: MediaQuery.of(context).size.width * 0.8, - padding: const EdgeInsets.only(left: 4, right: 16), - child: FloatingActionButton.extended( - heroTag: 'nextButtonRegistration', - highlightElevation: 0, - elevation: 0, - focusElevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(20), - ), - backgroundColor: isLoading ? Colors.grey : appTheme.blueA400, - onPressed: isLoading - ? null - : () async { - if (step == 6) { - if (registrationConsultantCubit.state.acceptOffer) { - setState(() { - isLoading = true; - }); - try { - await registrationConsultantCubit.registerConsultant(); - if (!context.mounted) return; - await showModalBottomSheet( - useRootNavigator: true, - showDragHandle: true, - context: context, - builder: (context) => Container( - padding: const EdgeInsets.all(16), - width: MediaQuery.of(context).size.width, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Text( - 'Спасибо!\nВаши данные отправлены на модерацию', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 20, - height: 1, - fontWeight: FontWeight.w600, - ), - ), - const SizedBox(height: 16), - Lottie.asset( - 'assets/lottie_animations/success.json', - width: 160, - height: 160, - ), - const SizedBox(height: 16), - const Text( - 'В течении трех рабочих дней Вам придет уведомление о смене статуса', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 16, - height: 1, - fontWeight: FontWeight.w500, - ), - ), - const SizedBox(height: 16), - InkWell( - onTap: () { - Navigator.of(context).pop(); - GoRouter.of(context).pop(); - }, - child: Ink( - width: MediaQuery.of(context).size.width - 32, - height: 52, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - color: appTheme.blueA400, - ), - child: const Center( - child: Text( - 'Закрыть', + child: BlocBuilder( + builder: (context, state) { + if (state.loading == false) { + return Scaffold( + floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, + floatingActionButton: Row( + children: [ + Container( + height: 48, + width: MediaQuery.of(context).size.width * 0.2, + padding: const EdgeInsets.only(left: 16, right: 4), + child: FloatingActionButton.extended( + heroTag: 'backButtonRegistration', + highlightElevation: 0, + focusElevation: 0, + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + backgroundColor: const Color(0xFFEAF2FD), + onPressed: () async { + setState(() { + pageController.previousPage( + duration: const Duration(milliseconds: 350), + curve: Curves.easeInOut, + ); + }); + }, + label: Icon( + Icons.arrow_back_ios_new_rounded, + color: appTheme.blueA400, + ), + ), + ), + if (state.requestModel?.educationModel.requestState == ModerationStatus.canceled) + InkWell( + onTap: () { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text(state.requestModel!.canceledModeration!.title), + content: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + for (int i = 0; i < state.requestModel!.canceledModeration!.additional!.length; i++) ...[ + Text('• ${state.requestModel!.canceledModeration!.additional![i]}'), + ] + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('OK'), + ), + ], + ), + ); + }, + borderRadius: BorderRadius.circular(20), + child: Ink( + height: 48, + width: MediaQuery.of(context).size.width * 0.6, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: const Color(0x33FFCC00), + ), + child: const Center( + child: Text( + 'Комментарий', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Color(0xFF323F4B), + height: 1, + ), + ), + ), + ), + ), + Container( + height: 48, + width: state.requestModel?.educationModel.requestState == ModerationStatus.canceled + ? MediaQuery.of(context).size.width * 0.2 + : MediaQuery.of(context).size.width * 0.8, + padding: const EdgeInsets.only(left: 4, right: 16), + child: FloatingActionButton.extended( + heroTag: 'nextButtonRegistration', + highlightElevation: 0, + elevation: 0, + focusElevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + backgroundColor: isLoading + ? Colors.grey + : state.requestModel?.educationModel.requestState == ModerationStatus.canceled + ? const Color(0xFFEAF2FD) + : appTheme.blueA400, + onPressed: isLoading + ? null + : () async { + if (step == 6) { + if (registrationConsultantCubit.state.acceptOffer) { + setState(() { + isLoading = true; + }); + try { + await registrationConsultantCubit.registerConsultant(); + if (!context.mounted) return; + await showModalBottomSheet( + useRootNavigator: true, + showDragHandle: true, + context: context, + builder: (context) => Container( + padding: const EdgeInsets.all(16), + width: MediaQuery.of(context).size.width, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + 'Спасибо!\nВаши данные отправлены на модерацию', + textAlign: TextAlign.center, style: TextStyle( - color: Colors.white, - fontSize: 18, + fontSize: 20, + height: 1, fontWeight: FontWeight.w600, ), ), - ), + const SizedBox(height: 16), + Lottie.asset( + 'assets/lottie_animations/success.json', + width: 160, + height: 160, + ), + const SizedBox(height: 16), + const Text( + 'В течении трех рабочих дней Вам придет уведомление о смене статуса', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + height: 1, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 16), + InkWell( + onTap: () { + Navigator.of(context).pop(); + GoRouter.of(context).pop(); + }, + child: Ink( + width: MediaQuery.of(context).size.width - 32, + height: 52, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: appTheme.blueA400, + ), + child: const Center( + child: Text( + 'Закрыть', + style: TextStyle( + color: Colors.white, + fontSize: 18, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ), + ], ), ), - ], - ), - ), - ); - } catch (e) { - if (!context.mounted) return; - showDialog( - context: context, - builder: (context) => AlertDialog( - actionsPadding: const EdgeInsets.symmetric(horizontal: 4), - content: Text(e.toString()), - actions: [ - TextButton( - child: const Text('Ок'), - onPressed: () { - Navigator.of(context).pop(); - }, + ); + } catch (e) { + if (!context.mounted) return; + showDialog( + context: context, + builder: (context) => AlertDialog( + actionsPadding: const EdgeInsets.symmetric(horizontal: 4), + content: Text(e.toString()), + actions: [ + TextButton( + child: const Text('Ок'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ), + ); + } finally { + setState(() { + isLoading = false; + }); + } + } else { + showDialog( + context: context, + builder: (context) => AlertDialog( + actionsPadding: const EdgeInsets.symmetric(horizontal: 4), + content: const Text('Примите договор публичной офёрты'), + actions: [ + TextButton( + child: const Text('Ок'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], ), - ], + ); + } + } else { + FocusManager.instance.primaryFocus?.unfocus(); + setState(() { + pageController.nextPage( + duration: const Duration(milliseconds: 350), + curve: Curves.easeInOut, + ); + }); + } + }, + label: isLoading + ? const CircularProgressIndicator() + : state.requestModel?.educationModel.requestState == ModerationStatus.canceled + ? Icon( + Icons.arrow_forward_ios_outlined, + color: appTheme.blueA400, + ) + : Text( + 'Продолжить', + style: theme.textTheme.titleSmall!.copyWith(color: Colors.white), ), - ); - } finally { - setState(() { - isLoading = false; - }); - } - } else { - showDialog( - context: context, - builder: (context) => AlertDialog( - actionsPadding: const EdgeInsets.symmetric(horizontal: 4), - content: const Text('Примите договор публичной офёрты'), - actions: [ - TextButton( - child: const Text('Ок'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - ], - ), - ); - } - } else { - FocusManager.instance.primaryFocus?.unfocus(); - setState(() { - pageController.nextPage( - duration: const Duration(milliseconds: 350), - curve: Curves.easeInOut, - ); - }); - } - }, - label: isLoading ? const CircularProgressIndicator() : Text( - 'Продолжить', - style: theme.textTheme.titleSmall!.copyWith(color: Colors.white), + ), + ), + ], + ), + appBar: AppBar( + automaticallyImplyLeading: false, + leading: Builder( + builder: (context) => IconButton( + icon: const Icon(Icons.close_rounded), + onPressed: () => GoRouter.of(context).pop(), + ), + ), + centerTitle: true, + title: SvgPicture.asset( + ImageConstant.imgLogoEatvio, + height: 48, + fit: BoxFit.contain, + ), + actions: [ + Padding( + padding: const EdgeInsets.only(right: 16), + child: Text('шаг $step из 6'), + ), + ], + bottom: PreferredSize( + preferredSize: Size(MediaQuery.of(context).size.width, 32), + child: Padding( + padding: const EdgeInsets.all(16), + child: TweenAnimationBuilder( + duration: const Duration(milliseconds: 350), + curve: Curves.easeInOut, + tween: Tween( + begin: 1 / 6, + end: progressValue, + ), + builder: (context, value, _) => LinearProgressIndicator( + value: value, + borderRadius: BorderRadius.circular(16), + minHeight: 8, + backgroundColor: Colors.grey.shade100, + valueColor: AlwaysStoppedAnimation(appTheme.blueA400), + ), + ), + ), ), ), - ), - ], - ), - appBar: AppBar( - automaticallyImplyLeading: false, - leading: Builder( - builder: (context) => IconButton( - icon: const Icon(Icons.close_rounded), - onPressed: () => GoRouter.of(context).pop(), - ), - ), - centerTitle: true, - title: SvgPicture.asset( - ImageConstant.imgLogoEatvio, - height: 48, - fit: BoxFit.contain, - ), - actions: [ - Padding( - padding: const EdgeInsets.only(right: 16), - child: Text('шаг $step из 6'), - ), - ], - bottom: PreferredSize( - preferredSize: Size(MediaQuery.of(context).size.width, 32), - child: Padding( - padding: const EdgeInsets.all(16), - child: TweenAnimationBuilder( - duration: const Duration(milliseconds: 350), - curve: Curves.easeInOut, - tween: Tween( - begin: 1 / 6, - end: progressValue, - ), - builder: (context, value, _) => LinearProgressIndicator( - value: value, - borderRadius: BorderRadius.circular(16), - minHeight: 8, - backgroundColor: Colors.grey.shade100, - valueColor: AlwaysStoppedAnimation(appTheme.blueA400), - ), + body: PageView( + physics: const NeverScrollableScrollPhysics(), + controller: pageController, + onPageChanged: (index) { + setState(() { + step = index + 1; + progressValue = step / 6; + }); + }, + children: const [ + CertificatesAndDiplomasScreen(), + PhotoOrScansScreen(), + AdditionalSettingsScreen(), + SocialNetworksScreen(), + RegistrationAsScreen(), + LastStepScreen(), + ], ), - ), - ), - ), - body: PageView( - physics: const NeverScrollableScrollPhysics(), - controller: pageController, - onPageChanged: (index) { - setState(() { - step = index + 1; - progressValue = step / 6; - }); - }, - children: const [ - CertificatesAndDiplomasScreen(), - PhotoOrScansScreen(), - AdditionalSettingsScreen(), - SocialNetworksScreen(), - RegistrationAsScreen(), - LastStepScreen(), - ], - ), + ); + } else { + return const Scaffold( + body: Loader(), + ); + } + }, ), ); } diff --git a/lib/features/consultant/become_consultant/repositories/consultant_repository.dart b/lib/features/consultant/become_consultant/repositories/consultant_repository.dart index 6af88cb5..89eef1c8 100644 --- a/lib/features/consultant/become_consultant/repositories/consultant_repository.dart +++ b/lib/features/consultant/become_consultant/repositories/consultant_repository.dart @@ -14,11 +14,18 @@ class ConsultantRepository { Future registerConsultant({ required ConsultantProfileModel consultant, + bool update = false, }) async { try { - return await consultantService.consultantRegistration( - consultantModel: consultant, - ); + if (update) { + return await consultantService.consultantUpdate( + consultantModel: consultant, + ); + } else { + return await consultantService.consultantRegistration( + consultantModel: consultant, + ); + } } catch (e) { rethrow; } @@ -57,4 +64,12 @@ class ConsultantRepository { rethrow; } } + + Future getMyRequestStatus(String slug) async { + try { + return await consultantService.getMyRequestStatus(slug: slug); + } catch (e) { + rethrow; + } + } } diff --git a/lib/features/consultant/become_consultant/services/consultant_service.dart b/lib/features/consultant/become_consultant/services/consultant_service.dart index fbf7541d..bfde5a92 100644 --- a/lib/features/consultant/become_consultant/services/consultant_service.dart +++ b/lib/features/consultant/become_consultant/services/consultant_service.dart @@ -24,4 +24,14 @@ abstract class ConsultantService { Future getConsultantRequestStatus({ @Path() required String slug, }); + + @GET('/api/consultant_request/{slug}/status') + Future getMyRequestStatus({ + @Path() required String slug, + }); + + @PUT('/api/consultant_request/update') + Future consultantUpdate({ + @Body() required ConsultantProfileModel consultantModel, + }); } diff --git a/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart b/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart index 8e0d4a8b..6eb41358 100644 --- a/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart +++ b/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart @@ -293,6 +293,7 @@ class CreateDietCubit extends Cubit { final diet = Diet( id: 0, name: state.dietData.name ?? '', + slug: '', image: imageInBase64, duration: state.dietData.duration ?? 0, state: state.dietData.state ?? DietState.active, diff --git a/lib/features/create_diet/presentation/diet_preview_screen.dart b/lib/features/create_diet/presentation/diet_preview_screen.dart index 884c283d..3901841f 100644 --- a/lib/features/create_diet/presentation/diet_preview_screen.dart +++ b/lib/features/create_diet/presentation/diet_preview_screen.dart @@ -192,7 +192,7 @@ class _DietPreviewScreenState extends State { actions: [ CustomPopup( isAuthor: widget.diet.author.authorIsMe, - path: 'diet/${widget.diet.id}', + path: 'diet/${widget.diet.slug}', complainedContentType: ComplainedContent.diet, ), const SizedBox(width: 16), diff --git a/lib/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_cubit.dart b/lib/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_cubit.dart index 43273ae6..f13d3d02 100644 --- a/lib/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_cubit.dart +++ b/lib/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_cubit.dart @@ -16,6 +16,7 @@ import 'package:path_provider/path_provider.dart'; class CreateRecipeCubit extends Cubit { final RecipeRepository recipeRepository; final GlossaryRepository glossaryRepository; + CreateRecipeCubit({ required this.recipeRepository, required this.glossaryRepository, @@ -192,7 +193,7 @@ class CreateRecipeCubit extends Cubit { recipe.steps!.map( (e) async => StepEntity( description: e.description, - image: await downloadImageAsFile('$baseUrl/storage/${e.image}'), + image: e.image.isEmpty ? null : await downloadImageAsFile('$baseUrl/storage/${e.image}'), ), ), ); diff --git a/lib/features/diets/presentation/pages/about_diet_screen.dart b/lib/features/diets/presentation/pages/about_diet_screen.dart index 4dd3878d..2252324e 100644 --- a/lib/features/diets/presentation/pages/about_diet_screen.dart +++ b/lib/features/diets/presentation/pages/about_diet_screen.dart @@ -318,7 +318,7 @@ class _AboutDietScreenState extends State { actions: [ CustomPopup( isAuthor: widget.diet.author.authorIsMe, - path: 'diet/${widget.diet.id}', + path: 'diet/${widget.diet.slug}', complainedContentType: ComplainedContent.diet, id: widget.diet.id, diet: widget.diet, @@ -499,7 +499,7 @@ class _AboutDietScreenState extends State { actions: [ CustomPopup( isAuthor: widget.diet.author.authorIsMe, - path: 'diet/${widget.diet.id}', + path: 'diet/${widget.diet.slug}', complainedContentType: ComplainedContent.diet, id: widget.diet.id, diet: widget.diet, @@ -526,7 +526,7 @@ class _AboutDietScreenState extends State { actions: [ CustomPopup( isAuthor: widget.diet.author.authorIsMe, - path: 'diet/${widget.diet.id}', + path: 'diet/${widget.diet.slug}', complainedContentType: ComplainedContent.diet, id: widget.diet.id, diet: widget.diet, diff --git a/lib/features/feed/models/diets_pagination_model.dart b/lib/features/feed/models/diets_pagination_model.dart index 868f6556..d519d963 100644 --- a/lib/features/feed/models/diets_pagination_model.dart +++ b/lib/features/feed/models/diets_pagination_model.dart @@ -20,6 +20,7 @@ abstract class DietsPagination with _$DietsPagination { abstract class Diet with _$Diet { const factory Diet({ @JsonKey(name: "id") required int id, + @JsonKey(name: "slug") String? slug, @JsonKey(name: "name") required String name, @JsonKey(name: "image") required String image, @JsonKey(name: "duration") required int duration, diff --git a/lib/features/feed/presentation/widgets/diets_widget.dart b/lib/features/feed/presentation/widgets/diets_widget.dart index e857e979..3b0a7662 100644 --- a/lib/features/feed/presentation/widgets/diets_widget.dart +++ b/lib/features/feed/presentation/widgets/diets_widget.dart @@ -90,7 +90,7 @@ class _DietsWidgetState extends State { borderRadius: BorderRadius.circular(4), child: CustomPopup( isAuthor: widget.diet.author.authorIsMe, - path: 'diet/${widget.diet.id}', + path: 'diet/${widget.diet.slug}', id: widget.diet.id, complainedContentType: ComplainedContent.diet, diet: widget.diet, diff --git a/lib/features/feed/presentation/widgets/plan_widget.dart b/lib/features/feed/presentation/widgets/plan_widget.dart index e47ca1db..8a8229b8 100644 --- a/lib/features/feed/presentation/widgets/plan_widget.dart +++ b/lib/features/feed/presentation/widgets/plan_widget.dart @@ -62,8 +62,9 @@ class _PlanWidgetState extends State { borderRadius: const BorderRadius.vertical(top: Radius.circular(12)), child: CachedNetworkImage( imageUrl: '$baseUrl/storage/${widget.plan.image}', - fit: BoxFit.fitWidth, + fit: BoxFit.cover, width: MediaQuery.of(context).size.width, + height: 426, ), ), Positioned( @@ -95,7 +96,7 @@ class _PlanWidgetState extends State { borderRadius: BorderRadius.circular(4), child: CustomPopup( isAuthor: widget.plan.author.authorIsMe, - path: 'plan/${widget.plan.id}', + path: 'plan/${widget.plan.slug}', id: widget.plan.id, slug: widget.plan.slug, complainedContentType: ComplainedContent.plan, diff --git a/lib/features/plans/presentation/pages/about_plan_screen.dart b/lib/features/plans/presentation/pages/about_plan_screen.dart index 72cb71bd..6b8980cf 100644 --- a/lib/features/plans/presentation/pages/about_plan_screen.dart +++ b/lib/features/plans/presentation/pages/about_plan_screen.dart @@ -113,7 +113,7 @@ class _AboutPlanScreenState extends State { actions: [ CustomPopup( isAuthor: widget.plan.author.authorIsMe, - path: 'plan/${widget.plan.id}', + path: 'plan/${widget.plan.slug}', complainedContentType: ComplainedContent.plan, slug: widget.plan.slug, ), @@ -143,7 +143,7 @@ class _AboutPlanScreenState extends State { actions: [ CustomPopup( isAuthor: widget.plan.author.authorIsMe, - path: 'plan/${widget.plan.id}', + path: 'plan/${widget.plan.slug}', complainedContentType: ComplainedContent.plan, slug: widget.plan.slug, ), @@ -362,7 +362,7 @@ class _AboutPlanScreenState extends State { actions: [ CustomPopup( isAuthor: widget.plan.author.authorIsMe, - path: 'plan/${widget.plan.id}', + path: 'plan/${widget.plan.slug}', complainedContentType: ComplainedContent.plan, slug: widget.plan.slug, ), diff --git a/lib/features/profile/models/profile_model.dart b/lib/features/profile/models/profile_model.dart index df952ec3..8d13bc7e 100644 --- a/lib/features/profile/models/profile_model.dart +++ b/lib/features/profile/models/profile_model.dart @@ -1,3 +1,4 @@ +import 'package:eatvio_app/features/consultant/become_consultant/models/consultation_request_model.dart'; import 'package:eatvio_app/features/my_finance/models/card_model.dart'; import 'package:eatvio_app/features/profile/models/badge_model.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -50,7 +51,7 @@ abstract class EducationModel with _$EducationModel { @JsonKey(name: "fb_link") String? fbLink, @JsonKey(name: "tg_link") String? tgLink, @JsonKey(name: "personal_site_link") String? personalSiteLink, - @JsonKey(name: "request_state") String? requestState, + @JsonKey(name: "request_state") required ModerationStatus requestState, }) = _EducationModel; factory EducationModel.fromJson(Map json) => _$EducationModelFromJson(json); diff --git a/lib/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart b/lib/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart index cdbab793..28f654f2 100644 --- a/lib/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart +++ b/lib/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart @@ -33,6 +33,7 @@ class ProfileCubit extends Cubit { ); } catch (e) { emit(ProfileState.error(errorMessage: e.toString())); + rethrow; } } diff --git a/lib/features/profile/presentation/pages/profile_screen.dart b/lib/features/profile/presentation/pages/profile_screen.dart index d5d360d8..ef9aac1a 100644 --- a/lib/features/profile/presentation/pages/profile_screen.dart +++ b/lib/features/profile/presentation/pages/profile_screen.dart @@ -33,6 +33,7 @@ import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:go_router/go_router.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:image_picker/image_picker.dart'; +import 'package:intl/intl.dart'; import 'package:share_plus/share_plus.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -92,12 +93,15 @@ class _ProfileScreenState extends State { } return widget.author == null || widget.author!.authorIsMe ? _myProfileScreen(state) : _profileScreen(state); } else if (state is ProfileStateError) { - return DataErrorWidget( - onReload: () async { - widget.author == null || widget.author!.authorIsMe - ? await profileCubit.getMyProfile() - : await profileCubit.getProfileBySlug(widget.author!.authorSlug); - }, + return Scaffold( + appBar: AppBar(), + body: DataErrorWidget( + onReload: () async { + widget.author == null || widget.author!.authorIsMe + ? await profileCubit.getMyProfile() + : await profileCubit.getProfileBySlug(widget.author!.authorSlug); + }, + ), ); } else { return Scaffold( @@ -329,7 +333,7 @@ class _ProfileScreenState extends State { ), const SizedBox(height: 8), SizedBox( - height: 378, + height: 781, child: PageView.builder( itemBuilder: (BuildContext context, int index) { return PlanWidget( @@ -347,6 +351,7 @@ class _ProfileScreenState extends State { ), const SizedBox(height: 8), _bullets(_currentBullet, state.plansList.length), + const SizedBox(height: 8), ], ); } @@ -435,12 +440,12 @@ class _ProfileScreenState extends State { padding: const EdgeInsets.only(bottom: 16), child: Column( children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - const Text( + Text( 'Дипломы\nи сертификаты', style: TextStyle( color: Color(0xFF323F4B), @@ -449,14 +454,19 @@ class _ProfileScreenState extends State { fontWeight: FontWeight.w600, ), ), - Text( - widget.author == null || widget.author!.authorIsMe ? 'Редактировать' : '', - style: const TextStyle( - color: Color(0xFF2F80ED), - fontSize: 16, - fontWeight: FontWeight.w500, - ), - ), + // GestureDetector( + // onTap: () { + // GoRouter.of(context).pushNamed('stepperBecomeConsultantScreen', extra: state.profile.slug); + // }, + // child: Text( + // widget.author == null || widget.author!.authorIsMe ? 'Редактировать' : '', + // style: const TextStyle( + // color: Color(0xFF2F80ED), + // fontSize: 16, + // fontWeight: FontWeight.w500, + // ), + // ), + // ), ], ), ), @@ -531,12 +541,12 @@ class _ProfileScreenState extends State { padding: const EdgeInsets.only(bottom: 16), child: Column( children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - const Text( + Text( 'Образование', style: TextStyle( color: Color(0xFF323F4B), @@ -544,14 +554,19 @@ class _ProfileScreenState extends State { fontWeight: FontWeight.w600, ), ), - Text( - widget.author == null || widget.author!.authorIsMe ? 'Редактировать' : '', - style: const TextStyle( - color: Color(0xFF2F80ED), - fontSize: 16, - fontWeight: FontWeight.w500, - ), - ), + // GestureDetector( + // onTap: () { + // GoRouter.of(context).pushNamed('stepperBecomeConsultantScreen', extra: state.profile.slug); + // }, + // child: Text( + // widget.author == null || widget.author!.authorIsMe ? 'Редактировать' : '', + // style: const TextStyle( + // color: Color(0xFF2F80ED), + // fontSize: 16, + // fontWeight: FontWeight.w500, + // ), + // ), + // ), ], ), ), @@ -584,6 +599,11 @@ class _ProfileScreenState extends State { } _educationBlock(String title, String date) { + final parsedDate = DateTime.tryParse(date); + final formattedDate = parsedDate != null + ? DateFormat('d MMMM y', 'ru_RU').format(parsedDate) + : date; + return SizedBox( width: double.infinity, child: Material( @@ -605,7 +625,7 @@ class _ProfileScreenState extends State { ), const SizedBox(height: 4), Text( - date, + formattedDate, style: const TextStyle( height: 1, color: Color(0xFF6D6F71), @@ -620,6 +640,7 @@ class _ProfileScreenState extends State { ); } + _socialLinks(ProfileStateLoaded state) { if (!state.profile.roles.contains('consultant')) { return const SizedBox.shrink(); diff --git a/lib/features/recipe/presentation/widgets/my_recipe_widget.dart b/lib/features/recipe/presentation/widgets/my_recipe_widget.dart index 1deb983f..370b4756 100644 --- a/lib/features/recipe/presentation/widgets/my_recipe_widget.dart +++ b/lib/features/recipe/presentation/widgets/my_recipe_widget.dart @@ -6,7 +6,6 @@ import 'package:eatvio_app/core/theme/theme_helper.dart'; import 'package:eatvio_app/core/utils/localization_utils.dart'; import 'package:eatvio_app/core/utils/toasts.dart'; import 'package:eatvio_app/core/widgets/custom_outlined_button.dart'; -import 'package:eatvio_app/features/create_recipe/presentation/pages/recipe_create_screen.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart'; import 'package:eatvio_app/features/recipe/models/my_recipe_model.dart'; import 'package:eatvio_app/features/recipe/presentation/cubit/my_recipes_cubit/my_recieps_cubit.dart'; @@ -131,29 +130,6 @@ class _MyRecipeWidgetState extends State { padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Column( children: [ - Row( - children: [ - Expanded( - child: CustomOutlinedButton( - onPressed: () async { - GoRouter.of(context).pushNamed( - RecipeCreateScreen.name, - extra: await context.read().getRecipeById(widget.recipe.slug), - ); - }, - text: s.edit, - height: 52, - buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700), - buttonStyle: ButtonStyle( - shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(20))), - backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), - side: const WidgetStatePropertyAll(BorderSide.none), - ), - ), - ), - ], - ), - const SizedBox(height: 8), Row( children: [ Expanded( diff --git a/lib/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart b/lib/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart index e3113e78..af748b69 100644 --- a/lib/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart +++ b/lib/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart @@ -58,7 +58,6 @@ class RegistrationCubit extends Cubit { ), ); await TokenStorage.saveTokenInStorage(token); - AppRouter.navigatorKey.currentContext?.go('/feed-screen'); AppRouter.navigatorKey.currentContext?.pushNamed('verifyEmailScreen'); } catch (e) { log(e.toString()); diff --git a/lib/features/registration/presentation/pages/verify_email_screen.dart b/lib/features/registration/presentation/pages/verify_email_screen.dart index 75f38712..ed4ea11f 100644 --- a/lib/features/registration/presentation/pages/verify_email_screen.dart +++ b/lib/features/registration/presentation/pages/verify_email_screen.dart @@ -17,6 +17,13 @@ class _VerifyEmailScreenState extends State { final List _focusNodes = List.generate(4, (_) => FocusNode()); final List _controllers = List.generate(4, (_) => TextEditingController()); String email = ''; + late final GoRouter goRouter; + + @override + void initState() { + super.initState(); + goRouter = GoRouter.of(context); + } @override void dispose() { @@ -48,7 +55,7 @@ class _VerifyEmailScreenState extends State { }); } else if (state is VerifyEmailStateVerifySuccess) { showSuccessToast('Почта успешно подтверждена'); - GoRouter.of(context).pop(); + goRouter.pushNamed('feedScreen'); } else if (state is VerifyEmailStateVerifyError) { showErrorToast("Неверный код. Попробуйте снова."); for (var controller in _controllers) { diff --git a/lib/features/settings/presentation/bloc/settings_cubit/settings_cubit.dart b/lib/features/settings/presentation/bloc/settings_cubit/settings_cubit.dart index f0a388a4..1bc68637 100644 --- a/lib/features/settings/presentation/bloc/settings_cubit/settings_cubit.dart +++ b/lib/features/settings/presentation/bloc/settings_cubit/settings_cubit.dart @@ -1,3 +1,5 @@ +import 'package:eatvio_app/features/consultant/become_consultant/models/consultation_request_model.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/repositories/consultant_repository.dart'; import 'package:eatvio_app/features/profile/models/profile_model.dart'; import 'package:eatvio_app/features/profile/repositories/profile_repository.dart'; import 'package:eatvio_app/features/settings/models/profile_settings_model.dart'; @@ -8,19 +10,31 @@ import 'package:flutter_bloc/flutter_bloc.dart'; class SettingsCubit extends Cubit { final ProfileRepository profileRepository; final SettingsRepository settingsRepository; + final ConsultantRepository consultantRepository; SettingsCubit({ required this.profileRepository, required this.settingsRepository, + required this.consultantRepository, }) : super(const SettingsState.loading()); Future init() async { + final profile = await profileRepository.getMyProfile(); + late final ConsultationRequestModel? consultantInfo; try { - emit(SettingsState.loaded( - profileSettings: await settingsRepository.getProfileSettings(), - profileDetails: await profileRepository.getMyProfileDetails(), - profile: await profileRepository.getMyProfile(), - ),); + consultantInfo = await consultantRepository.getMyRequestStatus(profile.slug); + } catch (e) { + consultantInfo = null; + } + try { + emit( + SettingsState.loaded( + profileSettings: await settingsRepository.getProfileSettings(), + profileDetails: await profileRepository.getMyProfileDetails(), + profile: profile, + consultationRequestModel: consultantInfo, + ), + ); } catch (e) { emit(SettingsState.error(errorMessage: e.toString())); } diff --git a/lib/features/settings/presentation/bloc/settings_cubit/settings_state.dart b/lib/features/settings/presentation/bloc/settings_cubit/settings_state.dart index 34922051..f220fe5e 100644 --- a/lib/features/settings/presentation/bloc/settings_cubit/settings_state.dart +++ b/lib/features/settings/presentation/bloc/settings_cubit/settings_state.dart @@ -1,3 +1,4 @@ +import 'package:eatvio_app/features/consultant/become_consultant/models/consultation_request_model.dart'; import 'package:eatvio_app/features/profile/models/profile_model.dart'; import 'package:eatvio_app/features/settings/models/profile_settings_model.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -14,6 +15,7 @@ abstract class SettingsState with _$SettingsState { required ProfileSettingsModel profileSettings, required ProfileDetailsModel profileDetails, required ProfileModel profile, + ConsultationRequestModel? consultationRequestModel, }) = SettingsStateLoaded; const factory SettingsState.error({ diff --git a/lib/features/settings/presentation/pages/settings_screen.dart b/lib/features/settings/presentation/pages/settings_screen.dart index 18d6a261..8afe8cd7 100644 --- a/lib/features/settings/presentation/pages/settings_screen.dart +++ b/lib/features/settings/presentation/pages/settings_screen.dart @@ -1,6 +1,7 @@ import 'package:eatvio_app/core/const.dart'; import 'package:eatvio_app/core/widgets/data_error_widget.dart'; import 'package:eatvio_app/core/widgets/loader.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/models/consultation_request_model.dart'; import 'package:eatvio_app/features/settings/entities/settings_entity.dart'; import 'package:eatvio_app/features/settings/presentation/bloc/settings_cubit/settings_cubit.dart'; import 'package:eatvio_app/features/settings/presentation/bloc/settings_cubit/settings_state.dart'; @@ -58,11 +59,7 @@ class _SettingsScreenState extends State { const SizedBox(height: 12), _aboutEatvio(state), const SizedBox(height: 12), - if (!state.profile.roles.contains('consultant')) - Padding( - padding: const EdgeInsets.only(bottom: 8), - child: _becomeConsultantButton(state), - ), + _becomeConsultantButton(state), _deleteAccountButton(state), ], ), @@ -355,31 +352,84 @@ class _SettingsScreenState extends State { } _becomeConsultantButton(SettingsStateLoaded state) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: InkWell( - onTap: () => GoRouter.of(context).pushNamed('becomeConsultantScreen'), - borderRadius: BorderRadius.circular(20), - child: Ink( - height: 52, - width: MediaQuery.of(context).size.width - 16, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - color: appTheme.blueA400, - ), - child: const Center( - child: Text( - 'Стать консультантом', - style: TextStyle( - color: Colors.white, - height: 1, - fontSize: 18, + if (state.consultationRequestModel == null) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16) + const EdgeInsets.only(bottom: 8), + child: InkWell( + onTap: () => GoRouter.of(context).pushNamed('becomeConsultantScreen'), + borderRadius: BorderRadius.circular(20), + child: Ink( + height: 52, + width: MediaQuery.of(context).size.width - 16, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: appTheme.blueA400, + ), + child: const Center( + child: Text( + 'Стать консультантом', + style: TextStyle( + color: Colors.white, + height: 1, + fontSize: 18, + ), ), ), ), ), - ), - ); + ); + } else { + if (state.consultationRequestModel!.educationModel.requestState == ModerationStatus.created) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16) + const EdgeInsets.only(bottom: 8), + child: Ink( + height: 52, + width: MediaQuery.of(context).size.width - 16, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: const Color(0xFFEAEAEA), + ), + child: const Center( + child: Text( + 'Данные на проверке', + style: TextStyle( + color: Colors.black, + height: 1, + fontSize: 18, + ), + ), + ), + ), + ); + } else if (state.consultationRequestModel!.educationModel.requestState == ModerationStatus.canceled) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16) + const EdgeInsets.only(bottom: 8), + child: InkWell( + onTap: () => GoRouter.of(context).pushNamed('stepperBecomeConsultantScreen', extra: state.profile.slug), + borderRadius: BorderRadius.circular(20), + child: Ink( + height: 52, + width: MediaQuery.of(context).size.width - 16, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: const Color(0x33FFCC00), + ), + child: const Center( + child: Text( + 'Заявка обработана', + style: TextStyle( + color: Colors.black, + height: 1, + fontSize: 18, + ), + ), + ), + ), + ), + ); + } + } + return const SizedBox.shrink(); } _deleteAccountButton(SettingsStateLoaded state) { diff --git a/pubspec.yaml b/pubspec.yaml index 02918a68..97712189 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: eatvio_app description: A new Flutter project. -version: 1.1.1+30 +version: 1.1.2+32 publish_to: 'none' environment: