forked from eatvio/eatvio_app
feat(personalDiets): diets suggestions
This commit is contained in:
@@ -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<DiaryModel> diaries,
|
||||
@JsonKey(name: 'personal_diet_id') required int? personalDietId,
|
||||
}) = _ConsultationModel;
|
||||
|
||||
factory ConsultationModel.fromJson(Map<String, dynamic> json) => _$ConsultationModelFromJson(json);
|
||||
|
||||
@@ -16,6 +16,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';
|
||||
@@ -89,7 +90,9 @@ class _MyDietWidgetState extends State<MyDietWidget> {
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Html(
|
||||
data: widget.diet.details.length > 200 ? '${widget.diet.details.substring(0, 200).replaceAll('\n', '<br>')}...' : widget.diet.details.replaceAll('\n', '<br>'),
|
||||
data: widget.diet.details.length > 200
|
||||
? '${widget.diet.details.substring(0, 200).replaceAll('\n', '<br>')}...'
|
||||
: widget.diet.details.replaceAll('\n', '<br>'),
|
||||
style: {
|
||||
"*": Style(
|
||||
margin: Margins.zero,
|
||||
@@ -128,6 +131,7 @@ class _MyDietWidgetState extends State<MyDietWidget> {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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<PersonalDietSuggestionState> {
|
||||
final DietRepository dietRepository;
|
||||
final PersonalDietSuggestionRepository personalDietSuggestionService;
|
||||
late final int dietId;
|
||||
PersonalDietSuggestionCubit({required this.dietRepository, required this.personalDietSuggestionService}) : super(PersonalDietSuggestionState());
|
||||
|
||||
Future<void> 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<void> 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<bool> 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<bool> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<ConsultationModel> consultationsWithDiet,
|
||||
@Default([]) List<ConsultationModel> consultationsWithoutDiet,
|
||||
@Default('') String dietName,
|
||||
@Default(false) bool isLoading,
|
||||
@Default(null) String? error,
|
||||
}) = _PersonalDietSuggestionState;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
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: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';
|
||||
|
||||
class ConsultationWidget extends StatelessWidget {
|
||||
const ConsultationWidget({super.key, required this.consultationModel});
|
||||
final ConsultationModel consultationModel;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
color: appTheme.whiteA700,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
ListTile(
|
||||
leading: Container(
|
||||
decoration: const BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Image.network(consultationModel.userProfilePhotoUrl),
|
||||
),
|
||||
),
|
||||
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 {
|
||||
context.read<PersonalDietSuggestionCubit>().reattachDietToConsultation(consultationId: consultationModel.id);
|
||||
},
|
||||
)
|
||||
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 {
|
||||
context.read<PersonalDietSuggestionCubit>().attachDietToConsultation(consultationId: consultationModel.id);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
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<PersonalDietSuggestionCubit>()..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<PersonalDietSuggestionCubit, PersonalDietSuggestionState>(
|
||||
builder: (context, state) {
|
||||
return Scaffold(
|
||||
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],
|
||||
);
|
||||
}),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
...List.generate(state.consultationsWithoutDiet.length, (index) {
|
||||
return ConsultationWidget(
|
||||
consultationModel: state.consultationsWithoutDiet[index],
|
||||
);
|
||||
})
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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<List<ConsultationModel>> getConsultationWithPersonalDiets() async{
|
||||
try {
|
||||
return (await personalDietSuggestionService.getConsultationWithPersonalDiets()).data;
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> attachPersonalDiet({required int consultationId, required int dietId}) {
|
||||
try {
|
||||
return personalDietSuggestionService.attachPersonalDiet(consultationId: consultationId, dietId: dietId);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> reattachPersonalDiet({required int consultationId, required int dietId}) {
|
||||
try {
|
||||
return personalDietSuggestionService.reattachPersonalDiet(consultationId: consultationId, dietId: dietId);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
|
||||
|
||||
class PersonalDietSuggestionService {
|
||||
final Dio dio;
|
||||
PersonalDietSuggestionService(this.dio);
|
||||
|
||||
Future<ConsultationPaginationModel> getConsultationWithPersonalDiets() async {
|
||||
try {
|
||||
final response =
|
||||
await dio.get('/api/consultations', queryParameters: {'filters[plan][has_personal_diet][\$personal_diet]': '1', 'sort[]': 'start_date:desc'});
|
||||
return ConsultationPaginationModel.fromJson(response.data);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> 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<void> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user