Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
run: |
mkdir -p Projects/App/Resources
if [ ! -f Projects/App/Resources/Common.xcconfig ]; then
printf "BASE_URL = https://hellodoriworld.com\nKAKAO_NATIVE_APP_KEY =\n" > Projects/App/Resources/Common.xcconfig
printf 'BASE_URL = https:/$()/hellodoriworld.com\nKAKAO_NATIVE_APP_KEY =\n' > Projects/App/Resources/Common.xcconfig
fi
echo "✅ xcconfig file is ready"

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ jobs:
- name: Prepare xcconfig
run: |
mkdir -p Projects/App/Resources
printf "BASE_URL = ${{ vars.BASE_URL }}\nKAKAO_NATIVE_APP_KEY = ${{ secrets.KAKAO_NATIVE_APP_KEY }}\n" \
printf 'BASE_URL = ${{ vars.BASE_URL }}\nKAKAO_NATIVE_APP_KEY = ${{ secrets.KAKAO_NATIVE_APP_KEY }}\n' \
> Projects/App/Resources/Common.xcconfig

- name: Install Tuist dependencies
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/deploy_testflight.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,10 @@ jobs:
- name: Prepare xcconfig
run: |
mkdir -p Projects/App/Resources
printf "BASE_URL = ${{ vars.BASE_URL }}\nKAKAO_NATIVE_APP_KEY = ${{ secrets.KAKAO_NATIVE_APP_KEY }}\nPROFILE_NAME = ${PROVISIONING_PROFILE_SPECIFIER}\n" \
printf 'BASE_URL = ${{ vars.BASE_URL }}\nKAKAO_NATIVE_APP_KEY = ${{ secrets.KAKAO_NATIVE_APP_KEY }}\n' \
> Projects/App/Resources/Common.xcconfig
printf 'PROFILE_NAME = %s\n' "${PROVISIONING_PROFILE_SPECIFIER}" \
>> Projects/App/Resources/Common.xcconfig

- name: Install Tuist dependencies
run: tuist install
Expand Down
1 change: 1 addition & 0 deletions Projects/App/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ let project = Project.dori(
DoriModules.calendar.module.projectDependency,
DoriModules.history.module.projectDependency,
DoriModules.myPage.module.projectDependency,
DoriModules.notification.module.projectDependency,
DoriModules.network.module.projectDependency,
DoriModules.networkImpl.module.projectDependency,
DoriModules.kakaoAuth.module.projectDependency,
Expand Down
2 changes: 2 additions & 0 deletions Projects/App/Sources/DoriApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import FeatureOnboarding
import FeatureAddDori
import FeatureHistory
import FeatureCalendar
import FeatureNotification
import PlatformKakaoAuth
import PlatformKeychain
import PlatformFCM
Expand Down Expand Up @@ -79,6 +80,7 @@ struct DoriApp: App {
)
$0.fcmPushTestAPIClient = .live(networkService: networkService)
$0.notificationSettingsAPIClient = .live(networkService: networkService)
$0.notificationListAPIClient = .live(networkService: networkService)
}

storeBox.store = store
Expand Down
1 change: 1 addition & 0 deletions Projects/App/Sources/MainTabView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct MainTabFeature {
var isTabBarVisible: Bool {
history.path.isEmpty &&
calendar.addDori == nil &&
calendar.notificationList == nil &&
myPage.navigationPath.isEmpty
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "notificaiton_off.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "notification_setting.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions Projects/Core/DoriDesignSystem/Sources/DoriEmptyView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ public extension DoriEmptyView.Content {
title: "검색된 도리가 없어요.",
description: "해당 도리의 기록을 찾을 수 없어요.\n다른 이름으로 검색해보세요."
)

/// 알림함이 비어 있을 때
static let notificationList = DoriEmptyView.Content(
image: UIAsset.Images.placeholderEmpty.image,
title: "아직 도착한 알림이 없어요",
description: "새로운 소식이 오면 여기에서 알려드릴게요!"
)
}

// MARK: - Preview
Expand Down
14 changes: 14 additions & 0 deletions Projects/Feature/Calendar/Sources/CalendarFeature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import ComposableArchitecture
import Foundation
import FeatureAddDori
import FeatureNotification
import DoriCore

@Reducer
Expand All @@ -17,6 +18,7 @@ public struct CalendarFeature {
@ObservableState
public struct State: Equatable, Sendable {
@Presents public var addDori: AddDoriFeature.State?
@Presents public var notificationList: NotificationListFeature.State?

public var currentMonth: Date
public var selectedType: TransactionType = .judori
Expand Down Expand Up @@ -44,7 +46,9 @@ public struct CalendarFeature {
public enum Action: Equatable, Sendable {
case onAppear
case fabTapped
case notificationBellTapped
case addDori(PresentationAction<AddDoriFeature.Action>)
case notificationList(PresentationAction<NotificationListFeature.Action>)
case goToPreviousMonth
case goToNextMonth
case selectedTypeChanged(TransactionType)
Expand All @@ -67,6 +71,13 @@ public struct CalendarFeature {
state.addDori = AddDoriFeature.State()
return .none

case .notificationBellTapped:
state.notificationList = NotificationListFeature.State()
return .none

case .notificationList:
return .none

case .addDori(.presented(.delegate(.doriCreated))):
state.addDori = nil
return .none
Expand Down Expand Up @@ -137,6 +148,9 @@ public struct CalendarFeature {
.ifLet(\.$addDori, action: \.addDori) {
AddDoriFeature()
}
.ifLet(\.$notificationList, action: \.notificationList) {
NotificationListFeature()
}
}

private func fetchMonthlyData(month: Date, type: TransactionType) -> Effect<Action> {
Expand Down
18 changes: 17 additions & 1 deletion Projects/Feature/Calendar/Sources/CalendarView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import SwiftUI
import ComposableArchitecture
import DoriDesignSystem
import FeatureAddDori
import FeatureNotification

public struct CalendarView: View {
@Bindable var store: StoreOf<CalendarFeature>
Expand Down Expand Up @@ -64,7 +65,17 @@ public struct CalendarView: View {
}
.scrollDisabled(true)
.background(.bgPrimary)
.doriNavigationBar(DoriNavigationBarConfig.titleWithActions("캘린더"))
.doriNavigationBar(
DoriNavigationBarConfig.titleWithActions(
"캘린더",
trailing: [
.iconButton(
image: UIAsset.Icons.notificaitonOff.image.renderingMode(.template),
action: { store.send(.notificationBellTapped) }
)
]
)
)
.onAppear { store.send(.onAppear) }
.overlay(alignment: .bottomTrailing) {
FloatingActionButton {
Expand All @@ -77,6 +88,11 @@ public struct CalendarView: View {
) { addDoriStore in
AddDoriView(store: addDoriStore)
}
.navigationDestination(
item: $store.scope(state: \.notificationList, action: \.notificationList)
) { notificationStore in
NotificationListView(store: notificationStore)
}
.sheet(
isPresented: Binding(
get: { store.selectedDay != nil },
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions Projects/Feature/MyPage/Sources/MyPageFeature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import ComposableArchitecture
import DoriDesignSystem
import DoriNetwork
import FeatureNotification
import Foundation
import PlatformKeychain

Expand Down
1 change: 1 addition & 0 deletions Projects/Feature/MyPage/Sources/MyPageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import ComposableArchitecture
import DoriCore
import DoriDesignSystem
import FeatureNotification
import SwiftUI

public struct MyPageView: View {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import FeatureNotification
import SnapshotTesting
import SwiftUI
import XCTest
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import ComposableArchitecture
import FeatureNotification
import SnapshotTesting
import SwiftUI
import XCTest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,18 @@
import DoriDesignSystem
import SwiftUI

struct DoriToggleSwitch: View {
public struct DoriToggleSwitch: View {
@Binding var isOn: Bool

private let width: CGFloat = 51
private let height: CGFloat = 31
private let thumbSize: CGFloat = 23

var body: some View {
public init(isOn: Binding<Bool>) {
self._isOn = isOn
}

public var body: some View {
ZStack {
Capsule()
.fill(isOn ? UIAsset.Colors.brandMain.color : UIAsset.Colors.borderInput.color)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//
// NotificationListAPIClient.swift
// Dori-iOS
//
// Created by 강동영 on 6/11/26.
//

import ComposableArchitecture
import DoriNetwork
import Foundation

// MARK: - API Client

@DependencyClient
public struct NotificationListAPIClient: Sendable {
/// 알림함 목록 조회. cursor 가 nil 이면 첫 페이지.
public var fetchNotifications: @Sendable (_ cursor: String?, _ size: Int) async throws -> NotificationPageResponse
}

enum NotificationListAPIClientError: LocalizedError {
case unconfigured
case invalidResponse
case backendError(String)

var errorDescription: String? {
switch self {
case .unconfigured:
return "NotificationListAPIClient가 구성되지 않았습니다."
case .invalidResponse:
return "서버 응답이 올바르지 않습니다."
case .backendError(let message):
return message
}
}
}

extension NotificationListAPIClient: DependencyKey {
public static let liveValue = Self(
fetchNotifications: { _, _ in throw NotificationListAPIClientError.unconfigured }
)
}

extension NotificationListAPIClient: TestDependencyKey {
public static let previewValue = Self(
fetchNotifications: { _, _ in
NotificationPageResponse(
items: [
NotificationItemResponse(
id: 10,
typeCode: "DORI_ALERT",
title: "결혼식 알림",
body: "내일 홍길동님의 결혼식 일정이 있어요!",
targetType: "DORI",
targetId: 10,
partnerId: 2,
readAt: nil,
pushedAt: "2026-05-26T14:00:26.794863464",
createdAt: "2026-05-26T14:00:26.794884463"
)
],
size: 20,
nextCursor: nil,
hasNext: false
)
}
)

public static let testValue = Self()
}

public extension NotificationListAPIClient {
static func live(networkService: any NetworkService) -> Self {
Self(
fetchNotifications: { cursor, size in
let endpoint = FetchNotificationsEndpoint(cursor: cursor, size: size)
let response = try await networkService.request(
endpoint,
responseType: SuccessResponse<NotificationPageResponse>.self
)
if let apiError = response.error {
throw NotificationListAPIClientError.backendError(
apiError.message ?? "알림 목록 조회에 실패했습니다."
)
}
guard response.success, let data = response.data else {
throw NotificationListAPIClientError.invalidResponse
}
return data
}
)
}
}

public extension DependencyValues {
var notificationListAPIClient: NotificationListAPIClient {
get { self[NotificationListAPIClient.self] }
set { self[NotificationListAPIClient.self] = newValue }
}
}
Loading
Loading