diff --git a/lib/api/survey_api_service.dart b/lib/api/survey_api_service.dart index e779778..0319f13 100644 --- a/lib/api/survey_api_service.dart +++ b/lib/api/survey_api_service.dart @@ -1,5 +1,6 @@ import 'package:dio/dio.dart'; import 'package:retrofit/http.dart'; +import 'package:survey_flutter/model/response/survey_detail_data_response.dart'; import 'package:survey_flutter/model/response/surveys_container_response.dart'; part 'survey_api_service.g.dart'; @@ -13,4 +14,9 @@ abstract class SurveyApiService { @Query('page[number]') int pageNumber, @Query('page[size]') int pageSize, ); + + @GET('/surveys/{surveyId}') + Future getSurveyDetail( + @Path('surveyId') String surveyId, + ); } diff --git a/lib/model/answer_model.dart b/lib/model/answer_model.dart new file mode 100644 index 0000000..65686d8 --- /dev/null +++ b/lib/model/answer_model.dart @@ -0,0 +1,28 @@ +import 'package:survey_flutter/model/response/answer_response.dart'; +import 'package:survey_flutter/utils/string_extension.dart'; + +class AnswerModel { + final String id; + final String type; + final String text; + final int displayOrder; + final String displayType; + + const AnswerModel({ + required this.id, + required this.type, + required this.text, + required this.displayOrder, + required this.displayType, + }); +} + +extension AnswerModelExtension on AnswerResponse { + AnswerModel toAnswerModel() => AnswerModel( + id: id.orEmpty(), + type: type.orEmpty(), + text: text.orEmpty(), + displayOrder: displayOrder ?? 0, + displayType: displayType.orEmpty(), + ); +} diff --git a/lib/model/question_model.dart b/lib/model/question_model.dart new file mode 100644 index 0000000..b9dc646 --- /dev/null +++ b/lib/model/question_model.dart @@ -0,0 +1,30 @@ +import 'package:survey_flutter/model/answer_model.dart'; +import 'package:survey_flutter/model/response/question_response.dart'; +import 'package:survey_flutter/utils/string_extension.dart'; + +class QuestionModel { + final String id; + final String type; + final String text; + final String displayType; + final List answers; + + QuestionModel({ + required this.id, + required this.type, + required this.text, + required this.displayType, + required this.answers, + }); +} + +extension QuestionModelExtension on QuestionResponse { + QuestionModel toQuestionModel() => QuestionModel( + id: id.orEmpty(), + type: type.orEmpty(), + text: text.orEmpty(), + displayType: displayType.orEmpty(), + answers: + answers?.map((answer) => answer.toAnswerModel()).toList() ?? [], + ); +} diff --git a/lib/model/response/answer_response.dart b/lib/model/response/answer_response.dart new file mode 100644 index 0000000..5b491e5 --- /dev/null +++ b/lib/model/response/answer_response.dart @@ -0,0 +1,28 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'answer_response.g.dart'; + +@JsonSerializable() +class AnswerResponse { + @JsonKey(name: 'id') + final String? id; + @JsonKey(name: 'type') + final String? type; + @JsonKey(name: 'text') + final String? text; + @JsonKey(name: 'display_order') + final int? displayOrder; + @JsonKey(name: 'display_type') + final String? displayType; + + AnswerResponse({ + this.id, + this.type, + this.text, + this.displayOrder, + this.displayType, + }); + + factory AnswerResponse.fromJson(Map json) => + _$AnswerResponseFromJson(json); +} diff --git a/lib/model/response/question_response.dart b/lib/model/response/question_response.dart new file mode 100644 index 0000000..0c848ce --- /dev/null +++ b/lib/model/response/question_response.dart @@ -0,0 +1,29 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:survey_flutter/model/response/answer_response.dart'; + +part 'question_response.g.dart'; + +@JsonSerializable() +class QuestionResponse { + @JsonKey(name: 'id') + final String? id; + @JsonKey(name: 'type') + final String? type; + @JsonKey(name: 'text') + final String? text; + @JsonKey(name: 'display_type') + final String? displayType; + @JsonKey(name: 'answers') + final List? answers; + + QuestionResponse({ + this.id, + this.type, + this.text, + this.displayType, + this.answers, + }); + + factory QuestionResponse.fromJson(Map json) => + _$QuestionResponseFromJson(json); +} diff --git a/lib/model/response/survey_detail_data_response.dart b/lib/model/response/survey_detail_data_response.dart new file mode 100644 index 0000000..3906d57 --- /dev/null +++ b/lib/model/response/survey_detail_data_response.dart @@ -0,0 +1,15 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:survey_flutter/model/response/survey_detail_response.dart'; + +part 'survey_detail_data_response.g.dart'; + +@JsonSerializable() +class SurveyDetailDataResponse { + @JsonKey(name: 'data') + final SurveyDetailResponse? surveyDetailResponse; + + SurveyDetailDataResponse(this.surveyDetailResponse); + + factory SurveyDetailDataResponse.fromJson(Map json) => + _$SurveyDetailDataResponseFromJson(json); +} diff --git a/lib/model/response/survey_detail_response.dart b/lib/model/response/survey_detail_response.dart new file mode 100644 index 0000000..586d308 --- /dev/null +++ b/lib/model/response/survey_detail_response.dart @@ -0,0 +1,35 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:survey_flutter/model/response/question_response.dart'; + +part 'survey_detail_response.g.dart'; + +@JsonSerializable() +class SurveyDetailResponse { + @JsonKey(name: 'id') + final String? id; + @JsonKey(name: 'type') + final String? type; + @JsonKey(name: 'title') + final String? title; + @JsonKey(name: 'description') + final String? description; + @JsonKey(name: 'cover_image_url') + final String? coverImageUrl; + @JsonKey(name: 'survey_type') + final String? surveyType; + @JsonKey(name: 'questions') + final List? questions; + + SurveyDetailResponse({ + this.id, + this.type, + this.title, + this.description, + this.coverImageUrl, + this.surveyType, + this.questions, + }); + + factory SurveyDetailResponse.fromJson(Map json) => + _$SurveyDetailResponseFromJson(json); +} diff --git a/lib/model/survey_detail_model.dart b/lib/model/survey_detail_model.dart new file mode 100644 index 0000000..28f929a --- /dev/null +++ b/lib/model/survey_detail_model.dart @@ -0,0 +1,37 @@ +import 'package:survey_flutter/model/question_model.dart'; +import 'package:survey_flutter/model/response/survey_detail_response.dart'; +import 'package:survey_flutter/utils/string_extension.dart'; + +class SurveyDetailModel { + final String id; + final String type; + final String title; + final String description; + final String coverImageUrl; + final String surveyType; + final List questions; + + const SurveyDetailModel({ + required this.id, + required this.type, + required this.title, + required this.description, + required this.coverImageUrl, + required this.surveyType, + required this.questions, + }); +} + +extension SurveyDetailModelExtension on SurveyDetailResponse { + SurveyDetailModel toSurveyDetailModel() => SurveyDetailModel( + id: id.orEmpty(), + type: type.orEmpty(), + title: type.orEmpty(), + description: description.orEmpty(), + coverImageUrl: coverImageUrl.orEmpty(), + surveyType: surveyType.orEmpty(), + questions: + questions?.map((question) => question.toQuestionModel()).toList() ?? + [], + ); +} diff --git a/lib/repositories/survey_repository.dart b/lib/repositories/survey_repository.dart index 4f7074e..da2663a 100644 --- a/lib/repositories/survey_repository.dart +++ b/lib/repositories/survey_repository.dart @@ -3,6 +3,7 @@ import 'package:survey_flutter/api/data_sources/token_data_source.dart'; import 'package:survey_flutter/api/exception/network_exceptions.dart'; import 'package:survey_flutter/api/survey_api_service.dart'; import 'package:survey_flutter/di/provider/dio_provider.dart'; +import 'package:survey_flutter/model/survey_detail_model.dart'; import 'package:survey_flutter/model/survey_model.dart'; import 'package:survey_flutter/storage/survey_storage.dart'; @@ -21,6 +22,8 @@ abstract class SurveyRepository { required int pageNumber, required int pageSize, }); + + Future getSurveyDetail(String surveyid); } class SurveyRepositoryImpl extends SurveyRepository { @@ -45,4 +48,19 @@ class SurveyRepositoryImpl extends SurveyRepository { throw NetworkExceptions.fromDioException(exception); } } + + @override + Future getSurveyDetail(String surveyid) async { + try { + final response = await _apiService.getSurveyDetail(surveyid); + final surveyDetailResponse = response.surveyDetailResponse; + if (surveyDetailResponse == null) { + // TODO: Update catching + throw const NetworkExceptions.unexpectedError(); + } + return surveyDetailResponse.toSurveyDetailModel(); + } catch (exception) { + throw NetworkExceptions.fromDioException(exception); + } + } } diff --git a/lib/usecases/get_survey_detail_use_case.dart b/lib/usecases/get_survey_detail_use_case.dart new file mode 100644 index 0000000..a56a825 --- /dev/null +++ b/lib/usecases/get_survey_detail_use_case.dart @@ -0,0 +1,20 @@ +import 'package:survey_flutter/model/survey_detail_model.dart'; +import 'package:survey_flutter/repositories/survey_repository.dart'; +import 'package:survey_flutter/usecases/base/base_use_case.dart'; + +class GetSurveyDetailUseCase extends UseCase { + final SurveyRepository _surveyRepository; + + GetSurveyDetailUseCase(this._surveyRepository); + + @override + // ignore: avoid_renaming_method_parameters + Future> call(String surveyId) async { + try { + final result = await _surveyRepository.getSurveyDetail(surveyId); + return Success(result); + } catch (exception) { + return Failed(UseCaseException(exception)); + } + } +} diff --git a/lib/utils/string_extension.dart b/lib/utils/string_extension.dart new file mode 100644 index 0000000..a1b6876 --- /dev/null +++ b/lib/utils/string_extension.dart @@ -0,0 +1,4 @@ +extension StringExtension on String? { + String unWrappedOr(String fallback) => this ?? fallback; + String orEmpty() => unWrappedOr(''); +}