11import SwiftUI
22
3- struct CouponUsageDetails : View {
3+ struct CouponRestrictions : View {
44
5- @ObservedObject private var viewModel : CouponUsageDetailsViewModel
5+ @State private var showingAllowedEmails : Bool = false
6+ @ObservedObject private var viewModel : CouponRestrictionsViewModel
67
7- init ( viewModel: CouponUsageDetailsViewModel ) {
8+ // Tracks the scale of the view due to accessibility changes
9+ @ScaledMetric private var scale : CGFloat = 1.0
10+
11+ init ( viewModel: CouponRestrictionsViewModel ) {
812 self . viewModel = viewModel
913 }
1014
1115 var body : some View {
1216 GeometryReader { geometry in
1317 ScrollView {
1418 VStack ( alignment: . leading, spacing: 0 ) {
15- ListHeaderView ( text: Localization . usageRestriction. uppercased ( ) , alignment: . left)
16- . padding ( . horizontal, insets: geometry. safeAreaInsets)
1719 VStack ( alignment: . leading, spacing: 0 ) {
18- Divider ( )
1920 TitleAndTextFieldRow ( title: String . localizedStringWithFormat ( Localization . minimumSpend, viewModel. currencySymbol) ,
2021 placeholder: Localization . none,
2122 text: $viewModel. minimumSpend,
22- editable: false ,
2323 keyboardType: . decimalPad)
2424 . padding ( . horizontal, insets: geometry. safeAreaInsets)
2525 Divider ( )
@@ -28,7 +28,6 @@ struct CouponUsageDetails: View {
2828 TitleAndTextFieldRow ( title: String . localizedStringWithFormat ( Localization . maximumSpend, viewModel. currencySymbol) ,
2929 placeholder: Localization . none,
3030 text: $viewModel. maximumSpend,
31- editable: false ,
3231 keyboardType: . decimalPad)
3332 . padding ( . horizontal, insets: geometry. safeAreaInsets)
3433 Divider ( )
@@ -37,7 +36,6 @@ struct CouponUsageDetails: View {
3736 TitleAndTextFieldRow ( title: Localization . usageLimitPerCoupon,
3837 placeholder: Localization . unlimited,
3938 text: $viewModel. usageLimitPerCoupon,
40- editable: false ,
4139 keyboardType: . asciiCapableNumberPad)
4240 . padding ( . horizontal, insets: geometry. safeAreaInsets)
4341 Divider ( )
@@ -46,20 +44,18 @@ struct CouponUsageDetails: View {
4644 TitleAndTextFieldRow ( title: Localization . usageLimitPerUser,
4745 placeholder: Localization . unlimited,
4846 text: $viewModel. usageLimitPerUser,
49- editable: false ,
5047 keyboardType: . asciiCapableNumberPad)
5148 . padding ( . horizontal, insets: geometry. safeAreaInsets)
5249 Divider ( )
50+ . padding ( . leading, Constants . margin)
51+ . padding ( . leading, insets: geometry. safeAreaInsets)
5352 }
5453 . background ( Color ( . listForeground) )
55- . padding ( . bottom, Constants . margin)
5654
5755 VStack ( alignment: . leading, spacing: 0 ) {
58- Divider ( )
5956 TitleAndTextFieldRow ( title: Localization . limitUsageToXItems,
6057 placeholder: Localization . allQualifyingInCart,
6158 text: $viewModel. limitUsageToXItems,
62- editable: false ,
6359 keyboardType: . asciiCapableNumberPad)
6460 . padding ( . horizontal, insets: geometry. safeAreaInsets)
6561 Divider ( )
@@ -68,62 +64,114 @@ struct CouponUsageDetails: View {
6864 TitleAndValueRow ( title: Localization . allowedEmails,
6965 value: viewModel. allowedEmails. isNotEmpty ?
7066 . content( viewModel. allowedEmails) :
71- . content( Localization . noRestrictions) )
72- . padding ( . horizontal, insets: geometry. safeAreaInsets)
67+ . content( Localization . noRestrictions) ,
68+ selectionStyle: . disclosure) {
69+ showingAllowedEmails = true
70+ }
71+ . padding ( . horizontal, insets: geometry. safeAreaInsets)
72+
7373 Divider ( )
74+ . padding ( . leading, Constants . margin)
75+ . padding ( . leading, insets: geometry. safeAreaInsets)
7476 }
75- . background ( Color ( . listForeground) )
76- . padding ( . top, Constants . margin)
7777
78- ListHeaderView ( text: Localization . usageLimits. uppercased ( ) , alignment: . left)
79- . padding ( . horizontal, insets: geometry. safeAreaInsets)
80- VStack ( alignment: . leading, spacing: 0 ) {
81- Divider ( )
82- TitleAndValueRow ( title: Localization . individualUseOnly,
83- value: . content( viewModel. individualUseOnly ? Localization . yes : Localization . no) )
78+ VStack ( alignment: . leading, spacing: Constants . verticalSpacing) {
79+ TitleAndToggleRow ( title: Localization . individualUseOnly,
80+ isOn: $viewModel. individualUseOnly)
81+ . padding ( . horizontal, Constants . margin)
8482 . padding ( . horizontal, insets: geometry. safeAreaInsets)
85- . padding ( . vertical , Constants . verticalSpacing )
83+
8684 Divider ( )
8785 . padding ( . leading, Constants . margin)
8886 . padding ( . leading, insets: geometry. safeAreaInsets)
89- TitleAndValueRow ( title: Localization . excludeSaleItems,
90- value: . content( viewModel. excludeSaleItems ? Localization . yes : Localization . no) )
87+
88+ Text ( Localization . individualUseDescription)
89+ . footnoteStyle ( )
90+ . padding ( . horizontal, Constants . margin)
91+ . padding ( . horizontal, insets: geometry. safeAreaInsets)
92+
93+ TitleAndToggleRow ( title: Localization . excludeSaleItems,
94+ isOn: $viewModel. excludeSaleItems)
95+ . padding ( . horizontal, Constants . margin)
9196 . padding ( . horizontal, insets: geometry. safeAreaInsets)
92- . padding ( . vertical , Constants . verticalSpacing )
97+
9398 Divider ( )
99+ . padding ( . leading, Constants . margin)
100+ . padding ( . leading, insets: geometry. safeAreaInsets)
101+
102+ Text ( Localization . excludeSaleItemsDescription)
103+ . footnoteStyle ( )
104+ . padding ( . horizontal, Constants . margin)
105+ . padding ( . horizontal, insets: geometry. safeAreaInsets)
94106 }
95- . background ( Color ( . listForeground) )
96- . padding ( . bottom, Constants . margin)
107+ . padding ( . vertical, Constants . margin)
97108 }
109+
110+ VStack ( alignment: . leading, spacing: Constants . margin) {
111+ Text ( Localization . exclusions. uppercased ( ) )
112+ . footnoteStyle ( )
113+ Button ( action: {
114+ // TODO: show product selection
115+ } ) {
116+ HStack {
117+ Image ( uiImage: UIImage . plusImage)
118+ . resizable ( )
119+ . frame ( width: Constants . plusIconSize * scale, height: Constants . plusIconSize * scale)
120+ Text ( Localization . excludeProducts)
121+ }
122+ }
123+ . buttonStyle ( SecondaryButtonStyle ( labelFont: . body) )
124+
125+ Button ( action: {
126+ // TODO: show category selection
127+ } ) {
128+ HStack {
129+ Image ( uiImage: UIImage . plusImage)
130+ . resizable ( )
131+ . frame ( width: Constants . plusIconSize * scale, height: Constants . plusIconSize * scale)
132+ Text ( Localization . excludeProductCategories)
133+ }
134+ }
135+ . buttonStyle ( SecondaryButtonStyle ( labelFont: . body) )
136+ }
137+ . padding ( . vertical, Constants . sectionSpacing)
138+ . padding ( . horizontal, Constants . margin)
139+ . padding ( . horizontal, insets: geometry. safeAreaInsets)
140+ . frame ( maxWidth: . infinity, alignment: . leading)
98141 }
99- . background ( Color ( . listBackground ) )
142+ . background ( Color ( . listForeground ) )
100143 . ignoresSafeArea ( . container, edges: [ . horizontal] )
144+
145+ LazyNavigationLink ( destination: CouponAllowedEmails ( emailFormats: $viewModel. allowedEmails) , isActive: $showingAllowedEmails) {
146+ EmptyView ( )
147+ }
101148 }
102- . navigationTitle ( Localization . usageDetails )
149+ . navigationTitle ( Localization . usageRestriction )
103150 }
104151}
105152
106- private extension CouponUsageDetails {
153+ private extension CouponRestrictions {
107154 enum Constants {
108155 static let margin : CGFloat = 16
109156 static let verticalSpacing : CGFloat = 8
157+ static let sectionSpacing : CGFloat = 30
158+ static let plusIconSize : CGFloat = 16
110159 }
111160
112161 enum Localization {
113- static let usageDetails = NSLocalizedString ( " Usage Details " , comment: " Navigation title for usage details screen " )
114162 static let usageRestriction = NSLocalizedString (
115163 " Usage Restrictions " ,
116164 comment: " Title for the usage restrictions section on coupon usage details screen "
117165 )
118166 static let minimumSpend = NSLocalizedString (
119- " Minimum Spend (%1$@)" ,
167+ " Min. Spend (%1$@)" ,
120168 comment: " Title for the minimum spend row on coupon usage details screen with currency symbol within the brackets. " +
121- " Reads like: Minimum Spend ($) "
169+ " Reads like: Min. Spend ($) "
122170 )
123171 static let maximumSpend = NSLocalizedString (
124- " Maximum Spend (%1$@)" ,
172+ " Max. Spend (%1$@)" ,
125173 comment: " Title for the maximum spend row on coupon usage details screen with currency symbol within the brackets. " +
126- " Reads like: Maximum Spend ($) "
174+ " Reads like: Max. Spend ($) "
127175 )
128176 static let usageLimitPerCoupon = NSLocalizedString (
129177 " Usage Limit Per Coupon " ,
@@ -141,42 +189,52 @@ private extension CouponUsageDetails {
141189 " Allowed Emails " ,
142190 comment: " Title for the allowed email row in coupon usage details screen. "
143191 )
144- static let usageLimits = NSLocalizedString ( " Usage Limits " , comment: " Title for the usage limits section on coupon usage details screen " )
145192 static let individualUseOnly = NSLocalizedString (
146193 " Individual Use Only " ,
147194 comment: " Title for the individual use only row in coupon usage details screen. "
148195 )
196+ static let individualUseDescription = NSLocalizedString (
197+ " Turn this on if the coupon cannot be used in conjunction with other coupons. " ,
198+ comment: " Description for the individual use only row in coupon usage details screen. "
199+ )
149200 static let excludeSaleItems = NSLocalizedString (
150201 " Exclude Sale Items " ,
151202 comment: " Title for the exclude sale items row in coupon usage details screen. "
152203 )
204+ static let excludeSaleItemsDescription = NSLocalizedString (
205+ " Turn this on if the coupon should not apply to items on sale. " +
206+ " Per-item coupons will only work if the item is not on sale. " +
207+ " Per-cart coupons will only work if there are items in the cart that are not on sale. " ,
208+ comment: " Description for the exclude sale items row in coupon usage details screen. "
209+ )
153210 static let none = NSLocalizedString ( " None " , comment: " Value for fields in Coupon Usage Details screen when no value is set " )
154211 static let unlimited = NSLocalizedString ( " Unlimited " , comment: " Value for fields in Coupon Usage Details screen when no limit is set " )
155212 static let allQualifyingInCart = NSLocalizedString (
156- " All Qualifying in Cart " ,
213+ " All Qualifying " ,
157214 comment: " Value for the limit usage to X items row in Coupon Usage Details screen when no limit is set "
158215 )
159216 static let noRestrictions = NSLocalizedString (
160217 " No Restrictions " ,
161218 comment: " Value for the allowed emails row in Coupon Usage Details screen when no restriction is set "
162219 )
163- static let yes = NSLocalizedString (
164- " Yes " ,
165- comment: " Value for the individual use only row or the exclude sale items row in Coupon Usage Details screen when the value is true "
220+ static let exclusions = NSLocalizedString ( " Exclusions " , comment: " Title of the exclusions section in Coupon Usage Details screen " )
221+ static let excludeProducts = NSLocalizedString (
222+ " Exclude Products " ,
223+ comment: " Title of the action button to add products to the exclusion list in Coupon Usage Details screen "
166224 )
167- static let no = NSLocalizedString (
168- " No " ,
169- comment: " Value for the individual use only row or the exclude sale items row in Coupon Usage Details screen when the value is false "
225+ static let excludeProductCategories = NSLocalizedString (
226+ " Exclude Product Categories " ,
227+ comment: " Title of the action button to add product categories to the exclusion list in Coupon Usage Details screen"
170228 )
171229 }
172230}
173231
174232#if DEBUG
175- struct CouponUsageDetails_Previews : PreviewProvider {
233+ struct CouponRestrictions_Previews : PreviewProvider {
176234 static var previews : some View {
177- CouponUsageDetails ( viewModel: . init( coupon: . sampleCoupon) )
235+ CouponRestrictions ( viewModel: . init( coupon: . sampleCoupon) )
178236
179- CouponUsageDetails ( viewModel: . init( coupon: . sampleCoupon) )
237+ CouponRestrictions ( viewModel: . init( coupon: . sampleCoupon) )
180238 . previewLayout ( . fixed( width: 715 , height: 320 ) )
181239 }
182240}
0 commit comments