Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// postCommonQuestLikeResponseDTO.swift

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

파일명 표기 불일치

헤더 주석의 파일명이 실제 파일명과 대소문자가 다릅니다 (postCommonQuestLikeResponseDTO.swiftPostCommonQuestLikeResponseDTO.swift). Swift 컨벤션에 따라 타입명과 일치하는 파일명을 사용하므로, 헤더 주석도 PostCommonQuestLikeResponseDTO.swift로 수정해야 합니다.

수정 제안
 //
-//  postCommonQuestLikeResponseDTO.swift
+//  PostCommonQuestLikeResponseDTO.swift
 //  ByeBoo-iOS
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// postCommonQuestLikeResponseDTO.swift
//
// PostCommonQuestLikeResponseDTO.swift
// ByeBoo-iOS
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ByeBoo-iOS/ByeBoo-iOS/Data/Model/PostCommonQuestLikeResponseDTO.swift` at
line 2, Header comment filename casing doesn't match the actual file/type name;
update the top-of-file header in PostCommonQuestLikeResponseDTO.swift so the
commented filename reads "PostCommonQuestLikeResponseDTO.swift" to match the
Swift file/type naming convention (e.g., the struct/class
PostCommonQuestLikeResponseDTO).

// ByeBoo-iOS
//
// Created by 이나연 on 6/10/26.
//

import Foundation

struct PostCommonQuestLikeResponseDTO: Decodable {
let likeCount: Int
let isLiked: Bool
}

extension PostCommonQuestLikeResponseDTO {
func toEntity() -> CommonQuestLikeEntity {
.init(isLiked: isLiked, likeCount: likeCount)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ enum CommonQuestAPI {
case fetchCommonQuestDetail(asnwerID: Int)
case updateCommonQuest(answerID: Int, dto: UpdateCommonQuestRequestDTO)
case deleteCommonQuest(answerID: Int)
case postCommonQuestLike(answerID: Int)
}

extension CommonQuestAPI: EndPoint {
Expand All @@ -23,7 +24,7 @@ extension CommonQuestAPI: EndPoint {
switch self {
case .fetchCommonQuest, .fetchCommonQuestDetail:
return "/api/v2/common-quests"
case .postCommonQuest, .updateCommonQuest, .deleteCommonQuest:
case .postCommonQuest, .updateCommonQuest, .deleteCommonQuest, .postCommonQuestLike:
return "/api/v1/common-quests"
}
}
Expand All @@ -36,12 +37,14 @@ extension CommonQuestAPI: EndPoint {
return ""
case .updateCommonQuest(let answerID, _), .deleteCommonQuest(let answerID), .fetchCommonQuestDetail(let answerID):
return "/\(answerID)"
case .postCommonQuestLike(let answerID):
return "/\(answerID)/likes"
}
}

var method: HTTPMethod {
switch self {
case .postCommonQuest:
case .postCommonQuest, .postCommonQuestLike:
return .post
case .fetchCommonQuest, .fetchCommonQuestDetail:
return .get
Expand All @@ -54,14 +57,15 @@ extension CommonQuestAPI: EndPoint {

var headers: HeaderType {
switch self {
case .postCommonQuest, .fetchCommonQuest, .updateCommonQuest, .deleteCommonQuest, .fetchCommonQuestDetail:
case .postCommonQuest, .fetchCommonQuest, .updateCommonQuest, .deleteCommonQuest, .fetchCommonQuestDetail,
.postCommonQuestLike:
return .withAuth
}
}

var parameterEncoding: any ParameterEncoding {
switch self {
case .postCommonQuest, .updateCommonQuest:
case .postCommonQuest, .updateCommonQuest, .postCommonQuestLike:
return JSONEncoding.default
case .fetchCommonQuest, .deleteCommonQuest, .fetchCommonQuestDetail:
return URLEncoding.default
Expand All @@ -70,7 +74,7 @@ extension CommonQuestAPI: EndPoint {

var queryParameters: [String : String]? {
switch self {
case .postCommonQuest, .updateCommonQuest, .deleteCommonQuest, .fetchCommonQuestDetail:
case .postCommonQuest, .updateCommonQuest, .deleteCommonQuest, .fetchCommonQuestDetail, .postCommonQuestLike:
return nil
case .fetchCommonQuest(let date, let cursor):
if let cursor {
Expand All @@ -87,7 +91,7 @@ extension CommonQuestAPI: EndPoint {
switch self {
case .postCommonQuest(_, let dto):
return try? dto.toDictionary()
case .fetchCommonQuest, .deleteCommonQuest, .fetchCommonQuestDetail:
case .fetchCommonQuest, .deleteCommonQuest, .fetchCommonQuestDetail, .postCommonQuestLike:
return nil
case .updateCommonQuest(_, let dto):
return try? dto.toDictionary()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,12 @@ struct DefaultCommonQuestRepository: CommonQuestInterface {

return commonQuestDetail.toEntity(userID: userID)
}

func postCommonQuestLikes(answerID: Int) async throws -> CommonQuestLikeEntity {
let response = try await network.request(
CommonQuestAPI.postCommonQuestLike(answerID: answerID),
decodingType: PostCommonQuestLikeResponseDTO.self
)
return response.toEntity()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,13 @@ struct DomainDependencyAssembler: DependencyAssembler {
DIContainer.shared.register(type: DeleteCommonQuestUseCase.self) { _ in
return DefaultDeleteCommonQuestUseCase(repository: commonQuestRepository)
}

DIContainer.shared.register(type: FetchCommonQuestDetailUseCase.self) { _ in
return DefaultFetchCommonQuestDetailUseCase(repository: commonQuestRepository)
}

DIContainer.shared.register(type: PostCommonQuestLikeUseCase.self) { _ in
return DefaultPostCommonQuestLikeUseCase(repository: commonQuestRepository)
}
}
}
13 changes: 13 additions & 0 deletions ByeBoo-iOS/ByeBoo-iOS/Domain/Entity/CommonQuestLikeEntity.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// CommonQuestLikeEntity.swift
// ByeBoo-iOS
//
// Created by 이나연 on 6/13/26.
//

import Foundation

struct CommonQuestLikeEntity {
let isLiked: Bool
let likeCount: Int
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ protocol CommonQuestInterface {
func updateCommonQuest(answerID: Int, answer: String) async throws
func deleteCommonQuest(answerID: Int) async throws
func fetchCommonQuestDetail(answerID: Int) async throws -> CommonQuestDetailEntity
func postCommonQuestLikes(answerID: Int) async throws -> CommonQuestLikeEntity
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// PostCommonQuestLikeUseCase.swift
// ByeBoo-iOS
//
// Created by 이나연 on 6/10/26.
//

import Foundation

protocol PostCommonQuestLikeUseCase {
func execute(answerID: Int) async throws -> CommonQuestLikeEntity
}

struct DefaultPostCommonQuestLikeUseCase: PostCommonQuestLikeUseCase {
private let repository: CommonQuestInterface

init(repository: CommonQuestInterface) {
self.repository = repository
}

func execute(answerID: Int) async throws -> CommonQuestLikeEntity {
return try await repository.postCommonQuestLikes(answerID: answerID)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ extension CommonQuestAnswerCell {
userNicknameLabel.text = answer.writer
answerID = answer.answerID
questContentView.configure(
answerID: answer.answerID,
content: answer.content,
writtenAt: writtenAt,
isLiked: answer.isLiked,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ final class CommonQuestMyAnswerCell: UITableViewCell {
extension CommonQuestMyAnswerCell {

func bind(
answerID: Int,
question: String,
content: String,
writtenAt: String,
Expand All @@ -104,6 +105,7 @@ extension CommonQuestMyAnswerCell {
) {
questionContentLabel.text = question
questContentView.configure(
answerID: answerID,
content: content,
writtenAt: writtenAt,
isLiked: isLiked,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import UIKit

protocol CommonQuestLikeCommentProtocol: AnyObject {
func likeButtonDidTap()
func likeButtonDidTap(answerID: Int)
}

final class QuestContentView: BaseView {
Expand All @@ -26,6 +26,7 @@ final class QuestContentView: BaseView {

weak var delegate: CommonQuestLikeCommentProtocol?

private var answerID: Int = 0
private var likeCounts: Int = 0

override func setUI() {
Expand Down Expand Up @@ -102,13 +103,15 @@ final class QuestContentView: BaseView {
}

func configure(
answerID: Int,
content: String,
writtenAt: String? = nil,
isLiked: Bool,
likeCount: Int,
commentCount: Int,
showAllText: Bool
) {
self.answerID = answerID
self.likeCounts = likeCount
answerContentTextView.do {
$0.textContainer.maximumNumberOfLines = showAllText ? 0 : 2
Expand All @@ -123,11 +126,13 @@ final class QuestContentView: BaseView {
commentCountLabel.text = String(commentCount)
}

func updateUI(likeCount: Int, isLiked: Bool) {
likeCountLabel.text = String(likeCount)
likeButton.isSelected = isLiked
}

@objc
private func likeButtonDidTap() {
likeButton.isSelected.toggle()
likeCounts += likeButton.isSelected ? 1 : -1
likeCountLabel.text = String(likeCounts)
delegate?.likeButtonDidTap()
delegate?.likeButtonDidTap(answerID: self.answerID)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ final class CommonQuestHistoryView: BaseView {
private let answerView = UIView()
private let profileIconImageView = UIImageView()
private let userNicknameLabel = UILabel()
private let questContentView = QuestContentView()
private(set) var questContentView = QuestContentView()
private(set) var commentListView = SelfSizingTableView()
private let commentTextView = CommentTextView()

Expand Down Expand Up @@ -165,6 +165,7 @@ extension CommonQuestHistoryView {
extension CommonQuestHistoryView {

func configure(
answerID: Int,
question: String,
writtenAt: String,
profileIcon: UIImage,
Expand All @@ -177,6 +178,7 @@ extension CommonQuestHistoryView {
questionContentLabel.text = question
dateLabel.text = writtenAt
questContentView.configure(
answerID: answerID,
content: content,
isLiked: isLiked,
likeCount: likeCount,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ final class CommonQuestHistoryViewController: BaseViewController {
$0.separatorStyle = .none
$0.register(CommentTableViewCell.self)
}
rootView.questContentView.delegate = self
}
}

Expand Down Expand Up @@ -231,13 +232,27 @@ extension CommonQuestHistoryViewController {
}
}
.store(in: &cancellable)

viewModel.output.commonQuestLikeCountPublisher
.receive(on: DispatchQueue.main)
.sink { [weak self] result in
switch result {
case .success(let result):
let entity = result.entity
self?.rootView.questContentView.updateUI(likeCount: entity.likeCount, isLiked: entity.isLiked)
case .failure(let error):
ByeBooLogger.error(error)
}
}
.store(in: &cancellable)
}

private func bindData(entity: CommonQuestDetailEntity) {
let answer = entity.answer
self.writerID = answer.writerID

rootView.configure(
answerID: answerID,
question: entity.question,
writtenAt: ServerDateFormatter.shared.relativeTimeString(from: answer.writtenAt) ?? "", //TODO: ViewModel로 수정
profileIcon: ProfileIcon.image(for: answer.profileIcon) ?? .relievedBadge,
Expand Down Expand Up @@ -288,3 +303,9 @@ extension CommonQuestHistoryViewController: KeyboardHandleProtocol {
}
}
}

extension CommonQuestHistoryViewController: CommonQuestLikeCommentProtocol {
func likeButtonDidTap(answerID: Int) {
viewModel.action(.likeButtonDidTap(answerID: answerID))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ extension CommonQuestMyAnswersViewController {
private func bind() {
bindName()
bindCommonQuestAnswers()
bindLikeCount()
}

private func bindName() {
Expand Down Expand Up @@ -98,6 +99,38 @@ extension CommonQuestMyAnswersViewController {
}
.store(in: &cancellable)
}

private func bindLikeCount() {
viewModel.output.commonQuestLikeCountPublisher
.receive(on: DispatchQueue.main)
.sink { [weak self] result in
switch result {
case .success(let result):
let entity = result.entity
self?.updateLikeCount(
answerID: result.answerID,
likeCount: entity.likeCount,
isLiked: entity.isLiked
)
case .failure(let error):
ByeBooLogger.error(error)
}
}
.store(in: &cancellable)
}

private func updateLikeCount(answerID: Int, likeCount: Int, isLiked: Bool) {
guard let answerIndex = viewModel.indexOfAnswer(answerID: answerID) else {
return
}

let indexPath = IndexPath(row: 0, section: answerIndex)
guard let cell = rootView.answersTableView.cellForRow(at: indexPath) as? CommonQuestMyAnswerCell else {
return
}

cell.questContentView.updateUI(likeCount: likeCount, isLiked: isLiked)
}
}

extension CommonQuestMyAnswersViewController: UITableViewDelegate {
Expand Down Expand Up @@ -191,6 +224,7 @@ extension CommonQuestMyAnswersViewController: UITableViewDataSource {
let cell: CommonQuestMyAnswerCell = tableView.dequeueReusableCell(for: indexPath)
cell.questContentView.delegate = self
cell.bind(
answerID: answer.answerID,
question: answer.question,
content: answer.content,
writtenAt: answer.writtenAt,
Expand All @@ -203,7 +237,7 @@ extension CommonQuestMyAnswersViewController: UITableViewDataSource {
}

extension CommonQuestMyAnswersViewController: CommonQuestLikeCommentProtocol {
func likeButtonDidTap() {
// TODO: like button
func likeButtonDidTap(answerID: Int) {
viewModel.action(.likeButtonDidTap(answerID: answerID))
}
}
Loading
Loading