Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
fe7dcc6
Expand POSOrder and POSOrderItem for details view needs
staskus Aug 29, 2025
8943b05
Allow setting bottom content on POSPageHeaderView
staskus Sep 1, 2025
fce7b2d
Create PointOfSaleOrderDetailsViewHelper to handle calculations and f…
staskus Sep 1, 2025
3abcc28
Add PointOfSaleOrderDetailsViewHelperTests
staskus Sep 1, 2025
c8dad49
Improve PointOfSaleOrderDetailsView to wireframe designs
staskus Sep 1, 2025
1dfc8b1
Manage selected order within orders controller
staskus Sep 2, 2025
0b94d0d
Add a simple loading view for Order Details
staskus Sep 2, 2025
f969b12
Move PointOfSaleOrderBadgeView into a separate view to reuse
staskus Sep 2, 2025
eb02d0c
Merge branch 'trunk' into woomob-1138-woo-poshistorical-orders-order-…
staskus Sep 2, 2025
d4012be
Remove unused code
staskus Sep 2, 2025
4bc8c86
Fix warning: Backward matching of the unlabeled trailing closure is d…
staskus Sep 3, 2025
ffdc18b
Rename OrdersViewState to POSOrdersViewState
staskus Sep 3, 2025
a87b614
Remove PointOfSaleOrderDetailsViewHelper
staskus Sep 3, 2025
45b67cd
Expand Order+CurrencyFormattedValues with ability to inject currency …
staskus Sep 3, 2025
50bf66e
Create POSOrderMapper to set formatted and calculated totals on POSOrder
staskus Sep 3, 2025
1eec56c
Use formatted values from order in list and details view
staskus Sep 3, 2025
3c3694b
Update PreviewHelpers.swift
staskus Sep 3, 2025
f39d665
Update tests
staskus Sep 3, 2025
2663256
Remove unused code
staskus Sep 4, 2025
4ea5462
Create POSOrderMapperTests
staskus Sep 4, 2025
3c8b718
Remove errors when fetching images
staskus Sep 4, 2025
ffc3a14
Update PointOfSaleOrderDetailsView.swift
staskus Sep 4, 2025
dc6e7c7
Remove unused code
staskus Sep 4, 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
16 changes: 12 additions & 4 deletions Modules/Sources/Yosemite/PointOfSale/OrderList/POSOrder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public struct POSOrder: Equatable, Hashable {
public let id: Int64
public let number: String
public let dateCreated: Date
public let datePaid: Date?
public let status: OrderStatusEnum
public let total: String
public let customerEmail: String?
Expand All @@ -18,11 +19,13 @@ public struct POSOrder: Equatable, Hashable {
public let lineItems: [POSOrderItem]
public let refunds: [POSOrderRefund]
public let currency: String
public let currencySymbol: String
public let discountTotal: String
public let totalTax: String

public init(id: Int64,
number: String,
dateCreated: Date,
datePaid: Date? = nil,
status: OrderStatusEnum,
total: String,
customerEmail: String? = nil,
Expand All @@ -31,10 +34,12 @@ public struct POSOrder: Equatable, Hashable {
lineItems: [POSOrderItem] = [],
refunds: [POSOrderRefund] = [],
currency: String,
currencySymbol: String) {
discountTotal: String,
totalTax: String) {
self.id = id
self.number = number
self.dateCreated = dateCreated
self.datePaid = datePaid
self.status = status
self.total = total
self.customerEmail = customerEmail
Expand All @@ -43,7 +48,8 @@ public struct POSOrder: Equatable, Hashable {
self.lineItems = lineItems
self.refunds = refunds
self.currency = currency
self.currencySymbol = currencySymbol
self.discountTotal = discountTotal
self.totalTax = totalTax
}
}

Expand All @@ -63,6 +69,7 @@ public extension POSOrder {
id: order.orderID,
number: order.number,
dateCreated: order.dateCreated,
datePaid: order.datePaid,
status: order.status,
total: order.total,
customerEmail: customerEmail,
Expand All @@ -71,7 +78,8 @@ public extension POSOrder {
lineItems: posLineItems,
refunds: posRefunds,
currency: order.currency,
currencySymbol: order.currencySymbol
discountTotal: order.discountTotal,
totalTax: order.totalTax
)
}
}
25 changes: 23 additions & 2 deletions Modules/Sources/Yosemite/PointOfSale/OrderList/POSOrderItem.swift
Original file line number Diff line number Diff line change
@@ -1,20 +1,36 @@
import Foundation
import struct NetworkingCore.OrderItem
import struct NetworkingCore.OrderItemAttribute

public struct POSOrderItem: Equatable, Hashable {
public let itemID: Int64
public let name: String
public let productID: Int64
public let variationID: Int64
public let quantity: Decimal
public let price: NSDecimalNumber
public let subtotal: String
public let total: String
public let attributes: [OrderItemAttribute]

public init(itemID: Int64,
name: String,
productID: Int64,
variationID: Int64,
quantity: Decimal,
total: String) {
price: NSDecimalNumber,
subtotal: String,
total: String,
attributes: [OrderItemAttribute]) {
self.itemID = itemID
self.name = name
self.productID = productID
self.variationID = variationID
self.quantity = quantity
self.price = price
self.subtotal = subtotal
self.total = total
self.attributes = attributes
}
}

Expand All @@ -24,8 +40,13 @@ public extension POSOrderItem {
self.init(
itemID: orderItem.itemID,
name: orderItem.name,
productID: orderItem.productID,
variationID: orderItem.variationID,
quantity: orderItem.quantity,
total: orderItem.total
price: orderItem.price,
subtotal: orderItem.subtotal,
total: orderItem.total,
attributes: orderItem.attributes
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,19 @@ import class Yosemite.Store

protocol PointOfSaleOrderListControllerProtocol {
var ordersViewState: OrderListState { get }
var selectedOrder: POSOrder? { get }
func loadOrders() async
func refreshOrders() async
func loadNextOrders() async
func selectOrder(_ order: POSOrder?)
}

@Observable final class PointOfSaleOrderListController: PointOfSaleOrderListControllerProtocol {
var ordersViewState: OrderListState
private let paginationTracker: AsyncPaginationTracker
private var fetchStrategy: PointOfSaleOrderListFetchStrategy
private var cachedOrders: [POSOrder] = []
private(set) var selectedOrder: POSOrder?

init(orderListFetchStrategyFactory: PointOfSaleOrderListFetchStrategyFactoryProtocol,
initialState: OrderListState = .loading([])) {
Expand Down Expand Up @@ -118,4 +121,9 @@ protocol PointOfSaleOrderListControllerProtocol {

ordersViewState = .loading(cachedOrders)
}

@MainActor
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one does not require MainActor, if we want to run it in the main actor then we need to make the function and conformance async

Suggested change
@MainActor

func selectOrder(_ order: POSOrder?) {
selectedOrder = order
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import SwiftUI

struct PointOfSaleOrderDetailsEmptyView: View {
var body: some View {
// TODO: WOOMOB-1136
VStack(spacing: 0) {
POSPageHeaderView(
title: "Orders",
backButtonConfiguration: nil
)

VStack {
Spacer()
Text("No Orders Loaded")
.font(.posBodyLargeRegular())
.foregroundStyle(Color.posOnSurfaceVariantHighest)
Spacer()
}
}
.background(Color.posSurface)
.navigationBarHidden(true)
}
}

#if DEBUG
#Preview {
PointOfSaleOrderDetailsEmptyView()
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import SwiftUI

struct PointOfSaleOrderDetailsLoadingView: View {
var body: some View {
VStack(spacing: 0) {
POSPageHeaderView(
title: Localization.orderDetailsTitle,
backButtonConfiguration: nil,
trailingContent: { shimmeringHeaderTrailingContent },
bottomContent: { shimmeringHeaderBottomContent }
)

ScrollView {
VStack(alignment: .leading, spacing: POSSpacing.medium) {
shimmeringProductsSection
shimmeringTotalsSection
}
.padding(.horizontal, POSPadding.medium)
}
}
.background(Color.posSurface)
.navigationBarHidden(true)
}

// MARK: - Shimmer Components

@ViewBuilder
private var shimmeringHeaderTrailingContent: some View {
GeometryReader { geometry in
HStack {
Spacer()
Rectangle()
.fill(Color.posOnSurfaceVariantLowest)
.frame(width: geometry.size.width * 0.3, height: 16)
.clipShape(RoundedRectangle(cornerRadius: 4))
.shimmering()
}
}
.frame(height: 16)
}

@ViewBuilder
private var shimmeringHeaderBottomContent: some View {
GeometryReader { geometry in
VStack(alignment: .leading, spacing: POSSpacing.xSmall) {
Rectangle()
.fill(Color.posOnSurfaceVariantLowest)
.frame(width: geometry.size.width * 0.5, height: 16)
.clipShape(RoundedRectangle(cornerRadius: 4))
.shimmering()
}
}
.frame(height: 16)
}

@ViewBuilder
private var shimmeringProductsSection: some View {
VStack(alignment: .leading, spacing: POSSpacing.medium) {
Text(Localization.productsTitle)
.font(.posBodyLargeBold)
.foregroundStyle(Color.posOnSurface)

VStack(spacing: POSSpacing.small) {
ForEach(0..<2, id: \.self) { _ in
shimmeringProductRow
}
}
}
.padding(POSPadding.medium)
.background(Color.posSurfaceContainerLowest)
.posItemCardBorderStyles()
}

@ViewBuilder
private var shimmeringProductRow: some View {
GeometryReader { geometry in
HStack(alignment: .top, spacing: POSSpacing.medium) {
Rectangle()
.fill(Color.posOnSurfaceVariantLowest)
.frame(width: 40, height: 40)
.clipShape(RoundedRectangle(cornerRadius: POSCornerRadiusStyle.small.value))
.shimmering()

VStack(alignment: .leading, spacing: POSSpacing.xSmall) {
Rectangle()
.fill(Color.posOnSurfaceVariantLowest)
.frame(width: geometry.size.width * 0.45, height: 20)
.clipShape(RoundedRectangle(cornerRadius: 4))
.shimmering()

Rectangle()
.fill(Color.posOnSurfaceVariantLowest)
.frame(width: geometry.size.width * 0.35, height: 16)
.clipShape(RoundedRectangle(cornerRadius: 4))
.shimmering()
}

Spacer()

Rectangle()
.fill(Color.posOnSurfaceVariantLowest)
.frame(width: geometry.size.width * 0.2, height: 20)
.clipShape(RoundedRectangle(cornerRadius: 4))
.shimmering()
}
.padding(.vertical, POSPadding.small)
}
.frame(height: 60)
}

@ViewBuilder
private var shimmeringTotalsSection: some View {
VStack(alignment: .leading, spacing: POSSpacing.medium) {
Text(Localization.totalsTitle)
.font(.posBodyLargeBold)
.foregroundStyle(Color.posOnSurface)

VStack(spacing: POSSpacing.medium) {
shimmeringTotalsRow
shimmeringTotalsRow
shimmeringTotalsRow

Divider()
.background(Color.posSurfaceDim)

shimmeringTotalsRow
shimmeringTotalsRow
}
}
.padding(POSPadding.medium)
.background(Color.posSurfaceContainerLowest)
.posItemCardBorderStyles()
}

@ViewBuilder
private var shimmeringTotalsRow: some View {
GeometryReader { geometry in
HStack {
Rectangle()
.fill(Color.posOnSurfaceVariantLowest)
.frame(width: geometry.size.width * 0.3, height: 20)
.clipShape(RoundedRectangle(cornerRadius: 4))
.shimmering()

Spacer()

Rectangle()
.fill(Color.posOnSurfaceVariantLowest)
.frame(width: geometry.size.width * 0.25, height: 20)
.clipShape(RoundedRectangle(cornerRadius: 4))
.shimmering()
}
}
.frame(height: 20)
}
}

private enum Localization {
static let orderDetailsTitle = NSLocalizedString(
"pos.orderDetailsLoadingView.title",
value: "Order",
comment: "Title for the order details screen when no specific order is selected"
)

static let productsTitle = NSLocalizedString(
"pos.orderDetailsLoadingView.productsTitle",
value: "Products",
comment: "Section title for the products list"
)

static let totalsTitle = NSLocalizedString(
"pos.orderDetailsLoadingView.totalsTitle",
value: "Totals",
comment: "Section title for the order totals breakdown"
)
}

#if DEBUG
#Preview {
PointOfSaleOrderDetailsLoadingView()
}
#endif
Loading