-
Notifications
You must be signed in to change notification settings - Fork 9
/
TransactionHistory+View.swift
136 lines (121 loc) · 3.68 KB
/
TransactionHistory+View.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import ComposableArchitecture
import SwiftUI
extension TransactionHistory.State {
var showEmptyState: Bool {
sections.isEmpty && !loading.isLoading
}
}
// MARK: - TransactionHistory.View
extension TransactionHistory {
@MainActor
public struct View: SwiftUI.View {
private let store: StoreOf<TransactionHistory>
public init(store: StoreOf<TransactionHistory>) {
self.store = store
}
public var body: some SwiftUI.View {
NavigationStack {
WithViewStore(store, observe: { $0 }, send: { .view($0) }) { viewStore in
let selection = viewStore.binding(get: \.currentMonth, send: ViewAction.selectedMonth)
VStack(spacing: .zero) {
VStack(spacing: .small2) {
AccountCard(account: viewStore.account)
.padding(.horizontal, .medium3)
if let filters = viewStore.activeFilters.nilIfEmpty {
ActiveFiltersView(filters: filters) { id in
store.send(.view(.filterCrossTapped(id)), animation: .default)
}
}
HScrollBar(items: viewStore.availableMonths, selection: selection)
.background(.app.white)
}
.padding(.top, .small3)
.padding(.bottom, .small1)
.background(.app.white)
TableView(
sections: viewStore.sections,
scrollTarget: viewStore.scrollTarget
) { action in
store.send(.view(.transactionsTableAction(action)))
}
.ignoresSafeArea(edges: .bottom)
.opacity(viewStore.sections == [] ? 0 : 1)
.background(alignment: .top) {
if viewStore.loading.isLoading {
ProgressView()
.padding(.small3)
}
}
}
.background {
if viewStore.showEmptyState {
Text(L10n.TransactionHistory.noTransactions)
.textStyle(.sectionHeader)
.foregroundStyle(.app.gray2)
}
}
.background(.app.gray5)
.toolbar {
ToolbarItem(placement: .topBarLeading) {
CloseButton {
store.send(.view(.closeTapped))
}
}
ToolbarItem(placement: .topBarTrailing) {
Button(asset: AssetResource.transactionHistoryFilterList) {
store.send(.view(.filtersTapped))
}
}
}
}
.radixToolbar(title: L10n.TransactionHistory.title, alwaysVisible: false)
}
.onAppear {
store.send(.view(.onAppear))
}
.destinations(with: store)
.showDeveloperDisclaimerBanner(store.bannerStore)
}
private static let coordSpace = "TransactionHistory"
}
struct ActiveFiltersView: SwiftUI.View {
let filters: IdentifiedArrayOf<TransactionHistoryFilters.State.Filter>
let crossAction: (TransactionFilter) -> Void
var body: some SwiftUI.View {
ScrollView(.horizontal) {
HStack {
ForEach(filters) { filter in
TransactionFilterView(filter: filter, action: { _ in }, crossAction: crossAction)
}
Spacer(minLength: 0)
}
.padding(.horizontal, .medium3)
}
}
}
}
private extension StoreOf<TransactionHistory> {
var destination: PresentationStoreOf<TransactionHistory.Destination> {
func scopeState(state: State) -> PresentationState<TransactionHistory.Destination.State> {
state.$destination
}
return scope(state: scopeState, action: Action.destination)
}
}
@MainActor
private extension View {
func destinations(with store: StoreOf<TransactionHistory>) -> some View {
let destinationStore = store.destination
return sheet(store: destinationStore.scope(state: \.filters, action: \.filters)) {
TransactionHistoryFilters.View(store: $0)
}
}
}
// MARK: - DateRangeItem
public struct DateRangeItem: ScrollBarItem, Sendable, Hashable, Identifiable {
public var id: Date { startDate }
public let caption: String
let startDate: Date
let endDate: Date
var range: Range<Date> { startDate ..< endDate }
}