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
19 changes: 19 additions & 0 deletions Mark-In/Sources/App/DIContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,24 @@ extension DIContainer {

register(folderRepository)
register(linkRepository)

/// UseCase
let fetchLinkListUseCase: FetchLinkListUseCase = FetchLinkListUseCaseImpl(
linkRepository: linkRepository
)
let fetchFolderListUseCase: FetchFolderListUseCase = FetchFolderListUseCaseImpl(
folderRepository: folderRepository
)
let generateLinkUseCase: GenerateLinkUseCase = GenerateLinkUseCaseImpl(
linkRepository: linkRepository
)
let generateFolderUseCase: GenerateFolderUseCase = GenerateFolderUseCaseImpl(
folderRepository: folderRepository
)

register(fetchLinkListUseCase)
register(fetchFolderListUseCase)
register(generateLinkUseCase)
register(generateFolderUseCase)
}
}
6 changes: 4 additions & 2 deletions Mark-In/Sources/Data/Repositories/FolderRepositoryImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ struct FolderRepositoryImpl: FolderRepository {

func update(userID: String, folder: Folder) async throws {
/// 1. Folder 문서 참조 생성
let path = FirebasePath.folders(userID: userID).path + "/\(folder.id)"
let folderID = folder.id ?? ""
let path = FirebasePath.folders(userID: userID).path + "/\(folderID)"
let folderDocRef = db.document(path)

/// 2. Entity를 DTO로 변환
Expand All @@ -84,7 +85,8 @@ struct FolderRepositoryImpl: FolderRepository {

func delete(userID: String, folder: Folder) async throws {
/// 1. Folder 문서 참조 생성
let path = FirebasePath.folders(userID: userID).path + "/\(folder.id)"
let folderID = folder.id ?? ""
let path = FirebasePath.folders(userID: userID).path + "/\(folderID)"
let folderDocRef = db.document(path)

/// 2. Folder 삭제
Expand Down
2 changes: 1 addition & 1 deletion Mark-In/Sources/Domain/Entities/Folder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import Foundation

struct Folder: Equatable, Hashable {
var id: String
var id: String?
var name: String
var createdBy: Date
}
2 changes: 1 addition & 1 deletion Mark-In/Sources/Domain/Entities/Link.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Foundation

struct Link {
struct Link: Hashable {
var id: String
var url: String
var title: String?
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// FetchFolderListUseCaseImpl.swift
// Mark-In
//
// Created by 이정동 on 5/11/25.
//

import Foundation

struct FetchFolderListUseCaseImpl: FetchFolderListUseCase {

private let folderRepository: FolderRepository

init(folderRepository: FolderRepository) {
self.folderRepository = folderRepository
}

func execute(userID: String) async throws -> [Folder] {
try await folderRepository.fetchAll(userID: userID)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// FetchLinkListUseCaseImpl.swift
// Mark-In
//
// Created by 이정동 on 5/11/25.
//

import Foundation

struct FetchLinkListUseCaseImpl: FetchLinkListUseCase {

private let linkRepository: LinkRepository

init(linkRepository: LinkRepository) {
self.linkRepository = linkRepository
}

func execute(userID: String) async throws -> [Link] {
try await linkRepository.fetchAll(userID: userID)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ struct GenerateFolderUseCaseImpl: GenerateFolderUseCase {
self.folderRepository = folderRepository
}

func execute(name: String) async throws -> Folder {
let writeFolder = WriteFolder(name: name)
func execute(writeFolder: WriteFolder) async throws -> Folder {

// TODO: #29번 PR 머지 후 AuthManager를 통해 현재 로그인 유저 정보 가져옴
let user = "123"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// GenerateLinkUseCaseImpl.swift
// Mark-In
//
// Created by 이정동 on 5/11/25.
//

import Foundation

struct GenerateLinkUseCaseImpl: GenerateLinkUseCase {

private let linkRepository: LinkRepository

init(linkRepository: LinkRepository) {
self.linkRepository = linkRepository
}

func execute(writeLink: WriteLink) async throws -> Link {

// TODO: #29번 PR 머지 후 AuthManager를 통해 현재 로그인 유저 정보 가져옴
let user = "testUser"

let newLink = try await linkRepository.create(userID: user, link: writeLink)
return newLink
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// FetchFolderListUseCase.swift
// Mark-In
//
// Created by 이정동 on 5/11/25.
//

import Foundation

protocol FetchFolderListUseCase {
func execute(userID: String) async throws -> [Folder]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// FetchLinkListUseCase.swift
// Mark-In
//
// Created by 이정동 on 5/11/25.
//

import Foundation

protocol FetchLinkListUseCase {
func execute(userID: String) async throws -> [Link]
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
import Foundation

protocol GenerateFolderUseCase {
func execute(name: String) async throws -> Folder
func execute(writeFolder: WriteFolder) async throws -> Folder
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// GenerateLinkUseCase.swift
// Mark-In
//
// Created by 이정동 on 5/11/25.
//

import Foundation

protocol GenerateLinkUseCase {
func execute(writeLink: WriteLink) async throws -> Link
}
2 changes: 1 addition & 1 deletion Mark-In/Sources/Feature/AddFolder/AddFolderView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ struct AddFolderView: View {
.disabled(title.isEmpty || isSaving)

Button {
viewModel.send(.didTapAddLinkButton(title: title))
viewModel.send(.didTapAddFolderButton(name: title))
} label: {
Text("추가")
.padding(.vertical, 4)
Expand Down
10 changes: 5 additions & 5 deletions Mark-In/Sources/Feature/AddFolder/AddFolderViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ final class AddFolderViewModel: Reducer {
}

enum Action {
case didTapAddLinkButton(title: String)
case didTapAddFolderButton(name: String)
case didCompleteSave(Folder)
case updateErrorState(Bool)
}
Expand All @@ -26,8 +26,7 @@ final class AddFolderViewModel: Reducer {
private(set) var state: State = .init()

init() {
// TODO: DIContainer PR 머지 이후 DIContainer를 통해 의존성 주입
self.generateFolderUseCase = GenerateFolderUseCaseImpl(folderRepository: FolderRepositoryImpl())
self.generateFolderUseCase = DIContainer.shared.resolve()
}

func send(_ action: Action) {
Expand All @@ -37,12 +36,13 @@ final class AddFolderViewModel: Reducer {

func reduce(state: inout State, action: Action) -> Effect<Action> {
switch action {
case .didTapAddLinkButton(let title):
case .didTapAddFolderButton(let name):
state.isLoading = true

return .run {
do {
let result = try await self.generateFolderUseCase.execute(name: title)
let writeFolder = WriteFolder(name: name)
let result = try await self.generateFolderUseCase.execute(writeFolder: writeFolder)
return .didCompleteSave(result)
} catch {
return .updateErrorState(true)
Expand Down
80 changes: 61 additions & 19 deletions Mark-In/Sources/Feature/AddLink/AddLinkView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,29 @@ import SwiftUI

import DesignSystem

// TODO: 후에 제거 예정
private struct TestFolder1: Hashable {
var id: String
var name: String

static let dummy: [Self] = [
.init(id: "1", name: "Root"),
.init(id: "2", name: "Work"),
.init(id: "3", name: "Personal"),
]
}

struct AddLinkView: View {
@Environment(\.dismiss) var dismiss
@State private var viewModel = AddLinkViewModel()
@State private var title: String = ""
@State private var url: String = ""

@State private var currentFolder: TestFolder1 = TestFolder1.dummy[0]
@State private var currentFolder: Folder

private let folders: [Folder]
private let completion: (Link) -> Void

private var isSaving: Bool {
viewModel.state.isSaving
}

init(
folders: [Folder],
completion: @escaping (Link) -> Void
) {
self.folders = folders
self._currentFolder = State(initialValue: folders[0])
self.completion = completion
}

var body: some View {
VStack {
Expand All @@ -35,7 +40,7 @@ struct AddLinkView: View {

VStack(spacing: 8) {
Picker("", selection: $currentFolder) {
ForEach(TestFolder1.dummy, id: \.self) { folder in
ForEach(folders, id: \.self) { folder in
Label(title: {
Text(folder.name)
}, icon: {
Expand All @@ -47,16 +52,23 @@ struct AddLinkView: View {
.pickerStyle(.menu)
.labelsHidden()

TextField("", text: $title, prompt: Text("제목"))
TextField("", text: $url, prompt: Text("주소"))
.textFieldStyle(.roundedBorder)

TextField("", text: $url, prompt: Text("주소"))
TextField("", text: $title, prompt: Text("제목(선택)"))
.textFieldStyle(.roundedBorder)
}
.padding(.top, 14)
.disabled(isSaving)


HStack {
if isSaving {
ProgressView()
.frame(width: 12, height: 12)
.scaleEffect(0.4, anchor: .center)
}

Button {
dismiss()
} label: {
Expand All @@ -71,10 +83,15 @@ struct AddLinkView: View {
.stroke(.markBlack10, lineWidth: 0.5)
}
}
.disabled(isSaving)

Button {
// TODO: 링크 추가 로직
dismiss()
let link = WriteLink(
url: url,
title: title,
folderID: currentFolder.id
)
viewModel.send(.addLinkButtonTapped(link: link))
} label: {
Text("추가")
.padding(.vertical, 4)
Expand All @@ -83,6 +100,7 @@ struct AddLinkView: View {
.background(.markPoint)
.clipShape(RoundedRectangle(cornerRadius: 6))
}
.disabled(url.isEmpty || isSaving)
}
.frame(maxWidth: .infinity, alignment: .trailing)
.padding(.top, 18)
Expand All @@ -91,9 +109,33 @@ struct AddLinkView: View {
}
.padding(20)
.frame(width: 400)
.onChange(of: viewModel.state.createdLink) {
guard let link = $1 else { return }
completion(link)
dismiss()
}
.alert(
"링크 생성에 실패했습니다.",
isPresented: .init(
get: { viewModel.state.isError },
set: { viewModel.send(.occurError($0)) }
)
) {
Button(role: .cancel) {
} label: {
Text("확인")
}
}
}
}

#Preview {
AddLinkView()
AddLinkView(
folders: [
.init(id: "", name: "기본폴더", createdBy: .now),
.init(id: "1", name: "폴더1", createdBy: .now),
]
) {
print($0)
}
}
Loading
Loading