Skip to content

Commit

Permalink
[Feature/#328] 자기 소개 웹뷰 연결 (#348)
Browse files Browse the repository at this point in the history
* feat: BaseWebViewType 자기소개 웹 뷰 추가

* feat: 자기소개 및 프로필 사진 업로드 완료 브릿지 추가

* feat: 자기소개 웹 뷰 연결

* feat: 자기소개 작성 안한 사용자 도착한 보틀 볼 수 있도록 수정
  • Loading branch information
leemhyungyu authored Nov 7, 2024
1 parent a062fdf commit 19eac8e
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 221 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ public enum BottleWebViewAction: Equatable {
/// 프로필 사진 수정 완료
case profileImageDidChanged

// MARK: - Introduction Setup
/// 자기소개 & 프로필 사진 등록 완료
case introductionDidCompleted

public init?(
type: String,
message: String? = nil,
Expand Down Expand Up @@ -146,6 +150,11 @@ public enum BottleWebViewAction: Equatable {

case "onProfileImageEditComplete":
self = .profileImageDidChanged

// MARK: - Introduction Setup

case "onIntroductionComplete":
self = .introductionDidCompleted

default:
return nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public enum BottleWebViewType {
case bottleArrival
case editProfile
case goodFeeling
case introductionSetup
case openURL(url: String)

var path: String {
Expand All @@ -44,6 +45,8 @@ public enum BottleWebViewType {
return "profile/edit"
case .goodFeeling:
return "bottles/sents"
case .introductionSetup:
return "/intro/create"
case .openURL:
return ""
}
Expand All @@ -69,6 +72,9 @@ public enum BottleWebViewType {
case .goodFeeling:
return makeUrlWithToken(path)

case .introductionSetup:
return makeUrlWithToken(path)

case let .openURL(url):
return URL(string: url)!
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ import Foundation

import DomainProfileInterface
import DomainProfile
import SharedDesignSystem

import CoreToastInterface
import CoreLoggerInterface

import CoreToastInterface

import ComposableArchitecture

@Reducer
Expand All @@ -24,128 +27,36 @@ public struct IntroductionSetupFeature {

@ObservableState
public struct State: Equatable {
public var introductionText: String
public var textFieldState: TextFieldState
public var keywordItem: [ClipItem]
public var isNextButtonDisable: Bool
public var maxLength: Int
public var isLoading: Bool

public init(
introductionText: String = "",
textFieldState: TextFieldState = .enabled,
keywordItem: [ClipItem] = [],
isNextButtonDisable: Bool = true,
maxLength: Int = 50,
isLoading: Bool = false
) {
self.introductionText = introductionText
self.textFieldState = textFieldState
self.keywordItem = keywordItem
self.isNextButtonDisable = isNextButtonDisable
self.maxLength = maxLength
self.isLoading = isLoading
}
public init() {}
}

public enum Action: BindableAction {
// View Life Cycle
case onLoad

// User Action
case texFieldDidFocused(isFocused: Bool)
case profileSelectDidFatched(ProfileSelect)
case nextButtonDidTapped
case onTapGesture
case backButtonDidTapped

// Delegate
case delegate(Delegate)
case binding(BindingAction<State>)

public enum Delegate {
case nextButtonDidTapped(introductionText: String)
}
public enum Action {
// Web Bridge
case closeWebView
case presentToastDidRequired(message: String)
}

public var body: some ReducerOf<Self> {
BindingReducer()
reducer
}
}

extension IntroductionSetupFeature {
public init() {
@Dependency(\.dismiss) var dismiss
@Dependency(\.toastClient) var toastClient

let reducer = Reduce<State, Action> { state, action in
@Dependency(\.profileClient) var profileClient

switch action {
case .onLoad:
state.isLoading = true
return .run { send in
let profileSelect = try await profileClient.fetchProfileSelect()
await send(.profileSelectDidFatched(profileSelect))
}
case let .texFieldDidFocused(isFocused):
state.textFieldState = isFocused ? .focused : .active
return .none
case .profileSelectDidFatched(let profileSelect):
// TODO: 코드 개선
// TODO: 없으면 ClipItem nil로
state.keywordItem = [
ClipItem(
title: "내 키워드를 참고해보세요",
list: [profileSelect.job, profileSelect.mbti, "\(profileSelect.region.city) \(profileSelect.region.state)", "\(profileSelect.height)", profileSelect.smoke, profileSelect.alcohol]
),

ClipItem(
title: "나의 성격은",
list: profileSelect.keyword
),

ClipItem(
title: "내가 푹 빠진 취미는",
list: (profileSelect.interset.culture ?? [])
+ (profileSelect.interset.entertainment ?? [])
+ (profileSelect.interset.sports ?? [])
+ (profileSelect.interset.etc ?? [])
)
]
state.isLoading = false
return .none
case .binding(\.introductionText):
if state.introductionText.count >= state.maxLength {
state.textFieldState = .focused
state.isNextButtonDisable = false
} else {
state.textFieldState = .error
state.isNextButtonDisable = true
}
return .none

case .nextButtonDidTapped:
return .run { [introductionText = state.introductionText] send in
Log.debug("nextButtonDidTapped")
await send(.delegate(.nextButtonDidTapped(introductionText: introductionText)))
}
case .onTapGesture:
if state.introductionText.count == 0 {
state.textFieldState = .enabled
} else {
state.textFieldState = .active
}
return .none

case .backButtonDidTapped:
case .closeWebView:
return .run { _ in
await dismiss()
await dismiss()
}

case .binding(_):
return .none

case .delegate:
case let .presentToastDidRequired(message):
toastClient.presentToast(message: message)
return .none
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@

import SwiftUI

import SharedDesignSystem
import FeatureBaseWebViewInterface

import CoreLoggerInterface

import SharedDesignSystem

import ComposableArchitecture

public struct IntroductionSetupView: View {
Expand All @@ -22,88 +25,28 @@ public struct IntroductionSetupView: View {

public var body: some View {
WithPerceptionTracking {
if store.isLoading {
LoadingIndicator()
} else {
ScrollView {
introductionTitle
introductionTextField
keywordList
nextButton
}.onTapGesture {
store.send(.onTapGesture)
}.setNavigationBar {
makeNaivgationleftButton {
store.send(.backButtonDidTapped)
}
BaseWebView(type: .introductionSetup) { action in
switch action {
case .webViewLoadingDidCompleted:
break

case .closeWebView:
store.send(.closeWebView)

case .introductionDidCompleted:
store.send(.closeWebView)

case let .showTaost(message):
store.send(.presentToastDidRequired(message: message))

default:
Log.assertion(message: "not handled action: \(action)")
}
}
}
.onLoad {
store.send(.onLoad)
}
.scrollIndicators(.hidden)
.ignoresSafeArea(.all, edges: .bottom)
.ignoresSafeArea(.all, edges: [.bottom, .top])
.toolbar(.hidden, for: .bottomBar)
}
}

private extension IntroductionSetupView {
var introductionTitle: some View {
TitleView(
pageInfo: PageInfo(nowPage: 1, totalCount: 2),
title: "보틀에 담을\n소개를 작성해 주세요",
caption: "수정이 어려우니 신중하게 작성해주세요"
)
.padding(.top, .xl)
.padding(.bottom, 32)
.padding(.horizontal, .md)
}

var introductionTextField: some View {
LinesTextField(
textFieldType: .introduction,
textFieldState: $store.textFieldState,
text: $store.introductionText,
placeHolder: "호기심이 많고 새로운 경험을 즐깁니다. 주말엔 책을 읽거나 맛집을 찾아다니며 여유를 즐기고, 친구들과 소소한 모임으로 에너지를 충전해요.",
errorMessage: "최소 \(store.maxLength)글자 이상 작성해주세요",
textLimit: 300
)
.focused($isTextFieldFocused)
.padding(.horizontal, .md)
.padding(.bottom, .sm)
.onChange(of: isTextFieldFocused) { isFocused in
store.send(.texFieldDidFocused(isFocused: isFocused))
}
.onChange(of: store.textFieldState) { textFieldState in
Log.error(textFieldState)
isTextFieldFocused = textFieldState == .active || textFieldState == .enabled ? false : true
}
}

var keywordList: some View {
ClipListContainerView(
clipItemList: store.keywordItem
)
.padding(.horizontal, .md)
.padding(.bottom, 47)
}

var nextButton: some View {
SolidButton(
title: "다음",
sizeType: .full,
buttonType: .throttle,
action: { store.send(.nextButtonDidTapped) }
)
.padding(.horizontal, .md)
.padding(.bottom, .xl)
.disabled(store.isNextButtonDisable)
}
}

extension View {
func endTextEditing() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
.toolbar(.hidden, for: .navigationBar)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,6 @@ extension SandBeachRootFeature {

switch action {

// IntrodctionSetup Delegate
case let .path(.element(id: _, action:
.IntroductionSetup(.delegate(.nextButtonDidTapped(introductionText))))):
state.introduction = introductionText
state.path.append(.ProfileImageUpload(ProfileImageUploadFeature.State()))
return .none

// ProfileImageUpload Delegate
case let .path(.element(id: _, action:
.ProfileImageUpload(.delegate(.doneButtonDidTapped(selectedImageData))))):
Expand Down
Loading

0 comments on commit 19eac8e

Please sign in to comment.