diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index f33870db..d57d24d8 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -406,7 +406,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
- MARKETING_VERSION = 1.2.3;
+ MARKETING_VERSION = 1.3.3;
PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.eatvioapp.app 1747050044";
@@ -557,7 +557,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
- MARKETING_VERSION = 1.2.3;
+ MARKETING_VERSION = 1.3.3;
PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.eatvioapp.app 1747050044";
@@ -596,7 +596,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
- MARKETING_VERSION = 1.2.3;
+ MARKETING_VERSION = 1.3.3;
PRODUCT_BUNDLE_IDENTIFIER = com.eatvioapp.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.eatvioapp.app 1747050044";
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 7a90873e..15c18c06 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -21,7 +21,7 @@
CFBundleSignature
????
CFBundleVersion
- 81
+ 82
ITSAppUsesNonExemptEncryption
LSRequiresIPhoneOS
diff --git a/lib/core/di/cubit_registrations.dart b/lib/core/di/cubit_registrations.dart
index 9ff95e50..a52d8e84 100644
--- a/lib/core/di/cubit_registrations.dart
+++ b/lib/core/di/cubit_registrations.dart
@@ -39,6 +39,7 @@ import 'package:eatvio_app/features/my_finance/presentation/cubit/user_cards_cub
import 'package:eatvio_app/features/my_plans/presentation/cubit/my_plans_cubit.dart';
import 'package:eatvio_app/features/notifications/presentation/notifications_cubit/notifications_cubit.dart';
import 'package:eatvio_app/features/order_info/cubit/order_info_cubit.dart';
+import 'package:eatvio_app/features/personal_diet_suggestion/cubit/personal_diet_suggestion_cubit.dart';
import 'package:eatvio_app/features/plans/presentation/cubit/about_plan_cubit.dart';
import 'package:eatvio_app/features/profile/presentation/bloc/plans_cubit/plans_cubit.dart' as profile_plans;
import 'package:eatvio_app/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart';
@@ -145,5 +146,6 @@ class CubitRegistrations {
sl.registerFactory(() => UserDetailsCubit(profileRepository: sl()));
sl.registerFactory(() => MenuCubit(sl()));
sl.registerFactory(() => MarketingCubit(sl()));
+ sl.registerFactory(() => PersonalDietSuggestionCubit(dietRepository: sl(), personalDietSuggestionService: sl()));
}
}
diff --git a/lib/core/di/repository_registrations.dart b/lib/core/di/repository_registrations.dart
index 6d467810..dbfd1622 100644
--- a/lib/core/di/repository_registrations.dart
+++ b/lib/core/di/repository_registrations.dart
@@ -23,6 +23,7 @@ import 'package:eatvio_app/features/my_diets/repositories/my_diets_repository.da
import 'package:eatvio_app/features/my_finance/repositories/cards_repository.dart';
import 'package:eatvio_app/features/my_plans/repositories/my_diets_repository.dart';
import 'package:eatvio_app/features/notifications/repository/notifications_repository.dart';
+import 'package:eatvio_app/features/personal_diet_suggestion/repository/personal_diet_suggestion_repository.dart';
import 'package:eatvio_app/features/plans/repositories/plan_repository.dart';
import 'package:eatvio_app/features/plans/repositories/plans_repository.dart';
import 'package:eatvio_app/features/profile/repositories/profile_repository.dart';
@@ -68,6 +69,7 @@ class RepositoryRegistrations {
sl.registerLazySingleton(() => BlockedUsersRepository(blockedUserService: sl()));
sl.registerLazySingleton(() => CommentsRepository(service: sl()));
sl.registerLazySingleton(() => NotificationSettingsRepository(sl()));
+ sl.registerLazySingleton(() => PersonalDietSuggestionRepository(personalDietSuggestionService: sl()));
// Content repositories
sl.registerLazySingleton(() => BlogPostRepository(blogPostService: sl()));
diff --git a/lib/core/di/service_registrations.dart b/lib/core/di/service_registrations.dart
index 454d9064..7e14b3a7 100644
--- a/lib/core/di/service_registrations.dart
+++ b/lib/core/di/service_registrations.dart
@@ -25,6 +25,7 @@ import 'package:eatvio_app/features/my_diets/services/my_diets_service.dart';
import 'package:eatvio_app/features/my_finance/services/cards_service.dart';
import 'package:eatvio_app/features/my_plans/services/my_plans_service.dart';
import 'package:eatvio_app/features/notifications/service/notifications_service.dart';
+import 'package:eatvio_app/features/personal_diet_suggestion/services/personal_diet_suggestion_service.dart';
import 'package:eatvio_app/features/plans/services/plan_service.dart';
import 'package:eatvio_app/features/plans/services/plans_service.dart';
import 'package:eatvio_app/features/profile/services/profile_service.dart';
@@ -76,6 +77,7 @@ class ServiceRegistrations {
sl.registerLazySingleton(() => ConsultantRatingService(sl()));
sl.registerLazySingleton(() => NotificationSettingsService(sl()));
sl.registerLazySingleton(() => ViewsService(sl()));
+ sl.registerLazySingleton(() => PersonalDietSuggestionService(sl()));
// Content services
sl.registerLazySingleton(() => CreateRecipeService(sl()));
diff --git a/lib/core/routing/other_routes.dart b/lib/core/routing/other_routes.dart
index fd669e34..1110f88a 100644
--- a/lib/core/routing/other_routes.dart
+++ b/lib/core/routing/other_routes.dart
@@ -29,6 +29,7 @@ import 'package:eatvio_app/features/my_finance/presentation/pages/card_settings.
import 'package:eatvio_app/features/my_finance/presentation/pages/user_finance_screen.dart';
import 'package:eatvio_app/features/my_plans/presentation/my_plans_screen.dart';
import 'package:eatvio_app/features/order_info/presentation/info_by_order_screen.dart';
+import 'package:eatvio_app/features/personal_diet_suggestion/presentation/personal_diet_suggestion_screen.dart';
import 'package:eatvio_app/features/profile/models/profile_model.dart';
import 'package:eatvio_app/features/profile/presentation/pages/profile_screen.dart';
import 'package:eatvio_app/features/profile/presentation/pages/subs_screen.dart';
@@ -243,6 +244,11 @@ class OtherRoutes {
return UserDiaryScreen(diaryId: diaryId, currentPlanDay: currentPlanDay);
},
),
+ GoRoute(
+ path: PersonalDietSuggestionScreen.path,
+ name: PersonalDietSuggestionScreen.name,
+ builder: (context, state) => PersonalDietSuggestionScreen(dietId: state.extra as int,),
+ ),
];
}
}
diff --git a/lib/core/theme/theme_helper.dart b/lib/core/theme/theme_helper.dart
index be650ad3..75462df3 100644
--- a/lib/core/theme/theme_helper.dart
+++ b/lib/core/theme/theme_helper.dart
@@ -101,7 +101,7 @@ class PrimaryColors {
// Blue
Color get blue400 => const Color(0XFF43A6F2);
- Color get blueA400 => const Color(0XFF2F80ED);
+ Color get blueA400 => const Color(0XFF2F80ED);
// BlueGray
Color get blueGray400 => const Color(0XFF7B8794);
@@ -150,6 +150,8 @@ class PrimaryColors {
Color get green => const Color(0XFF0BB450);
+ Color get transparentGreen => const Color.fromARGB(12, 1, 154, 63);
+
// LightGreen
Color get lightGreen300 => const Color(0XFFB2DF8A);
diff --git a/lib/core/widgets/option_widget.dart b/lib/core/widgets/option_widget.dart
index 779f6c38..bed09c27 100644
--- a/lib/core/widgets/option_widget.dart
+++ b/lib/core/widgets/option_widget.dart
@@ -9,9 +9,10 @@ import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/material.dart';
class OptionWidget extends StatelessWidget {
- const OptionWidget({super.key, required this.option, this.disableDuration = false});
+ const OptionWidget({super.key, required this.option, this.disableDuration = false, required this.duration});
final PacketOptions? option;
final bool disableDuration;
+ final int duration;
@override
Widget build(BuildContext context) {
if (option == null) {
@@ -34,8 +35,12 @@ class OptionWidget extends StatelessWidget {
),
const SizedBox(height: 12),
if (!disableDuration) ...[
- const _OptionDurationWidget(duration: 7),
- const SizedBox(height: 16),
+ _OptionDurationWidget(duration: duration),
+ SizedBox(height: option?.hasPersonalDiet ?? false ? 8 : 12),
+ ],
+ if ((option?.hasPersonalDiet ?? false) && !disableDuration) ...[
+ const _OptionHasPersonalDietWidget(),
+ const SizedBox(height: 12),
],
const CustomDivider(),
const SizedBox(height: 16),
@@ -52,7 +57,6 @@ class OptionWidget extends StatelessWidget {
}
}
-
class _OptionDurationWidget extends StatelessWidget {
const _OptionDurationWidget({required this.duration});
final int duration;
@@ -92,3 +96,43 @@ class _OptionDurationWidget extends StatelessWidget {
);
}
}
+
+class _OptionHasPersonalDietWidget extends StatelessWidget {
+ const _OptionHasPersonalDietWidget();
+
+ @override
+ Widget build(BuildContext context) {
+ final s = S.of(context);
+ return Container(
+ decoration: BoxDecoration(borderRadius: BorderRadius.circular(4), color: appTheme.transparentGreen),
+ child: Row(
+ children: [
+ Padding(
+ padding: const EdgeInsets.symmetric(vertical: 4),
+ child: Container(
+ width: 4,
+ height: 20,
+ decoration: BoxDecoration(
+ color: appTheme.green,
+ borderRadius: const BorderRadius.only(
+ topRight: Radius.circular(100),
+ bottomRight: Radius.circular(100),
+ ),
+ ),
+ ),
+ ),
+ const SizedBox(
+ width: 12,
+ ),
+ Text(
+ s.personalDietCreating,
+ style: TextStyles.textSMedium.copyWith(color: appTheme.black),
+ ),
+ const SizedBox(
+ width: 12,
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/features/chat/presentation/pages/chat_screen.dart b/lib/features/chat/presentation/pages/chat_screen.dart
index 8ac88169..6b17ebb2 100644
--- a/lib/features/chat/presentation/pages/chat_screen.dart
+++ b/lib/features/chat/presentation/pages/chat_screen.dart
@@ -114,25 +114,6 @@ class _ChatScreenState extends State {
ChosenPlanStateEnum.statePendingPayment,
ChosenPlanStateEnum.stateInCoordination,
].contains(chosenPlan?.chosenPlanState);
-
- final showAboutOrderButton =
- state.chatRoom.chosenPlan != null && state.chatRoom.chosenPlan!.chosenPlanState != ChosenPlanStateEnum.stateCanceledByTheInitiator;
- BannerType? bannerType;
- if (chosenPlan == null || chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateCanceledByTheInitiator) {
- bannerType = null;
- } else if (amIConsultant && !state.hasCard) {
- bannerType = BannerType.card;
- } else if (amIConsultant && chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateInCoordination) {
- bannerType = BannerType.date;
- } else if (!amIConsultant &&
- (chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateStartDateHasBeenSet || chosenPlan.chosenPlanState == ChosenPlanStateEnum.statePendingPayment)) {
- bannerType = BannerType.payment;
- } else if (chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateDone && amIConsultant) {
- bannerType = BannerType.collectCharge;
- } else if (chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateLastDayFinished && !amIConsultant) {
- bannerType = BannerType.finishPlan;
- }
-
PacketOptions? chosenOption;
if (chosenPlan?.optionType == 'options1') {
chosenOption = chosenPlan?.plan.packet1Options;
@@ -141,6 +122,27 @@ class _ChatScreenState extends State {
} else if (chosenPlan?.optionType == 'options3') {
chosenOption = chosenPlan?.plan.packet3Options;
}
+
+ final showAboutOrderButton =
+ state.chatRoom.chosenPlan != null && state.chatRoom.chosenPlan!.chosenPlanState != ChosenPlanStateEnum.stateCanceledByTheInitiator;
+ BannerType? bannerType;
+ if (chosenPlan == null || chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateCanceledByTheInitiator) {
+ bannerType = null;
+ } else if (amIConsultant && !state.hasCard && chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateInCoordination) {
+ bannerType = BannerType.card;
+ } else if (amIConsultant && chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateInCoordination) {
+ bannerType = BannerType.date;
+ } else if (!amIConsultant &&
+ (chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateStartDateHasBeenSet || chosenPlan.chosenPlanState == ChosenPlanStateEnum.statePendingPayment)) {
+ bannerType = BannerType.payment;
+ } else if (chosenOption?.hasPersonalDiet == true && amIConsultant) {
+ bannerType = BannerType.setPersonalDiet;
+ } else if (chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateDone && amIConsultant) {
+ bannerType = BannerType.collectCharge;
+ } else if (chosenPlan.chosenPlanState == ChosenPlanStateEnum.stateLastDayFinished && !amIConsultant) {
+ bannerType = BannerType.finishPlan;
+ }
+
return Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBar(
@@ -317,6 +319,7 @@ class _ChatScreenState extends State {
chosenPlanId: chosenPlan?.id,
planName: chosenPlan?.plan.name,
planPrice: chosenOption?.price.toDouble(),
+ hasPersonalDiet: chosenOption?.hasPersonalDiet ?? false,
),
),
],
diff --git a/lib/features/chat/presentation/widgets/chose_plan_date_widget.dart b/lib/features/chat/presentation/widgets/chose_plan_date_widget.dart
index 5ec4e370..2744ba74 100644
--- a/lib/features/chat/presentation/widgets/chose_plan_date_widget.dart
+++ b/lib/features/chat/presentation/widgets/chose_plan_date_widget.dart
@@ -9,17 +9,28 @@ import 'package:eatvio_app/core/theme/custom_text_style.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
import 'package:flutter/material.dart';
+import 'package:flutter_portal/flutter_portal.dart';
+import 'package:flutter_svg/flutter_svg.dart';
class ChosePlanDateWidget extends StatefulWidget {
- const ChosePlanDateWidget({super.key, required this.chatCubit});
+ const ChosePlanDateWidget({super.key, required this.chatCubit, required this.hasPersonalDiet});
final ChatRoomCubit chatCubit;
-
+ final bool hasPersonalDiet;
@override
State createState() => _ChosePlanDateWidget();
}
class _ChosePlanDateWidget extends State {
- final startDate = [DateTime.now()];
+ late final List startDate;
+ bool visible = false;
+ @override
+ void initState() {
+ super.initState();
+ if (widget.hasPersonalDiet) {
+ startDate = [DateTime.now().add(const Duration(days: 2))];
+ }
+ }
+
@override
Widget build(BuildContext context) {
final s = S.of(context);
@@ -27,64 +38,129 @@ class _ChosePlanDateWidget extends State {
if (widget.chatCubit.state is ChatRoomStateLoaded) {
planName = (widget.chatCubit.state as ChatRoomStateLoaded).chatRoom.chosenPlan?.plan.name;
}
- return Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- const SizedBox(height: 4),
- const BottomSheetHandlerBar(),
- const SizedBox(height: 12),
- Text(
- planName ?? '',
- style: TextStyles.headingXLSemibold.copyWith(
- color: appTheme.black,
+ return GestureDetector(
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ const SizedBox(height: 4),
+ const BottomSheetHandlerBar(),
+ const SizedBox(height: 12),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Text(
+ planName ?? '',
+ style: TextStyles.headingXLSemibold.copyWith(
+ color: appTheme.black,
+ ),
+ ),
+ if (widget.hasPersonalDiet) ...[
+ const SizedBox(
+ width: 8,
+ ),
+ PortalTarget(
+ closeDuration: const Duration(milliseconds: 20),
+ anchor: const Aligned(
+ shiftToWithinBound: AxisFlag(x: true, y: true),
+ follower: Alignment.topRight,
+ target: Alignment.bottomLeft,
+ ),
+ portalFollower: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 20),
+ child: Container(
+ padding: const EdgeInsets.all(10),
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(12),
+ color: visible ? appTheme.whiteA700 : Colors.transparent,
+ boxShadow: visible
+ ? [
+ BoxShadow(
+ color: appTheme.black900.withValues(alpha: 0.15),
+ blurRadius: 4,
+ offset: const Offset(0, 4),
+ ),
+ ]
+ : null,
+ ),
+ child: AnimatedDefaultTextStyle(
+ style: TextStyles.textMMediumAuto.copyWith(
+ color: visible ? appTheme.black : Colors.transparent,
+ ),
+ duration: const Duration(milliseconds: 300),
+ child: Text(
+ s.chosenPlanStartDateDescr,
+ ),
+ ),
+ ),
+ ),
+ child: GestureDetector(
+ onTap: () {
+ setState(() {
+ visible = !visible;
+ });
+ },
+ child: SvgPicture.asset(
+ 'assets/icons/question_mark.svg',
+ width: 22,
+ height: 22,
+ colorFilter: ColorFilter.mode(
+ appTheme.blueA400,
+ BlendMode.srcIn,
+ ),
+ ),
+ ),
+ )
+ ]
+ ],
),
- ),
- const SizedBox(height: 12),
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 25.0),
- child: Text(
- s.chose_plan_start_date_2,
- textAlign: TextAlign.center,
- style: TextStyles.textMMedium.copyWith(
- color: appTheme.black,
+ const SizedBox(height: 12),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 25.0),
+ child: Text(
+ s.chose_plan_start_date_2,
+ textAlign: TextAlign.center,
+ style: TextStyles.textMMedium.copyWith(
+ color: appTheme.black,
+ ),
),
),
- ),
- const SizedBox(height: 12),
- const Padding(
- padding: EdgeInsets.symmetric(horizontal: 16.0),
- child: CustomDivider(),
- ),
- CalendarWidget(
- startDate: startDate,
- ),
- Padding(
- padding: const EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 28),
- child: CustomOutlinedButton(
- onPressed: () async {
- final result = await widget.chatCubit.choseStartPlanDate(startDate[0]);
- if (result) {
- showSuccessToast('Дата установлена');
- if (!context.mounted) return;
- Navigator.pop(context);
- } else {
- showErrorToast('Не удалось установить дату');
- if (!context.mounted) return;
- Navigator.pop(context);
- }
- },
- height: 60,
- text: s.confirm,
- buttonTextStyle: TextStyles.textLSemibold.copyWith(
- color: appTheme.whiteA700,
- ),
- buttonStyle: ButtonStyle(
- backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
- side: const WidgetStatePropertyAll(BorderSide.none),
+ const SizedBox(height: 12),
+ const Padding(
+ padding: EdgeInsets.symmetric(horizontal: 16.0),
+ child: CustomDivider(),
+ ),
+ CalendarWidget(
+ startDate: startDate,
+ ),
+ Padding(
+ padding: const EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 28),
+ child: CustomOutlinedButton(
+ onPressed: () async {
+ final result = await widget.chatCubit.choseStartPlanDate(startDate[0]);
+ if (result) {
+ showSuccessToast('Дата установлена');
+ if (!context.mounted) return;
+ Navigator.pop(context);
+ } else {
+ showErrorToast('Не удалось установить дату');
+ if (!context.mounted) return;
+ Navigator.pop(context);
+ }
+ },
+ height: 60,
+ text: s.confirm,
+ buttonTextStyle: TextStyles.textLSemibold.copyWith(
+ color: appTheme.whiteA700,
+ ),
+ buttonStyle: ButtonStyle(
+ backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
+ side: const WidgetStatePropertyAll(BorderSide.none),
+ ),
),
),
- ),
- ],
+ ],
+ ),
);
}
}
diff --git a/lib/features/chat/presentation/widgets/notification_banner.dart b/lib/features/chat/presentation/widgets/notification_banner.dart
index 8828863f..3a8203f9 100644
--- a/lib/features/chat/presentation/widgets/notification_banner.dart
+++ b/lib/features/chat/presentation/widgets/notification_banner.dart
@@ -9,6 +9,7 @@ import 'package:eatvio_app/features/chat/presentation/pages/payment_screen.dart'
import 'package:eatvio_app/features/chat/presentation/widgets/chose_plan_date_widget.dart';
import 'package:eatvio_app/features/chat/presentation/widgets/complete_plan_bottom_sheet.dart';
import 'package:eatvio_app/features/chat/presentation/widgets/plan_complain_bottom_sheet.dart';
+import 'package:eatvio_app/features/my_diets/presentation/my_diets_screen.dart';
import 'package:eatvio_app/features/my_finance/presentation/pages/card_settings.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/material.dart';
@@ -17,12 +18,12 @@ import 'package:flutter_svg/svg.dart';
import 'package:go_router/go_router.dart';
class NotificationBanner extends StatefulWidget {
- const NotificationBanner({super.key, required this.bannerType, this.planPrice, this.planName, this.chosenPlanId});
+ const NotificationBanner({super.key, required this.bannerType, this.planPrice, this.planName, this.chosenPlanId, this.hasPersonalDiet = false});
final BannerType bannerType;
final double? planPrice;
final String? planName;
final int? chosenPlanId;
-
+ final bool hasPersonalDiet;
@override
State createState() => _NotificationBannerState();
}
@@ -68,7 +69,8 @@ class _NotificationBannerState extends State {
BannerType.date => [
SizedBox(
width: size.width * 0.6,
- child: Text(s.choose_plan_start_date, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
+ child: Text(widget.hasPersonalDiet == true ? s.choose_plan_start_date_with_personal_diet : s.choose_plan_start_date,
+ style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
),
const SizedBox(height: 12),
GestureDetector(
@@ -78,6 +80,7 @@ class _NotificationBannerState extends State {
context: context,
builder: (context) => ChosePlanDateWidget(
chatCubit: cubit,
+ hasPersonalDiet: widget.hasPersonalDiet,
),
);
},
@@ -155,6 +158,20 @@ class _NotificationBannerState extends State {
),
const SizedBox(height: 8),
],
+ BannerType.setPersonalDiet => [
+ SizedBox(
+ width: size.width * 0.6,
+ child: Text(s.createPersonalDiet, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
+ ),
+ const SizedBox(height: 12),
+ GestureDetector(
+ onTap: () {
+ GoRouter.of(context).pushNamed(MyDietsScreen.name);
+ },
+ child: Text(s.goToMyDiets, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
+ ),
+ const SizedBox(height: 16),
+ ],
},
),
),
@@ -242,4 +259,4 @@ class _StarIcon extends StatelessWidget {
}
}
-enum BannerType { date, card, payment, collectCharge, finishPlan }
+enum BannerType { date, card, payment, collectCharge, finishPlan, setPersonalDiet }
diff --git a/lib/features/consultations/models/consultation_model.dart b/lib/features/consultations/models/consultation_model.dart
index 59c48f09..c73a8d37 100644
--- a/lib/features/consultations/models/consultation_model.dart
+++ b/lib/features/consultations/models/consultation_model.dart
@@ -22,6 +22,7 @@ abstract class ConsultationModel with _$ConsultationModel {
@JsonKey(name: 'end_date', fromJson: parseDate) required DateTime endDate,
@JsonKey(name: 'consultant_id') required int consultantId,
required List diaries,
+ @JsonKey(name: 'personal_diet_id') required int? personalDietId,
}) = _ConsultationModel;
factory ConsultationModel.fromJson(Map json) => _$ConsultationModelFromJson(json);
diff --git a/lib/features/create_plan/presentation/cubit/create_plan_cubit.dart b/lib/features/create_plan/presentation/cubit/create_plan_cubit.dart
index 96385904..2289b31f 100644
--- a/lib/features/create_plan/presentation/cubit/create_plan_cubit.dart
+++ b/lib/features/create_plan/presentation/cubit/create_plan_cubit.dart
@@ -67,6 +67,13 @@ class CreatePlanCubit extends Cubit {
validateSelectedOptionItems();
}
+ void togglePersonalizedDietOptionState() {
+ final options = [...state.planData.options];
+ options[state.selectedOptionIndex ?? 0] =
+ options[state.selectedOptionIndex ?? 0].copyWith(hasPersonalDiet: !options[state.selectedOptionIndex ?? 0].hasPersonalDiet);
+ emit(state.copyWith(planData: state.planData.copyWith(options: options)));
+ }
+
void setDuration(int index) {
emit(
state.copyWith(
@@ -418,18 +425,21 @@ class CreatePlanCubit extends Cubit {
'price': int.parse((state.planData.options[0].price as double).toStringAsFixed(0)),
'description_md': state.planData.options[0].description,
'items': Map.fromIterable(state.planData.options[0].items),
+ 'has_personal_diet': state.planData.options[0].hasPersonalDiet ? '1' : '0',
},
'packet2_options': {
'short': state.planData.options[1].short,
'price': int.parse((state.planData.options[1].price as double).toStringAsFixed(0)),
'description_md': state.planData.options[1].description,
'items': Map.fromIterable(state.planData.options[1].items),
+ 'has_personal_diet': state.planData.options[1].hasPersonalDiet ? '1' : '0',
},
'packet3_options': {
'short': state.planData.options[2].short,
'price': int.parse((state.planData.options[2].price as double).toStringAsFixed(0)),
'description_md': state.planData.options[2].description,
'items': Map.fromIterable(state.planData.options[2].items),
+ 'has_personal_diet': state.planData.options[2].hasPersonalDiet ? '1' : '0',
},
});
} else {
@@ -440,6 +450,7 @@ class CreatePlanCubit extends Cubit {
'price': int.parse((state.planData.options[0].price as double).toStringAsFixed(0)),
'description_md': state.planData.options[0].description,
'items': Map.fromIterable(state.planData.options[0].items),
+ 'has_personal_diet': state.planData.options[0].hasPersonalDiet ? '1' : '0',
},
});
}
diff --git a/lib/features/create_plan/presentation/widgets/option_widget.dart b/lib/features/create_plan/presentation/widgets/option_widget.dart
index 42362e96..24cde52b 100644
--- a/lib/features/create_plan/presentation/widgets/option_widget.dart
+++ b/lib/features/create_plan/presentation/widgets/option_widget.dart
@@ -90,7 +90,7 @@ class _OptionWidgetState extends State {
2 => thirdOptionCustomerPriceController,
_ => secondOptionCustomerPriceController,
};
-
+
final price = double.tryParse(customerPriceController.text.replaceAll('₽', ''));
creatorPriceController.text = '${((price ?? 0) * 0.8).toStringAsFixed(2)}₽';
firstOptionTitleController.text = state.planData.options[selectedOptionIndex].short;
@@ -255,33 +255,31 @@ class _OptionWidgetState extends State {
),
const SizedBox(height: 16),
const CustomDivider(),
- // const SizedBox(height: 16),
- // Row(
- // children: [
- // Checkbox(
- // value: isChecked,
- // activeColor: appTheme.gray,
- // checkColor: appTheme.gray,
- // fillColor: const WidgetStatePropertyAll(Colors.transparent),
- // side: WidgetStateBorderSide.resolveWith(
- // (Set states) {
- // return BorderSide(width: 1, color: appTheme.gray);
- // },
- // ),
- // onChanged: (bool? value) {
- // setState(() {
- // isChecked = value ?? false;
- // });
- // },
- // ),
- // Expanded(
- // child: Text(
- // s.option_personal_diet_desc,
- // style: TextStyles.textMMedium.copyWith(color: appTheme.black),
- // ),
- // ),
- // ],
- // ),
+ const SizedBox(height: 16),
+ Row(
+ children: [
+ Checkbox(
+ value: state.planData.options[selectedOptionIndex].hasPersonalDiet,
+ activeColor: appTheme.gray,
+ checkColor: appTheme.gray,
+ fillColor: const WidgetStatePropertyAll(Colors.transparent),
+ side: WidgetStateBorderSide.resolveWith(
+ (Set states) {
+ return BorderSide(width: 1, color: appTheme.gray);
+ },
+ ),
+ onChanged: (bool? value) {
+ context.read().togglePersonalizedDietOptionState();
+ },
+ ),
+ Expanded(
+ child: Text(
+ s.option_personal_diet_desc,
+ style: TextStyles.textMMedium.copyWith(color: appTheme.black),
+ ),
+ ),
+ ],
+ ),
],
),
);
diff --git a/lib/features/diets/presentation/widgets/calendar_widget.dart b/lib/features/diets/presentation/widgets/calendar_widget.dart
index 316913b3..1daace4b 100644
--- a/lib/features/diets/presentation/widgets/calendar_widget.dart
+++ b/lib/features/diets/presentation/widgets/calendar_widget.dart
@@ -13,8 +13,15 @@ class CalendarWidget extends StatefulWidget {
class _CalendarWidgetState extends State {
CalendarFormat _calendarFormat = CalendarFormat.week;
- DateTime _focusedDay = DateTime.now();
- DateTime? _selectedDay = DateTime.now();
+ late DateTime _focusedDay;
+ DateTime? _selectedDay;
+
+ @override
+ void initState() {
+ super.initState();
+ _selectedDay = widget.startDate.isEmpty ? DateTime.now() : widget.startDate[0];
+ _focusedDay = widget.startDate.isEmpty ? DateTime.now() : widget.startDate[0];
+ }
@override
Widget build(BuildContext context) {
return Column(
@@ -23,7 +30,7 @@ class _CalendarWidgetState extends State {
Padding(
padding: const EdgeInsets.only(top: 5),
child: TableCalendar(
- firstDay: DateTime.now(),
+ firstDay: widget.startDate.isEmpty ? DateTime.now() : widget.startDate[0],
lastDay: DateTime.utc(2030, 3, 14),
locale: 'ru_RU',
startingDayOfWeek: StartingDayOfWeek.monday,
diff --git a/lib/features/feed/models/plan_pagination_model.dart b/lib/features/feed/models/plan_pagination_model.dart
index 728ff0b7..6c948685 100644
--- a/lib/features/feed/models/plan_pagination_model.dart
+++ b/lib/features/feed/models/plan_pagination_model.dart
@@ -67,11 +67,19 @@ abstract class PacketOptions with _$PacketOptions {
@JsonKey(name: "price") required dynamic price,
@JsonKey(name: "short") required String short,
@JsonKey(name: "description_md") required String description,
+ @JsonKey(name: "has_personal_diet", fromJson: _parseHasPersonalDietField) required bool hasPersonalDiet,
}) = _PacketOptions;
factory PacketOptions.fromJson(Map json) => _$PacketOptionsFromJson(json);
- factory PacketOptions.empty() => PacketOptions(items: [], price: double.parse('1200'), short: '', description: '');
+ factory PacketOptions.empty() => PacketOptions(items: [], price: double.parse('1200'), short: '', description: '', hasPersonalDiet: false);
+}
+
+bool _parseHasPersonalDietField(dynamic json) {
+ if (json == null) return false;
+ if (json == '1') return true;
+ if (json == '0') return false;
+ return json as bool;
}
List _parseItems(dynamic json) {
diff --git a/lib/features/my_diets/presentation/widgets/my_diet_widget.dart b/lib/features/my_diets/presentation/widgets/my_diet_widget.dart
index c3c9c5a3..190f7834 100644
--- a/lib/features/my_diets/presentation/widgets/my_diet_widget.dart
+++ b/lib/features/my_diets/presentation/widgets/my_diet_widget.dart
@@ -17,6 +17,7 @@ import 'package:eatvio_app/features/my_diets/presentation/cubit/my_diets_cubit.d
import 'package:eatvio_app/features/my_diets/presentation/cubit/my_diets_state.dart';
import 'package:eatvio_app/features/my_diets/presentation/widgets/diet_deleted_bottom_sheet.dart';
import 'package:eatvio_app/features/my_diets/presentation/widgets/diet_drafetd_bottom_sheet.dart';
+import 'package:eatvio_app/features/personal_diet_suggestion/presentation/personal_diet_suggestion_screen.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -146,6 +147,7 @@ class _MyDietWidgetState extends State {
showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время');
}
} else if (state.selectedStateIndex == 2) {
+ GoRouter.of(context).pushNamed(PersonalDietSuggestionScreen.name, extra: widget.diet.id);
} else {
GoRouter.of(context).pushNamed(CreateDietScreen.name, extra: widget.diet);
}
diff --git a/lib/features/order_info/presentation/info_by_order_screen.dart b/lib/features/order_info/presentation/info_by_order_screen.dart
index 8fc20639..adce3286 100644
--- a/lib/features/order_info/presentation/info_by_order_screen.dart
+++ b/lib/features/order_info/presentation/info_by_order_screen.dart
@@ -132,9 +132,9 @@ class _InfoByOrderScreenContentState extends State {
const SizedBox(height: 8),
PlanInfo(title: plan.plan.name, description: plan.plan.details, imagePath: plan.plan.image),
const SizedBox(height: 8),
- OptionWidget(option: chosenOption, disableDuration: true),
+ OptionWidget(option: chosenOption, disableDuration: true, duration: plan.plan.duration),
const SizedBox(height: 8),
- PlanState(state: plan.chosenPlanState),
+ PlanState(state: plan.chosenPlanState, hasPersonalDiet: chosenOption?.hasPersonalDiet ?? false,),
const SizedBox(height: 20),
if (widget.successfulPayment == null)
CustomOutlinedButton(
diff --git a/lib/features/order_info/presentation/widgets/plan_state.dart b/lib/features/order_info/presentation/widgets/plan_state.dart
index c5c7c72a..f65b82bb 100644
--- a/lib/features/order_info/presentation/widgets/plan_state.dart
+++ b/lib/features/order_info/presentation/widgets/plan_state.dart
@@ -5,42 +5,65 @@ import 'package:eatvio_app/features/plans/enums/chosen_plan_state_enum.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/material.dart';
-class PlanState extends StatelessWidget {
- PlanState({super.key, required this.state});
+class PlanState extends StatefulWidget {
+ const PlanState({super.key, required this.state, required this.hasPersonalDiet});
final ChosenPlanStateEnum state;
- final List> states = [
- [
- ChosenPlanStateEnum.stateInited,
- ChosenPlanStateEnum.stateInCoordination,
- ],
- [
- ChosenPlanStateEnum.stateStartDateHasBeenSet,
- ChosenPlanStateEnum.statePendingPayment,
- ],
- [
- ChosenPlanStateEnum.statePaid,
- ],
- [
- ChosenPlanStateEnum.stateStarted,
- ChosenPlanStateEnum.stateInProgress,
- ChosenPlanStateEnum.stateLastDayStarted,
- ChosenPlanStateEnum.stateLastDayFinished,
- ],
- [
- ChosenPlanStateEnum.stateComplained,
- ChosenPlanStateEnum.stateDone,
- ChosenPlanStateEnum.stateChargeWasCollected,
- ]
- ];
+ final bool hasPersonalDiet;
+
+ @override
+ State createState() => _PlanStateState();
+}
+
+class _PlanStateState extends State {
+ late final List> states;
+
+ @override
+ void initState() {
+ super.initState();
+ if (widget.hasPersonalDiet) {
+ states = [
+ [ChosenPlanStateEnum.stateInited, ChosenPlanStateEnum.stateInCoordination],
+ [ChosenPlanStateEnum.stateStartDateHasBeenSet, ChosenPlanStateEnum.statePendingPayment],
+ [ChosenPlanStateEnum.statePaid],
+ [ChosenPlanStateEnum.personalDietSet],
+ [
+ ChosenPlanStateEnum.stateStarted,
+ ChosenPlanStateEnum.stateInProgress,
+ ChosenPlanStateEnum.stateLastDayStarted,
+ ChosenPlanStateEnum.stateLastDayFinished,
+ ],
+ [ChosenPlanStateEnum.stateComplained, ChosenPlanStateEnum.stateDone, ChosenPlanStateEnum.stateChargeWasCollected],
+ ];
+ } else {
+ states = [
+ [ChosenPlanStateEnum.stateInited, ChosenPlanStateEnum.stateInCoordination],
+ [ChosenPlanStateEnum.stateStartDateHasBeenSet, ChosenPlanStateEnum.statePendingPayment],
+ [ChosenPlanStateEnum.statePaid],
+ [
+ ChosenPlanStateEnum.stateStarted,
+ ChosenPlanStateEnum.stateInProgress,
+ ChosenPlanStateEnum.stateLastDayStarted,
+ ChosenPlanStateEnum.stateLastDayFinished,
+ ],
+ [ChosenPlanStateEnum.stateComplained, ChosenPlanStateEnum.stateDone, ChosenPlanStateEnum.stateChargeWasCollected],
+ ];
+ }
+ }
+
@override
Widget build(BuildContext context) {
final s = S.of(context);
- final titles = [s.order_created, s.startDateHasBeenSet, s.order_paid, s.in_progress, s.done];
+ final List titles;
+ if (widget.hasPersonalDiet) {
+ titles = [s.order_created, s.startDateHasBeenSet, s.order_paid, s.personal_diet_set, s.in_progress, s.done];
+ } else {
+ titles = [s.order_created, s.startDateHasBeenSet, s.order_paid, s.in_progress, s.done];
+ }
return MainBackgroundBouble(
padding: const EdgeInsets.all(16),
child: Column(
children: List.generate(states.length, (index) {
- final color = index <= states.indexWhere((element) => element.contains(state)) ? appTheme.greenA700 : appTheme.lightGray00;
+ final color = index <= states.indexWhere((element) => element.contains(widget.state)) ? appTheme.greenA700 : appTheme.lightGray00;
final text = titles[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -51,29 +74,16 @@ class PlanState extends StatelessWidget {
width: 24,
height: 24,
decoration: BoxDecoration(shape: BoxShape.circle, color: color),
- child: Center(
- child: Icon(
- Icons.check,
- color: appTheme.whiteA700,
- size: 14,
- ),
- ),
+ child: Center(child: Icon(Icons.check, color: appTheme.whiteA700, size: 14)),
),
const SizedBox(width: 12),
- Text(
- text,
- style: TextStyles.textMMedium.copyWith(color: appTheme.black),
- ),
+ Text(text, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
],
),
Padding(
padding: const EdgeInsets.only(left: 12),
- child: Container(
- height: 12,
- width: 1,
- color: color,
- ),
- )
+ child: Container(height: 12, width: 1, color: color),
+ ),
],
);
}),
diff --git a/lib/features/personal_diet_suggestion/cubit/personal_diet_suggestion_cubit.dart b/lib/features/personal_diet_suggestion/cubit/personal_diet_suggestion_cubit.dart
new file mode 100644
index 00000000..cde49e7e
--- /dev/null
+++ b/lib/features/personal_diet_suggestion/cubit/personal_diet_suggestion_cubit.dart
@@ -0,0 +1,67 @@
+import 'dart:developer';
+
+import 'package:eatvio_app/features/diets/repositories/diet_repository.dart';
+import 'package:eatvio_app/features/personal_diet_suggestion/cubit/personal_diet_suggestion_state.dart';
+import 'package:eatvio_app/features/personal_diet_suggestion/repository/personal_diet_suggestion_repository.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class PersonalDietSuggestionCubit extends Cubit {
+ final DietRepository dietRepository;
+ final PersonalDietSuggestionRepository personalDietSuggestionService;
+ late final int dietId;
+ PersonalDietSuggestionCubit({required this.dietRepository, required this.personalDietSuggestionService}) : super(PersonalDietSuggestionState());
+
+ Future setDietName(int dietId) async {
+ try {
+ emit(state.copyWith(isLoading: true, error: null));
+ final diet = await dietRepository.getDiet(dietId);
+ emit(state.copyWith(isLoading: false, dietName: diet.name));
+ } catch (e, st) {
+ log(e.toString(), stackTrace: st);
+ emit(state.copyWith(isLoading: false, error: e.toString()));
+ }
+ }
+
+ Future getConsultationWithPersonalDiets(int dietId) async {
+ try {
+ this.dietId = dietId;
+ emit(state.copyWith(isLoading: true, error: null));
+ setDietName(dietId);
+ final consultations = await personalDietSuggestionService.getConsultationWithPersonalDiets();
+ final consultationWithDiet = consultations.where((consultation) => consultation.personalDietId != null).toList();
+ final consultationWithoutDiet = consultations.where((consultation) => consultation.personalDietId == null).toList();
+ emit(state.copyWith(
+ isLoading: false,
+ consultationsWithDiet: consultationWithDiet,
+ consultationsWithoutDiet: consultationWithoutDiet,
+ ));
+ } catch (e, st) {
+ log(e.toString(), stackTrace: st);
+ emit(state.copyWith(isLoading: false, error: e.toString()));
+ }
+ }
+
+ Future attachDietToConsultation({
+ required int consultationId,
+ }) async {
+ try {
+ await personalDietSuggestionService.attachPersonalDiet(consultationId: consultationId, dietId: dietId);
+ return true;
+ } catch (e, st) {
+ log(e.toString(), stackTrace: st);
+ return false;
+ }
+ }
+
+ Future reattachDietToConsultation({
+ required int consultationId,
+ }) async {
+ try {
+ await personalDietSuggestionService.reattachPersonalDiet(consultationId: consultationId, dietId: dietId);
+ return true;
+ } catch (e, st) {
+ log(e.toString(), stackTrace: st);
+ return false;
+ }
+ }
+}
diff --git a/lib/features/personal_diet_suggestion/cubit/personal_diet_suggestion_state.dart b/lib/features/personal_diet_suggestion/cubit/personal_diet_suggestion_state.dart
new file mode 100644
index 00000000..da927703
--- /dev/null
+++ b/lib/features/personal_diet_suggestion/cubit/personal_diet_suggestion_state.dart
@@ -0,0 +1,16 @@
+import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
+import 'package:freezed_annotation/freezed_annotation.dart';
+
+part 'personal_diet_suggestion_state.freezed.dart';
+
+@freezed
+abstract class PersonalDietSuggestionState with _$PersonalDietSuggestionState {
+ factory PersonalDietSuggestionState({
+ @Default([]) List consultationsWithDiet,
+ @Default([]) List consultationsWithoutDiet,
+ @Default('') String dietName,
+ @Default(false) bool isLoading,
+ @Default(null) String? error,
+ }) = _PersonalDietSuggestionState;
+
+}
\ No newline at end of file
diff --git a/lib/features/personal_diet_suggestion/presentation/consultation_widget.dart b/lib/features/personal_diet_suggestion/presentation/consultation_widget.dart
new file mode 100644
index 00000000..fa64362c
--- /dev/null
+++ b/lib/features/personal_diet_suggestion/presentation/consultation_widget.dart
@@ -0,0 +1,358 @@
+import 'package:eatvio_app/core/app_config.dart';
+import 'package:eatvio_app/core/app_router.dart';
+import 'package:eatvio_app/core/locator_service.dart';
+import 'package:eatvio_app/core/theme/custom_text_style.dart';
+import 'package:eatvio_app/core/theme/theme_helper.dart';
+import 'package:eatvio_app/core/widgets/bottom_sheet_handler_bar.dart';
+import 'package:eatvio_app/core/widgets/bottom_sheet_with_blur.dart';
+import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
+import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
+import 'package:eatvio_app/features/personal_diet_suggestion/cubit/personal_diet_suggestion_cubit.dart';
+import 'package:eatvio_app/generated/l10n.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:go_router/go_router.dart';
+
+class ConsultationWidget extends StatelessWidget {
+ const ConsultationWidget({super.key, required this.consultationModel, required this.dietName});
+ final ConsultationModel consultationModel;
+ final String dietName;
+ @override
+ Widget build(BuildContext context) {
+ final s = S.of(context);
+ return Container(
+ padding: const EdgeInsets.all(16),
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(12),
+ color: appTheme.whiteA700,
+ ),
+ child: Column(
+ children: [
+ if (consultationModel.personalDietId == null)
+ Row(
+ children: [
+ CircleAvatar(
+ radius: 30,
+ backgroundImage: NetworkImage(sl().baseUrl + consultationModel.userProfilePhotoUrl),
+ ),
+ const SizedBox(width: 12),
+ Column(
+ mainAxisSize: MainAxisSize.min,
+ spacing: 4,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ consultationModel.userName,
+ style: TextStyles.textLSemibold.copyWith(color: appTheme.black),
+ ),
+ Text(
+ consultationModel.planTitle,
+ style: TextStyles.textMMedium.copyWith(color: const Color(0xFF88949F)),
+ ),
+ Text(
+ 'Старт: ${consultationModel.userName}',
+ style: TextStyles.textMMedium.copyWith(color: const Color(0xFF88949F)),
+ ),
+ ],
+ )
+ ],
+ )
+ else
+ Row(
+ children: [
+ CircleAvatar(
+ radius: 30,
+ backgroundImage: NetworkImage(sl().baseUrl + consultationModel.userProfilePhotoUrl),
+ ),
+ const SizedBox(width: 12),
+ Column(
+ mainAxisSize: MainAxisSize.min,
+ spacing: 4,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ consultationModel.userName,
+ style: TextStyles.textLSemibold.copyWith(color: appTheme.black),
+ ),
+ Text(
+ consultationModel.planTitle,
+ style: TextStyles.textMMedium.copyWith(color: const Color(0xFF88949F)),
+ ),
+ ],
+ )
+ ],
+ ),
+ const SizedBox(
+ height: 12,
+ ),
+ if (consultationModel.personalDietId != null)
+ CustomOutlinedButton(
+ text: s.changeDiet,
+ height: 52,
+ buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.gray),
+ buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.dividerColor)),
+ onPressed: () async {
+ showBottomSheetWithBlur(
+ userRootNavigator: true,
+ context: context,
+ height: null,
+ child: SuggestDietBottomSheet(
+ userName: consultationModel.userName,
+ dietName: dietName,
+ onTap: () async {
+ final result = await context.read().attachDietToConsultation(consultationId: consultationModel.id);
+ AppRouter.navigatorKey.currentContext?.pop();
+ if (result) {
+ if (!context.mounted) return;
+ showBottomSheetWithBlur(
+ userRootNavigator: true,
+ context: context,
+ height: null,
+ child: SuggestionSuccessBottomSheet(
+ userName: consultationModel.userName,
+ dietName: dietName,
+ ),
+ );
+ return;
+ }
+ if (!context.mounted) return;
+ showBottomSheetWithBlur(
+ userRootNavigator: true,
+ context: context,
+ height: null,
+ child: SuggestionFailureBottomSheet(
+ userName: consultationModel.userName,
+ dietName: dietName,
+ ),
+ );
+ },
+ ),
+ );
+ },
+ )
+ else
+ CustomOutlinedButton(
+ text: s.suggestDiet,
+ height: 52,
+ buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
+ buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)),
+ onPressed: () async {
+ showBottomSheetWithBlur(
+ userRootNavigator: true,
+ context: context,
+ height: null,
+ child: SuggestDietBottomSheet(
+ userName: consultationModel.userName,
+ dietName: dietName,
+ onTap: () async {
+ AppRouter.navigatorKey.currentContext?.pop();
+ final result = await context.read().attachDietToConsultation(consultationId: consultationModel.id);
+ if (result) {
+ if (!context.mounted) return;
+ showBottomSheetWithBlur(
+ userRootNavigator: true,
+ context: context,
+ height: null,
+ child: SuggestionSuccessBottomSheet(
+ userName: consultationModel.userName,
+ dietName: dietName,
+ ),
+ );
+ return;
+ }
+ if (!context.mounted) return;
+ showBottomSheetWithBlur(
+ userRootNavigator: true,
+ context: context,
+ height: null,
+ child: SuggestionFailureBottomSheet(
+ userName: consultationModel.userName,
+ dietName: dietName,
+ ),
+ );
+ },
+ ),
+ );
+ },
+ )
+ ],
+ ),
+ );
+ }
+}
+
+class SuggestDietBottomSheet extends StatefulWidget {
+ const SuggestDietBottomSheet({
+ super.key,
+ required this.userName,
+ required this.dietName,
+ required this.onTap,
+ });
+ final String userName;
+ final String dietName;
+ final Future Function() onTap;
+ @override
+ State createState() => _SuggestDietBottomSheet();
+}
+
+class _SuggestDietBottomSheet extends State {
+ @override
+ Widget build(BuildContext context) {
+ final s = S.of(context);
+ return Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 12.0),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ const SizedBox(
+ height: 8,
+ ),
+ const BottomSheetHandlerBar(),
+ const SizedBox(
+ height: 20,
+ ),
+ Text('Предложение диеты', style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black)),
+ const SizedBox(
+ height: 16,
+ ),
+ Text(
+ 'Предложить пользователю ${widget.userName} «${widget.dietName}»',
+ style: TextStyles.textSMedium.copyWith(color: appTheme.black),
+ textAlign: TextAlign.center,
+ ),
+ const SizedBox(
+ height: 8,
+ ),
+ CustomOutlinedButton(
+ text: s.toOffer,
+ height: 52,
+ buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
+ buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)),
+ onPressed: widget.onTap,
+ ),
+ const SizedBox(
+ height: 40,
+ ),
+ ],
+ ),
+ );
+ }
+}
+
+class SuggestionSuccessBottomSheet extends StatefulWidget {
+ const SuggestionSuccessBottomSheet({
+ super.key,
+ required this.userName,
+ required this.dietName,
+ });
+ final String userName;
+ final String dietName;
+
+ @override
+ State createState() => _SuggestionSuccessBottomSheet();
+}
+
+class _SuggestionSuccessBottomSheet extends State {
+ @override
+ Widget build(BuildContext context) {
+ final s = S.of(context);
+ return Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 12.0),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ const SizedBox(
+ height: 8,
+ ),
+ const BottomSheetHandlerBar(),
+ const SizedBox(
+ height: 20,
+ ),
+ Text('Предложение диеты', style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black)),
+ const SizedBox(
+ height: 16,
+ ),
+ Text(
+ '«${widget.dietName}» предложена пользователю ${widget.userName}',
+ style: TextStyles.textSMedium.copyWith(color: appTheme.black),
+ textAlign: TextAlign.center,
+ ),
+ const SizedBox(
+ height: 8,
+ ),
+ CustomOutlinedButton(
+ text: s.ok,
+ height: 52,
+ buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
+ buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)),
+ onPressed: () async {
+ AppRouter.navigatorKey.currentContext?.pop();
+ },
+ ),
+ const SizedBox(
+ height: 40,
+ ),
+ ],
+ ),
+ );
+ }
+}
+
+class SuggestionFailureBottomSheet extends StatefulWidget {
+ const SuggestionFailureBottomSheet({
+ super.key,
+ required this.userName,
+ required this.dietName,
+ });
+ final String userName;
+ final String dietName;
+
+ @override
+ State createState() => _SuggestionFailureBottomSheet();
+}
+
+class _SuggestionFailureBottomSheet extends State {
+ @override
+ Widget build(BuildContext context) {
+ final s = S.of(context);
+ return Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 12.0),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ const SizedBox(
+ height: 8,
+ ),
+ const BottomSheetHandlerBar(),
+ const SizedBox(
+ height: 20,
+ ),
+ Text('Предложение диеты', style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black)),
+ const SizedBox(
+ height: 16,
+ ),
+ Text(
+ 'Не удалось предложить диету ${widget.dietName} пользователю ${widget.userName}',
+ style: TextStyles.textSMedium.copyWith(color: appTheme.black),
+ textAlign: TextAlign.center,
+ ),
+ const SizedBox(
+ height: 8,
+ ),
+ CustomOutlinedButton(
+ text: s.ok,
+ height: 52,
+ buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
+ buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)),
+ onPressed: () async {
+ AppRouter.navigatorKey.currentContext?.pop();
+ },
+ ),
+ const SizedBox(
+ height: 40,
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/features/personal_diet_suggestion/presentation/personal_diet_suggestion_screen.dart b/lib/features/personal_diet_suggestion/presentation/personal_diet_suggestion_screen.dart
new file mode 100644
index 00000000..dad76406
--- /dev/null
+++ b/lib/features/personal_diet_suggestion/presentation/personal_diet_suggestion_screen.dart
@@ -0,0 +1,69 @@
+import 'package:eatvio_app/core/locator_service.dart';
+import 'package:eatvio_app/core/theme/custom_text_style.dart';
+import 'package:eatvio_app/core/theme/theme_helper.dart';
+import 'package:eatvio_app/core/widgets/loader.dart';
+import 'package:eatvio_app/features/personal_diet_suggestion/cubit/personal_diet_suggestion_cubit.dart';
+import 'package:eatvio_app/features/personal_diet_suggestion/cubit/personal_diet_suggestion_state.dart';
+import 'package:eatvio_app/features/personal_diet_suggestion/presentation/consultation_widget.dart';
+import 'package:eatvio_app/generated/l10n.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class PersonalDietSuggestionScreen extends StatelessWidget {
+ final int dietId;
+ const PersonalDietSuggestionScreen({super.key, required this.dietId});
+ static const path = '/personal-diet-suggestion';
+ static const name = 'personalDietSuggestion';
+ @override
+ Widget build(BuildContext context) {
+ return BlocProvider(
+ create: (context) => sl()..getConsultationWithPersonalDiets(dietId),
+ child: const PersonalDietSuggestionScreenContent(),
+ );
+ }
+}
+
+class PersonalDietSuggestionScreenContent extends StatelessWidget {
+ const PersonalDietSuggestionScreenContent({super.key});
+ @override
+ Widget build(BuildContext context) {
+ final s = S.of(context);
+ return BlocBuilder(
+ builder: (context, state) {
+ return Scaffold(
+ backgroundColor: appTheme.gray100,
+ appBar: AppBar(
+ centerTitle: true,
+ title: Text(
+ '${s.dietSuggestion}\n«${state.dietName}»',
+ style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
+ ),
+ ),
+ body: state.isLoading
+ ? const Center(child: Loader())
+ : SingleChildScrollView(
+ child: Column(
+ children: [
+ ...List.generate(state.consultationsWithDiet.length, (index) {
+ return ConsultationWidget(
+ consultationModel: state.consultationsWithDiet[index],
+ dietName: state.dietName,
+ );
+ }),
+ const SizedBox(
+ height: 12,
+ ),
+ ...List.generate(state.consultationsWithoutDiet.length, (index) {
+ return ConsultationWidget(
+ consultationModel: state.consultationsWithoutDiet[index],
+ dietName: state.dietName,
+ );
+ })
+ ],
+ ),
+ ),
+ );
+ },
+ );
+ }
+}
diff --git a/lib/features/personal_diet_suggestion/repository/personal_diet_suggestion_repository.dart b/lib/features/personal_diet_suggestion/repository/personal_diet_suggestion_repository.dart
new file mode 100644
index 00000000..23c32436
--- /dev/null
+++ b/lib/features/personal_diet_suggestion/repository/personal_diet_suggestion_repository.dart
@@ -0,0 +1,32 @@
+import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
+import 'package:eatvio_app/features/personal_diet_suggestion/services/personal_diet_suggestion_service.dart';
+
+class PersonalDietSuggestionRepository {
+ final PersonalDietSuggestionService personalDietSuggestionService;
+
+ PersonalDietSuggestionRepository({required this.personalDietSuggestionService});
+
+ Future> getConsultationWithPersonalDiets() async{
+ try {
+ return (await personalDietSuggestionService.getConsultationWithPersonalDiets()).data;
+ } catch (e) {
+ rethrow;
+ }
+ }
+
+ Future attachPersonalDiet({required int consultationId, required int dietId}) {
+ try {
+ return personalDietSuggestionService.attachPersonalDiet(consultationId: consultationId, dietId: dietId);
+ } catch (e) {
+ rethrow;
+ }
+ }
+
+ Future reattachPersonalDiet({required int consultationId, required int dietId}) {
+ try {
+ return personalDietSuggestionService.reattachPersonalDiet(consultationId: consultationId, dietId: dietId);
+ } catch (e) {
+ rethrow;
+ }
+ }
+}
diff --git a/lib/features/personal_diet_suggestion/services/personal_diet_suggestion_service.dart b/lib/features/personal_diet_suggestion/services/personal_diet_suggestion_service.dart
new file mode 100644
index 00000000..0a10c26e
--- /dev/null
+++ b/lib/features/personal_diet_suggestion/services/personal_diet_suggestion_service.dart
@@ -0,0 +1,36 @@
+import 'package:dio/dio.dart';
+import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
+
+class PersonalDietSuggestionService {
+ final Dio dio;
+ PersonalDietSuggestionService(this.dio);
+
+ Future getConsultationWithPersonalDiets() async {
+ try {
+ final response = await dio.get('/api/consultations', queryParameters: {
+ 'filters[plan][has_personal_diet][\$personal_diet]': '1',
+ 'filters[last_state][\$notIn][]': ['done', 'charge_was_collected', 'complained', 'last_day_finished', 'canceled_by_the_initiator', 'inited'],
+ 'sort[]': 'start_date:desc',
+ });
+ return ConsultationPaginationModel.fromJson(response.data);
+ } catch (e) {
+ rethrow;
+ }
+ }
+
+ Future attachPersonalDiet({required int consultationId, required int dietId}) async {
+ try {
+ await dio.post('/api/chosen_plans/$consultationId/attach_diet', data: {'diet_id': dietId});
+ } catch (e) {
+ rethrow;
+ }
+ }
+
+ Future reattachPersonalDiet({required int consultationId, required int dietId}) async {
+ try {
+ await dio.post('/api/chosen_plans/$consultationId/re_attach_diet', data: {'diet_id': dietId});
+ } catch (e) {
+ rethrow;
+ }
+ }
+}
diff --git a/lib/features/plans/enums/chosen_plan_state_enum.dart b/lib/features/plans/enums/chosen_plan_state_enum.dart
index 0b768d5f..2f37ec30 100644
--- a/lib/features/plans/enums/chosen_plan_state_enum.dart
+++ b/lib/features/plans/enums/chosen_plan_state_enum.dart
@@ -27,6 +27,8 @@ enum ChosenPlanStateEnum {
stateComplained,
@JsonValue('done')
stateDone,
+ @JsonValue('personal_diet_setted')
+ personalDietSet,
@JsonValue('charge_was_collected')
stateChargeWasCollected;
@@ -40,6 +42,7 @@ enum ChosenPlanStateEnum {
ChosenPlanStateEnum.stateLastDayFinished,
ChosenPlanStateEnum.stateDone,
ChosenPlanStateEnum.stateInProgress,
+ ChosenPlanStateEnum.personalDietSet,
];
}
@@ -64,7 +67,8 @@ enum ChosenPlanStateEnum {
ChosenPlanStateEnum.stateLastDayStarted,
ChosenPlanStateEnum.stateLastDayFinished,
ChosenPlanStateEnum.stateComplained,
- ChosenPlanStateEnum.stateDone
+ ChosenPlanStateEnum.stateDone,
+ ChosenPlanStateEnum.personalDietSet
];
}
}
diff --git a/lib/features/plans/presentation/pages/about_plan_screen.dart b/lib/features/plans/presentation/pages/about_plan_screen.dart
index 64a437c1..4ab8dd24 100644
--- a/lib/features/plans/presentation/pages/about_plan_screen.dart
+++ b/lib/features/plans/presentation/pages/about_plan_screen.dart
@@ -505,12 +505,15 @@ class _AboutPlanScreenState extends State {
switch (state.chosenOptionIndex) {
1 => OptionWidget(
option: state.planModel?.packet2Options,
+ duration: state.planModel?.duration ?? 0,
),
2 => OptionWidget(
option: state.planModel?.packet3Options,
+ duration: state.planModel?.duration ?? 0,
),
_ => OptionWidget(
option: state.planModel?.packet1Options,
+ duration: state.planModel?.duration ?? 0,
),
},
const SizedBox(
diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart
index 907d842b..3402d123 100644
--- a/lib/generated/intl/messages_en.dart
+++ b/lib/generated/intl/messages_en.dart
@@ -138,6 +138,7 @@ class MessageLookup extends MessageLookupByLibrary {
"Если вы любите мучные продукты, но хотите придерживаться диеты, вам подходит диета с добавленим мучных блюд на основе цельнозерновых вариантов. В них больше сложных углеводов и клетчатки, что способствует длительному чувству сытости и поддерживает здоровье пищеварительной системы.",
),
"carbohydrates": MessageLookupByLibrary.simpleMessage("Углеводы"),
+ "changeDiet": MessageLookupByLibrary.simpleMessage("Заменить диету"),
"chargeApproved": MessageLookupByLibrary.simpleMessage("Выплата одобрена"),
"chargeCollectionFailed": MessageLookupByLibrary.simpleMessage(
"Не удалось оформить выплату",
@@ -158,6 +159,10 @@ class MessageLookup extends MessageLookupByLibrary {
"choose_plan_start_date": MessageLookupByLibrary.simpleMessage(
"Выберите дату старта плана питания",
),
+ "choose_plan_start_date_with_personal_diet":
+ MessageLookupByLibrary.simpleMessage(
+ "Выберите дату старта плана питания с учетом составления персональной диеты",
+ ),
"choose_start_diet_date": MessageLookupByLibrary.simpleMessage(
"Выберите дату старты диеты. Она отобразиться у Вас в дневнике",
),
@@ -165,6 +170,9 @@ class MessageLookup extends MessageLookupByLibrary {
"chose_plan_start_date_2": MessageLookupByLibrary.simpleMessage(
"Выберите дату старты плана. Она отобразиться в дневнике пользователя",
),
+ "chosenPlanStartDateDescr": MessageLookupByLibrary.simpleMessage(
+ "Дату старта плана можно выбрать не ранее, чем через два. Такое ограничение дается на создание персональной диеты",
+ ),
"circumference_empty": MessageLookupByLibrary.simpleMessage(
"Все замеры обязательны к заполнению",
),
@@ -246,6 +254,9 @@ class MessageLookup extends MessageLookupByLibrary {
"Не удалось обновить диету",
),
"country": MessageLookupByLibrary.simpleMessage("Страна"),
+ "createPersonalDiet": MessageLookupByLibrary.simpleMessage(
+ "Составьте персональную диету",
+ ),
"create_diet": MessageLookupByLibrary.simpleMessage("Создание диеты"),
"cunsutation_was_paid_successfully": MessageLookupByLibrary.simpleMessage(
"Поздравляем, консультация успешно оплачена",
@@ -274,6 +285,7 @@ class MessageLookup extends MessageLookupByLibrary {
"deleted": MessageLookupByLibrary.simpleMessage("Удалена"),
"diary": MessageLookupByLibrary.simpleMessage("Дневник"),
"diet": MessageLookupByLibrary.simpleMessage("Диета"),
+ "dietSuggestion": MessageLookupByLibrary.simpleMessage("Предложение диеты"),
"diet_author": MessageLookupByLibrary.simpleMessage("Автор диеты"),
"diet_has_been_sent_to_draft": MessageLookupByLibrary.simpleMessage(
"снята с публикации и перенесена в черновик",
@@ -393,6 +405,9 @@ class MessageLookup extends MessageLookupByLibrary {
"from_z_to_a": MessageLookupByLibrary.simpleMessage("Название: Я-А"),
"gallery": MessageLookupByLibrary.simpleMessage("Галерея"),
"general_info": MessageLookupByLibrary.simpleMessage("Общая информация"),
+ "goToMyDiets": MessageLookupByLibrary.simpleMessage(
+ "Перейти к моим диетам",
+ ),
"go_to_diary": MessageLookupByLibrary.simpleMessage("Перейти в дневник"),
"gr": MessageLookupByLibrary.simpleMessage("гр"),
"grams": MessageLookupByLibrary.simpleMessage("гр"),
@@ -570,6 +585,12 @@ class MessageLookup extends MessageLookupByLibrary {
"pcs": MessageLookupByLibrary.simpleMessage("шт"),
"pending_payment": MessageLookupByLibrary.simpleMessage("Ожидается оплата"),
"personal": MessageLookupByLibrary.simpleMessage("Персональные"),
+ "personalDietCreating": MessageLookupByLibrary.simpleMessage(
+ "Составление индивидуальной диеты",
+ ),
+ "personal_diet_set": MessageLookupByLibrary.simpleMessage(
+ "Персональная диета установлена",
+ ),
"personal_diet_state": MessageLookupByLibrary.simpleMessage("Персональная"),
"photo": MessageLookupByLibrary.simpleMessage("Фото"),
"physical_fitness": MessageLookupByLibrary.simpleMessage(
@@ -699,6 +720,7 @@ class MessageLookup extends MessageLookupByLibrary {
"successfully_published": MessageLookupByLibrary.simpleMessage(
"успешно опубликован",
),
+ "suggestDiet": MessageLookupByLibrary.simpleMessage("Предложить диету"),
"suicide": MessageLookupByLibrary.simpleMessage("Склонение к самоубийству"),
"takes_pills": MessageLookupByLibrary.simpleMessage("Принимает лекарства"),
"tap_on_link_to_pay": MessageLookupByLibrary.simpleMessage(
diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart
index c987d1e5..71f87fc9 100644
--- a/lib/generated/l10n.dart
+++ b/lib/generated/l10n.dart
@@ -3434,6 +3434,86 @@ class S {
);
}
+ /// `Составление индивидуальной диеты`
+ String get personalDietCreating {
+ return Intl.message(
+ 'Составление индивидуальной диеты',
+ name: 'personalDietCreating',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Предложение диеты`
+ String get dietSuggestion {
+ return Intl.message(
+ 'Предложение диеты',
+ name: 'dietSuggestion',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Предложить диету`
+ String get suggestDiet {
+ return Intl.message(
+ 'Предложить диету',
+ name: 'suggestDiet',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Заменить диету`
+ String get changeDiet {
+ return Intl.message(
+ 'Заменить диету',
+ name: 'changeDiet',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Выберите дату старта плана питания с учетом составления персональной диеты`
+ String get choose_plan_start_date_with_personal_diet {
+ return Intl.message(
+ 'Выберите дату старта плана питания с учетом составления персональной диеты',
+ name: 'choose_plan_start_date_with_personal_diet',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Дату старта плана можно выбрать не ранее, чем через два. Такое ограничение дается на создание персональной диеты`
+ String get chosenPlanStartDateDescr {
+ return Intl.message(
+ 'Дату старта плана можно выбрать не ранее, чем через два. Такое ограничение дается на создание персональной диеты',
+ name: 'chosenPlanStartDateDescr',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Составьте персональную диету`
+ String get createPersonalDiet {
+ return Intl.message(
+ 'Составьте персональную диету',
+ name: 'createPersonalDiet',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Перейти к моим диетам`
+ String get goToMyDiets {
+ return Intl.message(
+ 'Перейти к моим диетам',
+ name: 'goToMyDiets',
+ desc: '',
+ args: [],
+ );
+ }
+
/// `Удаление аккаунта`
String get accountDeleting {
return Intl.message(
@@ -3504,6 +3584,16 @@ class S {
return Intl.message('Покупатель', name: 'customer', desc: '', args: []);
}
+ /// `Персональная диета установлена`
+ String get personal_diet_set {
+ return Intl.message(
+ 'Персональная диета установлена',
+ name: 'personal_diet_set',
+ desc: '',
+ args: [],
+ );
+ }
+
/// `Поздравляем!`
String get congratulations {
return Intl.message(
diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb
index 916fdcfa..c64c0321 100644
--- a/lib/l10n/intl_en.arb
+++ b/lib/l10n/intl_en.arb
@@ -408,6 +408,14 @@
"copy": "Скопировать",
"reply": "Ответить",
"deleteComment": "Удалить комментарий",
+ "personalDietCreating": "Составление индивидуальной диеты",
+ "dietSuggestion": "Предложение диеты",
+ "suggestDiet": "Предложить диету",
+ "changeDiet": "Заменить диету",
+ "choose_plan_start_date_with_personal_diet": "Выберите дату старта плана питания с учетом составления персональной диеты",
+ "chosenPlanStartDateDescr": "Дату старта плана можно выбрать не ранее, чем через два. Такое ограничение дается на создание персональной диеты",
+ "createPersonalDiet": "Составьте персональную диету",
+ "goToMyDiets": "Перейти к моим диетам",
"accountDeleting": "Удаление аккаунта",
"youShureYouWantToDeleteAccount": "Вы уверены, что хотите удалить аккаунт?",
"itCantBeRecovered": "Его нельзя будет восстановить",
@@ -416,6 +424,7 @@
"resend": "Отправить повторно",
"notifications": "Уведомления",
"customer": "Покупатель",
+ "personal_diet_set": "Персональная диета установлена",
"congratulations": "Поздравляем!",
"youWithUs": "Вы с итвио уже\n",
"fourteenDays": "14 дней",
diff --git a/pubspec.yaml b/pubspec.yaml
index 75b80445..d3819b86 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
name: eatvio_app
description: A new Flutter project.
-version: 1.3.2+81
+version: 1.3.3+82
publish_to: 'none'
environment: