From 371cab73fb0197e329bd2d4298fb6dbfd39bbecb Mon Sep 17 00:00:00 2001 From: Younghoon Ahn Date: Thu, 7 Dec 2023 00:25:50 +0900 Subject: [PATCH] =?UTF-8?q?fixme:=20=EC=BD=94=EB=93=9C=201=EC=B0=A8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../D3N/Sources/Domain/D3NAPIProvider.swift | 2 +- .../FetchSolvedQuizListResponseDTO.swift | 2 +- .../Domain/Quiz/Entity/SolvedQuizEntity.swift | 31 +++++++-- .../D3N/Sources/Domain/Quiz/QuizService.swift | 5 -- .../Domain/Quiz/SolvedQuizClient.swift | 44 +++++++++++++ .../Domain/Quiz/SolvedQuizService.swift | 41 ++++++++++++ .../Feature/MyPage/Main/MyPageMainStore.swift | 10 +-- .../Feature/MyPage/Main/MyPageMainView.swift | 2 +- .../SolvedQuizView.swift} | 10 +-- .../Cell/SolvedQuizListItemCellStore.swift | 64 +++++++++++++++++++ .../Cell/SolvedQuizListItemCellView.swift | 38 +++++++++++ 11 files changed, 224 insertions(+), 25 deletions(-) create mode 100644 Targets/D3N/Sources/Domain/Quiz/SolvedQuizClient.swift create mode 100644 Targets/D3N/Sources/Domain/Quiz/SolvedQuizService.swift rename Targets/D3N/Sources/Feature/MyPage/{SolvedNews/SolvedNewsView.swift => Solved/SolvedQuizView.swift} (85%) create mode 100644 Targets/D3N/Sources/Feature/Quiz/List/Cell/SolvedQuizListItemCellStore.swift create mode 100644 Targets/D3N/Sources/Feature/Quiz/List/Cell/SolvedQuizListItemCellView.swift diff --git a/Targets/D3N/Sources/Domain/D3NAPIProvider.swift b/Targets/D3N/Sources/Domain/D3NAPIProvider.swift index cdd9825..3aba786 100644 --- a/Targets/D3N/Sources/Domain/D3NAPIProvider.swift +++ b/Targets/D3N/Sources/Domain/D3NAPIProvider.swift @@ -61,7 +61,7 @@ final class D3NAPIProvider { } } - private static func request(target: T) async -> Result { + public static func request(target: T) async -> Result { await withCheckedContinuation { continuation in provider.request(MultiTarget(target)) { result in continuation.resume(returning: result) diff --git a/Targets/D3N/Sources/Domain/Quiz/DTO/Response/FetchSolvedQuizListResponseDTO.swift b/Targets/D3N/Sources/Domain/Quiz/DTO/Response/FetchSolvedQuizListResponseDTO.swift index 20ce57b..09c6d3e 100644 --- a/Targets/D3N/Sources/Domain/Quiz/DTO/Response/FetchSolvedQuizListResponseDTO.swift +++ b/Targets/D3N/Sources/Domain/Quiz/DTO/Response/FetchSolvedQuizListResponseDTO.swift @@ -1,5 +1,5 @@ // -// SwiftUIView.swift +// FetchSolvedQuizListResponseDTO.swift // D3N // // Created by Younghoon Ahn on 11/28/23. diff --git a/Targets/D3N/Sources/Domain/Quiz/Entity/SolvedQuizEntity.swift b/Targets/D3N/Sources/Domain/Quiz/Entity/SolvedQuizEntity.swift index 26b8092..9fbc10d 100644 --- a/Targets/D3N/Sources/Domain/Quiz/Entity/SolvedQuizEntity.swift +++ b/Targets/D3N/Sources/Domain/Quiz/Entity/SolvedQuizEntity.swift @@ -8,12 +8,29 @@ import Foundation -public struct SolvedQuizEntity: Equatable { +public struct SolvedQuizEntity: Equatable, Codable { let id: Int - let question: String - let choiceList: [String] - let answer: Int - let reason: String - let selectedAnswer: Int - let news: NewsEntity + let question: String + let choiceList: [String] + let answer: Int + let reason: String + let selectedAnswer: Int + let news: NewsEntity + + init(id: Int, + question: String, + choiceList: [String], + answer: Int, + reason: String, + selectedAnswer: Int, + news: NewsEntity + ) { + self.id = id + self.question = question + self.choiceList = choiceList + self.answer = answer + self.reason = reason + self.selectedAnswer = selectedAnswer + self.news = news + } } diff --git a/Targets/D3N/Sources/Domain/Quiz/QuizService.swift b/Targets/D3N/Sources/Domain/Quiz/QuizService.swift index 5ca3550..5fe0a7b 100644 --- a/Targets/D3N/Sources/Domain/Quiz/QuizService.swift +++ b/Targets/D3N/Sources/Domain/Quiz/QuizService.swift @@ -12,7 +12,6 @@ import Moya public enum QuizService { case fetch(newsId: Int) - case fetchSolved(newsId: Int) case submit(quizs: [QuizEntity]) case updateTime(quizId: Int, secondTime: Int) } @@ -23,7 +22,6 @@ extension QuizService: TargetType { public var path: String { switch self { case .fetch: return "quiz/list" - case .fetchSolved: return "quiz/list/solved" case .submit: return "quiz/list/submit" case .updateTime: return "quiz/time" } @@ -32,7 +30,6 @@ extension QuizService: TargetType { public var method: Moya.Method { switch self { case .fetch: return .get - case .fetchSolved: return .get case .submit: return .post case .updateTime: return .patch } @@ -42,8 +39,6 @@ extension QuizService: TargetType { switch self { case let .fetch(newsId: id): return .requestParameters(parameters: ["newsId": id], encoding: URLEncoding.queryString) - case let .fetchSolved(newsId: id): - return .requestParameters(parameters: ["newsId": id], encoding: URLEncoding.queryString) case let .submit(quizs): let dto: SubmitQuizListRequestDTO = quizs.compactMap { if let userAnswer = $0.selectedAnswer { diff --git a/Targets/D3N/Sources/Domain/Quiz/SolvedQuizClient.swift b/Targets/D3N/Sources/Domain/Quiz/SolvedQuizClient.swift new file mode 100644 index 0000000..4bab933 --- /dev/null +++ b/Targets/D3N/Sources/Domain/Quiz/SolvedQuizClient.swift @@ -0,0 +1,44 @@ +// +// SolvedQuizClient.swift +// D3N +// +// Created by Younghoon Ahn on 11/29/23. +// Copyright © 2023 sju. All rights reserved. +// + +import Foundation + +import ComposableArchitecture +import Moya + +struct SolvedQuizClient { + var fetch: (Int) async -> Result<[SolvedQuizEntity], D3NAPIError> +} + +extension SolvedQuizClient: TestDependencyKey { + static let previewValue = Self( + fetch: { _ in .failure(.none) } + ) + + static let testValue = Self( + fetch: unimplemented("\(Self.self).fetch") + ) +} + +extension DependencyValues { + var solvedQuizClient: SolvedQuizClient { + get { self[SolvedQuizClient.self] } + } +} + +extension SolvedQuizClient: DependencyKey { + static let liveValue = SolvedQuizClient( + fetch: { _ in + let target: TargetType = SolvedQuizService.fetch + let response: Result = await D3NAPIkProvider.reqeust(target: target) + + return response.map { $0.map { $0.toEntity() } } + } + ) +} + diff --git a/Targets/D3N/Sources/Domain/Quiz/SolvedQuizService.swift b/Targets/D3N/Sources/Domain/Quiz/SolvedQuizService.swift new file mode 100644 index 0000000..8b35146 --- /dev/null +++ b/Targets/D3N/Sources/Domain/Quiz/SolvedQuizService.swift @@ -0,0 +1,41 @@ +// +// SolvedQuizService.swift +// D3N +// +// Created by Younghoon Ahn on 11/29/23. +// Copyright © 2023 sju. All rights reserved. +// + +import Foundation + +import Moya + +public enum SolvedQuizService { + case fetch +} + +extension SolvedQuizService: TargetType { + public var baseURL: URL { URL(string: Environment.baseURL)! } + + public var path: String { + switch self { + case .fetch: return "quiz/list/solved" + } + } + + public var method: Moya.Method { + switch self { + case .fetch: return .get + } + } + + public var task: Task { + switch self { + case .fetch: + return .requestPlain + } + } + + public var headers: [String: String]? { nil } +} + diff --git a/Targets/D3N/Sources/Feature/MyPage/Main/MyPageMainStore.swift b/Targets/D3N/Sources/Feature/MyPage/Main/MyPageMainStore.swift index 44d6598..9a18515 100644 --- a/Targets/D3N/Sources/Feature/MyPage/Main/MyPageMainStore.swift +++ b/Targets/D3N/Sources/Feature/MyPage/Main/MyPageMainStore.swift @@ -24,15 +24,15 @@ public struct MyPageMainStore: Reducer { case appleUnlinkRequest case appleUnlinkResponse(Result) - case solvedNewsButtonTapped + case solvedQuizButtonTapped case alert(PresentationAction) case delegate(Delegate) public enum Delegate: Equatable { case unlinked - case solvedNewsButtonTapped - case select(NewsEntity) + case solvedQuizButtonTapped + case select(SolvedQuizEntity) } public enum Alert: Equatable { @@ -66,8 +66,8 @@ public struct MyPageMainStore: Reducer { return .run { send in await send(.appleUnlinkResponse(await authClient.appleUnlink())) } - case .solvedNewsButtonTapped: - return .send(.delegate(.solvedNewsButtonTapped)) + case .solvedQuizButtonTapped: + return .send(.delegate(.solvedQuizButtonTapped)) case .appleUnlinkResponse(.success), .appleUnlinkResponse(.failure): return .send(.delegate(.unlinked)) diff --git a/Targets/D3N/Sources/Feature/MyPage/Main/MyPageMainView.swift b/Targets/D3N/Sources/Feature/MyPage/Main/MyPageMainView.swift index 8207973..9e3ea95 100644 --- a/Targets/D3N/Sources/Feature/MyPage/Main/MyPageMainView.swift +++ b/Targets/D3N/Sources/Feature/MyPage/Main/MyPageMainView.swift @@ -35,7 +35,7 @@ public struct MyPageMainView: View { private func personalSection(viewStore: ViewStoreOf) -> some View { Section { Button( action: { - viewStore.send(.solvedNewsButtonTapped) + viewStore.send(.solvedQuizButtonTapped) }, label:{ Label( title:{ diff --git a/Targets/D3N/Sources/Feature/MyPage/SolvedNews/SolvedNewsView.swift b/Targets/D3N/Sources/Feature/MyPage/Solved/SolvedQuizView.swift similarity index 85% rename from Targets/D3N/Sources/Feature/MyPage/SolvedNews/SolvedNewsView.swift rename to Targets/D3N/Sources/Feature/MyPage/Solved/SolvedQuizView.swift index 05205c1..4f557cc 100644 --- a/Targets/D3N/Sources/Feature/MyPage/SolvedNews/SolvedNewsView.swift +++ b/Targets/D3N/Sources/Feature/MyPage/Solved/SolvedQuizView.swift @@ -11,10 +11,10 @@ import SwiftUI import ComposableArchitecture -public struct SolvedNewsView: View { - let store: StoreOf +public struct SolvedQuizView: View { + let store: StoreOf - public init(store: StoreOf) { + public init(store: StoreOf) { self.store = store } @@ -35,11 +35,11 @@ public struct SolvedNewsView: View { } } - private var newsListItemsView: some View { + private var QuizListItemsView: some View { WithViewStore(self.store, observe: { $0 }) { viewStore in if viewStore.state.isEmptyNewsEntityList() { return AnyView( - Text("아직 풀어본 뉴스가 없어요") + Text("아직 풀어본 퀴즈가 없어요") .font(.title2) .foregroundColor(.gray) .padding() diff --git a/Targets/D3N/Sources/Feature/Quiz/List/Cell/SolvedQuizListItemCellStore.swift b/Targets/D3N/Sources/Feature/Quiz/List/Cell/SolvedQuizListItemCellStore.swift new file mode 100644 index 0000000..f30f6e0 --- /dev/null +++ b/Targets/D3N/Sources/Feature/Quiz/List/Cell/SolvedQuizListItemCellStore.swift @@ -0,0 +1,64 @@ +// +// SolvedQuizListItemCellStore.swift +// D3N +// +// Created by Younghoon Ahn on 12/1/23. +// Copyright © 2023 sju. All rights reserved. +// + +import Foundation + +import ComposableArchitecture + +public struct SolvedQuizListItemCellStore: Reducer { + public struct State: Equatable, Identifiable { + public var id: Int + + var question: String + var choices: [String] + var answer: Int + var reason: String + var userAnswer: Int + var news: NewsEntity + + init( + id: Int = .init(), + question: String, + choices: [String], + answer: Int, + reason: String, + userAnswer: Int, + news: NewsEntity + ) { + self.id = id + self.question = question + self.choices = choices + self.answer = answer + self.reason = reason + self.userAnswer = userAnswer + self.news = news + } + } + + public enum Action: Equatable { + case onAppear + + case delegate(Delegate) + + public enum Delegate: Equatable { + case submit(Int) + } + } + + public var body: some ReducerOf { + Reduce { state, action in + switch action { + case .onAppear: + return .none + + default: + return .none + } + } + } +} diff --git a/Targets/D3N/Sources/Feature/Quiz/List/Cell/SolvedQuizListItemCellView.swift b/Targets/D3N/Sources/Feature/Quiz/List/Cell/SolvedQuizListItemCellView.swift new file mode 100644 index 0000000..fa32976 --- /dev/null +++ b/Targets/D3N/Sources/Feature/Quiz/List/Cell/SolvedQuizListItemCellView.swift @@ -0,0 +1,38 @@ +// +// SolvedQuizListItemCellView.swift +// D3N +// +// Created by Younghoon Ahn on 12/1/23. +// Copyright © 2023 sju. All rights reserved. +// + +import Foundation +import SwiftUI + +import ComposableArchitecture + +public struct SolvedQuizListItemCellView: View { + let store: StoreOf + + public init(store: StoreOf) { + self.store = store + } + + public var body: some View { + WithViewStore(self.store, observe: { $0 }) { viewStore in + VStack { + Text(viewStore.state.question) + .padding(.top, 40) + + Spacer() + + ForEach(Array(viewStore.choices.enumerated()), id: \.offset) { index, choice in + VStack{ + Text("Hello123") + } + } + .padding() + } + } + } +}