forked from eatvio/eatvio_app
fix: show personal diet name and consultant notifications
This commit is contained in:
@@ -194,6 +194,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
: mapConsultationProgress(
|
||||
state: chosenPlan.chosenPlanState,
|
||||
hasPersonalDiet: chosenOption?.hasPersonalDiet ?? false,
|
||||
personalDietName: chosenPlan.personalDietName,
|
||||
);
|
||||
final bannerType = resolveChatBanner(
|
||||
progress: progress,
|
||||
|
||||
@@ -24,6 +24,7 @@ abstract class ConsultationModel with _$ConsultationModel {
|
||||
@JsonKey(name: 'consultant_id') required int consultantId,
|
||||
required List<DiaryModel> diaries,
|
||||
@JsonKey(name: 'personal_diet_id') required int? personalDietId,
|
||||
@JsonKey(name: 'personal_diet_name') String? personalDietName,
|
||||
}) = _ConsultationModel;
|
||||
|
||||
factory ConsultationModel.fromJson(Map<String, dynamic> json) => _$ConsultationModelFromJson(json);
|
||||
|
||||
@@ -10,12 +10,14 @@ class ConsultationProgress {
|
||||
required this.showProgressPlank,
|
||||
required this.dietStatus,
|
||||
required this.phase,
|
||||
this.personalDietName,
|
||||
});
|
||||
|
||||
final Set<ConsultationStep> completedSteps;
|
||||
final bool showProgressPlank;
|
||||
final PersonalDietStatus dietStatus;
|
||||
final ConsultationPhase phase;
|
||||
final String? personalDietName;
|
||||
|
||||
bool isStepCompleted(ConsultationStep step) => completedSteps.contains(step);
|
||||
|
||||
|
||||
@@ -97,7 +97,12 @@ class _ConsultationCardWidgetState extends State<ConsultationCardWidget> {
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
),
|
||||
child: Text(
|
||||
s.personal_diet_proposed,
|
||||
widget.consultationsModel.personalDietName == null ||
|
||||
widget.consultationsModel.personalDietName!.isEmpty
|
||||
? s.personal_diet_proposed
|
||||
: s.personal_diet_proposed_named(
|
||||
widget.consultationsModel.personalDietName!,
|
||||
),
|
||||
style: TextStyles.textXSSemibold.copyWith(
|
||||
color: appTheme.greenA700,
|
||||
),
|
||||
|
||||
@@ -42,8 +42,12 @@ class PersonalDietStatusChip extends StatelessWidget {
|
||||
return (s.payment_failed, appTheme.lightRed, appTheme.red);
|
||||
}
|
||||
if (progress.dietStatus == PersonalDietStatus.proposed) {
|
||||
final dietName = progress.personalDietName;
|
||||
final label = dietName == null || dietName.isEmpty
|
||||
? s.personal_diet_proposed
|
||||
: s.personal_diet_proposed_named(dietName);
|
||||
return (
|
||||
s.personal_diet_proposed,
|
||||
label,
|
||||
appTheme.transparentGreen,
|
||||
appTheme.greenA700,
|
||||
);
|
||||
|
||||
@@ -4,12 +4,14 @@ import 'package:eatvio_app/features/plans/enums/chosen_plan_state_enum.dart';
|
||||
ConsultationProgress mapConsultationProgress({
|
||||
required ChosenPlanStateEnum state,
|
||||
required bool hasPersonalDiet,
|
||||
String? personalDietName,
|
||||
}) {
|
||||
return ConsultationProgress(
|
||||
completedSteps: _completedSteps(state),
|
||||
showProgressPlank: _showProgressPlank(state),
|
||||
dietStatus: _dietStatus(state, hasPersonalDiet),
|
||||
phase: _phase(state),
|
||||
personalDietName: personalDietName,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2174,6 +2174,56 @@ class PersonalDietIsDefinedToCustomerNotification implements BaseNotificationMod
|
||||
}
|
||||
}
|
||||
|
||||
class PersonalDietIsDefinedToAuthorNotification implements BaseNotificationModel {
|
||||
@override
|
||||
final NotificationType type;
|
||||
@override
|
||||
final bool isRead;
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
final int chosenPlanId;
|
||||
final int dietId;
|
||||
final String planName;
|
||||
final String userName;
|
||||
final String consultantName;
|
||||
final String dietName;
|
||||
final String role;
|
||||
final String peerSlug;
|
||||
final String peerImagePath;
|
||||
|
||||
PersonalDietIsDefinedToAuthorNotification({
|
||||
required this.type,
|
||||
required this.isRead,
|
||||
required this.createdAt,
|
||||
required this.chosenPlanId,
|
||||
required this.dietId,
|
||||
required this.planName,
|
||||
required this.userName,
|
||||
required this.consultantName,
|
||||
required this.dietName,
|
||||
required this.role,
|
||||
required this.peerSlug,
|
||||
required this.peerImagePath,
|
||||
});
|
||||
|
||||
factory PersonalDietIsDefinedToAuthorNotification.fromJson(Map<String, dynamic> json, NotificationType type, {bool? isRead, String? createdAt}) {
|
||||
return PersonalDietIsDefinedToAuthorNotification(
|
||||
type: type,
|
||||
isRead: isRead ?? false,
|
||||
createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()),
|
||||
chosenPlanId: json['chosen_plan_id'] ?? 0,
|
||||
dietId: json['diet_id'] ?? 0,
|
||||
planName: json['plan_name'] ?? '',
|
||||
userName: json['user_name'] ?? '',
|
||||
consultantName: json['consultant_name'] ?? '',
|
||||
dietName: json['diet_name'] ?? '',
|
||||
role: json['role']?.toString() ?? '',
|
||||
peerSlug: json['peer_slug'] ?? '',
|
||||
peerImagePath: json['peer_image_path'] ?? '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// New Model Classes for Comprehensive Support
|
||||
|
||||
class ConsultantEducationUpdatedNotification implements BaseNotificationModel {
|
||||
@@ -2480,6 +2530,7 @@ enum NotificationType {
|
||||
chosenPlanFinishedToConsultant,
|
||||
stayOnTrackToCustomer,
|
||||
personalDietIsDefinedToCustomer,
|
||||
personalDietIsDefinedToAuthor,
|
||||
|
||||
// Comments
|
||||
entityCommented,
|
||||
@@ -2602,6 +2653,7 @@ enum NotificationType {
|
||||
'stay-on-track-to-customer' => NotificationType.stayOnTrackToCustomer,
|
||||
'diary-reminder-for-users' => NotificationType.diaryReminderForUsers,
|
||||
'personal-diet-is-defined-to-customer' => NotificationType.personalDietIsDefinedToCustomer,
|
||||
'personal-diet-is-defined-to-author' => NotificationType.personalDietIsDefinedToAuthor,
|
||||
|
||||
// New additions
|
||||
'consultant-education-updated' => NotificationType.consultantEducationUpdated,
|
||||
|
||||
@@ -277,6 +277,12 @@ class NotificationsCubit extends Cubit<NotificationsState> {
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.personalDietIsDefinedToAuthor => PersonalDietIsDefinedToAuthorNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.consultantEducationUpdated => ConsultantEducationUpdatedNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
|
||||
@@ -122,6 +122,9 @@ class NotificationWidget extends StatelessWidget {
|
||||
PersonalDietIsDefinedToCustomerNotification() => _PersonalDietIsDefinedToCustomerWidget(
|
||||
notification: notification as PersonalDietIsDefinedToCustomerNotification,
|
||||
),
|
||||
PersonalDietIsDefinedToAuthorNotification() => _PersonalDietIsDefinedToAuthorWidget(
|
||||
notification: notification as PersonalDietIsDefinedToAuthorNotification,
|
||||
),
|
||||
// New Widgets
|
||||
ConsultantEducationUpdatedNotification() => _ConsultantEducationUpdatedWidget(notification: notification as ConsultantEducationUpdatedNotification),
|
||||
ComplaintRegisteredNotification() => _ComplaintRegisteredWidget(notification: notification as ComplaintRegisteredNotification),
|
||||
@@ -1273,6 +1276,27 @@ class _PersonalDietIsDefinedToCustomerWidget extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _PersonalDietIsDefinedToAuthorWidget extends StatelessWidget {
|
||||
const _PersonalDietIsDefinedToAuthorWidget({required this.notification});
|
||||
final PersonalDietIsDefinedToAuthorNotification notification;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final userName = notification.userName.isNotEmpty ? notification.userName : 'Пользователь';
|
||||
final dietName = notification.dietName.isNotEmpty ? ', выбранная диета: «${notification.dietName}»' : '';
|
||||
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: 'Вы предложили персональную диету пользователю $userName$dietName',
|
||||
createdAt: notification.createdAt,
|
||||
onTap: notification.peerSlug.isEmpty
|
||||
? null
|
||||
: () {
|
||||
context.push(RouteConstants.profileScreen, extra: notification.peerSlug);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ConsultantEducationUpdatedWidget extends StatelessWidget {
|
||||
const _ConsultantEducationUpdatedWidget({required this.notification});
|
||||
final ConsultantEducationUpdatedNotification notification;
|
||||
|
||||
@@ -413,6 +413,12 @@ class NotificationsService {
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.personalDietIsDefinedToAuthor => PersonalDietIsDefinedToAuthorNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.consultantEducationUpdated => ConsultantEducationUpdatedNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
|
||||
@@ -15,6 +15,7 @@ abstract class ChosenPlanModel with _$ChosenPlanModel {
|
||||
@JsonKey(name: 'last_state') required ChosenPlanStateEnum chosenPlanState,
|
||||
@JsonKey(name: 'chat_id') required String chatId,
|
||||
@JsonKey(name: 'consultant_id') required int consultantId,
|
||||
@JsonKey(name: 'personal_diet_name') String? personalDietName,
|
||||
@JsonKey(name: 'plan') required PlanModel plan,
|
||||
}) = _ChosenPlanModel;
|
||||
|
||||
|
||||
@@ -28,36 +28,38 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
static String m2(dietDuration, dietDayWord, planDuration, planDayWord) =>
|
||||
"Not suitable: diet lasts ${dietDuration} ${dietDayWord}, plan lasts ${planDuration} ${planDayWord}.";
|
||||
|
||||
static String m3(planName) => "План «${planName}» начался";
|
||||
static String m3(name) => "Diet «${name}» proposed";
|
||||
|
||||
static String m4(planName, name) =>
|
||||
static String m4(planName) => "План «${planName}» начался";
|
||||
|
||||
static String m5(planName, name) =>
|
||||
"План «${planName}» с пользователем ${name} начался";
|
||||
|
||||
static String m5(duration, dayWord) => "Plan for ${duration} ${dayWord}";
|
||||
static String m6(duration, dayWord) => "Plan for ${duration} ${dayWord}";
|
||||
|
||||
static String m6(percent, amount) =>
|
||||
static String m7(percent, amount) =>
|
||||
"Discount ${percent}% — you save ${amount} ₽";
|
||||
|
||||
static String m7(date) => "Start: ${date}";
|
||||
static String m8(date) => "Start: ${date}";
|
||||
|
||||
static String m8(step) => "шаг ${step} из 2";
|
||||
static String m9(step) => "шаг ${step} из 2";
|
||||
|
||||
static String m9(planName, name) =>
|
||||
static String m10(planName, name) =>
|
||||
"Завтра начинается план «${planName}» с пользователем ${name}";
|
||||
|
||||
static String m10(planName) =>
|
||||
static String m11(planName) =>
|
||||
"Завтра начнется прохождение плана «${planName}»";
|
||||
|
||||
static String m11(name, planName) =>
|
||||
static String m12(name, planName) =>
|
||||
"Пользователь ${name} отменил подписку на план «${planName}»";
|
||||
|
||||
static String m12(name, planName) =>
|
||||
static String m13(name, planName) =>
|
||||
"Пользователь ${name} оплатил план «${planName}»";
|
||||
|
||||
static String m13(name, planName) =>
|
||||
static String m14(name, planName) =>
|
||||
"Пользователь ${name} подписался на план «${planName}»";
|
||||
|
||||
static String m14(planName) => "Вы отменили подписку на план «${planName}»";
|
||||
static String m15(planName) => "Вы отменили подписку на план «${planName}»";
|
||||
|
||||
final messages = _notInlinedMessages(_notInlinedMessages);
|
||||
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
|
||||
@@ -696,6 +698,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"personal_diet_proposed": MessageLookupByLibrary.simpleMessage(
|
||||
"Personal diet proposed",
|
||||
),
|
||||
"personal_diet_proposed_named": m3,
|
||||
"personal_diet_replaces_tomorrow": MessageLookupByLibrary.simpleMessage(
|
||||
"The change takes effect tomorrow",
|
||||
),
|
||||
@@ -715,18 +718,18 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Физическая форма",
|
||||
),
|
||||
"place_of_living": MessageLookupByLibrary.simpleMessage("Место проживания"),
|
||||
"planStarted": m3,
|
||||
"planStarted": m4,
|
||||
"planWillBeConfirmedAfterThreeDays": MessageLookupByLibrary.simpleMessage(
|
||||
"Если вы не подтвердите, то план через три дня подтвердится автоматически",
|
||||
),
|
||||
"planWithUserStarted": m4,
|
||||
"planWithUserStarted": m5,
|
||||
"plan_author": MessageLookupByLibrary.simpleMessage("Автор плана"),
|
||||
"plan_desc": MessageLookupByLibrary.simpleMessage("Описание плана"),
|
||||
"plan_desc_example": MessageLookupByLibrary.simpleMessage(
|
||||
"Большое подробное, привлекательное описание плана",
|
||||
),
|
||||
"plan_duration": MessageLookupByLibrary.simpleMessage("Срок плана"),
|
||||
"plan_duration_label": m5,
|
||||
"plan_duration_label": m6,
|
||||
"plan_label_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"План для поддержания формы",
|
||||
),
|
||||
@@ -763,7 +766,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Promo code applied!",
|
||||
),
|
||||
"promo_code": MessageLookupByLibrary.simpleMessage("Promo code"),
|
||||
"promo_discount_hint": m6,
|
||||
"promo_discount_hint": m7,
|
||||
"promo_invalid": MessageLookupByLibrary.simpleMessage(
|
||||
"Promo code not found or expired",
|
||||
),
|
||||
@@ -884,13 +887,13 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Выбрана дата старта",
|
||||
),
|
||||
"startDiet": MessageLookupByLibrary.simpleMessage("Начать диету"),
|
||||
"start_date_label": m7,
|
||||
"start_date_label": m8,
|
||||
"statistic": MessageLookupByLibrary.simpleMessage("Статистика"),
|
||||
"step": MessageLookupByLibrary.simpleMessage("Шаг"),
|
||||
"step_by_step_photo_recipe": MessageLookupByLibrary.simpleMessage(
|
||||
"Пошаговый фоторецепт",
|
||||
),
|
||||
"step_widget": m8,
|
||||
"step_widget": m9,
|
||||
"successfully_published": MessageLookupByLibrary.simpleMessage(
|
||||
"успешно опубликован",
|
||||
),
|
||||
@@ -915,8 +918,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"toOffer": MessageLookupByLibrary.simpleMessage("Предложить"),
|
||||
"to_draft": MessageLookupByLibrary.simpleMessage("В черновик"),
|
||||
"to_order": MessageLookupByLibrary.simpleMessage("Заказать"),
|
||||
"tommorowPlanWithUserWillStart": m9,
|
||||
"tomorrowYourPlanWillStart": m10,
|
||||
"tommorowPlanWithUserWillStart": m10,
|
||||
"tomorrowYourPlanWillStart": m11,
|
||||
"try_again": MessageLookupByLibrary.simpleMessage("Попробовать снова"),
|
||||
"try_again_2": MessageLookupByLibrary.simpleMessage("Попробуйте ещё раз"),
|
||||
"typeAmoutOfReturn": MessageLookupByLibrary.simpleMessage(
|
||||
@@ -950,7 +953,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Верхние показатели давления:",
|
||||
),
|
||||
"upper": MessageLookupByLibrary.simpleMessage("Верхнее"),
|
||||
"userCanceldThePlanSubscription": m11,
|
||||
"userCanceldThePlanSubscription": m12,
|
||||
"userConfirmedPlanCompletion": MessageLookupByLibrary.simpleMessage(
|
||||
"Пользователь подтвердил прохождения плана. В ближайшее время Вы получите",
|
||||
),
|
||||
@@ -958,8 +961,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"Пользователь подтвердил прохождения плана.",
|
||||
),
|
||||
"userPaidThePlan": m12,
|
||||
"userSubscribedToPlan": m13,
|
||||
"userPaidThePlan": m13,
|
||||
"userSubscribedToPlan": m14,
|
||||
"user_authorization": MessageLookupByLibrary.simpleMessage(
|
||||
"Аутентификация",
|
||||
),
|
||||
@@ -1089,7 +1092,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"youCanComplain": MessageLookupByLibrary.simpleMessage(
|
||||
"Если вас что-то не устроило, вы можете подать жалобу",
|
||||
),
|
||||
"youCanceledSubscriptionToPlan": m14,
|
||||
"youCanceledSubscriptionToPlan": m15,
|
||||
"youShureYouWantToCancelOrder": MessageLookupByLibrary.simpleMessage(
|
||||
"Вы уверены, что хотите отменить заказ?",
|
||||
),
|
||||
|
||||
@@ -26,12 +26,14 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
static String m2(dietDuration, dietDayWord, planDuration, planDayWord) =>
|
||||
"Не подходит: диета на ${dietDuration} ${dietDayWord}, план на ${planDuration} ${planDayWord}.";
|
||||
|
||||
static String m5(duration, dayWord) => "План на ${duration} ${dayWord}";
|
||||
static String m3(name) => "Диета «${name}» предложена";
|
||||
|
||||
static String m6(percent, amount) =>
|
||||
static String m6(duration, dayWord) => "План на ${duration} ${dayWord}";
|
||||
|
||||
static String m7(percent, amount) =>
|
||||
"Скидка ${percent}% — вы экономите ${amount} ₽";
|
||||
|
||||
static String m7(date) => "Старт: ${date}";
|
||||
static String m8(date) => "Старт: ${date}";
|
||||
|
||||
final messages = _notInlinedMessages(_notInlinedMessages);
|
||||
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
|
||||
@@ -340,6 +342,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"personal_diet_proposed": MessageLookupByLibrary.simpleMessage(
|
||||
"Диета предложена",
|
||||
),
|
||||
"personal_diet_proposed_named": m3,
|
||||
"personal_diet_replaces_tomorrow": MessageLookupByLibrary.simpleMessage(
|
||||
"Замена действует со следующего дня",
|
||||
),
|
||||
@@ -355,7 +358,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Большое подробное, привлекательное описание плана",
|
||||
),
|
||||
"plan_duration": MessageLookupByLibrary.simpleMessage("Срок плана"),
|
||||
"plan_duration_label": m5,
|
||||
"plan_duration_label": m6,
|
||||
"plan_label_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"План для поддержания формы",
|
||||
),
|
||||
@@ -383,7 +386,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Промокод применён!",
|
||||
),
|
||||
"promo_code": MessageLookupByLibrary.simpleMessage("Промокод"),
|
||||
"promo_discount_hint": m6,
|
||||
"promo_discount_hint": m7,
|
||||
"promo_invalid": MessageLookupByLibrary.simpleMessage(
|
||||
"Промокод не найден или истёк",
|
||||
),
|
||||
@@ -444,7 +447,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Выбрана дата старта",
|
||||
),
|
||||
"startDiet": MessageLookupByLibrary.simpleMessage("Начать диету"),
|
||||
"start_date_label": m7,
|
||||
"start_date_label": m8,
|
||||
"suggestDiet": MessageLookupByLibrary.simpleMessage("Предложить диету"),
|
||||
"tell_your_schedule": MessageLookupByLibrary.simpleMessage(
|
||||
"Расскажите в свободной форме о том как просыпаетесь, когда едите, когда ложитесь спать:",
|
||||
|
||||
@@ -4574,6 +4574,16 @@ class S {
|
||||
);
|
||||
}
|
||||
|
||||
/// `Diet «{name}» proposed`
|
||||
String personal_diet_proposed_named(String name) {
|
||||
return Intl.message(
|
||||
'Diet «$name» proposed',
|
||||
name: 'personal_diet_proposed_named',
|
||||
desc: '',
|
||||
args: [name],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Personal diet not proposed`
|
||||
String get personal_diet_not_proposed {
|
||||
return Intl.message(
|
||||
|
||||
@@ -540,6 +540,12 @@
|
||||
"video_call_notification_end": "End call",
|
||||
"order_in_progress": "Order in progress",
|
||||
"personal_diet_proposed": "Personal diet proposed",
|
||||
"personal_diet_proposed_named": "Diet «{name}» proposed",
|
||||
"@personal_diet_proposed_named": {
|
||||
"placeholders": {
|
||||
"name": {"type": "String"}
|
||||
}
|
||||
},
|
||||
"personal_diet_not_proposed": "Personal diet not proposed",
|
||||
"change_personal_diet": "Change personal diet",
|
||||
"personal_diet_replaces_tomorrow": "The change takes effect tomorrow",
|
||||
|
||||
@@ -295,6 +295,12 @@
|
||||
"choose_plan_start_date_with_personal_diet": "Выберите дату старта плана питания с учетом составления персональной диеты",
|
||||
"order_in_progress": "Заказ в работе",
|
||||
"personal_diet_proposed": "Диета предложена",
|
||||
"personal_diet_proposed_named": "Диета «{name}» предложена",
|
||||
"@personal_diet_proposed_named": {
|
||||
"placeholders": {
|
||||
"name": {"type": "String"}
|
||||
}
|
||||
},
|
||||
"personal_diet_not_proposed": "Диета не предложена",
|
||||
"change_personal_diet": "Заменить диету",
|
||||
"personal_diet_replaces_tomorrow": "Замена действует со следующего дня",
|
||||
|
||||
@@ -55,6 +55,7 @@ void main() {
|
||||
final progress = mapConsultationProgress(
|
||||
state: ChosenPlanStateEnum.personalDietSet,
|
||||
hasPersonalDiet: true,
|
||||
personalDietName: 'Индивидуальный план питания',
|
||||
);
|
||||
expect(progress.showProgressPlank, isTrue);
|
||||
expect(progress.dietStatus, PersonalDietStatus.proposed);
|
||||
@@ -73,7 +74,10 @@ void main() {
|
||||
|
||||
expect(find.text(s.order_in_progress), findsNWidgets(2));
|
||||
expect(find.byType(PersonalDietStatusChip), findsOneWidget);
|
||||
expect(find.text(s.personal_diet_proposed), findsOneWidget);
|
||||
expect(
|
||||
find.text(s.personal_diet_proposed_named('Индивидуальный план питания')),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.byType(ConsultationProgressPlank), findsOneWidget);
|
||||
expect(find.byIcon(Icons.check), findsNWidgets(2));
|
||||
},
|
||||
|
||||
@@ -174,11 +174,13 @@ void main() {
|
||||
'consultant_id': 1,
|
||||
'diaries': [],
|
||||
'personal_diet_id': null,
|
||||
'personal_diet_name': 'Индивидуальный план питания',
|
||||
};
|
||||
|
||||
final model = ConsultationModel.fromJson(json);
|
||||
|
||||
expect(model.chatId, 'direct-chat-uuid');
|
||||
expect(model.personalDietName, 'Индивидуальный план питания');
|
||||
});
|
||||
|
||||
test('fromJson allows missing chat_id', () {
|
||||
|
||||
@@ -153,6 +153,29 @@ void main() {
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('shows personal diet name in status chip', (tester) async {
|
||||
final consultation = mockConsultation.copyWith(
|
||||
personalDietId: 1,
|
||||
personalDietName: 'Индивидуальный план питания',
|
||||
);
|
||||
|
||||
await mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(
|
||||
wrap(ConsultationCardWidget(consultationsModel: consultation)),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final s = S.of(tester.element(find.byType(ConsultationCardWidget)));
|
||||
|
||||
expect(
|
||||
find.text(
|
||||
s.personal_diet_proposed_named('Индивидуальный план питания'),
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('renders diary days', (tester) async {
|
||||
await mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(
|
||||
|
||||
@@ -21,11 +21,16 @@ Widget _wrap(Widget child) {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _chip(ChosenPlanStateEnum state, {bool hasPersonalDiet = true}) {
|
||||
Widget _chip(
|
||||
ChosenPlanStateEnum state, {
|
||||
bool hasPersonalDiet = true,
|
||||
String? personalDietName,
|
||||
}) {
|
||||
return PersonalDietStatusChip(
|
||||
progress: mapConsultationProgress(
|
||||
state: state,
|
||||
hasPersonalDiet: hasPersonalDiet,
|
||||
personalDietName: personalDietName,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -55,6 +60,24 @@ void main() {
|
||||
expect(find.text(s.personal_diet_proposed), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('proposed с названием показывает имя диеты', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
_wrap(
|
||||
_chip(
|
||||
ChosenPlanStateEnum.stateStarted,
|
||||
personalDietName: 'Индивидуальный план питания',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final s = S.of(tester.element(find.byType(PersonalDietStatusChip)));
|
||||
|
||||
expect(
|
||||
find.text(s.personal_diet_proposed_named('Индивидуальный план питания')),
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('notProposed показывает personal_diet_not_proposed', (
|
||||
tester,
|
||||
) async {
|
||||
|
||||
@@ -275,5 +275,15 @@ void main() {
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('personalDietName передаётся в ConsultationProgress', () {
|
||||
final progress = mapConsultationProgress(
|
||||
state: ChosenPlanStateEnum.personalDietSet,
|
||||
hasPersonalDiet: true,
|
||||
personalDietName: 'Индивидуальный план питания',
|
||||
);
|
||||
|
||||
expect(progress.personalDietName, 'Индивидуальный план питания');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -92,6 +92,7 @@ void main() {
|
||||
DiaryReminderForUsersNotification.fromJson(base, NotificationType.diaryReminderForUsers);
|
||||
DiaryReminderForUsersNotification.fromJson({'created_at': c, 'data': <String, dynamic>{}}, NotificationType.diaryReminderForUsers);
|
||||
PersonalDietIsDefinedToCustomerNotification.fromJson(base, NotificationType.personalDietIsDefinedToCustomer);
|
||||
PersonalDietIsDefinedToAuthorNotification.fromJson(base, NotificationType.personalDietIsDefinedToAuthor);
|
||||
ConsultantEducationUpdatedNotification.fromJson(base, NotificationType.consultantEducationUpdated);
|
||||
ComplaintRegisteredNotification.fromJson(base, NotificationType.complaintRegistered);
|
||||
ContentUnpublishedNotification.fromJson(base, NotificationType.contentUnpublished);
|
||||
|
||||
@@ -50,6 +50,7 @@ void main() {
|
||||
'stay-on-track-to-customer': NotificationType.stayOnTrackToCustomer,
|
||||
'diary-reminder-for-users': NotificationType.diaryReminderForUsers,
|
||||
'personal-diet-is-defined-to-customer': NotificationType.personalDietIsDefinedToCustomer,
|
||||
'personal-diet-is-defined-to-author': NotificationType.personalDietIsDefinedToAuthor,
|
||||
};
|
||||
|
||||
cases.forEach((key, expected) {
|
||||
@@ -671,6 +672,34 @@ void main() {
|
||||
expect(notification.type, NotificationType.personalizedDietIsDefined);
|
||||
});
|
||||
|
||||
test('PersonalDietIsDefinedToAuthorNotification.fromJson parses all fields', () {
|
||||
final json = {
|
||||
'chosen_plan_id': 12,
|
||||
'diet_id': 34,
|
||||
'plan_name': 'Plan',
|
||||
'user_name': 'Client',
|
||||
'consultant_name': 'Consultant',
|
||||
'diet_name': 'Personal diet',
|
||||
'role': 'consultant',
|
||||
'peer_slug': 'client-slug',
|
||||
'peer_image_path': 'avatars/client.png',
|
||||
'created_at': '2024-01-30T12:00:00Z',
|
||||
};
|
||||
|
||||
final notification = PersonalDietIsDefinedToAuthorNotification.fromJson(
|
||||
json,
|
||||
NotificationType.personalDietIsDefinedToAuthor,
|
||||
isRead: false,
|
||||
);
|
||||
|
||||
expect(notification.chosenPlanId, 12);
|
||||
expect(notification.dietId, 34);
|
||||
expect(notification.userName, 'Client');
|
||||
expect(notification.dietName, 'Personal diet');
|
||||
expect(notification.peerSlug, 'client-slug');
|
||||
expect(notification.type, NotificationType.personalDietIsDefinedToAuthor);
|
||||
});
|
||||
|
||||
test('ChosenPlanFinishedToClientNotification.fromJson parses all fields', () {
|
||||
final json = {
|
||||
'plan_name': 'Finished Plan',
|
||||
|
||||
@@ -1212,6 +1212,31 @@ void main() {
|
||||
expect(find.byType(NotificationWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays PersonalDietIsDefinedToAuthorNotification', (
|
||||
tester,
|
||||
) async {
|
||||
final notification = PersonalDietIsDefinedToAuthorNotification(
|
||||
type: NotificationType.personalDietIsDefinedToAuthor,
|
||||
isRead: false,
|
||||
createdAt: testDate,
|
||||
chosenPlanId: 1,
|
||||
dietId: 1,
|
||||
planName: 'Plan',
|
||||
userName: 'Client',
|
||||
consultantName: 'Consultant',
|
||||
dietName: 'Test Diet',
|
||||
role: 'consultant',
|
||||
peerSlug: 'client-slug',
|
||||
peerImagePath: '',
|
||||
);
|
||||
|
||||
await tester.pumpWidget(createTestWidget(notification));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.textContaining('Вы предложили персональную диету пользователю Client'), findsOneWidget);
|
||||
expect(find.textContaining('Test Diet'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays UnknownNotification', (tester) async {
|
||||
final notification = UnknownNotification(
|
||||
type: NotificationType.unknown,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/features/notifications/models/notification_model.dart';
|
||||
import 'package:eatvio_app/features/notifications/service/notifications_service.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
@@ -1454,6 +1455,42 @@ void main() {
|
||||
expect(result, isNotNull);
|
||||
expect(result!['notifications'], isA<List>());
|
||||
expect(result['notifications'].length, 1);
|
||||
expect(result['notifications'].first, isA<PersonalDietIsDefinedToCustomerNotification>());
|
||||
});
|
||||
|
||||
test('getNotifications - обрабатывает PersonalDietIsDefinedToAuthor', () async {
|
||||
const page = 1;
|
||||
final response = Response(
|
||||
data: {
|
||||
'data': [
|
||||
{
|
||||
'type': 'personal-diet-is-defined-to-author',
|
||||
'data': {
|
||||
'diet_name': 'Test Diet',
|
||||
'diet_id': 1,
|
||||
'user_name': 'Client',
|
||||
},
|
||||
'read_at': null,
|
||||
'created_at': '2024-01-01T12:00:00Z',
|
||||
},
|
||||
],
|
||||
'current_page': 1,
|
||||
'last_page': 1,
|
||||
'per_page': 10,
|
||||
'total': 1,
|
||||
},
|
||||
statusCode: 200,
|
||||
requestOptions: RequestOptions(path: '/api/profile/notifications'),
|
||||
);
|
||||
|
||||
when(mockDio.get(any)).thenAnswer((_) async => response);
|
||||
|
||||
final result = await notificationsService.getNotifications(page: page);
|
||||
|
||||
expect(result, isNotNull);
|
||||
expect(result!['notifications'], isA<List>());
|
||||
expect(result['notifications'].length, 1);
|
||||
expect(result['notifications'].first, isA<PersonalDietIsDefinedToAuthorNotification>());
|
||||
});
|
||||
|
||||
test('getNotifications - обрабатывает UserDailyReportCompleted', () async {
|
||||
|
||||
@@ -60,6 +60,7 @@ void main() {
|
||||
'last_state': 'initied',
|
||||
'chat_id': 'chat-1',
|
||||
'consultant_id': 1,
|
||||
'personal_diet_name': 'Индивидуальный план питания',
|
||||
'plan': {
|
||||
'id': 1,
|
||||
'slug': 'test-plan',
|
||||
@@ -94,6 +95,7 @@ void main() {
|
||||
expect(chosenPlan.optionType, 'options1');
|
||||
expect(chosenPlan.chosenPlanState, ChosenPlanStateEnum.stateInited);
|
||||
expect(chosenPlan.chatId, 'chat-1');
|
||||
expect(chosenPlan.personalDietName, 'Индивидуальный план питания');
|
||||
});
|
||||
|
||||
test('toJson serializes ChosenPlanModel correctly', () {
|
||||
@@ -207,6 +209,7 @@ void main() {
|
||||
'last_state': 'initied',
|
||||
'chat_id': 'chat-1',
|
||||
'consultant_id': 1,
|
||||
'personal_diet_name': 'Индивидуальный план питания',
|
||||
'plan': {
|
||||
'id': 1,
|
||||
'slug': 'test-plan',
|
||||
|
||||
Reference in New Issue
Block a user