forked from eatvio/eatvio_app
331 lines
16 KiB
Dart
331 lines
16 KiB
Dart
import 'package:collection/collection.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/custom_divider.dart';
|
|
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
|
import 'package:eatvio_app/core/widgets/show_error_dialog.dart';
|
|
import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
|
|
import 'package:eatvio_app/features/diary/presentation/pages/diary_screen.dart';
|
|
import 'package:eatvio_app/features/my_finance/presentation/pages/card_settings.dart';
|
|
import 'package:eatvio_app/features/plans/enums/chosen_plan_state_enum.dart';
|
|
import 'package:eatvio_app/features/user_details/presentation/user_details_screen.dart';
|
|
import 'package:eatvio_app/generated/l10n.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
|
|
class ConsultationCardWidget extends StatefulWidget {
|
|
final ConsultationModel consultationsModel;
|
|
|
|
const ConsultationCardWidget({super.key, required this.consultationsModel});
|
|
|
|
@override
|
|
State<ConsultationCardWidget> createState() => _ConsultationCardWidgetState();
|
|
}
|
|
|
|
class _ConsultationCardWidgetState extends State<ConsultationCardWidget> {
|
|
final List<String> titles = const [
|
|
'Дневник не заполнялся и никаких движений в тот день не было.',
|
|
'Начат дневник питания, но не закончен.',
|
|
'Дневник заполнен, но не прокомментирован консультантом.',
|
|
'Дневник закончен и прокомментирован консультантом но не просмотрен пользователем.',
|
|
'Дневник заполнен, прокомментирован консультантом и после этого клиент просмотрел комментарии.',
|
|
];
|
|
|
|
final List<Color> legendColors = const [Colors.white, Color(0xFFF0C497), Color(0xFFFF9500), Color(0xFF2F80ED), Color(0xFF4CD964)];
|
|
|
|
late final List<(int, DiaryModel)> givenDaysWithDayNumber;
|
|
final List<List<DiaryStateEnum>> legendStates = [
|
|
[DiaryStateEnum.init],
|
|
[DiaryStateEnum.started, DiaryStateEnum.lastDayStarted],
|
|
[DiaryStateEnum.finished, DiaryStateEnum.lastDayFinished],
|
|
[DiaryStateEnum.commented, DiaryStateEnum.lastDayCommented],
|
|
[DiaryStateEnum.reviewedByUser],
|
|
];
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
final startPlanDate = widget.consultationsModel.startDate;
|
|
givenDaysWithDayNumber = List.generate(widget.consultationsModel.diaries.length, (index) {
|
|
final dayNumber = widget.consultationsModel.diaries[index].date.difference(startPlanDate).inDays;
|
|
return (dayNumber, widget.consultationsModel.diaries[index]);
|
|
});
|
|
widget.consultationsModel.diaries;
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final s = S.of(context);
|
|
return Material(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(12),
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
GestureDetector(
|
|
onTap: () => GoRouter.of(context).pushNamed('profileScreen', extra: widget.consultationsModel.userSlug),
|
|
child: Row(
|
|
children: [
|
|
CircleAvatar(radius: 30, backgroundImage: NetworkImage(widget.consultationsModel.userProfilePhotoUrl)),
|
|
const SizedBox(width: 12),
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
widget.consultationsModel.userName,
|
|
style: const TextStyle(height: 1, color: Color(0xFF323F4B), fontSize: 16, fontWeight: FontWeight.w600),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
widget.consultationsModel.planTitle,
|
|
style: const TextStyle(height: 1, color: Color(0xFF88949F), fontSize: 14, fontWeight: FontWeight.w500),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
GestureDetector(
|
|
onTap: () {
|
|
GoRouter.of(context).pushNamed(UserDetailsScreen.name, extra: widget.consultationsModel.userSlug);
|
|
},
|
|
child: Text(
|
|
'Анкета пользователя',
|
|
style: TextStyle(
|
|
color: appTheme.blueA400,
|
|
decoration: TextDecoration.underline,
|
|
decorationColor: appTheme.blueA400,
|
|
fontWeight: FontWeight.w500,
|
|
height: 1,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
const CustomDivider(),
|
|
const SizedBox(height: 12),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text(
|
|
'День ${widget.consultationsModel.currentDiaryDay} из ${widget.consultationsModel.duration}',
|
|
style: const TextStyle(height: 1, color: Color(0xFF323F4B), fontSize: 16, fontWeight: FontWeight.w500),
|
|
),
|
|
GestureDetector(
|
|
onTap: () {
|
|
showModalBottomSheet(
|
|
context: context,
|
|
useSafeArea: true,
|
|
useRootNavigator: true,
|
|
showDragHandle: true,
|
|
builder: (context) => Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
const Text(
|
|
'Легенда',
|
|
style: TextStyle(height: 1, fontSize: 20, fontWeight: FontWeight.w700, color: Color(0xFF323F4B)),
|
|
),
|
|
const SizedBox(height: 16),
|
|
ListView.separated(
|
|
shrinkWrap: true,
|
|
physics: const NeverScrollableScrollPhysics(),
|
|
itemBuilder: (context, index) => _legendTitle(titles[index], legendColors[index]),
|
|
separatorBuilder: (context, index) => const SizedBox(height: 16),
|
|
itemCount: titles.length,
|
|
),
|
|
const SizedBox(height: 16),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
},
|
|
child: const Icon(Icons.help_outline_rounded, color: Color(0xFF323F4B), size: 20),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 16),
|
|
SingleChildScrollView(
|
|
scrollDirection: Axis.horizontal,
|
|
child: Row(
|
|
children: List.generate(widget.consultationsModel.duration, (index) {
|
|
final day = givenDaysWithDayNumber.firstWhereOrNull((e) => e.$1 == index);
|
|
final hasActivity = day != null && day.$2.state != DiaryStateEnum.init;
|
|
final canConsultantOpenThisDay =
|
|
day != null &&
|
|
(day.$2.state != DiaryStateEnum.init && day.$2.state != DiaryStateEnum.started && day.$2.state != DiaryStateEnum.lastDayStarted);
|
|
return Padding(
|
|
padding: const EdgeInsets.only(right: 12),
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.end,
|
|
children: [
|
|
InkWell(
|
|
onTap: () {
|
|
if (!hasActivity || !canConsultantOpenThisDay) {
|
|
showErrorDialog(
|
|
context,
|
|
title: s.you_can_not_open_this_day,
|
|
description: '${widget.consultationsModel.userName} ${s.has_not_filled_it_yet}',
|
|
);
|
|
return;
|
|
}
|
|
GoRouter.of(context).push(UserDiaryScreen.path, extra: {'diaryId': day.$2.id, 'currentDiaryDay': index + 1});
|
|
},
|
|
borderRadius: BorderRadius.circular(100),
|
|
child: Ink(
|
|
decoration: BoxDecoration(
|
|
color: hasActivity ? appTheme.dividerColor : appTheme.dividerColor.withValues(alpha: 0.4),
|
|
borderRadius: BorderRadius.circular(100),
|
|
),
|
|
width: 58,
|
|
height: 32,
|
|
child: Center(
|
|
child: Text(
|
|
(index + 1).toString(),
|
|
style: TextStyles.textMSemibold.copyWith(color: hasActivity ? appTheme.gray : appTheme.gray.withValues(alpha: 0.4)),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
if (hasActivity) ...[
|
|
const SizedBox(height: 4),
|
|
switch (day.$2.state) {
|
|
DiaryStateEnum.init => const SizedBox.shrink(),
|
|
DiaryStateEnum.started => Container(
|
|
width: 8,
|
|
height: 8,
|
|
decoration: BoxDecoration(shape: BoxShape.circle, color: legendColors[1]),
|
|
),
|
|
DiaryStateEnum.lastDayStarted => Container(
|
|
width: 8,
|
|
height: 8,
|
|
decoration: BoxDecoration(shape: BoxShape.circle, color: legendColors[1]),
|
|
),
|
|
DiaryStateEnum.finished => Container(
|
|
width: 8,
|
|
height: 8,
|
|
decoration: BoxDecoration(shape: BoxShape.circle, color: legendColors[2]),
|
|
),
|
|
DiaryStateEnum.lastDayFinished => Container(
|
|
width: 8,
|
|
height: 8,
|
|
decoration: BoxDecoration(shape: BoxShape.circle, color: legendColors[2]),
|
|
),
|
|
DiaryStateEnum.commented => Container(
|
|
width: 8,
|
|
height: 8,
|
|
decoration: BoxDecoration(shape: BoxShape.circle, color: legendColors[3]),
|
|
),
|
|
DiaryStateEnum.lastDayCommented => Container(
|
|
width: 8,
|
|
height: 8,
|
|
decoration: BoxDecoration(shape: BoxShape.circle, color: legendColors[3]),
|
|
),
|
|
DiaryStateEnum.reviewedByUser => Container(
|
|
width: 8,
|
|
height: 8,
|
|
decoration: BoxDecoration(shape: BoxShape.circle, color: legendColors[4]),
|
|
),
|
|
},
|
|
const SizedBox(height: 12),
|
|
] else
|
|
const SizedBox(height: 24),
|
|
],
|
|
),
|
|
);
|
|
}),
|
|
),
|
|
),
|
|
const CustomDivider(),
|
|
const SizedBox(height: 12),
|
|
Text(
|
|
'${widget.consultationsModel.consultationOptionPrice.toStringAsFixed(0)} ₽',
|
|
style: const TextStyle(color: Color(0xFF019A3E), fontSize: 20, fontWeight: FontWeight.w600),
|
|
),
|
|
const SizedBox(height: 16),
|
|
Row(
|
|
children: [
|
|
InkWell(
|
|
borderRadius: BorderRadius.circular(20),
|
|
onTap: () {
|
|
final lastActiveDay = givenDaysWithDayNumber
|
|
.where((e) => e.$2.state == DiaryStateEnum.finished || e.$2.state == DiaryStateEnum.lastDayFinished)
|
|
.lastOrNull;
|
|
if (lastActiveDay != null) {
|
|
GoRouter.of(context).push(UserDiaryScreen.path, extra: {'diaryId': lastActiveDay.$2.id, 'currentDiaryDay': lastActiveDay.$1});
|
|
return;
|
|
}
|
|
showErrorDialog(
|
|
context,
|
|
title: s.you_can_not_open_this_day,
|
|
description: '${widget.consultationsModel.userName} ${s.has_not_filled_it_yet}',
|
|
);
|
|
},
|
|
child: Ink(
|
|
width: MediaQuery.of(context).size.width - 32 - 52 - 8,
|
|
padding: const EdgeInsets.all(16),
|
|
decoration: BoxDecoration(borderRadius: BorderRadius.circular(20), color: appTheme.blueA400),
|
|
child: const Center(
|
|
child: Text(
|
|
'Комментировать отчёт',
|
|
style: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w600),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(width: 8),
|
|
InkWell(
|
|
borderRadius: BorderRadius.circular(20),
|
|
onTap: () {},
|
|
child: Ink(
|
|
height: 52,
|
|
width: 52,
|
|
decoration: BoxDecoration(borderRadius: BorderRadius.circular(20), color: const Color(0xFFF6F6F6)),
|
|
child: const Center(child: Icon(Icons.chat_outlined, size: 24)),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
// Кнопка получения выплаты
|
|
if (widget.consultationsModel.chosenPlanState == ChosenPlanStateEnum.stateDone) ...[
|
|
const SizedBox(height: 16),
|
|
CustomOutlinedButton(
|
|
text: s.collectCharge,
|
|
height: 52,
|
|
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
|
buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.green)),
|
|
onPressed: () async {
|
|
GoRouter.of(context).push(CardSettingsScreen.path, extra: widget.consultationsModel.id);
|
|
},
|
|
),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Row _legendTitle(String text, Color color) {
|
|
return Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Container(
|
|
height: 20,
|
|
width: 20,
|
|
decoration: BoxDecoration(shape: BoxShape.circle, color: color),
|
|
),
|
|
const SizedBox(width: 12),
|
|
Flexible(
|
|
child: Text(
|
|
text,
|
|
style: const TextStyle(height: 1, fontSize: 16, fontWeight: FontWeight.w500, color: Color(0xFF323F4B)),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|