Skip to content

Commit

Permalink
feat : 영업 시간 로직 수정 (#74)
Browse files Browse the repository at this point in the history
  • Loading branch information
k2645 committed Jan 20, 2024
1 parent 4ebd160 commit 479a3a5
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 97 deletions.
4 changes: 4 additions & 0 deletions KCS/KCS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
59F478BD2B5AE180002FEF9E /* FetchStoresUseCaseImplTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59F478BC2B5AE180002FEF9E /* FetchStoresUseCaseImplTests.swift */; };
8FE699E5DAEEDFE5A53D5E82 /* Pods_KCS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E11E3144529848C9A0FC6F77 /* Pods_KCS.framework */; };
A802D1F62B5277630091FDE7 /* CertificationLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A802D1F52B5277620091FDE7 /* CertificationLabel.swift */; };
A81EFBB32B5BC57800D0C0D7 /* OpenClosedContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81EFBB22B5BC57800D0C0D7 /* OpenClosedContent.swift */; };
A89087042B4E7F3500767225 /* FilterButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = A89087032B4E7F3500767225 /* FilterButton.swift */; };
A890870A2B4EF00B00767225 /* SystemImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A89087092B4EF00B00767225 /* SystemImage.swift */; };
A890870D2B4EF91600767225 /* UIView+SetLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A890870C2B4EF91600767225 /* UIView+SetLayer.swift */; };
Expand Down Expand Up @@ -132,6 +133,7 @@
5FF0FF2386EEB69182D6EA4C /* Pods-KCSUnitTest.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-KCSUnitTest.debug.xcconfig"; path = "Target Support Files/Pods-KCSUnitTest/Pods-KCSUnitTest.debug.xcconfig"; sourceTree = "<group>"; };
9EA5C8EA72EA9E937C11400A /* Pods-KCS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-KCS.debug.xcconfig"; path = "Target Support Files/Pods-KCS/Pods-KCS.debug.xcconfig"; sourceTree = "<group>"; };
A802D1F52B5277620091FDE7 /* CertificationLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CertificationLabel.swift; sourceTree = "<group>"; };
A81EFBB22B5BC57800D0C0D7 /* OpenClosedContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenClosedContent.swift; sourceTree = "<group>"; };
A89087032B4E7F3500767225 /* FilterButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterButton.swift; sourceTree = "<group>"; };
A89087092B4EF00B00767225 /* SystemImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemImage.swift; sourceTree = "<group>"; };
A890870C2B4EF91600767225 /* UIView+SetLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+SetLayer.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -349,6 +351,7 @@
59C306A52B4D966C00862625 /* CertificationType.swift */,
A8ACB7DC2B58E3DE00540BD1 /* OpenClosedType.swift */,
5977BE732B57FA7A00725C90 /* FilteredStores.swift */,
A81EFBB22B5BC57800D0C0D7 /* OpenClosedContent.swift */,
);
path = Entity;
sourceTree = "<group>";
Expand Down Expand Up @@ -715,6 +718,7 @@
5977BE9E2B59ACE800725C90 /* ImageCache.swift in Sources */,
59C306A42B4D7EBA00862625 /* Marker.swift in Sources */,
5977BE662B553BA800725C90 /* HomeViewModelImpl.swift in Sources */,
A81EFBB32B5BC57800D0C0D7 /* OpenClosedContent.swift in Sources */,
5977BE5C2B5535A100725C90 /* FetchRefreshStoresUseCaseImpl.swift in Sources */,
A8ACB7E22B594F7400540BD1 /* StoreInformationViewModelImpl.swift in Sources */,
59C306CF2B50399C00862625 /* RequestLocationDTO.swift in Sources */,
Expand Down
15 changes: 15 additions & 0 deletions KCS/KCS/Domain/Entity/OpenClosedContent.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// OpenClosedContent.swift
// KCS
//
// Created by 김영현 on 1/20/24.
//

import Foundation

struct OpenClosedContent {

let openClosedType: OpenClosedType
let openingHour: String

}
10 changes: 9 additions & 1 deletion KCS/KCS/Domain/Entity/OpenClosedType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,16 @@ import Foundation
enum OpenClosedType: String {

case open = "영업 중"
case closed = "금일 영업 마감"
case closed = "영업 종료"
case breakTime = "브레이크 타임"
case dayOff = "휴무일"
case none = ""

}

enum OpenClose {

case open
case close

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ protocol GetOpenClosedUseCase {

func execute(
openingHours: [RegularOpeningHours]
) -> OpenClosedType
) -> OpenClosedContent

}
172 changes: 137 additions & 35 deletions KCS/KCS/Domain/UseCase/GetOpenClosedUseCaseImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,47 +11,156 @@ struct GetOpenClosedUseCaseImpl: GetOpenClosedUseCase {

func execute(
openingHours: [RegularOpeningHours]
) -> OpenClosedType {
if openingHours.isEmpty {
return OpenClosedType.none
} else {
let openHours = openingHours.filter({ $0.open.day.index == Date().weekDay })
if openHours.isEmpty {
return OpenClosedType.dayOff
} else {
return isOpen(openHours: openHours)
}
}
) -> OpenClosedContent {
return getOpenClosedContent(openingHour: openingHours)
}

}

private extension GetOpenClosedUseCaseImpl {

func isOpen(openHours: [RegularOpeningHours]) -> OpenClosedType {
func getOpenClosedContent(openingHour: [RegularOpeningHours]) -> OpenClosedContent {
dump(openingHour)
let nowOpenClosedType = getOpenClosedType(openingHour: openingHour)
lazy var openingHourString: String = {
switch nowOpenClosedType {
case .none, .dayOff:
return OpenClosedType.none.rawValue
case .breakTime, .closed:
return getOpenClosedString(openingHour: openingHour, openClosedType: .open)
case .open:
return getOpenClosedString(openingHour: openingHour, openClosedType: .close)
}
}()

return OpenClosedContent(openClosedType: nowOpenClosedType, openingHour: openingHourString)

}
}

private extension GetOpenClosedUseCaseImpl {

func getOpenClosedType(openingHour: [RegularOpeningHours]) -> OpenClosedType {

if openingHour.isEmpty {
return OpenClosedType.none
}

let openCloseTime = getOpenClosedTimeArray(openingHours: openingHour)

let now = Date().toSecond()
var openTimes: [Int] = []
var closeTimes: [Int] = []
openHours.forEach { businessHour in
do {
openTimes.append(try toSecond(businessHour: businessHour.open, openClose: .open))
closeTimes.append(try toSecond(businessHour: businessHour.close, openClose: .close))
} catch OpeningHourError.wrongHour {
print(OpeningHourError.wrongHour.description)
} catch OpeningHourError.wrongMinute {
print(OpeningHourError.wrongMinute.description)
} catch {
print(error)

for idx in 0..<(openCloseTime.count - 1) {
let firstTime = openCloseTime[idx]
let secondTime = openCloseTime[idx + 1]
if firstTime <= now && now < secondTime {
if idx % 2 == 0 {
if secondTime - firstTime <= 10800 {
return OpenClosedType.breakTime
} else {
return OpenClosedType.closed
}
} else {
return OpenClosedType.open
}
}
}

for idx in openTimes.indices {
if openTimes[idx] <= now && now <= closeTimes[idx] {
return OpenClosedType.open
return OpenClosedType.dayOff
}

func getOpenClosedString(openingHour: [RegularOpeningHours], openClosedType: OpenClose) -> String {

let openCloseTime = getOpenClosedTimeArray(openingHours: openingHour)
let nextTime = openCloseTime.filter({ $0 > Date().toSecond() })

switch openClosedType {
case .open: // 00:00에 영업 시작
if let nextTime = nextTime.first {
if nextTime != 86400 * 2 {
let hour = (nextTime % 86400) / 3600
let minute = (nextTime % 3600) / 60
return String(format: "%02d:%02d에 영업 시작", hour, minute)
}
}
case .close: // 00:00에 영업 종료 or 00:00에 브레이크 타임 시작
if nextTime.count > 1 {
let firstNextTime = nextTime[0]
let secondNextTime = nextTime[1]
let hour = (firstNextTime % 86400) / 3600
let minute = (firstNextTime % 3600) / 60
if secondNextTime - firstNextTime <= 10800 { // 브레이크 타임
return String(format: "%02d:%02d에 브레이크타임 시작", hour, minute)
} else { // 영업 종료
return String(format: "%02d:%02d에 영업 종료", hour, minute)
}
}
}

return ""
}

func getOpenClosedTimeArray(openingHours: [RegularOpeningHours]) -> [Int] {

var openCloseTime: [Int] = []

let todayOpenHours = openingHours.filter { $0.open.day.index == Date().weekDay }
let yesterdayOpenHours = openingHours.filter { hour in
let yesterdayWeekDay = (Date().weekDay - 1) % 7 == 0 ? 7 : (Date().weekDay + 1) % 7
return hour.open.day.index == yesterdayWeekDay
}
let tomorrowOpenHours = openingHours.filter { hour in
let tomorrowWeekDay = (Date().weekDay + 1) % 7 == 0 ? 7 : (Date().weekDay + 1) % 7
return hour.open.day.index == tomorrowWeekDay
}

if todayOpenHours.isEmpty {
return []
}

if let businessHour = yesterdayOpenHours.last?.close {
if let time = catchHourError(businessHour: businessHour, openClose: .close) {
openCloseTime.append(time - 86400)
} else {
openCloseTime.append(0)
}
} else {
openCloseTime.append(0)
}

todayOpenHours.forEach { businessHour in
if let openHour = catchHourError(businessHour: businessHour.open, openClose: .open),
let closeHour = catchHourError(businessHour: businessHour.close, openClose: .close) {
openCloseTime.append(openHour)
openCloseTime.append(closeHour)
}
}

if let businessHour = tomorrowOpenHours.first?.open {
if let time = catchHourError(businessHour: businessHour, openClose: .open) {
openCloseTime.append(time + 86400)
} else {
openCloseTime.append(86400 * 2)
}
} else {
openCloseTime.append(86400 * 2)
}

return openCloseTime
}

func catchHourError(businessHour: BusinessHour, openClose: OpenClose) -> Int? {
do {
return try toSecond(businessHour: businessHour, openClose: openClose)
} catch OpeningHourError.wrongHour {
print(OpeningHourError.wrongHour.description)
} catch OpeningHourError.wrongMinute {
print(OpeningHourError.wrongMinute.description)
} catch {
print(error)
}

return OpenClosedType.closed
return nil
}

func toSecond(businessHour: BusinessHour, openClose: OpenClose) throws -> Int {
Expand All @@ -72,10 +181,3 @@ private extension GetOpenClosedUseCaseImpl {
}

}

enum OpenClose {

case open
case close

}
Original file line number Diff line number Diff line change
Expand Up @@ -116,16 +116,12 @@ private extension StoreInformationViewController {
.disposed(by: disposeBag)

viewModel.openClosedOutput
.bind { [weak self] openClosedType in
self?.storeOpenClosed.text = openClosedType.rawValue
.bind { [weak self] openClosedContent in
self?.storeOpenClosed.text = openClosedContent.openClosedType.rawValue
self?.openingHour.text = openClosedContent.openingHour
}
.disposed(by: disposeBag)

viewModel.openingHourOutput
.bind { [weak self] text in
self?.openingHour.text = text
}
.disposed(by: disposeBag)
}

func setBackgroundColor() {
Expand Down Expand Up @@ -198,8 +194,6 @@ extension StoreInformationViewController {
func setUIContents(store: Store) {
storeTitle.text = store.title
categoty.text = store.category
viewModel.action(input: .setOpenClosed(openingHour: store.openingHour))
viewModel.action(input: .setOpeningHour(openingHour: store.openingHour))
removeStackView()
store.certificationTypes
.map({
Expand All @@ -215,9 +209,10 @@ extension StoreInformationViewController {
}
.disposed(by: disposeBag)
}
if let thumbnailURL = store.localPhotos.first {
viewModel.action(input: .fetchThumbnailImage(url: thumbnailURL))
}
viewModel.action(input: .setInformationView(
openingHour: store.openingHour,
url: store.localPhotos.first)
)
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ final class StoreInformationViewModelImpl: StoreInformationViewModel {
let getOpenClosedUseCase: GetOpenClosedUseCase
let fetchImageUseCase: FetchImageUseCase

var openClosedOutput = PublishRelay<OpenClosedType>()
var openingHourOutput = PublishRelay<String>()
var openClosedOutput = PublishRelay<OpenClosedContent>()
var thumbnailImageOutput = PublishRelay<Data>()

init(getOpenClosedUseCase: GetOpenClosedUseCase, fetchImageUseCase: FetchImageUseCase) {
Expand All @@ -26,12 +25,11 @@ final class StoreInformationViewModelImpl: StoreInformationViewModel {

func action(input: StoreInformationViewInputCase) {
switch input {
case .setOpenClosed(let openingHour):
case .setInformationView(let openingHour, let url):
setOpenClosed(openingHour: openingHour)
case .setOpeningHour(let openingHour):
setOpeningHour(openingHour: openingHour)
case .fetchThumbnailImage(let url):
fetchThumbnailImage(url: url)
if let url = url {
fetchThumbnailImage(url: url)
}
}
}

Expand All @@ -45,12 +43,6 @@ private extension StoreInformationViewModelImpl {
openClosedOutput.accept(getOpenClosedUseCase.execute(openingHours: openingHour))
}

func setOpeningHour(
openingHour: [RegularOpeningHours]
) {
openingHourOutput.accept(openingHourString(openingHour: openingHour))
}

func fetchThumbnailImage(url: String) {
fetchImageUseCase.execute(url: url)
.subscribe(
Expand All @@ -65,28 +57,3 @@ private extension StoreInformationViewModelImpl {
}

}

private extension StoreInformationViewModelImpl {

func openingHourString(openingHour: [RegularOpeningHours]) -> String {
let openHours = openingHour.filter({ $0.open.day.index == Date().weekDay })
if openHours.isEmpty { return "" }

var openingHourStrings: [String] = []
if let openHour = openHours.first?.open.hour,
let openMin = openHours.first?.open.minute {
openingHourStrings.append(String(format: "%02d:%02d", openHour, openMin))
}
if let closeHour = openHours.last?.close.hour,
let closeMin = openHours.last?.close.minute {
if closeHour == 0 {
openingHourStrings.append(String(format: "%02d:%02d", 24, closeMin))
} else {
openingHourStrings.append(String(format: "%02d:%02d", closeHour, closeMin))
}
}

return openingHourStrings.joined(separator: " - ")
}

}
Loading

0 comments on commit 479a3a5

Please sign in to comment.