From 74ecbbdbffa45ac21a1b55e17b2461b3bc22f5d6 Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Mon, 2 Jun 2025 13:31:00 +0300 Subject: [PATCH 1/5] fix: plan widget in profile image size overflow --- lib/features/feed/presentation/widgets/plan_widget.dart | 3 ++- lib/features/profile/presentation/pages/profile_screen.dart | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/features/feed/presentation/widgets/plan_widget.dart b/lib/features/feed/presentation/widgets/plan_widget.dart index e47ca1db..c1ac6b90 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( diff --git a/lib/features/profile/presentation/pages/profile_screen.dart b/lib/features/profile/presentation/pages/profile_screen.dart index d5d360d8..174500c1 100644 --- a/lib/features/profile/presentation/pages/profile_screen.dart +++ b/lib/features/profile/presentation/pages/profile_screen.dart @@ -329,7 +329,7 @@ class _ProfileScreenState extends State { ), const SizedBox(height: 8), SizedBox( - height: 378, + height: 759, child: PageView.builder( itemBuilder: (BuildContext context, int index) { return PlanWidget( From 8a9a913420dbb0aee50e088e6f816ec4d13bf56e Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Mon, 2 Jun 2025 13:38:19 +0300 Subject: [PATCH 2/5] fix(recipe): infinity loading recipe edit --- .../bloc/create_recipe_cubit/create_recipe_cubit.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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}'), ), ), ); From f0a184b800642e98a3e4d7cc9bd9296291e3a2ed Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Mon, 2 Jun 2025 16:05:47 +0300 Subject: [PATCH 3/5] feat(consultant): update consultant info --- lib/core/app_router.dart | 7 +- lib/core/const.dart | 2 +- .../models/consultation_request_model.dart | 2 +- .../register_consultant_cubit.dart | 69 ++- .../register_consultant_state.dart | 1 + .../certificates_and_diplomas_screen.dart | 25 +- .../stepper_become_consultant_screen.dart | 482 +++++++++--------- .../repositories/consultant_repository.dart | 21 +- .../services/consultant_service.dart | 10 + .../presentation/pages/profile_screen.dart | 34 +- 10 files changed, 392 insertions(+), 261 deletions(-) diff --git a/lib/core/app_router.dart b/lib/core/app_router.dart index fec9b100..d29fea2d 100644 --- a/lib/core/app_router.dart +++ b/lib/core/app_router.dart @@ -293,7 +293,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/const.dart b/lib/core/const.dart index 31c47e9c..73e7ecfd 100644 --- a/lib/core/const.dart +++ b/lib/core/const.dart @@ -1,4 +1,4 @@ -String baseUrl = 'https://eatvio.ru'; + String baseUrl = 'https://eatvio.ru'; // String baseUrl = 'https://dev2.eatvio.com'; const List durationValues = [7, 14, 21]; 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..547ff856 100644 --- a/lib/features/consultant/become_consultant/models/consultation_request_model.dart +++ b/lib/features/consultant/become_consultant/models/consultation_request_model.dart @@ -8,7 +8,7 @@ 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, }) = _ConsultationRequestModel; 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..7ca3ac48 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,73 @@ 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, + ), + ); + } + + disableLoading() { + emit(state.copyWith(loading: false)); + } + updateConsultantProfileModel(ConsultantProfileModel consultant, [bool acceptOffer = false]) { - emit(RegisterConsultantState(consultant: consultant, acceptOffer: acceptOffer)); + emit(RegisterConsultantState(consultant: consultant, acceptOffer: acceptOffer, loading: false)); } registerConsultant() async { @@ -35,7 +98,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..32f495d9 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 @@ -8,5 +8,6 @@ abstract class RegisterConsultantState with _$RegisterConsultantState { const factory RegisterConsultantState({ required ConsultantProfileModel consultant, required bool acceptOffer, + required bool loading, }) = _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..b49610fc 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,7 @@ 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/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 +17,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 +29,271 @@ 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, + ), + ), + ), + 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( - 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(); + }, + ), + ], ), - ], - ), - ); - } 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), + ); + } + } 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/profile/presentation/pages/profile_screen.dart b/lib/features/profile/presentation/pages/profile_screen.dart index 174500c1..6c91bbff 100644 --- a/lib/features/profile/presentation/pages/profile_screen.dart +++ b/lib/features/profile/presentation/pages/profile_screen.dart @@ -449,12 +449,17 @@ 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, + ), ), ), ], @@ -544,12 +549,17 @@ 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, + ), ), ), ], From 7c354cc0a321a5ce6d80e3d3485bb21c684d2c9b Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Mon, 2 Jun 2025 17:51:27 +0300 Subject: [PATCH 4/5] feat(consultant): ***WIP: consultant request status in settings --- ios/Runner.xcodeproj/project.pbxproj | 6 +-- ios/Runner/Info.plist | 2 +- lib/core/const.dart | 2 +- lib/core/locator_service.dart | 2 +- .../presentation/pages/profile_screen.dart | 9 +++- .../bloc/settings_cubit/settings_cubit.dart | 24 +++++++-- .../bloc/settings_cubit/settings_state.dart | 2 + .../presentation/pages/settings_screen.dart | 50 +++++++++---------- 8 files changed, 59 insertions(+), 38 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index d535af69..b77d4412 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 = 22; 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 = 22; 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 = 22; DEVELOPMENT_TEAM = VL68C36HYS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 498d4b70..2b0b59b5 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -21,7 +21,7 @@ CFBundleSignature ???? CFBundleVersion - 21 + 22 ITSAppUsesNonExemptEncryption LSRequiresIPhoneOS diff --git a/lib/core/const.dart b/lib/core/const.dart index 73e7ecfd..31c47e9c 100644 --- a/lib/core/const.dart +++ b/lib/core/const.dart @@ -1,4 +1,4 @@ - String baseUrl = 'https://eatvio.ru'; +String baseUrl = 'https://eatvio.ru'; // String baseUrl = 'https://dev2.eatvio.com'; const List durationValues = [7, 14, 21]; 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/features/profile/presentation/pages/profile_screen.dart b/lib/features/profile/presentation/pages/profile_screen.dart index 6c91bbff..b9ecfff6 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'; @@ -594,6 +595,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( @@ -615,7 +621,7 @@ class _ProfileScreenState extends State { ), const SizedBox(height: 4), Text( - date, + formattedDate, style: const TextStyle( height: 1, color: Color(0xFF6D6F71), @@ -630,6 +636,7 @@ class _ProfileScreenState extends State { ); } + _socialLinks(ProfileStateLoaded state) { if (!state.profile.roles.contains('consultant')) { return const SizedBox.shrink(); 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..7c4ab26e 100644 --- a/lib/features/settings/presentation/pages/settings_screen.dart +++ b/lib/features/settings/presentation/pages/settings_screen.dart @@ -58,11 +58,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 +351,33 @@ 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, + ), ), ), ), ), - ), - ); + ); + } } _deleteAccountButton(SettingsStateLoaded state) { From c361e12d354f914b0a123937de31e309829b4342 Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Tue, 3 Jun 2025 18:17:03 +0300 Subject: [PATCH 5/5] Issue-483: WIP* moderation consultant request status and message --- lib/core/widgets/custom_popup.dart | 5 +- .../models/consultation_request_model.dart | 18 +++++ .../register_consultant_cubit.dart | 1 + .../register_consultant_state.dart | 2 + .../stepper_become_consultant_screen.dart | 70 +++++++++++++++++-- .../presentation/cubit/create_diet_cubit.dart | 1 + .../presentation/diet_preview_screen.dart | 2 +- .../presentation/pages/about_diet_screen.dart | 6 +- .../feed/models/diets_pagination_model.dart | 1 + .../presentation/widgets/diets_widget.dart | 2 +- .../presentation/widgets/plan_widget.dart | 2 +- .../presentation/pages/about_plan_screen.dart | 6 +- .../presentation/pages/profile_screen.dart | 3 +- .../widgets/my_recipe_widget.dart | 24 ------- .../presentation/pages/settings_screen.dart | 52 ++++++++++++++ 15 files changed, 151 insertions(+), 44 deletions(-) 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 547ff856..68549759 100644 --- a/lib/features/consultant/become_consultant/models/consultation_request_model.dart +++ b/lib/features/consultant/become_consultant/models/consultation_request_model.dart @@ -11,6 +11,7 @@ abstract class ConsultationRequestModel with _$ConsultationRequestModel { @JsonKey(name: 'rating_place') int? ratingPlace, @JsonKey(name: 'education_resource') required EducationModel educationModel, @JsonKey(name: 'cert_photos') required List photos, + @JsonKey(name: 'canceled_moderation') required 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 7ca3ac48..2eb9f373 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 @@ -76,6 +76,7 @@ class RegisterConsultantCubit extends Cubit { ), acceptOffer: false, loading: false, + requestModel: myRequestStatus, ), ); } 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 32f495d9..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'; @@ -9,5 +10,6 @@ abstract class RegisterConsultantState with _$RegisterConsultantState { required ConsultantProfileModel consultant, required bool acceptOffer, required bool loading, + ConsultationRequestModel? requestModel, }) = _RegisterConsultantState; } 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 b49610fc..a365c1fc 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,6 @@ 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'; @@ -80,9 +81,57 @@ class _StepperBecomeConsultantScreenState extends State 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: MediaQuery.of(context).size.width * 0.8, + width: state.requestModel?.canceledModeration.status == 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', @@ -92,7 +141,11 @@ class _StepperBecomeConsultantScreenState extends State { 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/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..5da0bf7e 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") required 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 c1ac6b90..8a8229b8 100644 --- a/lib/features/feed/presentation/widgets/plan_widget.dart +++ b/lib/features/feed/presentation/widgets/plan_widget.dart @@ -96,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/presentation/pages/profile_screen.dart b/lib/features/profile/presentation/pages/profile_screen.dart index b9ecfff6..a09ff174 100644 --- a/lib/features/profile/presentation/pages/profile_screen.dart +++ b/lib/features/profile/presentation/pages/profile_screen.dart @@ -330,7 +330,7 @@ class _ProfileScreenState extends State { ), const SizedBox(height: 8), SizedBox( - height: 759, + height: 781, child: PageView.builder( itemBuilder: (BuildContext context, int index) { return PlanWidget( @@ -348,6 +348,7 @@ class _ProfileScreenState extends State { ), const SizedBox(height: 8), _bullets(_currentBullet, state.plansList.length), + const SizedBox(height: 8), ], ); } 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/settings/presentation/pages/settings_screen.dart b/lib/features/settings/presentation/pages/settings_screen.dart index 7c4ab26e..90c516ca 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'; @@ -377,7 +378,58 @@ class _SettingsScreenState extends State { ), ), ); + } else { + if (state.consultationRequestModel!.canceledModeration.status == 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!.canceledModeration.status == 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) {