@@ -14,6 +14,7 @@ struct POSOrderDetailsView: View {
1414 @Environment ( \. siteTimezone) private var siteTimezone
1515 @Environment ( POSOrderListModel . self) private var orderListModel
1616 @Environment ( \. posAnalytics) private var analytics
17+ @Environment ( \. posFeatureFlags) private var featureFlags
1718 @State private var isShowingEmailReceiptView : Bool = false
1819
1920 private var shouldShowBackButton : Bool {
@@ -32,9 +33,7 @@ struct POSOrderDetailsView: View {
3233 title: POSOrderListView . Localization. orderTitle ( order. number) ,
3334 backButtonConfiguration: shouldShowBackButton ? . init( state: . enabled, action: onBack) : nil ,
3435 trailingContent: {
35- if actions. isNotEmpty {
36- actionsSection ( actions)
37- }
36+ actionsSection ( setup: availableActionsSetup)
3837 } ,
3938 bottomContent: {
4039 headerBottomContent ( for: order)
@@ -377,59 +376,102 @@ private extension POSOrderDetailsView {
377376
378377// MARK: - Actions
379378private extension POSOrderDetailsView {
380- enum POSOrderDetailsAction : Identifiable , CaseIterable {
379+ enum OrderDetailsAction : Identifiable , CaseIterable {
380+ case issueRefund
381381 case emailReceipt
382382
383383 var id : String { title }
384384
385385 var title : String {
386386 switch self {
387- case . emailReceipt :
388- Localization . emailReceiptActionTitle
387+ case . issueRefund : Localization . issueRefundActionTitle
388+ case . emailReceipt : Localization . emailReceiptActionTitle
389389 }
390390 }
391391
392- func available ( for order : POSOrder ) -> Bool {
392+ var accessibilityHint : String {
393393 switch self {
394+ case . issueRefund: Localization . issueRefundAccessibilityHint
395+ case . emailReceipt: Localization . emailReceiptAccessibilityHint
396+ }
397+ }
398+
399+ var priority : Int {
400+ switch self {
401+ case . issueRefund: 100
402+ case . emailReceipt: 50
403+ }
404+ }
405+
406+ func isAvailable( for order: POSOrder , flags: POSFeatureFlagProviding ) -> Bool {
407+ guard order. status == . completed else { return false }
408+ switch self {
409+ case . issueRefund:
410+ return flags. isFeatureFlagEnabled ( . pointOfSaleRefundsi1)
394411 case . emailReceipt:
395- order. status == . completed
412+ return true
413+ }
414+ }
415+ }
416+
417+ func handler( for action: OrderDetailsAction ) -> @MainActor ( ) -> Void {
418+ switch action {
419+ case . emailReceipt:
420+ return {
421+ analytics. track ( event: WooAnalyticsEvent . PointOfSale. orderDetailsEmailReceiptTapped ( ) )
422+ isShowingEmailReceiptView = true
396423 }
424+ case . issueRefund:
425+ return { }
397426 }
398427 }
399428
400- var actions : [ POSOrderDetailsAction ] {
401- POSOrderDetailsAction . allCases. filter { $0. available ( for: order) }
429+ struct OrderDetailsActionsSetup {
430+ let primary : OrderDetailsAction ?
431+ let secondary : [ OrderDetailsAction ]
432+ }
433+
434+ var availableActionsSetup : OrderDetailsActionsSetup {
435+ let available = OrderDetailsAction . allCases
436+ . filter { $0. isAvailable ( for: order, flags: featureFlags) }
437+ . sorted { $0. priority > $1. priority }
438+
439+ let primary = available. first
440+ let secondary = Array ( available. dropFirst ( ) )
441+
442+ return OrderDetailsActionsSetup ( primary: primary, secondary: secondary)
402443 }
403444
404445 @ViewBuilder
405- func actionsSection( _ actions: [ POSOrderDetailsAction ] ) -> some View {
406- VStack {
407- HStack {
408- ForEach ( actions) { action in
409- Button ( action: {
410- switch action {
411- case . emailReceipt:
412- analytics. track ( event: WooAnalyticsEvent . PointOfSale. orderDetailsEmailReceiptTapped ( ) )
413- isShowingEmailReceiptView = true
446+ func actionsSection( setup: OrderDetailsActionsSetup ) -> some View {
447+ if let primary = setup. primary {
448+ HStack ( spacing: POSSpacing . large) {
449+ Button ( primary. title, action: handler ( for: primary) )
450+ . buttonStyle ( POSFilledButtonStyle ( size: . extraSmall) )
451+ . accessibilityHint ( primary. accessibilityHint)
452+
453+ if !setup. secondary. isEmpty {
454+ Menu {
455+ ForEach ( setup. secondary) { action in
456+ Button ( action. title, action: handler ( for: action) )
457+ . accessibilityHint ( action. accessibilityHint)
414458 }
415- } ) {
416- Text ( Localization . emailReceiptActionTitle)
417- . lineLimit ( 1 )
418- . minimumScaleFactor ( 0.5 )
459+ } label: {
460+ Image ( systemName: " ellipsis " )
461+ . font ( . posBodyLargeBold)
462+ . dynamicTypeSize ( ... DynamicTypeSize . accessibility2)
463+ . foregroundColor ( . posOnSurface)
464+ . padding ( POSPadding . small)
419465 }
420- . buttonStyle ( POSFilledButtonStyle ( size: . extraSmall) )
421- . accessibilityHint ( accessibilityHint ( for: action) )
466+ . menuIndicator ( . hidden)
422467 }
423468 }
424- Spacer ( )
425469 }
426470 }
427471
428- private func accessibilityHint( for action: POSOrderDetailsAction ) -> String {
429- switch action {
430- case . emailReceipt:
431- return Localization . emailReceiptAccessibilityHint
432- }
472+ func emailReceiptAction( ) {
473+ analytics. track ( event: WooAnalyticsEvent . PointOfSale. orderDetailsEmailReceiptTapped ( ) )
474+ isShowingEmailReceiptView = true
433475 }
434476}
435477
@@ -529,6 +571,24 @@ private enum Localization {
529571 comment: " Accessibility hint for email receipt button on order details view "
530572 )
531573
574+ static let issueRefundActionTitle = NSLocalizedString (
575+ " pos.orderDetailsView.issueRefundAction.title " ,
576+ value: " Issue refund " ,
577+ comment: " Primary action button to start issuing a refund on the order details view "
578+ )
579+
580+ static let issueRefundAccessibilityHint = NSLocalizedString (
581+ " pos.orderDetailsView.issueRefundAction.accessibilityHint " ,
582+ value: " Start refund flow for this order " ,
583+ comment: " Accessibility hint for issue refund button "
584+ )
585+
586+ static let moreActionsA11yLabel = NSLocalizedString (
587+ " pos.orderDetailsView.moreActions.label " ,
588+ value: " More actions " ,
589+ comment: " Accessibility label for the overflow actions menu button (three dots) "
590+ )
591+
532592 static func headerBottomContentAccessibilityLabel( date: String , email: String ? , status: String ) -> String {
533593 let baseFormat = NSLocalizedString (
534594 " pos.orderDetailsView.headerBottomContent.accessibilityLabel " ,
0 commit comments