Skip to content

Commit f2237cd

Browse files
committed
[#60] 수정된 알림 조회 response 적용 및 알림 조회 수정
#60
1 parent 212233c commit f2237cd

9 files changed

Lines changed: 160 additions & 148 deletions

File tree

Codive/Features/Notification/Data/DTOs/NotificationDTO.swift

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,51 +7,48 @@
77

88
import Foundation
99

10+
enum NotificationType: String {
11+
case follow = "FOLLOW"
12+
case followRequest = "FOLLOW_REQUEST"
13+
case comment = "COMMENT"
14+
case reply = "REPLY"
15+
case like = "LIKE"
16+
case temperatureDaily = "TEMPERATURE_DAILY"
17+
case unknown = "UNKNOWN"
18+
}
19+
20+
enum ReadStatus: String {
21+
case read = "READ"
22+
case notRead = "NOT_READ"
23+
}
24+
25+
enum NotificationRedirectType: String {
26+
case none = "NONE"
27+
case historyRedirect = "HISTORY_REDIRECT"
28+
case memberRedirect = "MEMBER_REDIRECT"
29+
}
30+
31+
// MARK: - DTO
32+
1033
/// 알림 목록 조회
1134
struct NotificationListResponseDTO {
1235
let content: [NotificationListResponseItem]
1336
let isLast: Bool
1437
}
1538

39+
struct NotificationActionDTO {
40+
let redirectType: NotificationRedirectType
41+
let redirectInfo: String
42+
}
43+
1644
struct NotificationListResponseItem {
1745
let notificationId: Int64
1846
let notificationImageUrl: String
1947
let notificationContent: String
20-
let redirectInfo: String
21-
let redirectType: String
22-
let readStatus: String
48+
let notificationType: NotificationType
49+
let action: NotificationActionDTO
50+
let readStatus: ReadStatus
2351
let createdAt: String
24-
25-
enum CodingKeys: String, CodingKey {
26-
case notificationId
27-
case notificationImageUrl
28-
case notificationContent
29-
case redirectInfo
30-
case redirectType
31-
case readStatus
32-
case createdAt
33-
}
34-
35-
private func parseDate(_ dateString: String) -> Date {
36-
let formatter = ISO8601DateFormatter()
37-
formatter.formatOptions = [
38-
.withInternetDateTime,
39-
.withFractionalSeconds
40-
]
41-
return formatter.date(from: dateString) ?? Date()
42-
}
43-
44-
func toEntity() -> NotificationEntity {
45-
return NotificationEntity(
46-
notificationId: notificationId,
47-
notificationImageUrl: notificationImageUrl,
48-
notificationContent: notificationContent,
49-
redirectInfo: redirectInfo,
50-
redirectType: RedirectType(rawValue: redirectType) ?? .member,
51-
readStatus: ReadStatus(rawValue: readStatus) ?? .unread,
52-
createdAt: createdAt
53-
)
54-
}
5552
}
5653

5754
struct NotificationExistAPIResponseDTO {

Codive/Features/Notification/Data/Repositories/NotificationRepositoryImpl.swift

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,14 @@ final class NotificationRepositoryImpl: NotificationRepository {
2323
try await datasource.patchAllNotification()
2424
}
2525

26-
func fetchNotificationList(lastNotificationId: Int64?, size: Int32) async throws -> (content: [NotificationEntity], isLast: Bool) {
27-
let dto = try await datasource.fetchNotificationList(
26+
func fetchNotificationList(
27+
lastNotificationId: Int64?,
28+
size: Int32
29+
) async throws -> NotificationListResponseDTO {
30+
return try await datasource.fetchNotificationList(
2831
lastNotificationId: lastNotificationId,
2932
size: size
3033
)
31-
32-
return (
33-
content: dto.content.map { $0.toEntity() },
34-
isLast: dto.isLast
35-
)
3634
}
3735

3836
func fetchNotificationExist() async throws -> NotificationExistAPIResponseDTO {

Codive/Features/Notification/Data/Services/NotificationAPIService.swift

Lines changed: 78 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ protocol NotificationAPIServiceProtocol {
2525
}
2626

2727
final class NotificationAPIService: NotificationAPIServiceProtocol {
28-
28+
2929
private let client: Client
3030
private let jsonDecoder: JSONDecoder
31-
31+
3232
init(tokenProvider: TokenProvider = KeychainTokenProvider()) {
3333
self.client = CodiveAPIProvider.createClient(
3434
middlewares: [CodiveAuthMiddleware(provider: tokenProvider)]
@@ -41,7 +41,7 @@ extension NotificationAPIService {
4141
func patchEachNotification(notificationId: Int64) async throws {
4242
let input = Operations.updateReadStatus.Input(path: .init(notificationId: notificationId))
4343
let response = try await client.updateReadStatus(input)
44-
44+
4545
switch response {
4646
case .ok:
4747
return
@@ -64,18 +64,11 @@ extension NotificationAPIService {
6464
}
6565

6666
extension NotificationAPIService {
67-
private func formatDate(_ date: Date?) -> String {
68-
guard let date else { return "" }
67+
func fetchNotificationList(
68+
lastNotificationId: Int64?,
69+
size: Int32
70+
) async throws -> NotificationListResponseDTO {
6971

70-
let formatter = ISO8601DateFormatter()
71-
formatter.formatOptions = [
72-
.withInternetDateTime,
73-
.withFractionalSeconds
74-
]
75-
return formatter.string(from: date)
76-
}
77-
78-
func fetchNotificationList(lastNotificationId: Int64?, size: Int32) async throws -> NotificationListResponseDTO {
7972
let input = Operations.Notification_getNotificationList.Input(
8073
query: .init(
8174
lastNotificationId: lastNotificationId,
@@ -87,26 +80,32 @@ extension NotificationAPIService {
8780

8881
switch response {
8982
case .ok(let okResponse):
90-
let data = try await Data(collecting: okResponse.body.any, upTo: .max)
91-
92-
let decoded = try jsonDecoder.decode(Components.Schemas.BaseResponseSliceResponseNotificationListResponse.self, from: data)
93-
94-
let content: [NotificationListResponseItem] = decoded.result?.content?.map { item in
95-
NotificationListResponseItem(
96-
notificationId: item.notificationId ?? 0,
97-
notificationImageUrl: item.notificationImageUrl ?? "",
98-
notificationContent: item.notificationContent ?? "",
99-
redirectInfo: item.action?.redirectInfo ?? "",
100-
redirectType: item.action?.redirectType?.rawValue ?? "NONE",
101-
readStatus: item.readStatus?.rawValue ?? "NOT_READ",
102-
createdAt: formatDate(item.createdAt)
103-
)
104-
} ?? []
105-
106-
return NotificationListResponseDTO(content: content, isLast: decoded.result?.isLast ?? true)
107-
83+
let data = try await Data(
84+
collecting: okResponse.body.any,
85+
upTo: .max
86+
)
87+
88+
let decoded = try jsonDecoder.decode(
89+
Components.Schemas.BaseResponseSliceResponseNotificationListResponse.self,
90+
from: data
91+
)
92+
93+
guard let result = decoded.result else {
94+
throw NotificationAPIError.invalidResponse
95+
}
96+
97+
let content = mapNotificationItems(result.content)
98+
99+
return NotificationListResponseDTO(
100+
content: content,
101+
isLast: result.isLast ?? true
102+
)
103+
108104
case .undocumented(statusCode: let code, _):
109-
throw NotificationAPIError.serverError(statusCode: code, message: "알림 목록 조회 실패")
105+
throw NotificationAPIError.serverError(
106+
statusCode: code,
107+
message: "알림 목록 조회 실패"
108+
)
110109
}
111110
}
112111

@@ -124,7 +123,7 @@ extension NotificationAPIService {
124123
guard let item = decoded.result else {
125124
throw NotificationAPIError.invalidResponse
126125
}
127-
126+
128127
return ReportReceivedAPIResponseDTO(
129128
isReported: item.isReported ?? false,
130129
targetType: item.targetType.flatMap { ReportType(rawValue: $0.rawValue) }
@@ -137,7 +136,6 @@ extension NotificationAPIService {
137136
}
138137

139138
extension NotificationAPIService {
140-
141139
func fetchNotificationExist() async throws -> NotificationExistAPIResponseDTO {
142140

143141
let input = Operations.Notification_existsUnreadNotification.Input()
@@ -163,6 +161,50 @@ extension NotificationAPIService {
163161
}
164162
}
165163

164+
165+
extension NotificationAPIService {
166+
private func mapNotificationItems(
167+
_ items: [Components.Schemas.NotificationListResponse]?
168+
) -> [NotificationListResponseItem] {
169+
items?.map { item in
170+
let notificationType = NotificationType(
171+
rawValue: item.notificationType?.rawValue ?? ""
172+
) ?? .unknown
173+
174+
let readStatus = ReadStatus(
175+
rawValue: item.readStatus?.rawValue ?? ""
176+
) ?? .notRead
177+
178+
let redirectType = NotificationRedirectType(
179+
rawValue: item.action?.redirectType?.rawValue ?? ""
180+
) ?? .none
181+
182+
return NotificationListResponseItem(
183+
notificationId: item.notificationId ?? 0,
184+
notificationImageUrl: item.notificationImageUrl ?? "",
185+
notificationContent: item.notificationContent ?? "",
186+
notificationType: notificationType,
187+
action: NotificationActionDTO(
188+
redirectType: redirectType,
189+
redirectInfo: item.action?.redirectInfo ?? ""
190+
),
191+
readStatus: readStatus,
192+
createdAt: formatDate(item.createdAt)
193+
)
194+
} ?? []
195+
}
196+
197+
private func formatDate(_ date: Date?) -> String {
198+
guard let date else { return "" }
199+
200+
let formatter = ISO8601DateFormatter()
201+
formatter.formatOptions = [
202+
.withInternetDateTime,
203+
.withFractionalSeconds
204+
]
205+
return formatter.string(from: date)
206+
}
207+
}
166208
// MARK: - ClothAPIError
167209

168210
enum NotificationAPIError: LocalizedError {
@@ -172,7 +214,7 @@ enum NotificationAPIError: LocalizedError {
172214
case s3UploadFailed(statusCode: Int)
173215
case noClothIdsReturned
174216
case serverError(statusCode: Int, message: String)
175-
217+
176218
var errorDescription: String? {
177219
switch self {
178220
case .presignedUrlMismatch:

Codive/Features/Notification/Domain/Entities/NotificationEntity.swift

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,6 @@
77

88
import Foundation
99

10-
/// 알림 유형
11-
enum RedirectType: String, Codable {
12-
case member = "MEMBER_REDIRECT"
13-
case history = "HISTORY_REDIRECT"
14-
case weather = "WEATHER_REDIRECT"
15-
}
16-
17-
/// 알림 읽음/읽지 않음 유형
18-
enum ReadStatus: String, Codable {
19-
case read = "READ"
20-
case unread = "NOT_READ"
21-
}
22-
23-
/// 알림 목록 조회 api
24-
struct NotificationEntity: Codable, Identifiable {
25-
let notificationId: Int64
26-
let notificationImageUrl: String?
27-
let notificationContent: String
28-
let redirectInfo: String
29-
let redirectType: RedirectType
30-
var readStatus: ReadStatus
31-
let createdAt: String
32-
33-
var id: Int64 { notificationId }
34-
}
35-
3610
/// 신고 접수 유형
3711
enum ReportType: String, Codable {
3812
case HISTORY = "HISTORY"

Codive/Features/Notification/Domain/Protocols/NotificationRepository.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
protocol NotificationRepository {
99
func patchEachNotification(notificationId: Int64) async throws
1010
func patchAllNotification() async throws
11-
func fetchNotificationList(lastNotificationId: Int64?, size: Int32) async throws -> (content: [NotificationEntity], isLast: Bool)
11+
func fetchNotificationList(lastNotificationId: Int64?, size: Int32) async throws -> NotificationListResponseDTO
1212
func fetchNotificationExist() async throws -> NotificationExistAPIResponseDTO
1313
func fetchReportReceived() async throws -> ReportReceivedAPIResponseDTO
1414
}

Codive/Features/Notification/Domain/UseCases/NotificationUseCase.swift

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ final class NotificationUseCase {
2323
try await repository.patchAllNotification()
2424
}
2525

26-
func fetchNotificationList(lastNotificationId: Int64?, size: Int32) async throws -> (content: [NotificationEntity], isLast: Bool) {
26+
func fetchNotificationList(lastNotificationId: Int64?, size: Int32) async throws -> NotificationListResponseDTO {
2727
return try await repository.fetchNotificationList(
2828
lastNotificationId: lastNotificationId,
2929
size: size
@@ -33,8 +33,4 @@ final class NotificationUseCase {
3333
func fetchReportReceived() async throws -> ReportReceivedAPIResponseDTO {
3434
return try await repository.fetchReportReceived()
3535
}
36-
37-
// func fetchReportStatus() -> ReportEntity {
38-
// return false
39-
// }
4036
}

0 commit comments

Comments
 (0)