From 178c147b0e1e69a1c72c403988ce61c5dc1e5271 Mon Sep 17 00:00:00 2001 From: CowboyGH Date: Sun, 24 May 2026 17:06:55 +0700 Subject: [PATCH] refactor(dto): type duration_minutes as int to match backend Backend now returns duration_minutes as an integer, so the workout and testing catalog DTOs no longer need to parse strings. Drops the defensive _parseDurationMinutes helpers and the obsolete invalid- duration test case. Co-Authored-By: Claude Opus 4.7 --- .../catalog/data/dto/testing_catalog_item_dto.dart | 4 ++-- .../catalog/data/mappers/testing_catalog_mapper.dart | 2 +- .../workouts/data/dto/workout_summary_dto.dart | 4 ++-- .../workouts/data/mappers/workout_details_mapper.dart | 4 +--- .../workouts/data/mappers/workout_overview_mapper.dart | 4 +--- .../data/mappers/testing_catalog_mapper_test.dart | 10 +--------- .../tests/catalog/support/testings_dto_fixtures.dart | 4 ++-- .../workouts/support/workouts_dto_fixtures.dart | 6 +++--- 8 files changed, 13 insertions(+), 25 deletions(-) diff --git a/lib/features/tests/catalog/data/dto/testing_catalog_item_dto.dart b/lib/features/tests/catalog/data/dto/testing_catalog_item_dto.dart index 4ccfbe41..1f1c2c03 100644 --- a/lib/features/tests/catalog/data/dto/testing_catalog_item_dto.dart +++ b/lib/features/tests/catalog/data/dto/testing_catalog_item_dto.dart @@ -16,9 +16,9 @@ class TestingCatalogItemDto { /// Short testing description. final String description; - /// Approximate duration in minutes provided by the backend. + /// Approximate duration in minutes. @JsonKey(name: 'duration_minutes') - final String durationMinutes; + final int durationMinutes; /// Testing image path or URL. final String image; diff --git a/lib/features/tests/catalog/data/mappers/testing_catalog_mapper.dart b/lib/features/tests/catalog/data/mappers/testing_catalog_mapper.dart index 9bba54d9..a2ca1157 100644 --- a/lib/features/tests/catalog/data/mappers/testing_catalog_mapper.dart +++ b/lib/features/tests/catalog/data/mappers/testing_catalog_mapper.dart @@ -11,7 +11,7 @@ extension TestingCatalogItemMapper on TestingCatalogItemDto { id: id, title: title, description: description, - durationMinutes: int.tryParse(durationMinutes.trim()) ?? 0, + durationMinutes: durationMinutes, imageUrl: normalizeTestingImageUrl(image), categories: categories.map((category) => category.toEntity()).toList(growable: false), exercisesCount: exercisesCount, diff --git a/lib/features/workouts/data/dto/workout_summary_dto.dart b/lib/features/workouts/data/dto/workout_summary_dto.dart index 12d19a9a..28c8e3bc 100644 --- a/lib/features/workouts/data/dto/workout_summary_dto.dart +++ b/lib/features/workouts/data/dto/workout_summary_dto.dart @@ -14,9 +14,9 @@ class WorkoutSummaryDto { /// Short workout description. final String description; - /// Workout duration in minutes provided by the backend. + /// Workout duration in minutes. @JsonKey(name: 'duration_minutes') - final String durationMinutes; + final int durationMinutes; /// Workout preview image path or URL. final String? image; diff --git a/lib/features/workouts/data/mappers/workout_details_mapper.dart b/lib/features/workouts/data/mappers/workout_details_mapper.dart index 0a8cb98a..410deae2 100644 --- a/lib/features/workouts/data/mappers/workout_details_mapper.dart +++ b/lib/features/workouts/data/mappers/workout_details_mapper.dart @@ -19,7 +19,7 @@ extension WorkoutDetailsMapper on WorkoutDetailsDataDto { type: WorkoutDetailsItemType.workout, title: workout.title, description: workout.description, - durationMinutes: _parseDurationMinutes(workout.durationMinutes), + durationMinutes: workout.durationMinutes, imageUrl: normalizeWorkoutImageUrl(workout.image ?? ''), ), ]; @@ -29,5 +29,3 @@ int _durationSecondsToMinutes(int seconds) { if (seconds <= 0) return 0; return (seconds / 60).ceil(); } - -int _parseDurationMinutes(String rawValue) => int.tryParse(rawValue.trim()) ?? 0; diff --git a/lib/features/workouts/data/mappers/workout_overview_mapper.dart b/lib/features/workouts/data/mappers/workout_overview_mapper.dart index d2919a15..2acd5a8f 100644 --- a/lib/features/workouts/data/mappers/workout_overview_mapper.dart +++ b/lib/features/workouts/data/mappers/workout_overview_mapper.dart @@ -11,9 +11,7 @@ extension WorkoutOverviewMapper on UserWorkoutOverviewItemDto { isBlockedByActiveWorkout: hasActive && status != 'started', title: workout.title, description: workout.description, - durationMinutes: _parseDurationMinutes(workout.durationMinutes), + durationMinutes: workout.durationMinutes, imageUrl: normalizeWorkoutImageUrl(workout.image ?? ''), ); } - -int _parseDurationMinutes(String rawValue) => int.tryParse(rawValue.trim()) ?? 0; diff --git a/test/features/tests/catalog/data/mappers/testing_catalog_mapper_test.dart b/test/features/tests/catalog/data/mappers/testing_catalog_mapper_test.dart index eb4bed85..80e5fc61 100644 --- a/test/features/tests/catalog/data/mappers/testing_catalog_mapper_test.dart +++ b/test/features/tests/catalog/data/mappers/testing_catalog_mapper_test.dart @@ -8,7 +8,7 @@ void main() { group('TestingCatalogItemMapper.toEntity', () { test('maps dto to entity with normalized relative image url', () { final dto = createTestingCatalogItemDto( - durationMinutes: '15', + durationMinutes: 15, image: 'tests/balance.jpg', ); @@ -55,13 +55,5 @@ void main() { expect(entity.imageUrl, isEmpty); }); - - test('maps invalid duration to 0', () { - final dto = createTestingCatalogItemDto(durationMinutes: 'not_a_number'); - - final entity = dto.toEntity(); - - expect(entity.durationMinutes, 0); - }); }); } diff --git a/test/features/tests/catalog/support/testings_dto_fixtures.dart b/test/features/tests/catalog/support/testings_dto_fixtures.dart index 2b1752ef..8e56b1ea 100644 --- a/test/features/tests/catalog/support/testings_dto_fixtures.dart +++ b/test/features/tests/catalog/support/testings_dto_fixtures.dart @@ -19,7 +19,7 @@ TestingCatalogItemDto createTestingCatalogItemDto({ int id = 1, String title = 'Расширенная диагностика', String description = 'Описание теста', - String durationMinutes = '20', + int durationMinutes = 20, String image = 'test.jpg', List? categories, int exercisesCount = 4, @@ -45,7 +45,7 @@ TestingsResponseDto createTestingsResponseDto() => TestingsResponseDto( createTestingCatalogItemDto( id: 2, title: 'Быстрая проверка', - durationMinutes: '10', + durationMinutes: 10, image: 'https://cdn.example.com/testing-2.jpg', categories: [ createTestingCategoryDto(id: 3, name: 'Гибкость'), diff --git a/test/features/workouts/support/workouts_dto_fixtures.dart b/test/features/workouts/support/workouts_dto_fixtures.dart index 146b6d16..92bc3d9c 100644 --- a/test/features/workouts/support/workouts_dto_fixtures.dart +++ b/test/features/workouts/support/workouts_dto_fixtures.dart @@ -29,7 +29,7 @@ WorkoutsResponseDto createWorkoutsResponseDto() => WorkoutsResponseDto( id: 1, title: 'title', description: 'description', - durationMinutes: '1', + durationMinutes: 1, image: 'image.png', ), status: 'started', @@ -42,7 +42,7 @@ WorkoutsResponseDto createWorkoutsResponseDto() => WorkoutsResponseDto( id: 2, title: 'title', description: 'description', - durationMinutes: '2', + durationMinutes: 2, image: 'image_2.png', ), status: 'assigned', @@ -78,7 +78,7 @@ WorkoutDetailsResponseDto createWorkoutDetailsResponseDto({ id: 1, title: 'title', description: 'description', - durationMinutes: '1', + durationMinutes: 1, image: 'test.png', ), ),