diff --git a/assets/icons/reversed_exclamation_mark.svg b/assets/icons/reversed_exclamation_mark.svg
new file mode 100644
index 00000000..77b506bc
--- /dev/null
+++ b/assets/icons/reversed_exclamation_mark.svg
@@ -0,0 +1,4 @@
+
diff --git a/lib/core/app_router.dart b/lib/core/app_router.dart
index 78d7d25f..bee9eaf8 100644
--- a/lib/core/app_router.dart
+++ b/lib/core/app_router.dart
@@ -241,12 +241,10 @@ class AppRouter {
path: '/chat-screen',
name: 'chatScreen',
builder: (context, state) {
- final data = state.extra as Map;
- final chatsCubit = data['chatsCubit'] as ChatsCubit;
+ final data = state.extra as Map;
final chatId = data['chatId'] as String;
return ChatScreen(
- chatId: chatId,
- chatsCubit: chatsCubit,
+ chatId: chatId,
);
},
),
diff --git a/lib/core/const.dart b/lib/core/const.dart
index dfeae1fc..0b91d766 100644
--- a/lib/core/const.dart
+++ b/lib/core/const.dart
@@ -1,5 +1,5 @@
-String baseUrl = 'https://eatvio.ru';
-// String baseUrl = 'https://dev2.eatvio.com';
+// String baseUrl = 'https://eatvio.ru';
+String baseUrl = 'https://dev2.eatvio.com';
const List durationValues = [7, 14, 21];
@@ -8,4 +8,4 @@ const List planTypeValues = ['fit', 'slim', 'wellness', 'behavior'];
const newMessagesChannelName = 'private-new-chat-messages';
const newNotificationsChannelName = 'private-message-events';
-const directChatChannelName = 'private-direct-chat';
+const directChatChannelName = 'private-direct-chat';
\ No newline at end of file
diff --git a/lib/core/locator_service.dart b/lib/core/locator_service.dart
index 7e79faf4..cfca3868 100644
--- a/lib/core/locator_service.dart
+++ b/lib/core/locator_service.dart
@@ -87,6 +87,7 @@ Future init() async {
sl.registerLazySingleton(() => NotificationsCubit(wsManager: sl()));
sl.registerLazySingleton(() => FeedCubit(feedRepository: sl()));
sl.registerLazySingleton(() => ProfileAvatarCubit(profileRepository: sl()));
+ sl.registerLazySingleton(() => ChatsCubit(chatRepository: sl(), wsManager: sl(), profileRepository: sl()));
// Cubit factories
sl.registerFactory(() => RegistrationCubit(registrationRepository: sl()));
@@ -96,8 +97,7 @@ Future init() async {
sl.registerFactory(() => ProfileCubit(profileRepository: sl(), chatRepository: sl()));
sl.registerFactory(() => profilePlans.PlansCubit(plansRepository: sl()));
sl.registerFactory(() => DietsCubit(feedRepository: sl(), dietsRepository: sl()));
- sl.registerFactory(() => CommentsCubit(feedRepository: sl()));
- sl.registerFactory(() => ChatsCubit(chatRepository: sl(), wsManager: sl(), profileRepository: sl()));
+ sl.registerFactory(() => CommentsCubit(feedRepository: sl()));
sl.registerFactory(() => PlansCubit(feedRepository: sl(), planRepository: sl()));
sl.registerFactory(() => SettingsCubit(profileRepository: sl(), settingsRepository: sl()));
sl.registerFactory(() => RegisterConsultantCubit(consultantRepository: sl()));
diff --git a/lib/features/chat/presentation/pages/chat_screen.dart b/lib/features/chat/presentation/pages/chat_screen.dart
index 4144fbd5..4b2d8b94 100644
--- a/lib/features/chat/presentation/pages/chat_screen.dart
+++ b/lib/features/chat/presentation/pages/chat_screen.dart
@@ -11,6 +11,7 @@ import 'package:eatvio_app/features/chat/presentation/widgets/chat_bubble_widget
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/features/chat/presentation/widgets/notification_banner.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -19,10 +20,8 @@ import 'package:visibility_detector/visibility_detector.dart';
class ChatScreen extends StatefulWidget {
final String chatId;
- final ChatsCubit chatsCubit;
const ChatScreen({
required this.chatId,
- required this.chatsCubit,
super.key,
});
@@ -174,7 +173,9 @@ class _ChatScreenState extends State {
() async {
final result = await context.read().markMessagesAsRead(state.chatRoom.id, unreadMessagesIdsCopy);
if (!result) return;
- widget.chatsCubit.reduceUnreadMessagesCount(chatId: state.chatRoom.id, count: unreadMessagesIdsCopy.length);
+ context
+ .read()
+ .reduceUnreadMessagesCount(chatId: state.chatRoom.id, count: unreadMessagesIdsCopy.length);
unreadMessagesIdsCopy.clear();
},
);
@@ -203,7 +204,7 @@ class _ChatScreenState extends State {
() async {
final result = await context.read().markMessagesAsRead(state.chatRoom.id, unreadMessagesIds);
if (!result) return;
- widget.chatsCubit.reduceUnreadMessagesCount(chatId: state.chatRoom.id, count: unreadMessagesIds.length);
+ context.read().reduceUnreadMessagesCount(chatId: state.chatRoom.id, count: unreadMessagesIds.length);
unreadMessagesIds.clear();
},
);
diff --git a/lib/features/chat/presentation/widgets/chat_entry_widget.dart b/lib/features/chat/presentation/widgets/chat_entry_widget.dart
index 61e6ea17..66e0d700 100644
--- a/lib/features/chat/presentation/widgets/chat_entry_widget.dart
+++ b/lib/features/chat/presentation/widgets/chat_entry_widget.dart
@@ -28,7 +28,6 @@ class _ChatEntryWidgetState extends State {
'chatScreen',
extra: {
'chatId': widget.chatRoom.id.toString(),
- 'chatsCubit': context.read(),
},
),
child: Ink(
diff --git a/lib/features/chat/presentation/widgets/notification_banner.dart b/lib/features/chat/presentation/widgets/notification_banner.dart
new file mode 100644
index 00000000..5d3c8097
--- /dev/null
+++ b/lib/features/chat/presentation/widgets/notification_banner.dart
@@ -0,0 +1,77 @@
+import 'package:eatvio_app/core/theme/custom_text_style.dart';
+import 'package:eatvio_app/core/theme/theme_helper.dart';
+import 'package:eatvio_app/generated/l10n.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+
+class NotificationBanner extends StatelessWidget {
+ const NotificationBanner({super.key, required this.bannerType});
+ final BannerType bannerType;
+ @override
+ Widget build(BuildContext context) {
+ final size = MediaQuery.sizeOf(context);
+ final s = S.of(context);
+ return Container(
+ decoration: BoxDecoration(
+ color: appTheme.gray50,
+ borderRadius: BorderRadius.circular(20),
+ ),
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(top: 12, right: 8, left: 12),
+ child: SvgPicture.asset('assets/icons/reversed_exclamation_mark.svg', height: 68, width: 68),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(top: 16),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: switch (bannerType) {
+ BannerType.date => [
+ SizedBox(
+ width: size.width * 0.6,
+ child: Text(s.can_not_choose_start_date, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
+ ),
+ SizedBox(height: 12),
+ GestureDetector(
+ onTap: () {},
+ child: Text(s.add_card, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
+ ),
+ SizedBox(height: 16),
+ ],
+ BannerType.card => [
+ SizedBox(
+ width: size.width * 0.6,
+ child: Text(s.can_not_choose_start_date, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
+ ),
+ SizedBox(height: 12),
+ GestureDetector(
+ onTap: () {},
+ child: Text(s.add_card, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
+ ),
+ SizedBox(height: 16),
+ ],
+ BannerType.payment => [
+ SizedBox(
+ width: size.width * 0.6,
+ child: Text(s.can_not_choose_start_date, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
+ ),
+ SizedBox(height: 12),
+ GestureDetector(
+ onTap: () {},
+ child: Text(s.add_card, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
+ ),
+ SizedBox(height: 16),
+ ],
+ },
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
+
+enum BannerType { date, card, payment }
diff --git a/lib/features/plans/models/chosen_plan_model.dart b/lib/features/plans/models/chosen_plan_model.dart
new file mode 100644
index 00000000..525418b2
--- /dev/null
+++ b/lib/features/plans/models/chosen_plan_model.dart
@@ -0,0 +1,20 @@
+import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart';
+import 'package:freezed_annotation/freezed_annotation.dart';
+
+part 'chosen_plan_model.freezed.dart';
+part 'chosen_plan_model.g.dart';
+
+@freezed
+class ChosenPlanModel with _$ChosenPlanModel {
+
+ factory ChosenPlanModel({
+ @JsonKey() required int id,
+ @JsonKey(name: 'option_type') required String optionType,
+ @JsonKey(name: 'start_date') required DateTime startDate,
+ @JsonKey(name: 'chat_id') required String chatId,
+ @JsonKey(name: 'plan') required PlanModel plan,
+
+ }) = _ChosenPlanModel;
+
+ factory ChosenPlanModel.fromJson(Map json) => _$ChosenPlanModelFromJson(json);
+}
\ No newline at end of file
diff --git a/lib/features/plans/models/chosen_plan_model.freezed.dart b/lib/features/plans/models/chosen_plan_model.freezed.dart
new file mode 100644
index 00000000..b26b04cd
--- /dev/null
+++ b/lib/features/plans/models/chosen_plan_model.freezed.dart
@@ -0,0 +1,283 @@
+// coverage:ignore-file
+// GENERATED CODE - DO NOT MODIFY BY HAND
+// ignore_for_file: type=lint
+// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
+
+part of 'chosen_plan_model.dart';
+
+// **************************************************************************
+// FreezedGenerator
+// **************************************************************************
+
+T _$identity(T value) => value;
+
+final _privateConstructorUsedError = UnsupportedError(
+ 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
+
+ChosenPlanModel _$ChosenPlanModelFromJson(Map json) {
+ return _ChosenPlanModel.fromJson(json);
+}
+
+/// @nodoc
+mixin _$ChosenPlanModel {
+ @JsonKey()
+ int get id => throw _privateConstructorUsedError;
+ @JsonKey(name: 'option_type')
+ String get optionType => throw _privateConstructorUsedError;
+ @JsonKey(name: 'start_date')
+ DateTime get startDate => throw _privateConstructorUsedError;
+ @JsonKey(name: 'chat_id')
+ String get chatId => throw _privateConstructorUsedError;
+ @JsonKey(name: 'plan')
+ PlanModel get plan => throw _privateConstructorUsedError;
+
+ /// Serializes this ChosenPlanModel to a JSON map.
+ Map toJson() => throw _privateConstructorUsedError;
+
+ /// Create a copy of ChosenPlanModel
+ /// with the given fields replaced by the non-null parameter values.
+ @JsonKey(includeFromJson: false, includeToJson: false)
+ $ChosenPlanModelCopyWith get copyWith =>
+ throw _privateConstructorUsedError;
+}
+
+/// @nodoc
+abstract class $ChosenPlanModelCopyWith<$Res> {
+ factory $ChosenPlanModelCopyWith(
+ ChosenPlanModel value, $Res Function(ChosenPlanModel) then) =
+ _$ChosenPlanModelCopyWithImpl<$Res, ChosenPlanModel>;
+ @useResult
+ $Res call(
+ {@JsonKey() int id,
+ @JsonKey(name: 'option_type') String optionType,
+ @JsonKey(name: 'start_date') DateTime startDate,
+ @JsonKey(name: 'chat_id') String chatId,
+ @JsonKey(name: 'plan') PlanModel plan});
+
+ $PlanModelCopyWith<$Res> get plan;
+}
+
+/// @nodoc
+class _$ChosenPlanModelCopyWithImpl<$Res, $Val extends ChosenPlanModel>
+ implements $ChosenPlanModelCopyWith<$Res> {
+ _$ChosenPlanModelCopyWithImpl(this._value, this._then);
+
+ // ignore: unused_field
+ final $Val _value;
+ // ignore: unused_field
+ final $Res Function($Val) _then;
+
+ /// Create a copy of ChosenPlanModel
+ /// with the given fields replaced by the non-null parameter values.
+ @pragma('vm:prefer-inline')
+ @override
+ $Res call({
+ Object? id = null,
+ Object? optionType = null,
+ Object? startDate = null,
+ Object? chatId = null,
+ Object? plan = null,
+ }) {
+ return _then(_value.copyWith(
+ id: null == id
+ ? _value.id
+ : id // ignore: cast_nullable_to_non_nullable
+ as int,
+ optionType: null == optionType
+ ? _value.optionType
+ : optionType // ignore: cast_nullable_to_non_nullable
+ as String,
+ startDate: null == startDate
+ ? _value.startDate
+ : startDate // ignore: cast_nullable_to_non_nullable
+ as DateTime,
+ chatId: null == chatId
+ ? _value.chatId
+ : chatId // ignore: cast_nullable_to_non_nullable
+ as String,
+ plan: null == plan
+ ? _value.plan
+ : plan // ignore: cast_nullable_to_non_nullable
+ as PlanModel,
+ ) as $Val);
+ }
+
+ /// Create a copy of ChosenPlanModel
+ /// with the given fields replaced by the non-null parameter values.
+ @override
+ @pragma('vm:prefer-inline')
+ $PlanModelCopyWith<$Res> get plan {
+ return $PlanModelCopyWith<$Res>(_value.plan, (value) {
+ return _then(_value.copyWith(plan: value) as $Val);
+ });
+ }
+}
+
+/// @nodoc
+abstract class _$$ChosenPlanModelImplCopyWith<$Res>
+ implements $ChosenPlanModelCopyWith<$Res> {
+ factory _$$ChosenPlanModelImplCopyWith(_$ChosenPlanModelImpl value,
+ $Res Function(_$ChosenPlanModelImpl) then) =
+ __$$ChosenPlanModelImplCopyWithImpl<$Res>;
+ @override
+ @useResult
+ $Res call(
+ {@JsonKey() int id,
+ @JsonKey(name: 'option_type') String optionType,
+ @JsonKey(name: 'start_date') DateTime startDate,
+ @JsonKey(name: 'chat_id') String chatId,
+ @JsonKey(name: 'plan') PlanModel plan});
+
+ @override
+ $PlanModelCopyWith<$Res> get plan;
+}
+
+/// @nodoc
+class __$$ChosenPlanModelImplCopyWithImpl<$Res>
+ extends _$ChosenPlanModelCopyWithImpl<$Res, _$ChosenPlanModelImpl>
+ implements _$$ChosenPlanModelImplCopyWith<$Res> {
+ __$$ChosenPlanModelImplCopyWithImpl(
+ _$ChosenPlanModelImpl _value, $Res Function(_$ChosenPlanModelImpl) _then)
+ : super(_value, _then);
+
+ /// Create a copy of ChosenPlanModel
+ /// with the given fields replaced by the non-null parameter values.
+ @pragma('vm:prefer-inline')
+ @override
+ $Res call({
+ Object? id = null,
+ Object? optionType = null,
+ Object? startDate = null,
+ Object? chatId = null,
+ Object? plan = null,
+ }) {
+ return _then(_$ChosenPlanModelImpl(
+ id: null == id
+ ? _value.id
+ : id // ignore: cast_nullable_to_non_nullable
+ as int,
+ optionType: null == optionType
+ ? _value.optionType
+ : optionType // ignore: cast_nullable_to_non_nullable
+ as String,
+ startDate: null == startDate
+ ? _value.startDate
+ : startDate // ignore: cast_nullable_to_non_nullable
+ as DateTime,
+ chatId: null == chatId
+ ? _value.chatId
+ : chatId // ignore: cast_nullable_to_non_nullable
+ as String,
+ plan: null == plan
+ ? _value.plan
+ : plan // ignore: cast_nullable_to_non_nullable
+ as PlanModel,
+ ));
+ }
+}
+
+/// @nodoc
+@JsonSerializable()
+class _$ChosenPlanModelImpl implements _ChosenPlanModel {
+ _$ChosenPlanModelImpl(
+ {@JsonKey() required this.id,
+ @JsonKey(name: 'option_type') required this.optionType,
+ @JsonKey(name: 'start_date') required this.startDate,
+ @JsonKey(name: 'chat_id') required this.chatId,
+ @JsonKey(name: 'plan') required this.plan});
+
+ factory _$ChosenPlanModelImpl.fromJson(Map json) =>
+ _$$ChosenPlanModelImplFromJson(json);
+
+ @override
+ @JsonKey()
+ final int id;
+ @override
+ @JsonKey(name: 'option_type')
+ final String optionType;
+ @override
+ @JsonKey(name: 'start_date')
+ final DateTime startDate;
+ @override
+ @JsonKey(name: 'chat_id')
+ final String chatId;
+ @override
+ @JsonKey(name: 'plan')
+ final PlanModel plan;
+
+ @override
+ String toString() {
+ return 'ChosenPlanModel(id: $id, optionType: $optionType, startDate: $startDate, chatId: $chatId, plan: $plan)';
+ }
+
+ @override
+ bool operator ==(Object other) {
+ return identical(this, other) ||
+ (other.runtimeType == runtimeType &&
+ other is _$ChosenPlanModelImpl &&
+ (identical(other.id, id) || other.id == id) &&
+ (identical(other.optionType, optionType) ||
+ other.optionType == optionType) &&
+ (identical(other.startDate, startDate) ||
+ other.startDate == startDate) &&
+ (identical(other.chatId, chatId) || other.chatId == chatId) &&
+ (identical(other.plan, plan) || other.plan == plan));
+ }
+
+ @JsonKey(includeFromJson: false, includeToJson: false)
+ @override
+ int get hashCode =>
+ Object.hash(runtimeType, id, optionType, startDate, chatId, plan);
+
+ /// Create a copy of ChosenPlanModel
+ /// with the given fields replaced by the non-null parameter values.
+ @JsonKey(includeFromJson: false, includeToJson: false)
+ @override
+ @pragma('vm:prefer-inline')
+ _$$ChosenPlanModelImplCopyWith<_$ChosenPlanModelImpl> get copyWith =>
+ __$$ChosenPlanModelImplCopyWithImpl<_$ChosenPlanModelImpl>(
+ this, _$identity);
+
+ @override
+ Map toJson() {
+ return _$$ChosenPlanModelImplToJson(
+ this,
+ );
+ }
+}
+
+abstract class _ChosenPlanModel implements ChosenPlanModel {
+ factory _ChosenPlanModel(
+ {@JsonKey() required final int id,
+ @JsonKey(name: 'option_type') required final String optionType,
+ @JsonKey(name: 'start_date') required final DateTime startDate,
+ @JsonKey(name: 'chat_id') required final String chatId,
+ @JsonKey(name: 'plan') required final PlanModel plan}) =
+ _$ChosenPlanModelImpl;
+
+ factory _ChosenPlanModel.fromJson(Map json) =
+ _$ChosenPlanModelImpl.fromJson;
+
+ @override
+ @JsonKey()
+ int get id;
+ @override
+ @JsonKey(name: 'option_type')
+ String get optionType;
+ @override
+ @JsonKey(name: 'start_date')
+ DateTime get startDate;
+ @override
+ @JsonKey(name: 'chat_id')
+ String get chatId;
+ @override
+ @JsonKey(name: 'plan')
+ PlanModel get plan;
+
+ /// Create a copy of ChosenPlanModel
+ /// with the given fields replaced by the non-null parameter values.
+ @override
+ @JsonKey(includeFromJson: false, includeToJson: false)
+ _$$ChosenPlanModelImplCopyWith<_$ChosenPlanModelImpl> get copyWith =>
+ throw _privateConstructorUsedError;
+}
diff --git a/lib/features/plans/models/chosen_plan_model.g.dart b/lib/features/plans/models/chosen_plan_model.g.dart
new file mode 100644
index 00000000..52ecbdb7
--- /dev/null
+++ b/lib/features/plans/models/chosen_plan_model.g.dart
@@ -0,0 +1,27 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'chosen_plan_model.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+_$ChosenPlanModelImpl _$$ChosenPlanModelImplFromJson(
+ Map json) =>
+ _$ChosenPlanModelImpl(
+ id: (json['id'] as num).toInt(),
+ optionType: json['option_type'] as String,
+ startDate: DateTime.parse(json['start_date'] as String),
+ chatId: json['chat_id'] as String,
+ plan: PlanModel.fromJson(json['plan'] as Map),
+ );
+
+Map _$$ChosenPlanModelImplToJson(
+ _$ChosenPlanModelImpl instance) =>
+ {
+ 'id': instance.id,
+ 'option_type': instance.optionType,
+ 'start_date': instance.startDate.toIso8601String(),
+ 'chat_id': instance.chatId,
+ 'plan': instance.plan,
+ };
diff --git a/lib/features/plans/presentation/cubit/about_plan_cubit.dart b/lib/features/plans/presentation/cubit/about_plan_cubit.dart
index 20ca860b..4cf93e12 100644
--- a/lib/features/plans/presentation/cubit/about_plan_cubit.dart
+++ b/lib/features/plans/presentation/cubit/about_plan_cubit.dart
@@ -1,8 +1,10 @@
import 'dart:developer';
+import 'package:dio/dio.dart';
import 'package:easy_debounce/easy_debounce.dart';
import 'package:eatvio_app/core/utils/toasts.dart';
import 'package:eatvio_app/features/diets/repositories/diet_repository.dart';
+import 'package:eatvio_app/features/plans/models/chosen_plan_model.dart';
import 'package:eatvio_app/features/plans/presentation/cubit/about_plan_state.dart';
import 'package:eatvio_app/features/plans/repositories/plan_repository.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -125,4 +127,27 @@ class AboutPlanCubit extends Cubit {
},
);
}
+
+ Future chosePlan() async {
+ try {
+ final slug = state.planModel?.slug;
+ final optionIndex = state.chosenOptionIndex;
+ if (slug != null) {
+ final optionName = _getOptionNameFromIndex(optionIndex);
+ final body = {'options_type': optionName};
+ return await planRepository.chosePlan(slug, body);
+ }
+ } on DioException catch (e, st) {
+ log(e.toString(), stackTrace: st);
+ } catch (e, st) {
+ log(e.toString(), stackTrace: st);
+ }
+ return null;
+ }
+
+ String _getOptionNameFromIndex(int index) => switch (index) {
+ 1 => 'options2',
+ 2 => 'options3',
+ _ => 'options1',
+ };
}
diff --git a/lib/features/plans/presentation/pages/about_plan_screen.dart b/lib/features/plans/presentation/pages/about_plan_screen.dart
index 0022a4f2..c34985a1 100644
--- a/lib/features/plans/presentation/pages/about_plan_screen.dart
+++ b/lib/features/plans/presentation/pages/about_plan_screen.dart
@@ -10,6 +10,7 @@ import 'package:eatvio_app/core/widgets/bookmark_button.dart';
import 'package:eatvio_app/core/widgets/data_error_widget.dart';
import 'package:eatvio_app/core/widgets/info_row.dart';
import 'package:eatvio_app/core/widgets/loader.dart';
+import 'package:eatvio_app/core/widgets/show_error_dialog.dart';
import 'package:eatvio_app/features/diets/presentation/widgets/author_card.dart';
import 'package:eatvio_app/features/diets/presentation/widgets/expandable_text.dart';
import 'package:eatvio_app/features/diets/presentation/widgets/info_bouble.dart';
@@ -30,6 +31,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_portal/flutter_portal.dart';
import 'package:flutter_svg/svg.dart';
+import 'package:go_router/go_router.dart';
import '../widgets/option_widget.dart';
@@ -217,17 +219,21 @@ class _AboutPlanScreenState extends State {
borderRadius: BorderRadius.circular(16),
),
backgroundColor: appTheme.greenA700,
- onPressed: () {
- /// TODO: добавить обработку покупки плана
- // showModalBottomSheet(
- // context: context,
- // builder: (context) => StartDietBottomSheet(
- // aboutDietCubit: context.read(),
- // ),
- // );
+ onPressed: () async {
+ final chosenPlan = await context.read().chosePlan();
+ if (chosenPlan == null) {
+ showErrorDialog(context, title: 'Не удалось заказать план');
+ return;
+ }
+ GoRouter.of(context).pushReplacementNamed(
+ 'chatScreen',
+ extra: {
+ 'chatId': chosenPlan.chatId,
+ },
+ );
},
label: Text(
- s.startDiet,
+ s.to_order,
style: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
),
),
diff --git a/lib/features/plans/repositories/plan_repository.dart b/lib/features/plans/repositories/plan_repository.dart
index 313ad8b1..75ca7a08 100644
--- a/lib/features/plans/repositories/plan_repository.dart
+++ b/lib/features/plans/repositories/plan_repository.dart
@@ -1,9 +1,9 @@
import 'dart:async';
import 'package:eatvio_app/features/diets/repositories/diet_repository.dart';
import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart';
+import 'package:eatvio_app/features/plans/models/chosen_plan_model.dart';
import 'package:eatvio_app/features/plans/services/plan_service.dart';
-
class PlanRepository {
final PlanService planService;
@@ -48,9 +48,15 @@ class PlanRepository {
}
}
+ Future chosePlan(String slug, Map option ) async {
+ try {
+ return await planService.chosePlan(slug: slug, option: option);
+ } catch (e) {
+ rethrow;
+ }
+ }
+
void emitLikesStateToFeed(LikesState state) => _planLikeStateStreamController.add(state);
void emitFavoriteStateToFeed(FavoriteState state) => _planFavoriteStateStreamController.add(state);
void emitCommentsStateToFeed(CommentsState state) => _planCommentsStateStreamController.add(state);
}
-
-
diff --git a/lib/features/plans/services/plan_service.dart b/lib/features/plans/services/plan_service.dart
index d8a49a90..8a179760 100644
--- a/lib/features/plans/services/plan_service.dart
+++ b/lib/features/plans/services/plan_service.dart
@@ -1,20 +1,18 @@
-
-
import 'package:dio/dio.dart';
import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart';
+import 'package:eatvio_app/features/plans/models/chosen_plan_model.dart';
import 'package:retrofit/retrofit.dart';
part 'plan_service.g.dart';
@RestApi()
abstract class PlanService {
-
factory PlanService(Dio dio, {String baseUrl}) = _PlanService;
@GET('/api/plans/show/{slug}')
Future getPlan(@Path('slug') String slug);
- @POST('/api/plans/{slug}/like')
+ @POST('/api/plans/{slug}/like')
Future likePlan({
@Path() required String slug,
});
@@ -28,4 +26,10 @@ abstract class PlanService {
Future removeFromFavorite({
@Path() required String slug,
});
-}
\ No newline at end of file
+
+ @POST('/api/plans/{slug}/choose')
+ Future chosePlan({
+ @Path() required String slug,
+ @Body() required Map option,
+ });
+}
diff --git a/lib/features/plans/services/plan_service.g.dart b/lib/features/plans/services/plan_service.g.dart
index 09f90b41..189f1e31 100644
--- a/lib/features/plans/services/plan_service.g.dart
+++ b/lib/features/plans/services/plan_service.g.dart
@@ -101,6 +101,37 @@ class _PlanService implements PlanService {
await _dio.fetch(_options);
}
+ @override
+ Future chosePlan({
+ required String slug,
+ required Map option,
+ }) async {
+ final _extra = {};
+ final queryParameters = {};
+ final _headers = {};
+ final _data = {};
+ _data.addAll(option);
+ final _options = _setStreamType(
+ Options(method: 'POST', headers: _headers, extra: _extra)
+ .compose(
+ _dio.options,
+ '/api/plans/${slug}/choose',
+ queryParameters: queryParameters,
+ data: _data,
+ )
+ .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
+ );
+ final _result = await _dio.fetch