diff --git a/Poppool/Poppool/DataLayer/Network/API/AdminAPI/AdminAPIEndpoint.swift b/Poppool/Poppool/DataLayer/Network/API/AdminAPI/AdminAPIEndpoint.swift index 2f9a6433..40305bfe 100644 --- a/Poppool/Poppool/DataLayer/Network/API/AdminAPI/AdminAPIEndpoint.swift +++ b/Poppool/Poppool/DataLayer/Network/API/AdminAPI/AdminAPIEndpoint.swift @@ -1,5 +1,7 @@ import Foundation +struct EmptyResponse: Decodable {} + struct AdminAPIEndpoint { // MARK: - Store List diff --git a/Poppool/Poppool/DataLayer/Network/API/AdminAPI/ResponseDTO/AdminResponseDTO.swift b/Poppool/Poppool/DataLayer/Network/API/AdminAPI/ResponseDTO/AdminResponseDTO.swift index 329934c5..338ec553 100644 --- a/Poppool/Poppool/DataLayer/Network/API/AdminAPI/ResponseDTO/AdminResponseDTO.swift +++ b/Poppool/Poppool/DataLayer/Network/API/AdminAPI/ResponseDTO/AdminResponseDTO.swift @@ -40,6 +40,3 @@ struct GetAdminPopUpStoreDetailResponseDTO: Decodable { let imageUrl: String } } - -// MARK: - Empty Response -struct EmptyResponse: Decodable {} diff --git a/Poppool/Poppool/DataLayer/Network/API/MapAPI/MapAPIEndpoint.swift b/Poppool/Poppool/DataLayer/Network/API/MapAPI/MapAPIEndpoint.swift index da8bc4fd..334067a5 100644 --- a/Poppool/Poppool/DataLayer/Network/API/MapAPI/MapAPIEndpoint.swift +++ b/Poppool/Poppool/DataLayer/Network/API/MapAPI/MapAPIEndpoint.swift @@ -52,7 +52,6 @@ struct MapAPIEndpoint { } } -// MARK: - Query DTOs struct BoundQueryDTO: Encodable { let northEastLat: Double let northEastLon: Double diff --git a/Poppool/Poppool/DataLayer/Network/API/MapAPI/ResponseDTO/MapPopUpStoreDTO.swift b/Poppool/Poppool/DataLayer/Network/API/MapAPI/ResponseDTO/MapPopUpStoreDTO.swift index cd7bb5de..7f356980 100644 --- a/Poppool/Poppool/DataLayer/Network/API/MapAPI/ResponseDTO/MapPopUpStoreDTO.swift +++ b/Poppool/Poppool/DataLayer/Network/API/MapAPI/ResponseDTO/MapPopUpStoreDTO.swift @@ -29,11 +29,9 @@ struct MapPopUpStoreDTO: Codable { markerTitle: markerTitle, markerSnippet: markerSnippet, mainImageUrl: mainImageUrl - ) } } - struct GetViewBoundPopUpStoreListResponse: Decodable { let popUpStoreList: [MapPopUpStoreDTO] } diff --git a/Poppool/Poppool/DataLayer/RepositoryImpl/AdminRepositoryImpl.swift b/Poppool/Poppool/DataLayer/RepositoryImpl/AdminRepositoryImpl.swift index 71de6881..5856ca40 100644 --- a/Poppool/Poppool/DataLayer/RepositoryImpl/AdminRepositoryImpl.swift +++ b/Poppool/Poppool/DataLayer/RepositoryImpl/AdminRepositoryImpl.swift @@ -1,6 +1,5 @@ -import Foundation - import Alamofire +import Foundation import RxSwift final class AdminRepositoryImpl: AdminRepository { @@ -15,7 +14,7 @@ final class AdminRepositoryImpl: AdminRepository { } // MARK: - Store Methods - func fetchStoreList(query: String?, page: Int, size: Int) -> Observable { + func fetchStoreList(query: String?, page: Int, size: Int) -> Observable<[AdminStore]> { let endpoint = AdminAPIEndpoint.fetchStoreList( query: query, page: page, @@ -25,131 +24,135 @@ final class AdminRepositoryImpl: AdminRepository { with: endpoint, interceptor: tokenInterceptor ) + .map { response in + response.popUpStoreList?.map { + AdminStore(id: $0.id, name: $0.name, categoryName: $0.categoryName, mainImageUrl: $0.mainImageUrl) + } ?? [] + } } - func fetchStoreDetail(id: Int64) -> Observable { + func fetchStoreDetail(id: Int64) -> Observable { let endpoint = AdminAPIEndpoint.fetchStoreDetail(id: id) return provider.requestData( with: endpoint, interceptor: tokenInterceptor ) + .map { dto in + AdminStoreDetail( + id: dto.id, + name: dto.name, + categoryId: dto.categoryId, + categoryName: dto.categoryName, + description: dto.desc, + address: dto.address, + startDate: dto.startDate, + endDate: dto.endDate, + createUserId: dto.createUserId, + createDateTime: dto.createDateTime, + mainImageUrl: dto.mainImageUrl, + bannerYn: dto.bannerYn, + images: dto.imageList.map { + AdminStoreDetail.StoreImage( + id: $0.id, + imageUrl: $0.imageUrl + ) + }, + latitude: dto.latitude, + longitude: dto.longitude, + markerTitle: dto.markerTitle, + markerSnippet: dto.markerSnippet + ) + } .catch { error in if case .responseSerializationFailed = error as? AFError { - // 빈 데이터 응답시 기본값 반환 - return Observable.just(GetAdminPopUpStoreDetailResponseDTO.empty) + return Observable.empty() } throw error } } - func createStore(request: CreatePopUpStoreRequestDTO) -> Observable { - Logger.log(message: "createStore API 호출 시작", category: .info) - let endpoint = AdminAPIEndpoint.createStore(request: request) - Logger.log(message: "Request URL: \(endpoint.baseURL + endpoint.path)", category: .info) - Logger.log(message: "Request Body: \(request)", category: .info) - - return provider.requestData( - with: endpoint, - interceptor: tokenInterceptor - ) - .catch { error -> Observable in - if case .responseSerializationFailed(let reason) = error as? AFError, - case .inputDataNilOrZeroLength = reason { - // 빈 응답 데이터일 경우 성공으로 간주 - Logger.log(message: "빈 응답 데이터 처리: 성공으로 간주", category: .info) - return Observable.just(EmptyResponse()) - } - throw error - } - .do( - onNext: { _ in - Logger.log(message: "createStore API 호출 성공", category: .info) - }, - onError: { error in - Logger.log(message: "createStore API 호출 실패: \(error)", category: .error) - } + func createStore(params: CreateStoreParams) -> Completable { + let dto = CreatePopUpStoreRequestDTO( + name: params.name, + categoryId: params.categoryId, + desc: params.desc, + address: params.address, + startDate: params.startDate, + endDate: params.endDate, + mainImageUrl: params.mainImageUrl, + imageUrlList: params.imageUrlList, + latitude: params.latitude, + longitude: params.longitude, + markerTitle: params.markerTitle, + markerSnippet: params.markerSnippet, + startDateBeforeEndDate: params.startDateBeforeEndDate ) + let endpoint = AdminAPIEndpoint.createStore(request: dto) + return provider.request(with: endpoint, interceptor: tokenInterceptor) } - func updateStore(request: UpdatePopUpStoreRequestDTO) -> Observable { - let endpoint = AdminAPIEndpoint.updateStore(request: request) - - Logger.log(message: """ - Store Update 요청: - URL: \(endpoint.baseURL + endpoint.path) - Method: PUT - Request: \(request) - """, category: .debug) - - return provider.requestData( - with: endpoint, - interceptor: tokenInterceptor + func updateStore(params: UpdateStoreParams) -> Completable { + let dto = UpdatePopUpStoreRequestDTO( + popUpStore: UpdatePopUpStoreRequestDTO.PopUpStore( + id: params.id, + name: params.name, + categoryId: params.categoryId, + desc: params.desc, + address: params.address, + startDate: params.startDate, + endDate: params.endDate, + mainImageUrl: params.mainImageUrl, + bannerYn: !params.mainImageUrl.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty, + imageUrl: params.imageUrlList.compactMap { $0 }, + startDateBeforeEndDate: params.startDateBeforeEndDate + ), + location: UpdatePopUpStoreRequestDTO.Location( + latitude: params.latitude, + longitude: params.longitude, + markerTitle: params.markerTitle, + markerSnippet: params.markerSnippet + ), + imagesToAdd: params.imageUrlList.compactMap { $0 }, + imagesToDelete: params.imagesToDelete ) - .catch { error -> Observable in - Logger.log(message: "Update Store Error 발생: \(error)", category: .error) - - if let afError = error as? AFError { - switch afError { - case .responseSerializationFailed(let reason): - Logger.log(message: "Serialization 실패 reason: \(reason)", category: .error) - if case .inputDataNilOrZeroLength = reason { - Logger.log(message: "빈 응답 데이터 - 성공으로 처리", category: .info) - return Observable.just(EmptyResponse()) - } - default: - Logger.log(message: "기타 AFError: \(afError)", category: .error) - } - } - - throw error - } - .do(onNext: { _ in - Logger.log(message: "Store Update 성공", category: .info) - }, onError: { error in - Logger.log(message: "Store Update 최종 실패: \(error)", category: .error) - }) + let endpoint = AdminAPIEndpoint.updateStore(request: dto) + return provider.request(with: endpoint, interceptor: tokenInterceptor) } - func deleteStore(id: Int64) -> Observable { - Logger.log(message: "deleteStore API 호출 시작", category: .info) + func deleteStore(id: Int64) -> Completable { let endpoint = AdminAPIEndpoint.deleteStore(id: id) return provider.request(with: endpoint, interceptor: tokenInterceptor) - .andThen(Observable.just(EmptyResponse())) - .do( - onNext: { _ in - Logger.log(message: "deleteStore API 호출 성공", category: .info) - }, - onError: { error in - Logger.log(message: "deleteStore API 호출 실패: \(error)", category: .error) - } - ) } // MARK: - Notice Methods - func createNotice(request: CreateNoticeRequestDTO) -> Observable { - let endpoint = AdminAPIEndpoint.createNotice(request: request) - return provider.requestData( - with: endpoint, - interceptor: tokenInterceptor + func createNotice(params: CreateNoticeParams) -> Completable { + let dto = CreateNoticeRequestDTO( + title: params.title, + content: params.content, + imageUrlList: params.imageUrlList ) + let endpoint = AdminAPIEndpoint.createNotice(request: dto) + return provider.request(with: endpoint, interceptor: tokenInterceptor) } - func updateNotice(id: Int64, request: UpdateNoticeRequestDTO) -> Observable { - let endpoint = AdminAPIEndpoint.updateNotice(id: id, request: request) - return provider.requestData( - with: endpoint, - interceptor: tokenInterceptor + func updateNotice(params: UpdateNoticeParams) -> Completable { + let dto = UpdateNoticeRequestDTO( + title: params.title, + content: params.content, + imageUrlList: params.imageUrlList, + imagesToDelete: params.imagesToDelete ) + let endpoint = AdminAPIEndpoint.updateNotice(id: params.id, request: dto) + return provider.request(with: endpoint, interceptor: tokenInterceptor) } - func deleteNotice(id: Int64) -> Observable { + func deleteNotice(id: Int64) -> Completable { let endpoint = AdminAPIEndpoint.deleteNotice(id: id) - return provider.requestData( - with: endpoint, - interceptor: tokenInterceptor - ) + return provider.request(with: endpoint, interceptor: tokenInterceptor) } } + +// Helper extension - keeping this for utility purposes extension GetAdminPopUpStoreDetailResponseDTO { static var empty: GetAdminPopUpStoreDetailResponseDTO { return GetAdminPopUpStoreDetailResponseDTO( diff --git a/Poppool/Poppool/DataLayer/RepositoryImpl/AuthAPIRepositoryImpl.swift b/Poppool/Poppool/DataLayer/RepositoryImpl/AuthAPIRepositoryImpl.swift index a0847bd2..c1f27826 100644 --- a/Poppool/Poppool/DataLayer/RepositoryImpl/AuthAPIRepositoryImpl.swift +++ b/Poppool/Poppool/DataLayer/RepositoryImpl/AuthAPIRepositoryImpl.swift @@ -1,5 +1,4 @@ import Foundation - import RxSwift final class AuthAPIRepositoryImpl: AuthAPIRepository { @@ -20,8 +19,11 @@ final class AuthAPIRepositoryImpl: AuthAPIRepository { } } - func postTokenReissue() -> Observable { + func postTokenReissue() -> Observable { let endPoint = AuthAPIEndPoint.postTokenReissue() return provider.requestData(with: endPoint, interceptor: tokenInterceptor) + .map { responseDTO in + return responseDTO.toDomain() + } } } diff --git a/Poppool/Poppool/DataLayer/RepositoryImpl/CommentAPIRepositoryImpl.swift b/Poppool/Poppool/DataLayer/RepositoryImpl/CommentAPIRepositoryImpl.swift index 22ae8766..6fa51907 100644 --- a/Poppool/Poppool/DataLayer/RepositoryImpl/CommentAPIRepositoryImpl.swift +++ b/Poppool/Poppool/DataLayer/RepositoryImpl/CommentAPIRepositoryImpl.swift @@ -11,18 +11,21 @@ final class CommentAPIRepositoryImpl: CommentAPIRepository { self.provider = provider } - func postCommentAdd(request: PostCommentRequestDTO) -> Completable { - let endPoint = CommentAPIEndPoint.postCommentAdd(request: request) + func postCommentAdd(popUpStoreId: Int64, content: String?, commentType: String?, imageUrlList: [String?]) -> Completable { + let requestDTO = PostCommentRequestDTO(popUpStoreId: popUpStoreId, content: content, commentType: commentType, imageUrlList: imageUrlList) + let endPoint = CommentAPIEndPoint.postCommentAdd(request: requestDTO) return provider.request(with: endPoint, interceptor: tokenInterceptor) } - func deleteComment(request: DeleteCommentRequestDTO) -> Completable { - let endPoint = CommentAPIEndPoint.deleteComment(request: request) + func deleteComment(popUpStoreId: Int64, commentId: Int64) -> Completable { + let requestDTO = DeleteCommentRequestDTO(popUpStoreId: popUpStoreId, commentId: commentId) + let endPoint = CommentAPIEndPoint.deleteComment(request: requestDTO) return provider.request(with: endPoint, interceptor: tokenInterceptor) } - func editComment(request: PutCommentRequestDTO) -> Completable { - let endPoint = CommentAPIEndPoint.editComment(request: request) + func editComment(popUpStoreId: Int64, commentId: Int64, content: String?, imageUrlList: [PutCommentImageDataRequestDTO]?) -> Completable { + let requestDTO = PutCommentRequestDTO(popUpStoreId: popUpStoreId, commentId: commentId, content: content, imageUrlList: imageUrlList) + let endPoint = CommentAPIEndPoint.editComment(request: requestDTO) return provider.request(with: endPoint, interceptor: tokenInterceptor) } } diff --git a/Poppool/Poppool/DataLayer/RepositoryImpl/MapDirectionRepositoryImpl.swift b/Poppool/Poppool/DataLayer/RepositoryImpl/MapDirectionRepositoryImpl.swift index 8d0fa37c..25a7791f 100644 --- a/Poppool/Poppool/DataLayer/RepositoryImpl/MapDirectionRepositoryImpl.swift +++ b/Poppool/Poppool/DataLayer/RepositoryImpl/MapDirectionRepositoryImpl.swift @@ -3,7 +3,7 @@ import Foundation import RxSwift final class MapDirectionRepositoryImpl: MapDirectionRepository { - + private let provider: Provider private let tokenInterceptor = TokenInterceptor() diff --git a/Poppool/Poppool/DataLayer/RepositoryImpl/MapRepositoryImpl.swift b/Poppool/Poppool/DataLayer/RepositoryImpl/MapRepositoryImpl.swift index c78a6af6..08ffdbee 100644 --- a/Poppool/Poppool/DataLayer/RepositoryImpl/MapRepositoryImpl.swift +++ b/Poppool/Poppool/DataLayer/RepositoryImpl/MapRepositoryImpl.swift @@ -2,9 +2,8 @@ import Foundation import RxSwift -// MARK: - Implementation final class MapRepositoryImpl: MapRepository { - + private let provider: Provider init(provider: Provider) { @@ -17,7 +16,7 @@ final class MapRepositoryImpl: MapRepository { southWestLat: Double, southWestLon: Double, categories: [Int64] - ) -> Observable<[MapPopUpStoreDTO]> { + ) -> Observable<[MapPopUpStore]> { return provider.requestData( with: MapAPIEndpoint.locations_fetchStoresInBounds( northEastLat: northEastLat, @@ -28,13 +27,13 @@ final class MapRepositoryImpl: MapRepository { ), interceptor: TokenInterceptor() ) - .map { $0.popUpStoreList } + .map { $0.popUpStoreList.map { $0.toDomain() } } } func searchStores( query: String, categories: [Int64] - ) -> Observable<[MapPopUpStoreDTO]> { + ) -> Observable<[MapPopUpStore]> { return provider.requestData( with: MapAPIEndpoint.locations_searchStores( query: query, @@ -42,38 +41,31 @@ final class MapRepositoryImpl: MapRepository { ), interceptor: TokenInterceptor() ) - .map { $0.popUpStoreList } + .map { $0.popUpStoreList.map { $0.toDomain() } } } func fetchCategories() -> Observable<[CategoryResponse]> { - Logger.log(message: "카테고리 매핑 요청을 시작합니다.", category: .network) + Logger.log(message: "카테고리 목록 요청을 시작합니다.", category: .network) return provider.requestData( with: SignUpAPIEndpoint.signUp_getCategoryList(), interceptor: TokenInterceptor() ) - .do(onNext: { responseDTO in + .do(onNext: { _ in Logger.log( - message: """ - 카테고리 매핑 응답: - - Response: \(responseDTO) - - categoryResponseList: \(responseDTO.categoryResponseList) - """, + message: "카테고리 목록 응답 성공", category: .debug ) }) .map { responseDTO in - let categories = responseDTO.categoryResponseList.map { $0.toDomain() } - Logger.log(message: "매핑된 카테고리 데이터: \(categories)", category: .debug) - return categories + responseDTO.categoryResponseList.map { $0.toDomain() } } .catch { error in Logger.log( - message: "카테고리 매핑 요청 실패: \(error.localizedDescription)", + message: "카테고리 목록 요청 실패: \(error.localizedDescription)", category: .error ) throw error } } - } diff --git a/Poppool/Poppool/DomainLayer/Domain/UseCaseImpl/AdminUseCaseImpl.swift b/Poppool/Poppool/DomainLayer/Domain/UseCaseImpl/AdminUseCaseImpl.swift index 77097ed2..1f11e19f 100644 --- a/Poppool/Poppool/DomainLayer/Domain/UseCaseImpl/AdminUseCaseImpl.swift +++ b/Poppool/Poppool/DomainLayer/Domain/UseCaseImpl/AdminUseCaseImpl.swift @@ -1,5 +1,4 @@ import Foundation - import RxSwift final class AdminUseCaseImpl: AdminUseCase { @@ -10,53 +9,52 @@ final class AdminUseCaseImpl: AdminUseCase { self.repository = repository } - func fetchStoreList(query: String?, page: Int, size: Int) -> Observable { + func fetchStoreList(query: String?, page: Int, size: Int) -> Observable<[AdminStore]> { return repository.fetchStoreList(query: query, page: page, size: size) } - func fetchStoreDetail(id: Int64) -> Observable { + func fetchStoreDetail(id: Int64) -> Observable { return repository.fetchStoreDetail(id: id) } - func createStore(request: CreatePopUpStoreRequestDTO) -> Observable { - Logger.log(message: "createStore 호출 - 요청 데이터: \(request)", category: .debug) - return repository.createStore(request: request) - .do(onNext: { _ in - Logger.log(message: "createStore 성공", category: .info) - }, onError: { error in + func createStore(params: CreateStoreParams) -> Completable { + Logger.log(message: "createStore 호출 - 스토어명: \(params.name)", category: .debug) + return repository.createStore(params: params) + .do(onError: { error in Logger.log(message: "createStore 실패 - Error: \(error)", category: .error) + }, onCompleted: { + Logger.log(message: "createStore 성공", category: .info) }) } - func updateStore(request: UpdatePopUpStoreRequestDTO) -> Observable { + func updateStore(params: UpdateStoreParams) -> Completable { Logger.log(message: """ Updating store with location: - Latitude: \(request.location.latitude) - Longitude: \(request.location.longitude) + Latitude: \(params.latitude) + Longitude: \(params.longitude) """, category: .debug) - - return repository.updateStore(request: request) - .do(onNext: { _ in - Logger.log(message: "Store update successful", category: .debug) - }, onError: { error in + return repository.updateStore(params: params) + .do(onError: { error in Logger.log(message: "Store update failed: \(error)", category: .error) + }, onCompleted: { + Logger.log(message: "Store update successful", category: .debug) }) } - func deleteStore(id: Int64) -> Observable { + func deleteStore(id: Int64) -> Completable { return repository.deleteStore(id: id) } // Notice - func createNotice(request: CreateNoticeRequestDTO) -> Observable { - return repository.createNotice(request: request) + func createNotice(params: CreateNoticeParams) -> Completable { + return repository.createNotice(params: params) } - func updateNotice(id: Int64, request: UpdateNoticeRequestDTO) -> Observable { - return repository.updateNotice(id: id, request: request) + func updateNotice(params: UpdateNoticeParams) -> Completable { + return repository.updateNotice(params: params) } - func deleteNotice(id: Int64) -> Observable { + func deleteNotice(id: Int64) -> Completable { return repository.deleteNotice(id: id) } } diff --git a/Poppool/Poppool/DomainLayer/Domain/UseCaseImpl/AuthAPIUseCaseImpl.swift b/Poppool/Poppool/DomainLayer/Domain/UseCaseImpl/AuthAPIUseCaseImpl.swift index 841a4034..258cb9e0 100644 --- a/Poppool/Poppool/DomainLayer/Domain/UseCaseImpl/AuthAPIUseCaseImpl.swift +++ b/Poppool/Poppool/DomainLayer/Domain/UseCaseImpl/AuthAPIUseCaseImpl.swift @@ -1,5 +1,4 @@ import Foundation - import RxSwift final class AuthAPIUseCaseImpl: AuthAPIUseCase { @@ -15,7 +14,6 @@ final class AuthAPIUseCaseImpl: AuthAPIUseCase { } func postTokenReissue() -> Observable { - let endPoint = AuthAPIEndPoint.postTokenReissue() - return repository.postTokenReissue().map { $0.toDomain() } + return repository.postTokenReissue() } } diff --git a/Poppool/Poppool/DomainLayer/Domain/UseCaseImpl/CommentAPIUseCaseImpl.swift b/Poppool/Poppool/DomainLayer/Domain/UseCaseImpl/CommentAPIUseCaseImpl.swift index c7a31242..96b13ae4 100644 --- a/Poppool/Poppool/DomainLayer/Domain/UseCaseImpl/CommentAPIUseCaseImpl.swift +++ b/Poppool/Poppool/DomainLayer/Domain/UseCaseImpl/CommentAPIUseCaseImpl.swift @@ -1,9 +1,8 @@ import Foundation - import RxSwift final class CommentAPIUseCaseImpl: CommentAPIUseCase { - + private let repository: CommentAPIRepository init(repository: CommentAPIRepository) { @@ -11,14 +10,15 @@ final class CommentAPIUseCaseImpl: CommentAPIUseCase { } func postCommentAdd(popUpStoreId: Int64, content: String?, commentType: String?, imageUrlList: [String?]) -> Completable { - return repository.postCommentAdd(request: .init(popUpStoreId: popUpStoreId, content: content, commentType: commentType, imageUrlList: imageUrlList)) + return repository.postCommentAdd(popUpStoreId: popUpStoreId, content: content, commentType: commentType, imageUrlList: imageUrlList) } func deleteComment(popUpStoreId: Int64, commentId: Int64) -> Completable { - return repository.deleteComment(request: .init(popUpStoreId: popUpStoreId, commentId: commentId)) + return repository.deleteComment(popUpStoreId: popUpStoreId, commentId: commentId) } - func editComment(popUpStoreId: Int64, commentId: Int64, content: String?, imageUrlList: [PutCommentImageDataRequestDTO]?) -> Completable { - return repository.editComment(request: .init(popUpStoreId: popUpStoreId, commentId: commentId, content: content, imageUrlList: imageUrlList)) + func editComment(popUpStoreId: Int64, commentId: Int64, content: String?, imageUrlList: [String?]?) -> Completable { + let dtoList: [PutCommentImageDataRequestDTO]? = imageUrlList?.compactMap { $0 }.map { PutCommentImageDataRequestDTO(imageUrl: $0) } + return repository.editComment(popUpStoreId: popUpStoreId, commentId: commentId, content: content, imageUrlList: dtoList) } } diff --git a/Poppool/Poppool/DomainLayer/Domain/UseCaseImpl/MapUseCaseImpl.swift b/Poppool/Poppool/DomainLayer/Domain/UseCaseImpl/MapUseCaseImpl.swift index f06968c0..7ffd64c2 100644 --- a/Poppool/Poppool/DomainLayer/Domain/UseCaseImpl/MapUseCaseImpl.swift +++ b/Poppool/Poppool/DomainLayer/Domain/UseCaseImpl/MapUseCaseImpl.swift @@ -21,15 +21,18 @@ final class MapUseCaseImpl: MapUseCase { southWestLon: Double, categories: [Int64] ) -> Observable<[MapPopUpStore]> { - return repository.fetchStoresInBounds( northEastLat: northEastLat, northEastLon: northEastLon, southWestLat: southWestLat, southWestLon: southWestLon, - categories: categories // ← 그대로 넘긴다 + categories: categories ) - .map { $0.map { $0.toDomain() } } + .do(onNext: { stores in + Logger.log(message: "맵 범위 내 스토어 \(stores.count)개 로드됨", category: .debug) + }, onError: { error in + Logger.log(message: "맵 범위 내 스토어 로드 실패: \(error)", category: .error) + }) } func searchStores( @@ -38,23 +41,28 @@ final class MapUseCaseImpl: MapUseCase { ) -> Observable<[MapPopUpStore]> { return repository.searchStores( query: query, - categories: categories.map { Int64($0) ?? 0 } + categories: categories ) - .map { $0.map { $0.toDomain() } } + .do(onNext: { stores in + Logger.log(message: "'\(query)' 검색 결과 \(stores.count)개 로드됨", category: .debug) + }, onError: { error in + Logger.log(message: "스토어 검색 실패: \(error)", category: .error) + }) } + func filterStoresByLocation(_ stores: [MapPopUpStore], selectedRegions: [String]) -> [MapPopUpStore] { - guard !selectedRegions.isEmpty else { return stores } + guard !selectedRegions.isEmpty else { return stores } - return stores.filter { store in - let components = store.address.components(separatedBy: " ") - guard components.count >= 2 else { return false } + return stores.filter { store in + let components = store.address.components(separatedBy: " ") + guard components.count >= 2 else { return false } - let mainRegion = components[0].replacingOccurrences(of: "특별시", with: "") - .replacingOccurrences(of: "광역시", with: "") - let subRegion = components[1] + let mainRegion = components[0].replacingOccurrences(of: "특별시", with: "") + .replacingOccurrences(of: "광역시", with: "") + let subRegion = components[1] - return selectedRegions.contains("\(mainRegion)전체") || - selectedRegions.contains(subRegion) - } - } - } + return selectedRegions.contains("\(mainRegion)전체") || + selectedRegions.contains(subRegion) + } + } +} diff --git a/Poppool/Poppool/DomainLayer/DomainInterface/Entity/AdminResponse/AdminStore.swift b/Poppool/Poppool/DomainLayer/DomainInterface/Entity/AdminResponse/AdminStore.swift new file mode 100644 index 00000000..58db4f63 --- /dev/null +++ b/Poppool/Poppool/DomainLayer/DomainInterface/Entity/AdminResponse/AdminStore.swift @@ -0,0 +1,8 @@ +import Foundation + +struct AdminStore { + let id: Int64 + let name: String + let categoryName: String + let mainImageUrl: String +} diff --git a/Poppool/Poppool/DomainLayer/DomainInterface/Entity/AdminResponse/AdminStoreDetail.swift b/Poppool/Poppool/DomainLayer/DomainInterface/Entity/AdminResponse/AdminStoreDetail.swift new file mode 100644 index 00000000..dc8f91ef --- /dev/null +++ b/Poppool/Poppool/DomainLayer/DomainInterface/Entity/AdminResponse/AdminStoreDetail.swift @@ -0,0 +1,26 @@ +import Foundation + +struct AdminStoreDetail { + let id: Int64 + let name: String + let categoryId: Int64 + let categoryName: String + let description: String + let address: String + let startDate: String + let endDate: String + let createUserId: String + let createDateTime: String + let mainImageUrl: String + let bannerYn: Bool + let images: [StoreImage] + let latitude: Double + let longitude: Double + let markerTitle: String + let markerSnippet: String + + struct StoreImage { + let id: Int64 + let imageUrl: String + } +} diff --git a/Poppool/Poppool/DomainLayer/DomainInterface/Entity/AdminResponse/Params/AdminParams.swift b/Poppool/Poppool/DomainLayer/DomainInterface/Entity/AdminResponse/Params/AdminParams.swift new file mode 100644 index 00000000..8f5a9d7e --- /dev/null +++ b/Poppool/Poppool/DomainLayer/DomainInterface/Entity/AdminResponse/Params/AdminParams.swift @@ -0,0 +1,49 @@ +import Foundation + +struct CreateStoreParams { + let name: String + let categoryId: Int64 + let desc: String + let address: String + let startDate: String + let endDate: String + let mainImageUrl: String + let imageUrlList: [String?] + let latitude: Double + let longitude: Double + let markerTitle: String + let markerSnippet: String + let startDateBeforeEndDate: Bool +} + +struct UpdateStoreParams { + let id: Int64 + let name: String + let categoryId: Int64 + let desc: String + let address: String + let startDate: String + let endDate: String + let mainImageUrl: String + let imageUrlList: [String?] + let imagesToDelete: [Int64] + let latitude: Double + let longitude: Double + let markerTitle: String + let markerSnippet: String + let startDateBeforeEndDate: Bool +} + +struct CreateNoticeParams { + let title: String + let content: String + let imageUrlList: [String] +} + +struct UpdateNoticeParams { + let id: Int64 + let title: String + let content: String + let imageUrlList: [String] + let imagesToDelete: [Int64] +} diff --git a/Poppool/Poppool/DomainLayer/DomainInterface/Entity/MapResponse/MapPopUpStore.swift b/Poppool/Poppool/DomainLayer/DomainInterface/Entity/MapResponse/MapPopUpStore.swift index 2be1694e..65fc7ebb 100644 --- a/Poppool/Poppool/DomainLayer/DomainInterface/Entity/MapResponse/MapPopUpStore.swift +++ b/Poppool/Poppool/DomainLayer/DomainInterface/Entity/MapResponse/MapPopUpStore.swift @@ -1,5 +1,4 @@ import Foundation -import NMapsMap struct MapPopUpStore: Equatable { let id: Int64 @@ -14,29 +13,4 @@ struct MapPopUpStore: Equatable { let markerTitle: String let markerSnippet: String let mainImageUrl: String? - - var nmgCoordinate: NMGLatLng { - NMGLatLng(lat: latitude, lng: longitude) - } - - func toMarkerInput() -> MapMarker.Input { - return MapMarker.Input( - isSelected: false, - isCluster: false, - regionName: self.markerTitle, - count: 0 - ) - } - - func toStoreItem() -> StoreItem { - return StoreItem( - id: id, - thumbnailURL: mainImageUrl ?? "", - category: category, - title: name, - location: address, - dateRange: "\(startDate) ~ \(endDate)", - isBookmarked: false - ) - } } diff --git a/Poppool/Poppool/DomainLayer/DomainInterface/Repository/AdminRepository.swift b/Poppool/Poppool/DomainLayer/DomainInterface/Repository/AdminRepository.swift index da4112ec..8f87a343 100644 --- a/Poppool/Poppool/DomainLayer/DomainInterface/Repository/AdminRepository.swift +++ b/Poppool/Poppool/DomainLayer/DomainInterface/Repository/AdminRepository.swift @@ -3,13 +3,16 @@ import Foundation import RxSwift protocol AdminRepository { - func fetchStoreList(query: String?, page: Int, size: Int) -> Observable - func fetchStoreDetail(id: Int64) -> Observable - func createStore(request: CreatePopUpStoreRequestDTO) -> Observable - func updateStore(request: UpdatePopUpStoreRequestDTO) -> Observable - func deleteStore(id: Int64) -> Observable - - func createNotice(request: CreateNoticeRequestDTO) -> Observable - func updateNotice(id: Int64, request: UpdateNoticeRequestDTO) -> Observable - func deleteNotice(id: Int64) -> Observable + func fetchStoreList(query: String?, page: Int, size: Int) -> Observable<[AdminStore]> + func fetchStoreDetail(id: Int64) -> Observable + + func createStore(params: CreateStoreParams) -> Completable + + func updateStore(params: UpdateStoreParams) -> Completable + + func deleteStore(id: Int64) -> Completable + + func createNotice(params: CreateNoticeParams) -> Completable + func updateNotice(params: UpdateNoticeParams) -> Completable + func deleteNotice(id: Int64) -> Completable } diff --git a/Poppool/Poppool/DomainLayer/DomainInterface/Repository/AuthAPIRepository.swift b/Poppool/Poppool/DomainLayer/DomainInterface/Repository/AuthAPIRepository.swift index 630c801b..ba9ae29f 100644 --- a/Poppool/Poppool/DomainLayer/DomainInterface/Repository/AuthAPIRepository.swift +++ b/Poppool/Poppool/DomainLayer/DomainInterface/Repository/AuthAPIRepository.swift @@ -1,8 +1,7 @@ import Foundation - import RxSwift protocol AuthAPIRepository { func tryLogIn(userCredential: Encodable, socialType: String) -> Observable - func postTokenReissue() -> Observable + func postTokenReissue() -> Observable } diff --git a/Poppool/Poppool/DomainLayer/DomainInterface/Repository/CommentAPIRepository.swift b/Poppool/Poppool/DomainLayer/DomainInterface/Repository/CommentAPIRepository.swift index bd079fc8..e353e65c 100644 --- a/Poppool/Poppool/DomainLayer/DomainInterface/Repository/CommentAPIRepository.swift +++ b/Poppool/Poppool/DomainLayer/DomainInterface/Repository/CommentAPIRepository.swift @@ -3,7 +3,22 @@ import Foundation import RxSwift protocol CommentAPIRepository { - func postCommentAdd(request: PostCommentRequestDTO) -> Completable - func deleteComment(request: DeleteCommentRequestDTO) -> Completable - func editComment(request: PutCommentRequestDTO) -> Completable + func postCommentAdd( + popUpStoreId: Int64, + content: String?, + commentType: String?, + imageUrlList: [String?] + ) -> Completable + + func deleteComment( + popUpStoreId: Int64, + commentId: Int64 + ) -> Completable + + func editComment( + popUpStoreId: Int64, + commentId: Int64, + content: String?, + imageUrlList: [PutCommentImageDataRequestDTO]? + ) -> Completable } diff --git a/Poppool/Poppool/DomainLayer/DomainInterface/Repository/MapRepository.swift b/Poppool/Poppool/DomainLayer/DomainInterface/Repository/MapRepository.swift index 6f613828..4e6c1a19 100644 --- a/Poppool/Poppool/DomainLayer/DomainInterface/Repository/MapRepository.swift +++ b/Poppool/Poppool/DomainLayer/DomainInterface/Repository/MapRepository.swift @@ -5,7 +5,6 @@ // Created by 송영훈 on 4/14/25. // - import Foundation import RxSwift @@ -17,12 +16,12 @@ protocol MapRepository { southWestLat: Double, southWestLon: Double, categories: [Int64] - ) -> Observable<[MapPopUpStoreDTO]> + ) -> Observable<[MapPopUpStore]> func searchStores( query: String, categories: [Int64] - ) -> Observable<[MapPopUpStoreDTO]> + ) -> Observable<[MapPopUpStore]> func fetchCategories() -> Observable<[CategoryResponse]> } diff --git a/Poppool/Poppool/DomainLayer/DomainInterface/UseCase/AdminUseCase.swift b/Poppool/Poppool/DomainLayer/DomainInterface/UseCase/AdminUseCase.swift index 390c45fb..08c59b15 100644 --- a/Poppool/Poppool/DomainLayer/DomainInterface/UseCase/AdminUseCase.swift +++ b/Poppool/Poppool/DomainLayer/DomainInterface/UseCase/AdminUseCase.swift @@ -1,16 +1,18 @@ import Foundation - import RxSwift protocol AdminUseCase { - func fetchStoreList(query: String?, page: Int, size: Int) -> Observable - func fetchStoreDetail(id: Int64) -> Observable - func createStore(request: CreatePopUpStoreRequestDTO) -> Observable - func updateStore(request: UpdatePopUpStoreRequestDTO) -> Observable - func deleteStore(id: Int64) -> Observable - // Notice - func createNotice(request: CreateNoticeRequestDTO) -> Observable - func updateNotice(id: Int64, request: UpdateNoticeRequestDTO) -> Observable - func deleteNotice(id: Int64) -> Observable + func fetchStoreList(query: String?, page: Int, size: Int) -> Observable<[AdminStore]> + func fetchStoreDetail(id: Int64) -> Observable + + func createStore(params: CreateStoreParams) -> Completable + + func updateStore(params: UpdateStoreParams) -> Completable + + func deleteStore(id: Int64) -> Completable + + func createNotice(params: CreateNoticeParams) -> Completable + func updateNotice(params: UpdateNoticeParams) -> Completable + func deleteNotice(id: Int64) -> Completable } diff --git a/Poppool/Poppool/DomainLayer/DomainInterface/UseCase/CommentAPIUseCase.swift b/Poppool/Poppool/DomainLayer/DomainInterface/UseCase/CommentAPIUseCase.swift index be737e40..021c842a 100644 --- a/Poppool/Poppool/DomainLayer/DomainInterface/UseCase/CommentAPIUseCase.swift +++ b/Poppool/Poppool/DomainLayer/DomainInterface/UseCase/CommentAPIUseCase.swift @@ -5,5 +5,5 @@ import RxSwift protocol CommentAPIUseCase { func postCommentAdd(popUpStoreId: Int64, content: String?, commentType: String?, imageUrlList: [String?]) -> Completable func deleteComment(popUpStoreId: Int64, commentId: Int64) -> Completable - func editComment(popUpStoreId: Int64, commentId: Int64, content: String?, imageUrlList: [PutCommentImageDataRequestDTO]?) -> Completable + func editComment(popUpStoreId: Int64, commentId: Int64, content: String?, imageUrlList: [String?]?) -> Completable } diff --git a/Poppool/Poppool/DomainLayer/DomainInterface/UseCase/MapUseCase.swift b/Poppool/Poppool/DomainLayer/DomainInterface/UseCase/MapUseCase.swift index 9eb687da..f425adf0 100644 --- a/Poppool/Poppool/DomainLayer/DomainInterface/UseCase/MapUseCase.swift +++ b/Poppool/Poppool/DomainLayer/DomainInterface/UseCase/MapUseCase.swift @@ -1,11 +1,3 @@ -// -// MapUseCase.swift -// Poppool -// -// Created by 송영훈 on 4/14/25. -// - - import Foundation import RxSwift diff --git a/Poppool/Poppool/DomainLayer/DomainInterface/UseCase/SignUpAPIUseCase.swift b/Poppool/Poppool/DomainLayer/DomainInterface/UseCase/SignUpAPIUseCase.swift index e0dfeb36..8711e4a7 100644 --- a/Poppool/Poppool/DomainLayer/DomainInterface/UseCase/SignUpAPIUseCase.swift +++ b/Poppool/Poppool/DomainLayer/DomainInterface/UseCase/SignUpAPIUseCase.swift @@ -12,8 +12,8 @@ protocol SignUpAPIUseCase { interests: [Int64], appleAuthorizationCode: String? ) -> Completable - + func checkNickName(nickName: String) -> Observable - + func fetchCategoryList() -> Observable<[CategoryResponse]> } diff --git a/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminReactor.swift b/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminReactor.swift index c8984af1..4e9d8bc9 100644 --- a/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminReactor.swift +++ b/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminReactor.swift @@ -14,18 +14,18 @@ final class AdminReactor: Reactor { } enum Mutation { - case setStores([GetAdminPopUpStoreListResponseDTO.PopUpStore]) + case setStores([AdminStore]) case setIsLoading(Bool) case navigateToRegister(Bool) - case navigateToEdit(GetAdminPopUpStoreListResponseDTO.PopUpStore) // ✅ 수정 데이터 추가 + case navigateToEdit(AdminStore) // ✅ 수정 데이터 추가 } struct State { - var storeList: [GetAdminPopUpStoreListResponseDTO.PopUpStore] = [] + var storeList: [AdminStore] = [] var isLoading: Bool = false var shouldNavigateToRegister: Bool = false - var selectedStoreForEdit: GetAdminPopUpStoreListResponseDTO.PopUpStore? // ✅ 추가 + var selectedStoreForEdit: AdminStore? // ✅ 추가 } @@ -44,7 +44,7 @@ final class AdminReactor: Reactor { return .concat([ .just(.setIsLoading(true)), adminUseCase.fetchStoreList(query: nil, page: 0, size: 100) - .map { .setStores($0.popUpStoreList ?? []) }, // ✅ nil 방지 + .map { .setStores($0) }, // ✅ nil 방지 .just(.setIsLoading(false)) ]) @@ -57,7 +57,7 @@ final class AdminReactor: Reactor { }, onError: { error in Logger.log(message: "조회 실패 - 에러: \(error.localizedDescription)", category: .error) }) - .map { .setStores($0.popUpStoreList ?? []) }, // ✅ nil 방지 + .map { .setStores($0) }, .just(.setIsLoading(false)) ]) diff --git a/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminRegister/PopUpStoreRegisterReactor.swift b/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminRegister/PopUpStoreRegisterReactor.swift index 3321184e..fd4b5088 100644 --- a/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminRegister/PopUpStoreRegisterReactor.swift +++ b/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminRegister/PopUpStoreRegisterReactor.swift @@ -19,7 +19,7 @@ final class PopUpStoreRegisterReactor: Reactor { init( adminUseCase: AdminUseCase, presignedService: PreSignedService, - editingStore: GetAdminPopUpStoreListResponseDTO.PopUpStore? = nil + editingStore: AdminStore? = nil ) { self.adminUseCase = adminUseCase self.presignedService = presignedService @@ -89,7 +89,7 @@ final class PopUpStoreRegisterReactor: Reactor { case addDeletedImage(id: Int64, path: String) // 기존 스토어 데이터 설정 - case setStoreDetail(GetAdminPopUpStoreDetailResponseDTO) + case setStoreDetail(AdminStoreDetail) case setOriginalImageIds([String: Int64]) // UI 상태 관리 @@ -361,7 +361,7 @@ final class PopUpStoreRegisterReactor: Reactor { newState.address = storeDetail.address newState.lat = String(storeDetail.latitude) newState.lon = String(storeDetail.longitude) - newState.description = storeDetail.desc + newState.description = storeDetail.description // 날짜 파싱 let isoFormatter = ISO8601DateFormatter() @@ -619,7 +619,7 @@ final class PopUpStoreRegisterReactor: Reactor { // 이미지 ID 매핑 초기화 및 설정 var originalImageIds: [String: Int64] = [:] - for image in storeDetail.imageList { + for image in storeDetail.images { originalImageIds[image.imageUrl] = image.id } @@ -633,7 +633,7 @@ final class PopUpStoreRegisterReactor: Reactor { let dispatchGroup = DispatchGroup() let imageObservable = Observable.create { observer in - for imageData in storeDetail.imageList { + for imageData in storeDetail.images { // 중복 이미지 건너뛰기 if loadedImageUrls.contains(imageData.imageUrl) { continue @@ -746,7 +746,7 @@ final class PopUpStoreRegisterReactor: Reactor { return false } ?? imagePaths.first ?? "" - let request = CreatePopUpStoreRequestDTO( + let params = CreateStoreParams( name: state.name, categoryId: state.categoryId, desc: state.description, @@ -762,8 +762,8 @@ final class PopUpStoreRegisterReactor: Reactor { startDateBeforeEndDate: true ) - return self.adminUseCase.createStore(request: request) - .map { _ in .setSuccess(true) } + return self.adminUseCase.createStore(params: params) + .andThen(Observable.just(.setSuccess(true))) } } @@ -860,43 +860,26 @@ final class PopUpStoreRegisterReactor: Reactor { mainImage = "" } - // 업데이트 요청 생성 - let request = UpdatePopUpStoreRequestDTO( - popUpStore: .init( - id: storeId, - name: state.name, - categoryId: state.categoryId, - desc: state.description, - address: state.address, - startDate: dates.startDate, - endDate: dates.endDate, - mainImageUrl: mainImage, - bannerYn: !mainImage.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty, - imageUrl: allPaths, - startDateBeforeEndDate: true - ), - location: .init( - latitude: Double(state.lat) ?? 0, - longitude: Double(state.lon) ?? 0, - markerTitle: state.markerTitle, - markerSnippet: state.markerSnippet - ), - imagesToAdd: newImagePaths ?? [], - imagesToDelete: state.deletedImageIds + let params = UpdateStoreParams( + id: storeId, + name: state.name, + categoryId: state.categoryId, + desc: state.description, + address: state.address, + startDate: dates.startDate, + endDate: dates.endDate, + mainImageUrl: mainImage, + imageUrlList: allPaths, + imagesToDelete: state.deletedImageIds, + latitude: Double(state.lat) ?? 0, + longitude: Double(state.lon) ?? 0, + markerTitle: state.markerTitle, + markerSnippet: state.markerSnippet, + startDateBeforeEndDate: true ) - // 서버에 스토어 정보 업데이트 요청 - return adminUseCase.updateStore(request: request) - .flatMap { [weak self] _ -> Observable in - guard let self = self else { return .empty() } - - // S3에서 삭제된 이미지 제거 - if !state.deletedImagePaths.isEmpty { - self.deleteImagesFromS3(state.deletedImagePaths) - } - - return .just(.setSuccess(true)) - } + return self.adminUseCase.updateStore(params: params) + .andThen(Observable.just(.setSuccess(true))) } } diff --git a/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminRegister/PopUpStoreRegisterViewController.swift b/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminRegister/PopUpStoreRegisterViewController.swift index ed6fd4d0..3a33d18e 100644 --- a/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminRegister/PopUpStoreRegisterViewController.swift +++ b/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminRegister/PopUpStoreRegisterViewController.swift @@ -20,7 +20,7 @@ final class PopUpStoreRegisterViewController: BaseViewController { // MARK: - Initializer init( nickname: String, - editingStore: GetAdminPopUpStoreListResponseDTO.PopUpStore? = nil + editingStore: AdminStore? = nil ) { self.nickname = nickname self.mainView = PopUpRegisterView() diff --git a/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminStoreCell.swift b/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminStoreCell.swift index a29c4ee6..1789ce87 100644 --- a/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminStoreCell.swift +++ b/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminStoreCell.swift @@ -75,14 +75,13 @@ final class AdminStoreCell: UITableViewCell { } // MARK: - Configure - func configure(with store: GetAdminPopUpStoreListResponseDTO.PopUpStore) { + func configure(with store: AdminStore) { Logger.log(message: "셀 데이터 바인딩: \(store)", category: .debug) titleLabel.text = store.name categoryLabel.text = store.categoryName statusChip.text = "운영" - // mainImageUrl에서 baseURL 부분 제거 let imagePath = store.mainImageUrl.replacingOccurrences(of: Secrets.popPoolS3BaseURL, with: "") Logger.log(message: "이미지 경로: \(imagePath)", category: .debug) storeImageView.setPPImage(path: imagePath) diff --git a/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminViewController.swift b/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminViewController.swift index 45de4fb4..29c8b765 100644 --- a/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminViewController.swift +++ b/Poppool/Poppool/PresentationLayer/Presentation/Scene/Admin/AdminViewController.swift @@ -125,7 +125,6 @@ final class AdminViewController: BaseViewController, View { alert.addAction(UIAlertAction(title: "취소", style: .cancel)) - // iPad support if let popoverController = alert.popoverPresentationController { popoverController.sourceView = mainView.menuButton popoverController.sourceRect = mainView.menuButton.bounds @@ -154,7 +153,7 @@ final class AdminViewController: BaseViewController, View { present(alert, animated: true) } - private func showDeleteConfirmation(for store: GetAdminPopUpStoreListResponseDTO.PopUpStore) { + private func showDeleteConfirmation(for store: AdminStore) { let alert = UIAlertController( title: "삭제 확인", message: "\(store.name)을(를) 삭제하시겠습니까?", @@ -169,21 +168,40 @@ final class AdminViewController: BaseViewController, View { present(alert, animated: true) } - private func editStore(_ store: GetAdminPopUpStoreListResponseDTO.PopUpStore) { - let registerVC = PopUpStoreRegisterViewController( - nickname: nickname, - editingStore: store - ) - - // 수정할 때도 completionHandler 추가 - registerVC.completionHandler = { [weak self] in - self?.reactor?.action.onNext(.reloadData) - } - - navigationController?.pushViewController(registerVC, animated: true) + private func editStore(_ store: AdminStore) { + adminUseCase.fetchStoreDetail(id: store.id) + .observe(on: MainScheduler.instance) + .subscribe( + onNext: { [weak self] storeDetail in + guard let self = self else { return } + let updateParams = UpdateStoreParams( + id: storeDetail.id, + name: storeDetail.name, + categoryId: storeDetail.categoryId, + desc: storeDetail.description, + address: storeDetail.address, + startDate: storeDetail.startDate, + endDate: storeDetail.endDate, + mainImageUrl: storeDetail.mainImageUrl, + imageUrlList: storeDetail.images.map { $0.imageUrl }, + imagesToDelete: [], + latitude: storeDetail.latitude, + longitude: storeDetail.longitude, + markerTitle: storeDetail.markerTitle, + markerSnippet: storeDetail.markerSnippet, + startDateBeforeEndDate: true + ) + let registerVC = PopUpStoreRegisterViewController(nickname: self.nickname) + self.navigationController?.pushViewController(registerVC, animated: true) + }, + onError: { [weak self] error in + self?.showErrorAlert(message: "스토어 정보 조회 실패: \(error.localizedDescription)") + } + ) + .disposed(by: disposeBag) } - private func deleteStore(_ store: GetAdminPopUpStoreListResponseDTO.PopUpStore) { + private func deleteStore(_ store: AdminStore) { // 먼저 스토어 상세 정보를 가져와 모든 이미지 URL을 확인 adminUseCase.fetchStoreDetail(id: store.id) .observe(on: MainScheduler.instance) @@ -196,7 +214,7 @@ final class AdminViewController: BaseViewController, View { allImageUrls.append(storeDetail.mainImageUrl) // 다른 모든 이미지 URL 추가 - let otherImageUrls = storeDetail.imageList.map { $0.imageUrl } + let otherImageUrls = storeDetail.images.map { $0.imageUrl } allImageUrls.append(contentsOf: otherImageUrls) allImageUrls = Array(Set(allImageUrls)) @@ -208,7 +226,7 @@ final class AdminViewController: BaseViewController, View { .andThen(self.adminUseCase.deleteStore(id: store.id)) .observe(on: MainScheduler.instance) .subscribe( - onNext: { [weak self] _ in + onCompleted: { [weak self] in self?.reactor?.action.onNext(.reloadData) ToastMaker.createToast(message: "삭제되었습니다") }, @@ -275,8 +293,8 @@ final class AdminViewController: BaseViewController, View { .bind(to: mainView.tableView.rx.items( cellIdentifier: AdminStoreCell.identifier, cellType: AdminStoreCell.self - )) { _, item, cell in - cell.configure(with: item) + )) { _, store, cell in + cell.configure(with: store) } .disposed(by: disposeBag) } diff --git a/Poppool/Poppool/PresentationLayer/Presentation/Scene/Comment/NormalCommentEdit/NormalCommentEditReactor.swift b/Poppool/Poppool/PresentationLayer/Presentation/Scene/Comment/NormalCommentEdit/NormalCommentEditReactor.swift index a13c4ca9..b33014d9 100644 --- a/Poppool/Poppool/PresentationLayer/Presentation/Scene/Comment/NormalCommentEdit/NormalCommentEditReactor.swift +++ b/Poppool/Poppool/PresentationLayer/Presentation/Scene/Comment/NormalCommentEdit/NormalCommentEditReactor.swift @@ -181,7 +181,7 @@ final class NormalCommentEditReactor: Reactor { popUpStoreId: self.popUpID, commentId: self.originComment.commentID, content: newState.text, - imageUrlList: convertAddImages + convertKeepImages + convertDeleteImages + imageUrlList: (convertAddImages + convertKeepImages + convertDeleteImages).map { $0.imageUrl } ) .subscribe { [weak self, weak controller] in guard let self = self else { return } @@ -199,7 +199,7 @@ final class NormalCommentEditReactor: Reactor { popUpStoreId: self.popUpID, commentId: self.originComment.commentID, content: newState.text, - imageUrlList: convertAddImages + convertKeepImages + convertDeleteImages + imageUrlList: (convertAddImages + convertKeepImages + convertDeleteImages).map { $0.imageUrl } ) .subscribe { [weak self, weak controller] in guard let self = self else { return } diff --git a/Poppool/Poppool/PresentationLayer/Presentation/Scene/Map/MapView/MapViewController.swift b/Poppool/Poppool/PresentationLayer/Presentation/Scene/Map/MapView/MapViewController.swift index e6d07180..243ad3f6 100644 --- a/Poppool/Poppool/PresentationLayer/Presentation/Scene/Map/MapView/MapViewController.swift +++ b/Poppool/Poppool/PresentationLayer/Presentation/Scene/Map/MapView/MapViewController.swift @@ -513,7 +513,17 @@ class MapViewController: BaseViewController, View, CLLocationManagerDelegate, NM self.addMarkers(for: results) // 스토어 리스트 업데이트 - let storeItems = results.map { $0.toStoreItem() } + let storeItems = results.map { store in + StoreItem( + id: store.id, + thumbnailURL: store.mainImageUrl ?? "", + category: store.category, + title: store.name, + location: store.address, + dateRange: "\(store.startDate) ~ \(store.endDate)", + isBookmarked: false + ) + } self.storeListViewController.reactor?.action.onNext(.setStores(storeItems)) // 캐러셀 업데이트 @@ -1056,7 +1066,17 @@ class MapViewController: BaseViewController, View, CLLocationManagerDelegate, NM } private func updateListView(with results: [MapPopUpStore]) { // MapPopUpStore 배열을 StoreItem 배열로 변환 - let storeItems = results.map { $0.toStoreItem() } + let storeItems = results.map { store in + StoreItem( + id: store.id, + thumbnailURL: store.mainImageUrl ?? "", + category: store.category, + title: store.name, + location: store.address, + dateRange: "\(store.startDate) ~ \(store.endDate)", + isBookmarked: false + ) + } storeListViewController.reactor?.action.onNext(.setStores(storeItems)) } diff --git a/Poppool/Poppool/PresentationLayer/Presentation/Scene/MyPage/Main/MyPageReactor.swift b/Poppool/Poppool/PresentationLayer/Presentation/Scene/MyPage/Main/MyPageReactor.swift index 1b32e806..3150edd4 100644 --- a/Poppool/Poppool/PresentationLayer/Presentation/Scene/MyPage/Main/MyPageReactor.swift +++ b/Poppool/Poppool/PresentationLayer/Presentation/Scene/MyPage/Main/MyPageReactor.swift @@ -274,22 +274,16 @@ final class MyPageReactor: Reactor { let navigationController = UINavigationController(rootViewController: nextController) navigationController.modalPresentationStyle = .fullScreen controller.present(navigationController, animated: true) - case .moveToMyCommentScene(let controller): let nextController = MyCommentController() nextController.reactor = MyCommentReactor(userAPIUseCase: userAPIUseCase) controller.navigationController?.pushViewController(nextController, animated: true) - case .moveToAdminScene(let controller): // 관리자 VC let nickname = profileSection.inputDataList.first?.nickName ?? "" - let adminVC = AdminViewController( - nickname: nickname, - adminUseCase: DIContainer.resolve(AdminUseCase.self) - ) - adminVC.reactor = AdminReactor( - adminUseCase: DIContainer.resolve(AdminUseCase.self) - ) + let adminUseCase = DIContainer.resolve(AdminUseCase.self) + let adminVC = AdminViewController(nickname: nickname, adminUseCase: adminUseCase) + adminVC.reactor = AdminReactor(adminUseCase: adminUseCase) controller.navigationController?.pushViewController(adminVC, animated: true) }