fix: show personal diet name and consultant notifications

This commit is contained in:
2026-11-06 14:22:55 +03:00
parent ad70d0988e
commit 6c4572af55
26 changed files with 323 additions and 34 deletions

View File

@@ -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));
},

View File

@@ -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', () {

View File

@@ -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(

View File

@@ -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 {

View File

@@ -275,5 +275,15 @@ void main() {
);
}
});
test('personalDietName передаётся в ConsultationProgress', () {
final progress = mapConsultationProgress(
state: ChosenPlanStateEnum.personalDietSet,
hasPersonalDiet: true,
personalDietName: 'Индивидуальный план питания',
);
expect(progress.personalDietName, 'Индивидуальный план питания');
});
});
}

View File

@@ -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);

View File

@@ -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',

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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',