Skip to content

Commit

Permalink
Merge pull request #1196 from HedvigInsurance/fix/important-messages-…
Browse files Browse the repository at this point in the history
…carousel

Fix/important messages carousel
  • Loading branch information
sladan-hedvig authored Jan 24, 2024
2 parents ef61f07 + e5def41 commit d9b953e
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 68 deletions.
2 changes: 2 additions & 0 deletions Projects/EditCoInsured/Sources/View/CoInusuredInput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ struct CoInusuredInput: View {
.padding(.horizontal, 16)
.padding(.top, 4)
.padding(.bottom, 16)
.disabled(vm.isLoading || intentVm.isLoading)
}
.padding(.top, vm.actionType == .delete ? 16 : 0)
}
Expand Down Expand Up @@ -263,6 +264,7 @@ struct CoInusuredInput: View {
toggleField
}
.hFieldSize(.small)
.disabled(vm.isLoading || intentVm.isLoading)
}

@ViewBuilder
Expand Down
70 changes: 37 additions & 33 deletions Projects/Home/Sources/Components/ImportantMessagesView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,47 @@ import SwiftUI
import hCore
import hCoreUI

struct ImportantMessagesView: View {
struct ImportantMessageView: View {
let importantMessage: ImportantMessage
@PresentableStore var store: HomeStore
@State var showSafariView = false
@State var urlLink: URL?
var body: some View {
PresentableStoreLens(
HomeStore.self,
getter: { state in
state.importantMessage
}
) { importantMessage in
if let importantMessage, let message = importantMessage.message {
if let link = importantMessage.link, let urlLink = URL(string: link) {
InfoCard(text: message, type: .attention)
.buttons(
[
.init(
buttonTitle: L10n.ImportantMessage.hide,
buttonAction: {
store.send(.hideImportantMessage)
}
),
.init(
buttonTitle: L10n.ImportantMessage.readMore,
buttonAction: {
self.urlLink = urlLink
showSafariView = true
}
),
]
)
.sheet(isPresented: $showSafariView) {
SafariView(url: $urlLink)
}
} else {
InfoCard(text: message, type: .attention)
}
if let message = importantMessage.message {
if let link = importantMessage.link, let urlLink = URL(string: link) {
InfoCard(text: message, type: .attention)
.buttons(
[
.init(
buttonTitle: L10n.ImportantMessage.hide,
buttonAction: {
store.send(.hideImportantMessage(id: importantMessage.id))
}
),
.init(
buttonTitle: L10n.ImportantMessage.readMore,
buttonAction: {
self.urlLink = urlLink
showSafariView = true
}
),
]
)
.sheet(isPresented: $showSafariView) {
SafariView(url: $urlLink)
}
} else {
InfoCard(text: message, type: .attention)
.buttons(
[
.init(
buttonTitle: L10n.ImportantMessage.hide,
buttonAction: {
store.send(.hideImportantMessage(id: importantMessage.id))
}
)
]
)
}
}
}
Expand Down
37 changes: 23 additions & 14 deletions Projects/Home/Sources/HomeState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import hCoreUI
import hGraphQL

public struct ImportantMessage: Codable, Equatable {
let id: String
let message: String?
let link: String?
}
Expand Down Expand Up @@ -63,12 +64,12 @@ public struct HomeState: StateProtocol {
public var memberStateData: MemberStateData = .init(state: .loading, name: nil)
public var futureStatus: FutureStatus = .none
public var contracts: [Contract] = []
public var importantMessage: ImportantMessage? = nil
public var importantMessages: [ImportantMessage] = []
public var commonClaims: [CommonClaim] = []
public var allCommonClaims: [CommonClaim] = []
public var shouldShowTravelInsurance: Bool = false
public var toolbarOptionTypes: [ToolbarOptionType] = [.chat]
@Transient(defaultValue: false) var hideImportantMessage = false
@Transient(defaultValue: []) var hidenImportantMessages = [String]()
public var upcomingRenewalContracts: [Contract] {
return contracts.filter { $0.upcomingRenewal != nil }
}
Expand All @@ -79,13 +80,23 @@ public struct HomeState: StateProtocol {
return commonClaims.first(where: { $0.id == "30" || $0.id == "31" || $0.id == "32" }) != nil
}

func getImportantMessageToShow() -> [ImportantMessage] {
return importantMessages.filter { importantMessage in
!hidenImportantMessages.contains(importantMessage.id)
}
}

func getImportantMessage(with id: String) -> ImportantMessage? {
return importantMessages.first(where: { $0.id == id })
}

public init() {}
}

public enum HomeAction: ActionProtocol {
case fetchMemberState
case fetchImportantMessages
case setImportantMessage(message: ImportantMessage)
case setImportantMessages(messages: [ImportantMessage])
case connectPayments
case setMemberContractState(state: MemberStateData, contracts: [Contract])
case setFutureStatus(status: FutureStatus)
Expand All @@ -107,7 +118,7 @@ public enum HomeAction: ActionProtocol {

case setShowTravelInsurance(show: Bool)
case dismissOtherServices
case hideImportantMessage
case hideImportantMessage(id: String)
case openContractCertificate(url: URL, title: String)

case openHelpCenterTopicView(commonTopic: CommonTopic)
Expand Down Expand Up @@ -159,9 +170,11 @@ public final class HomeStore: LoadingStateStore<HomeState, HomeAction, HomeLoadi
return octopus
.client
.fetch(query: OctopusGraphQL.ImportantMessagesQuery())
.map { $0.currentMember.importantMessages.first }
.map { data in
.setImportantMessage(message: .init(message: data?.message, link: data?.link))
var messages = data.currentMember.importantMessages.compactMap({
ImportantMessage(id: $0.id, message: $0.message, link: $0.link)
})
return .setImportantMessages(messages: messages)
}
.valueThenEndSignal
case .fetchMemberState:
Expand Down Expand Up @@ -256,12 +269,8 @@ public final class HomeStore: LoadingStateStore<HomeState, HomeAction, HomeLoadi
newState.contracts = contracts
case .setFutureStatus(let status):
newState.futureStatus = status
case .setImportantMessage(let message):
if let text = message.message, text != "" {
newState.importantMessage = message
} else {
newState.importantMessage = nil
}
case .setImportantMessages(let messages):
newState.importantMessages = messages
case .fetchCommonClaims:
setLoading(for: .fetchCommonClaim)
case let .setCommonClaims(commonClaims):
Expand All @@ -271,8 +280,8 @@ public final class HomeStore: LoadingStateStore<HomeState, HomeAction, HomeLoadi
case let .setShowTravelInsurance(show):
newState.shouldShowTravelInsurance = show
setAllCommonClaims(&newState)
case .hideImportantMessage:
newState.hideImportantMessage = true
case let .hideImportantMessage(id):
newState.hidenImportantMessages.append(id)
case let .setChatNotification(hasNew):
newState.showChatNotification = hasNew
setAllCommonClaims(&newState)
Expand Down
8 changes: 5 additions & 3 deletions Projects/Home/Sources/Screens/Home.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,11 @@ extension HomeView {
}
}
case .future:
ImportantMessagesView()
FutureSectionInfoView(memberName: vm.memberStateData.name ?? "")
.slideUpFadeAppearAnimation()
VStack(spacing: 16) {
HomeBottomScrollView(memberId: memberId)
FutureSectionInfoView(memberName: vm.memberStateData.name ?? "")
.slideUpFadeAppearAnimation()
}
case .terminated:
VStack(spacing: 16) {
InfoCard(text: L10n.HomeTab.terminatedBody, type: .info)
Expand Down
58 changes: 40 additions & 18 deletions Projects/Home/Sources/Screens/HomeBottomScrollView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ struct HomeBottomScrollView: View {
items: vm.items.sorted(by: { $0.id < $1.id }),
previousHeight: height,
content: { content in
switch content.type {
switch content.id {
case .payment:
ConnectPaymentCardView()
case .renewal:
Expand All @@ -33,8 +33,11 @@ struct HomeBottomScrollView: View {
text: L10n.hometabAccountDeletionNotification,
type: .attention
)
case .importantMessage:
ImportantMessagesView()
case let .importantMessage(id):
let store: HomeStore = globalPresentableStoreContainer.get()
if let importantMessage = store.state.getImportantMessage(with: id) {
ImportantMessageView(importantMessage: importantMessage)
}
case .missingCoInsured:
CoInsuredInfoHomeView {
let contractStore: ContractStore = globalPresentableStoreContainer.get()
Expand Down Expand Up @@ -81,9 +84,13 @@ class HomeButtonScrollViewModel: ObservableObject {
private func handleItem(_ item: InfoCardType, with addItem: Bool) {
let item = InfoCardView(with: item)
if addItem {
self.items.insert(item)
_ = withAnimation {
self.items.insert(item)
}
} else {
self.items.remove(item)
_ = withAnimation {
self.items.remove(item)
}
}
}

Expand All @@ -106,18 +113,35 @@ class HomeButtonScrollViewModel: ObservableObject {
private func handleImportantMessages() {
let homeStore: HomeStore = globalPresentableStoreContainer.get()
homeStore.stateSignal.plain()
.map({ $0.importantMessage != nil && !$0.hideImportantMessage })
.map({ $0.getImportantMessageToShow() })
.distinct()
.publisher
.receive(on: RunLoop.main)
.sink(receiveValue: { [weak self] show in
self?.handleItem(.importantMessage, with: show)
.sink(receiveValue: { [weak self] importantMessages in guard let self = self else { return }
var oldItems = self.items
let itemsToRemove = oldItems.filter { view in
switch view.id {
case .importantMessage:
return true
default:
return false
}
}
for itemToRemove in itemsToRemove {
oldItems.remove(itemToRemove)
}
for importantMessage in importantMessages {
oldItems.insert(.init(with: .importantMessage(message: importantMessage.id)))
}
withAnimation {
self.items = oldItems
}
})
.store(in: &cancellables)
handleItem(
.importantMessage,
with: homeStore.state.importantMessage != nil && !homeStore.state.hideImportantMessage
)
let itemsToShow = homeStore.state.getImportantMessageToShow()
for importantMessage in itemsToShow {
self.handleItem(.importantMessage(message: importantMessage.id), with: true)
}
}

private func handleRenewalCardView() {
Expand Down Expand Up @@ -185,18 +209,16 @@ struct HomeBottomScrollView_Previews: PreviewProvider {
}

struct InfoCardView: Identifiable, Hashable {
let id: Int
let type: InfoCardType
let id: InfoCardType
init(with type: InfoCardType) {
self.id = type.rawValue
self.type = type
self.id = type
}
}

enum InfoCardType: Int {
enum InfoCardType: Hashable, Comparable {
case payment
case missingCoInsured
case importantMessage
case importantMessage(message: String)
case renewal
case deletedView
}
36 changes: 36 additions & 0 deletions Projects/hCoreUI/Sources/Pager/hPagerDots.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,39 @@ public struct hPagerDots: View {
}
}
}

public struct hPagerDotsBinded: View {
@Binding var currentIndex: Int

public var totalCount: Int

@hColorBuilder
func circleColor(_ index: Int) -> some hColor {
if index == currentIndex {
hTextColor.primary
} else {
hFillColor.opaqueTwo
}
}

public init(
currentIndex: Binding<Int>,
totalCount: Int
) {
self._currentIndex = currentIndex
self.totalCount = totalCount
}

public var body: some View {
HStack {
ForEach(0..<totalCount, id: \.self) { index in
Circle()
.fill(circleColor(index))
.frame(width: 6, height: 6)
}
}
.onChange(of: self.currentIndex) { index in
let ss = index
}
}
}
7 changes: 7 additions & 0 deletions Projects/hCoreUI/Sources/Views/InfoCardScrollView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ public struct InfoCardScrollView<Content: View, cardItem: Identifiable>: View {
scrollView.delegate = vm
scrollView.clipsToBounds = false
}
if items.count > 1 {
hPagerDotsBinded(currentIndex: $vm.activeCard, totalCount: items.count)
}

}
}

Expand Down Expand Up @@ -116,6 +120,9 @@ class InfoCardScrollViewModel: NSObject, ObservableObject, UIScrollViewDelegate
if valueOver > 0.5 {
indexToScroll += 1
}
withAnimation {
activeCard = indexToScroll
}
scrollView.setContentOffset(.init(x: CGFloat(indexToScroll) * cardWithSpacing, y: 0), animated: true)
}
}

0 comments on commit d9b953e

Please sign in to comment.