투표기능 추가
This commit is contained in:
parent
a2b7fef39e
commit
7e13689763
|
@ -11,6 +11,7 @@ import Kingfisher
|
|||
struct AuditionApplicantItemView: View {
|
||||
|
||||
let item: GetAuditionRoleApplicantItem
|
||||
let onClickVote: (Int) -> Void
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 5.3) {
|
||||
|
@ -47,6 +48,9 @@ struct AuditionApplicantItemView: View {
|
|||
.font(.custom(Font.medium.rawValue, size: 12))
|
||||
.foregroundColor(Color.gray77)
|
||||
}
|
||||
.onTapGesture {
|
||||
onClickVote(item.applicantId)
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 18.7)
|
||||
|
||||
|
@ -67,6 +71,7 @@ struct AuditionApplicantItemView: View {
|
|||
profileImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
|
||||
voiceUrl: "",
|
||||
voteCount: 777
|
||||
)
|
||||
),
|
||||
onClickVote: { _ in }
|
||||
)
|
||||
}
|
||||
|
|
|
@ -16,5 +16,5 @@ struct GetAuditionRoleApplicantItem: Decodable {
|
|||
let nickname: String
|
||||
let profileImageUrl: String
|
||||
let voiceUrl: String
|
||||
let voteCount: Int
|
||||
var voteCount: Int
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ enum AuditionApi {
|
|||
case getAuditionRoleDetail(auditionRoleId: Int)
|
||||
case getAuditionApplicantList(auditionRoleId: Int, sortType: AuditionApplicantSortType, page: Int, size: Int)
|
||||
case applyAudition(parameters: [MultipartFormData])
|
||||
case voteApplicant(applicantId: Int)
|
||||
}
|
||||
|
||||
extension AuditionApi: TargetType {
|
||||
|
@ -37,6 +38,9 @@ extension AuditionApi: TargetType {
|
|||
|
||||
case .applyAudition:
|
||||
return "/audition/applicant"
|
||||
|
||||
case .voteApplicant:
|
||||
return "/audition/vote"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,7 +50,7 @@ extension AuditionApi: TargetType {
|
|||
case .getAuditionList, .getAuditionDetail, . getAuditionRoleDetail, .getAuditionApplicantList:
|
||||
return .get
|
||||
|
||||
case .applyAudition:
|
||||
case .applyAudition, .voteApplicant:
|
||||
return .post
|
||||
}
|
||||
}
|
||||
|
@ -77,6 +81,10 @@ extension AuditionApi: TargetType {
|
|||
|
||||
case .applyAudition(let parameters):
|
||||
return .uploadMultipart(parameters)
|
||||
|
||||
case .voteApplicant(let applicantId):
|
||||
let request = VoteAuditionApplicantRequest(applicantId: applicantId)
|
||||
return .requestJSONEncodable(request)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,4 +39,8 @@ final class AuditionRepository {
|
|||
func applyAudition(parameters: [MultipartFormData]) -> AnyPublisher<Response, MoyaError> {
|
||||
return api.requestPublisher(.applyAudition(parameters: parameters))
|
||||
}
|
||||
|
||||
func voteApplicant(applicantId: Int) -> AnyPublisher<Response, MoyaError> {
|
||||
return api.requestPublisher(.voteApplicant(applicantId: applicantId))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,8 +87,12 @@ struct AuditionRoleDetailView: View {
|
|||
ForEach(0..<viewModel.applicantList.count, id: \.self) {
|
||||
let applicant = viewModel.applicantList[$0]
|
||||
|
||||
AuditionApplicantItemView(item: applicant)
|
||||
.padding(.bottom, $0 == viewModel.applicantList.count - 1 ? 33 : 0)
|
||||
AuditionApplicantItemView(
|
||||
item: applicant,
|
||||
onClickVote: {
|
||||
viewModel.voteApplicant(applicantId: $0)
|
||||
}
|
||||
).padding(.bottom, $0 == viewModel.applicantList.count - 1 ? 33 : 0)
|
||||
|
||||
if $0 == viewModel.applicantList.count - 1 {
|
||||
Color.clear
|
||||
|
@ -193,6 +197,17 @@ struct AuditionRoleDetailView: View {
|
|||
viewModel.deleteAllRecordingFilesWithNamePrefix("voiceon_now_voice")
|
||||
}
|
||||
}
|
||||
|
||||
if viewModel.isShowSodaDialog {
|
||||
SodaDialog(
|
||||
title: viewModel.dialogTitle,
|
||||
desc: viewModel.dialogDesc,
|
||||
confirmButtonTitle: "확인"
|
||||
) {
|
||||
viewModel.isShowSodaDialog = false
|
||||
viewModel.isShowNotifyVote = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,11 @@ final class AuditionRoleDetailViewModel: ObservableObject {
|
|||
@Published var soundData: Data? = nil
|
||||
@Published var phoneNumber = ""
|
||||
|
||||
@Published var isShowNotifyVote = true
|
||||
@Published var isShowSodaDialog = false
|
||||
@Published var dialogTitle = ""
|
||||
@Published var dialogDesc = ""
|
||||
|
||||
var page = 1
|
||||
var isLast = false
|
||||
private var pageSize = 10
|
||||
|
@ -262,6 +267,62 @@ final class AuditionRoleDetailViewModel: ObservableObject {
|
|||
}
|
||||
}
|
||||
|
||||
func voteApplicant(applicantId: Int) {
|
||||
isLoading = true
|
||||
|
||||
repository.voteApplicant(applicantId: applicantId)
|
||||
.sink { result in
|
||||
switch result {
|
||||
case .finished:
|
||||
DEBUG_LOG("finish")
|
||||
case .failure(let error):
|
||||
ERROR_LOG(error.localizedDescription)
|
||||
}
|
||||
} receiveValue: { response in
|
||||
self.isLoading = false
|
||||
let responseData = response.data
|
||||
|
||||
do {
|
||||
let jsonDecoder = JSONDecoder()
|
||||
let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData)
|
||||
|
||||
if decoded.success {
|
||||
if self.isShowNotifyVote {
|
||||
self.dialogTitle = "[오디션 응원]"
|
||||
self.dialogDesc = "오디션을 응원하셨습니다\n(무료응원 : 1계정당 1일 1회)\n1캔으로 추가 응원을 해보세요."
|
||||
self.isShowSodaDialog = true
|
||||
}
|
||||
|
||||
if let index = self.applicantList.firstIndex(where: { $0.applicantId == applicantId }) {
|
||||
var applicant = self.applicantList[index]
|
||||
applicant.voteCount += 1
|
||||
|
||||
self.applicantList.remove(at: index)
|
||||
self.applicantList.insert(applicant, at: index)
|
||||
}
|
||||
} else {
|
||||
if let message = decoded.message {
|
||||
if message.contains("오늘 응원은 여기까지") {
|
||||
self.dialogTitle = "[오늘 응원 제한]"
|
||||
self.dialogDesc = "오늘 응원은 여기까지!\n하루 최대 10회까지 이용이 가능합니다.\n내일 다시 이용해주세요."
|
||||
self.isShowSodaDialog = true
|
||||
} else {
|
||||
self.errorMessage = message
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} else {
|
||||
self.errorMessage = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
.store(in: &subscription)
|
||||
}
|
||||
|
||||
func deleteAllRecordingFilesWithNamePrefix(_ prefix: String) {
|
||||
let fileManager = FileManager.default
|
||||
let documentsURL = getDocumentsDirectory()
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
//
|
||||
// VoteAuditionApplicantRequest.swift
|
||||
// SodaLive
|
||||
//
|
||||
// Created by klaus on 1/7/25.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct VoteAuditionApplicantRequest: Encodable {
|
||||
let applicantId: Int
|
||||
let container: String = "ios"
|
||||
let timezone: String = TimeZone.current.identifier
|
||||
}
|
Loading…
Reference in New Issue