Skip to content

Commit

Permalink
[WEAV-74] 프로필 입력 - 회사 선택 (#29)
Browse files Browse the repository at this point in the history
* [WEAV-74] Drop Down View 생성

* [WEAV-74] 드롭다운, 회사 리스트 API 연결

* [WEAV-74] 없는 회사 선택 기능 구현

* [WEAV-74] 같은 회사 매칭 여부 선택 뷰 구현

* [WEAV-74] debug 전용 인증 건너뛰기 구현

* [WEAV-74] 회사 검색 뷰 로직 테스트코드 작성

* [CICD] Unit test Generate swift added.

* [WEAV-74] 회사 리스트 드롭다운 페이지네이션
  • Loading branch information
jisu15-kim authored Oct 10, 2024
1 parent fae7192 commit b39e340
Show file tree
Hide file tree
Showing 18 changed files with 931 additions and 15 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/unitTest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ jobs:
run: |
curl https://mise.run | sh
mise install
- name: Create Secret.swift file
run: |
echo '${{ secrets.SECRET_SWIFT }}' > ./Projects/Core/CoreKit/Sources/Secret.swift
- name: Install Tuist dependencies
run: mise x -- tuist install

Expand Down
2 changes: 2 additions & 0 deletions Projects/App/Sources/Navigation/NavigationStack.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ extension PathType {
AuthProfileGenderInputView()
case .authProfileAge:
AuthProfileAgeInputView()
case .authCompany:
AuthCompanyView()
case .authName:
AuthNameInputView()
}
Expand Down
22 changes: 21 additions & 1 deletion Projects/Core/CommonKit/Sources/Path/PathTypes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,22 @@ public enum PathType: Hashable {
public static var debugPreviewTypes: [PathType] = [
.designPreview,
.main,
.signUp(.authPhoneInput),
.signUp(
.authPhoneVerify(
SMSSendResponse(
userType: .NEW,
authCodeId: "tempCode",
phoneNumber: "010-1234-5678"
)
)
),
.signUp(.authAgreement),
.signUp(.authGreeting),
.signUp(.authProfileGender),
.signUp(.authProfileAge),
.signUp(.authCompany),
.signUp(.authName),
.signUp(.authPhoneInput)
]
#endif
Expand All @@ -35,6 +51,7 @@ public enum PathType: Hashable {
case .authGreeting: return "가입 후 환영"
case .authProfileGender: return "성별 입력"
case .authProfileAge: return "나이 입력"
case .authCompany: return "내 직장 입력"
case .authName: return "이름 입력"
}
}
Expand All @@ -49,6 +66,7 @@ public enum SignUpSubViewType: Hashable {
case authGreeting
case authProfileGender
case authProfileAge
case authCompany
case authName

public static func == (lhs: SignUpSubViewType, rhs: SignUpSubViewType) -> Bool {
Expand All @@ -69,8 +87,10 @@ public enum SignUpSubViewType: Hashable {
hasher.combine(4)
case .authProfileAge:
hasher.combine(5)
case .authName:
case .authCompany:
hasher.combine(6)
case .authName:
hasher.combine(7)
}
}
}
4 changes: 2 additions & 2 deletions Projects/Core/CoreKit/UnitTest/StringExtensionText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ final class PhoneNumberTests: XCTestCase {
"010123456789".isValidPhoneNumber(),
"유효하지 않은 번호 형식임에도 불구하고 true가 반환됨"
)
XCTAssertFalse(
XCTAssertTrue(
"010-1234-5678".isValidPhoneNumber(),
"하이픈이 포함된 경우 유효하지 않은 번호 형식임에도 불구하고 true가 반환됨"
"하이픈이 포함되었으나 유효한 번호인 경우 true를 반환해야 함"
)

// 텍스트가 포함된 경우
Expand Down
19 changes: 19 additions & 0 deletions Projects/Core/Model/Sources/Network/CompanySearchResponse.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// CompanySearchResponse.swift
// CommonKit
//
// Created by 김지수 on 10/9/24.
// Copyright © 2024 com.weave. All rights reserved.
//

import Foundation

public struct CompanySearchResponse {
public let id: String
public let name: String

public init(id: String, name: String) {
self.id = id
self.name = name
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// CompanyService.swift
// CommonKit
//
// Created by 김지수 on 10/9/24.
// Copyright © 2024 com.weave. All rights reserved.
//

import Foundation
import OpenapiGenerated
import Model

//MARK: - Service Protocol
public protocol CompanyServiceProtocol {
func requestSearchCompany(
keyword: String,
next: String?
) async throws -> ([CompanySearchResponse], String?)
}

//MARK: - Service
public final class CompanyService {
public static var shared = CompanyService()
private init() {}
}

extension CompanyService: CompanyServiceProtocol {
public func requestSearchCompany(
keyword: String,
next: String? = nil
) async throws -> ([CompanySearchResponse], String?) {
let response = try await client.searchCompanies(
query: .init(name: keyword, next: next)
).ok.body.json

let result = response.companies.map {
CompanySearchResponse(
id: $0.id,
name: $0.name
)
}
let next = response.next
return (result, next)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// CompanyServiceMock.swift
// CommonKit
//
// Created by 김지수 on 10/10/24.
// Copyright © 2024 com.weave. All rights reserved.
//

import Foundation
import Model

//MARK: - Service
public final class CompanyServiceMock: CompanyServiceProtocol {

public init() {}

public func requestSearchCompany(keyword: String, next: String?) async throws -> ([Model.CompanySearchResponse], String?) {
return ([
.init(id: "0", name: "현대글로비스"),
.init(id: "1", name: "현대자동차"),
.init(id: "2", name: "기아자동차"),
.init(id: "3", name: "채널톡"),
.init(id: "4", name: "닥터다이어리"),
.init(id: "5", name: "컬쳐커넥션"),
.init(id: "6", name: "엄청좋은회사"),
.init(id: "7", name: "로지텍"),
.init(id: "8", name: "스탠리"),
.init(id: "9", name: "스타벅스"),
.init(id: "10", name: "호날두주식회사"),
.init(id: "11", name: "애플"),
.init(id: "12", name: "엔비디아"),
], nil)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ actor LoggingMiddleware {
private let logger: Logger
package let bodyLoggingPolicy: BodyLoggingPolicy

package init(logger: Logger = defaultLogger, bodyLoggingConfiguration: BodyLoggingPolicy = .upTo(maxBytes: 2048)) {
package init(logger: Logger = defaultLogger, bodyLoggingConfiguration: BodyLoggingPolicy = .upTo(maxBytes: 10000)) {
self.logger = logger
self.bodyLoggingPolicy = bodyLoggingConfiguration
}
Expand Down Expand Up @@ -77,19 +77,17 @@ extension LoggingMiddleware: ServerMiddleware {

extension LoggingMiddleware {
func log(_ request: HTTPRequest, _ requestBody: BodyLoggingPolicy.BodyLog) {
logger.debug(
"Request: \(request.method, privacy: .public) \(request.path ?? "<nil>", privacy: .public) body: \(requestBody, privacy: .auto)"
)
let decodedPath = request.path?.removingPercentEncoding ?? "<nil>"
print("Request: \(request.method) \(decodedPath) body: \(requestBody)")
}

func log(_ request: HTTPRequest, _ response: HTTPResponse, _ responseBody: BodyLoggingPolicy.BodyLog) {
logger.debug(
"Response: \(request.method, privacy: .public) \(request.path ?? "<nil>", privacy: .public) \(response.status, privacy: .public) body: \(responseBody, privacy: .auto)"
)
let decodedPath = request.path?.removingPercentEncoding ?? "<nil>"
print("Response: \(request.method) \(decodedPath) \(response.status) body: \(responseBody)")
}

func log(_ request: HTTPRequest, failedWith error: any Error) {
logger.warning("Request failed. Error: \(error.localizedDescription)")
print("Request failed. Error: \(error.localizedDescription)")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,19 @@ import SwiftUI
public struct CTAButton<BackgroundStyle: ShapeStyle>: View {
private let title: String
private let backgroundStyle: BackgroundStyle
private let titleColor: Color = .white
private let titleColor: Color
private let isActive: Bool
private var handler: () -> Void

public init(
title: String,
titleColor: Color = .white,
backgroundStyle: BackgroundStyle = DesignCore.Colors.grey500,
isActive: Bool = true,
handler: @escaping () -> Void
) {
self.title = title
self.titleColor = titleColor
self.backgroundStyle = backgroundStyle
self.isActive = isActive
self.handler = handler
Expand Down
123 changes: 123 additions & 0 deletions Projects/DesignSystem/DesignCore/Sources/DropDown/DropDownView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
//
// DropDownView.swift
// DesignCore
//
// Created by 김지수 on 10/9/24.
// Copyright © 2024 com.weave. All rights reserved.
//

import SwiftUI

public protocol DropDownFetchable: Hashable, Equatable {
var id: String { get }
var name: String { get }
}

public struct DropDownPicker<Content: View>: View {

@FocusState var showDropDown: Bool

var tapHandler: ((Int) -> Void)?
var content: () -> Content

var dataSources: [any DropDownFetchable]
let itemSize: CGFloat = 56

var nextPageHandler: (() -> Void)?
var needCallNextPage = false

var frameHeight: CGFloat {
if !showDropDown {
return 0
}

if dataSources.count > 3 {
return itemSize * 3 + itemSize * 0.5
}

return itemSize * CGFloat(dataSources.count)
}

var frameOffset: CGFloat {
if !showDropDown {
return 0
}

if dataSources.count > 3 {
return 140
}

return 125 - 28 * CGFloat(3 - dataSources.count)
}

public init(
dataSources: [any DropDownFetchable],
showDropDown: FocusState<Bool>,
needCallNextPage: Bool = false,
@ViewBuilder content: @escaping () -> Content,
tapHandler: ((Int) -> Void)? = nil,
nextPageHandler: (() -> Void)? = nil
) {
self.dataSources = dataSources
self.content = content
self.tapHandler = tapHandler
self._showDropDown = showDropDown
self.nextPageHandler = nextPageHandler
self.needCallNextPage = needCallNextPage
}

public var body: some View {
VStack {
ZStack {
ZStack {
RoundedRectangle(cornerRadius: 24)
.foregroundStyle(.white) //
ScrollView {
LazyVStack(alignment: .leading, spacing: 0) {
ForEach(0 ..< dataSources.count, id: \.self) { index in
let item = dataSources[index]
Button(action: {
tapHandler?(index)
withAnimation {
showDropDown.toggle()
}
}, label: {
HStack(spacing: 16) {
Text(item.name)
.typography(.regular_14)
.multilineTextAlignment(.leading)
Spacer()
}
.foregroundStyle(DesignCore.Colors.grey500)
.frame(height: itemSize)
.padding(.horizontal, 16)
.background(.white)
})
}
}
.frame(maxWidth: .infinity, alignment: .leading)
if needCallNextPage {
ProgressView()
.padding(.bottom, 10)
.onAppear {
nextPageHandler?()
}
}
}
}
.clipShape(
RoundedRectangle(cornerRadius: 24)

)
.shadow(.default)
.animation(.easeInOut(duration: 0.2), value: frameOffset)
.frame(height: frameHeight)
.offset(y: frameOffset)

content()
}
.frame(height: 50)
}
.zIndex(999)
}
}
Loading

0 comments on commit b39e340

Please sign in to comment.