Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0e02cf2
Develop a compact version of ItemListErrorCardView to use in smaller …
staskus Sep 10, 2025
126066e
Allow configuring PointOfSaleItemListEmptyView with a protocol
staskus Sep 10, 2025
03b624c
Create PointOfSaleOrderListEmptyViewModel
staskus Sep 10, 2025
19ed405
Adjust PointOfSaleOrderListView to properly display empty and error v…
staskus Sep 10, 2025
60e85e1
Create previews for various PointOfSaleOrderListView states
staskus Sep 11, 2025
d0c3ed0
Remove unused code
staskus Sep 11, 2025
23ff8e9
Further adjustments to compact ItemListErrorCardView design
staskus Sep 11, 2025
2ba8654
Rename empty, error, and inlineError views to indicate reusability
staskus Sep 11, 2025
c267a93
Add padding to PointOfSaleOrderListView
staskus Sep 11, 2025
15003d1
Updated empty view when there are no orders loaded
staskus Sep 11, 2025
14d8703
Remove search button if orders don't exist
staskus Sep 11, 2025
b28a188
Remove errorImage
staskus Sep 11, 2025
4544006
Merge branch 'trunk' into woomob-1136-woo-poshistorical-orders-order-…
staskus Sep 15, 2025
ea6e0df
Add fullscreen error view of PointOfSaleOrderListView
staskus Sep 15, 2025
57ca0df
Remove unnecessary VStack
staskus Sep 15, 2025
32085af
Extract a list view into a separate view
staskus Sep 15, 2025
1b37a57
PointOfSaleItemListEmptyViewModel -> POSListEmptyViewModel
staskus Sep 15, 2025
d3f2e23
Merge branch 'trunk' into woomob-1136-woo-poshistorical-orders-order-…
staskus Sep 15, 2025
b8ef8ca
Rename PointOfSaleOrderList to POSOrderList
staskus Sep 15, 2025
b6996cd
Update Previews
staskus Sep 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import Foundation
import struct NetworkingCore.PagedItems

public protocol PointOfSaleOrderListFetchStrategy {
public protocol POSOrderListFetchStrategy {
func fetchOrders(pageNumber: Int) async throws -> PagedItems<POSOrder>
func loadOrder(orderID: Int64) async throws -> POSOrder
var supportsCaching: Bool { get }
var showsLoadingWithItems: Bool { get }
var id: String { get }
}

extension PointOfSaleOrderListFetchStrategy {
extension POSOrderListFetchStrategy {
var id: String {
String(describing: type(of: self))
}
}

struct PointOfSaleDefaultOrderListFetchStrategy: PointOfSaleOrderListFetchStrategy {
private let orderListService: PointOfSaleOrderListServiceProtocol
struct POSDefaultOrderListFetchStrategy: POSOrderListFetchStrategy {
private let orderListService: POSOrderListServiceProtocol
let supportsCaching: Bool = true
var showsLoadingWithItems: Bool = true

init(orderListService: PointOfSaleOrderListServiceProtocol) {
init(orderListService: POSOrderListServiceProtocol) {
self.orderListService = orderListService
}

Expand All @@ -33,14 +33,14 @@ struct PointOfSaleDefaultOrderListFetchStrategy: PointOfSaleOrderListFetchStrate
}
}

struct PointOfSaleSearchOrderListFetchStrategy: PointOfSaleOrderListFetchStrategy {
private let orderListService: PointOfSaleOrderListServiceProtocol
struct POSSearchOrderListFetchStrategy: POSOrderListFetchStrategy {
private let orderListService: POSOrderListServiceProtocol
private let searchTerm: String

var supportsCaching: Bool = false
var showsLoadingWithItems = false

init(orderListService: PointOfSaleOrderListServiceProtocol, searchTerm: String) {
init(orderListService: POSOrderListServiceProtocol, searchTerm: String) {
self.orderListService = orderListService
self.searchTerm = searchTerm
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import class Networking.AlamofireNetwork
import class Networking.OrdersRemote
import class WooFoundationCore.CurrencyFormatter

public protocol PointOfSaleOrderListFetchStrategyFactoryProtocol {
func defaultStrategy() -> PointOfSaleOrderListFetchStrategy
func searchStrategy(searchTerm: String) -> PointOfSaleOrderListFetchStrategy
public protocol POSOrderListFetchStrategyFactoryProtocol {
func defaultStrategy() -> POSOrderListFetchStrategy
func searchStrategy(searchTerm: String) -> POSOrderListFetchStrategy
}

public final class PointOfSaleOrderListFetchStrategyFactory: PointOfSaleOrderListFetchStrategyFactoryProtocol {
public final class POSOrderListFetchStrategyFactory: POSOrderListFetchStrategyFactoryProtocol {
private let siteID: Int64
private let ordersRemote: OrdersRemote
private let currencyFormatter: CurrencyFormatter
Expand All @@ -22,19 +22,19 @@ public final class PointOfSaleOrderListFetchStrategyFactory: PointOfSaleOrderLis
self.currencyFormatter = currencyFormatter
}

public func defaultStrategy() -> PointOfSaleOrderListFetchStrategy {
PointOfSaleDefaultOrderListFetchStrategy(
orderListService: PointOfSaleOrderListService(
public func defaultStrategy() -> POSOrderListFetchStrategy {
POSDefaultOrderListFetchStrategy(
orderListService: POSOrderListService(
siteID: siteID,
ordersRemote: ordersRemote,
currencyFormatter: currencyFormatter
)
)
}

public func searchStrategy(searchTerm: String) -> PointOfSaleOrderListFetchStrategy {
PointOfSaleSearchOrderListFetchStrategy(
orderListService: PointOfSaleOrderListService(
public func searchStrategy(searchTerm: String) -> POSOrderListFetchStrategy {
POSSearchOrderListFetchStrategy(
orderListService: POSOrderListService(
siteID: siteID,
ordersRemote: ordersRemote,
currencyFormatter: currencyFormatter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import struct NetworkingCore.Order
import protocol NetworkingCore.POSOrdersRemoteProtocol
import class WooFoundationCore.CurrencyFormatter

public final class PointOfSaleOrderListService: PointOfSaleOrderListServiceProtocol {
public final class POSOrderListService: POSOrderListServiceProtocol {
private let ordersRemote: POSOrdersRemoteProtocol
private let siteID: Int64
private let mapper: POSOrderMapper
Expand Down Expand Up @@ -39,9 +39,9 @@ public final class PointOfSaleOrderListService: PointOfSaleOrderListServiceProto
hasMorePages: pagedOrders.hasMorePages,
totalItems: pagedOrders.totalItems)
} catch AFError.explicitlyCancelled {
throw PointOfSaleOrderListServiceError.requestCancelled
throw POSOrderListServiceError.requestCancelled
} catch {
throw PointOfSaleOrderListServiceError.requestFailed
throw POSOrderListServiceError.requestFailed
}
}

Expand All @@ -65,9 +65,9 @@ public final class PointOfSaleOrderListService: PointOfSaleOrderListServiceProto
hasMorePages: pagedOrders.hasMorePages,
totalItems: pagedOrders.totalItems)
} catch AFError.explicitlyCancelled {
throw PointOfSaleOrderListServiceError.requestCancelled
throw POSOrderListServiceError.requestCancelled
} catch {
throw PointOfSaleOrderListServiceError.requestFailed
throw POSOrderListServiceError.requestFailed
}
}

Expand All @@ -76,9 +76,9 @@ public final class PointOfSaleOrderListService: PointOfSaleOrderListServiceProto
let order = try await ordersRemote.loadPOSOrder(siteID: siteID, orderID: orderID)
return mapper.map(order: order)
} catch AFError.explicitlyCancelled {
throw PointOfSaleOrderListServiceError.requestCancelled
throw POSOrderListServiceError.requestCancelled
} catch {
throw PointOfSaleOrderListServiceError.requestFailed
throw POSOrderListServiceError.requestFailed
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import Foundation
import struct NetworkingCore.PagedItems

public enum PointOfSaleOrderListServiceError: Error, Equatable {
public enum POSOrderListServiceError: Error, Equatable {
case requestFailed
case requestCancelled
}

public protocol PointOfSaleOrderListServiceProtocol {
public protocol POSOrderListServiceProtocol {
func providePointOfSaleOrders(pageNumber: Int) async throws -> PagedItems<POSOrder>
func searchPointOfSaleOrders(searchTerm: String, pageNumber: Int) async throws -> PagedItems<POSOrder>
func loadOrder(orderID: Int64) async throws -> POSOrder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import struct NetworkingCore.Order
import enum NetworkingCore.OrderStatusEnum
import WooFoundation

final class PointOfSaleOrderServiceTests: XCTestCase {
final class POSOrderListServiceTests: XCTestCase {
private let siteID: Int64 = 13092
private var orderProvider: PointOfSaleOrderListServiceProtocol!
private var orderProvider: POSOrderListServiceProtocol!
private var mockOrdersRemote: MockPOSOrdersRemote!

override func setUp() {
super.setUp()
mockOrdersRemote = MockPOSOrdersRemote()
orderProvider = PointOfSaleOrderListService(
orderProvider = POSOrderListService(
siteID: siteID,
ordersRemote: mockOrdersRemote,
currencyFormatter: CurrencyFormatter(currencySettings: CurrencySettings())
Expand All @@ -27,14 +27,14 @@ final class PointOfSaleOrderServiceTests: XCTestCase {
}

func test_PointOfSaleOrderServiceProtocol_when_fails_request_with_requestFailed_then_throws_error() async throws {
let expectedError = PointOfSaleOrderListServiceError.requestFailed
let expectedError = POSOrderListServiceError.requestFailed
mockOrdersRemote.mockPagedOrdersResult = .failure(expectedError)

do {
_ = try await orderProvider.providePointOfSaleOrders(pageNumber: 1)
XCTFail("Expected an error, but got success.")
} catch {
XCTAssertEqual(error as? PointOfSaleOrderListServiceError, expectedError)
XCTAssertEqual(error as? POSOrderListServiceError, expectedError)
}
}

Expand Down Expand Up @@ -111,7 +111,7 @@ final class PointOfSaleOrderServiceTests: XCTestCase {
do {
_ = try await orderProvider.providePointOfSaleOrders(pageNumber: 1)
XCTFail("Expected error to be thrown")
} catch PointOfSaleOrderListServiceError.requestFailed {
} catch POSOrderListServiceError.requestFailed {
// Expected
} catch {
XCTFail("Unexpected error occurred: \(error)")
Expand Down Expand Up @@ -144,7 +144,7 @@ final class PointOfSaleOrderServiceTests: XCTestCase {
}
}

private extension PointOfSaleOrderServiceTests {
private extension POSOrderListServiceTests {
enum TestError: Error {
case expectedError
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import Foundation
import Observation
import enum Yosemite.PointOfSaleOrderListServiceError
import protocol Yosemite.PointOfSaleOrderListServiceProtocol
import protocol Yosemite.PointOfSaleOrderListFetchStrategyFactoryProtocol
import protocol Yosemite.PointOfSaleOrderListFetchStrategy
import enum Yosemite.POSOrderListServiceError
import protocol Yosemite.POSOrderListServiceProtocol
import protocol Yosemite.POSOrderListFetchStrategyFactoryProtocol
import protocol Yosemite.POSOrderListFetchStrategy
import struct Yosemite.POSOrder
import struct Yosemite.POSOrderItem
import struct Yosemite.POSOrderRefund
import class Yosemite.Store

protocol PointOfSaleOrderListControllerProtocol {
protocol POSOrderListControllerProtocol {
var ordersViewState: POSOrderListState { get }
var selectedOrder: POSOrder? { get }
func loadOrders() async
Expand All @@ -19,18 +19,18 @@ protocol PointOfSaleOrderListControllerProtocol {
func updateOrder(orderID: Int64) async throws
}

protocol PointOfSaleSearchingOrderListControllerProtocol: PointOfSaleOrderListControllerProtocol {
protocol POSSearchingOrderListControllerProtocol: POSOrderListControllerProtocol {
func searchOrders(searchTerm: String) async
func clearSearchOrders()
}

@Observable final class PointOfSaleOrderListController: PointOfSaleSearchingOrderListControllerProtocol {
@Observable final class POSOrderListController: POSSearchingOrderListControllerProtocol {
var ordersViewState: POSOrderListState
private var strategyPaginationTracker: [String: AsyncPaginationTracker] = [:]
private var fetchStrategy: PointOfSaleOrderListFetchStrategy
private var fetchStrategy: POSOrderListFetchStrategy
private var cachedOrders: [POSOrder] = []
private(set) var selectedOrder: POSOrder?
private let orderListFetchStrategyFactory: PointOfSaleOrderListFetchStrategyFactoryProtocol
private let orderListFetchStrategyFactory: POSOrderListFetchStrategyFactoryProtocol
private var paginationTracker: AsyncPaginationTracker {
if let existing = strategyPaginationTracker[fetchStrategy.id] {
return existing
Expand All @@ -40,7 +40,7 @@ protocol PointOfSaleSearchingOrderListControllerProtocol: PointOfSaleOrderListCo
return tracker
}

init(orderListFetchStrategyFactory: PointOfSaleOrderListFetchStrategyFactoryProtocol,
init(orderListFetchStrategyFactory: POSOrderListFetchStrategyFactoryProtocol,
initialState: POSOrderListState = .loading([])) {
self.ordersViewState = initialState
self.orderListFetchStrategyFactory = orderListFetchStrategyFactory
Expand Down Expand Up @@ -133,7 +133,7 @@ protocol PointOfSaleSearchingOrderListControllerProtocol: PointOfSaleOrderListCo
}

return pagedOrders.hasMorePages
} catch PointOfSaleOrderListServiceError.requestCancelled {
} catch POSOrderListServiceError.requestCancelled {
return true
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import Foundation
import Observation
import struct Yosemite.POSOrder

@Observable final class PointOfSaleOrderListModel {
let ordersController: PointOfSaleSearchingOrderListControllerProtocol
@Observable final class POSOrderListModel {
let ordersController: POSSearchingOrderListControllerProtocol
let receiptSender: POSReceiptSending

init(ordersController: PointOfSaleSearchingOrderListControllerProtocol,
init(ordersController: POSSearchingOrderListControllerProtocol,
receiptSender: POSReceiptSending) {
self.ordersController = ordersController
self.receiptSender = receiptSender
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import SwiftUI

struct PointOfSaleItemListEmptyView: View {
protocol POSEmptyViewModelProtocol {
var title: String { get }
var subtitle: String { get }
var hint: String? { get }
var buttonTitle: String? { get }
var iconName: String { get }
}

struct POSListEmptyView: View {
@Environment(\.dynamicTypeSize) private var dynamicTypeSize
@Environment(\.floatingControlAreaSize) private var floatingControlAreaSize: CGSize
private let viewModel: PointOfSaleItemListEmptyViewModel
private let viewModel: any POSEmptyViewModelProtocol

private let onAction: (() -> Void)?

@State private var viewWidth: CGFloat = 0

@Environment(\.keyboardObserver) private var keyboard

init(viewModel: PointOfSaleItemListEmptyViewModel, onAction: (() -> Void)? = nil) {
init(viewModel: any POSEmptyViewModelProtocol, onAction: (() -> Void)? = nil) {
self.viewModel = viewModel
self.onAction = onAction
}
Expand Down Expand Up @@ -84,7 +92,7 @@ struct PointOfSaleItemListEmptyView: View {
}
}

private extension PointOfSaleItemListEmptyView {
private extension POSListEmptyView {
enum Constants {
static let iconSize: CGFloat = 88
}
Expand Down Expand Up @@ -243,7 +251,7 @@ struct PointOfSaleItemListEmptyViewModel {
// MARK: - Preview

#Preview {
PointOfSaleItemListEmptyView(
POSListEmptyView(
viewModel: PointOfSaleItemListEmptyViewModel(
itemListType: .coupons(search: false),
baseItem: .root
Expand All @@ -252,10 +260,14 @@ struct PointOfSaleItemListEmptyViewModel {
}

#Preview {
PointOfSaleItemListEmptyView(
POSListEmptyView(
viewModel: PointOfSaleItemListEmptyViewModel(
itemListType: .products(search: true),
baseItem: .root
)
) {}
}

// MARK: - Protocol Conformance

extension PointOfSaleItemListEmptyViewModel: POSEmptyViewModelProtocol {}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct PointOfSaleItemListFullscreenErrorView: View {

var body: some View {
PointOfSaleItemListFullscreenView {
PointOfSaleItemListErrorView(error: error, onAction: onAction)
POSListErrorView(error: error, onAction: onAction)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ private enum Localization {
#Preview {
PointOfSaleItemListFullscreenView(
content: {
PointOfSaleItemListErrorView(
POSListErrorView(
error: .init(errorType: .productsLoadError, title: "Error", subtitle: "Something went wrong", buttonText: "Fix it"))
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ private extension ChildItemList {
var emptyView: some View {
VStack {
headerView
PointOfSaleItemListEmptyView(
viewModel: PointOfSaleItemListEmptyViewModel(
POSListEmptyView(
viewModel: POSListEmptyViewModel(
itemListType: .products(search: false),
baseItem: node)) {
Task {
Expand All @@ -106,7 +106,7 @@ private extension ChildItemList {
Spacer()
}

PointOfSaleItemListErrorView(error: error, onAction: {
POSListErrorView(error: error, onAction: {
Task {
await itemsController.loadItems(base: node)
}
Expand Down
Loading