Skip to content

Commit be8c4b1

Browse files
authored
Merge pull request #7053 from woocommerce/issue/6493-coupon-creation-success
Coupons: Add coupon creation success screen
2 parents 5d810a0 + 932c244 commit be8c4b1

File tree

6 files changed

+149
-0
lines changed

6 files changed

+149
-0
lines changed

WooCommerce/Classes/Extensions/UIImage+Woo.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,20 @@ extension UIImage {
118118
return UIImage(named: "check-circle-partial")!
119119
}
120120

121+
/// Large checkmark image that is shown upon success
122+
///
123+
static var checkSuccessImage: UIImage {
124+
return UIImage(named: "check-success")!
125+
}
126+
121127
/// WooCommerce Styled Checkmark
122128
///
123129
static var checkmarkStyledImage: UIImage {
124130
let tintColor = UIColor.primary
125131
return checkmarkImage.imageWithTintColor(tintColor)!
126132
}
127133

134+
128135
/// Chevron Pointing Right
129136
///
130137
static var chevronImage: UIImage {
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import SwiftUI
2+
3+
/// A view to be displayed when a coupon is created successfully.
4+
///
5+
struct CouponCreationSuccess: View {
6+
let couponCode: String
7+
let shareMessage: String
8+
let onDismiss: () -> Void
9+
10+
@State private var showingShareSheet: Bool = false
11+
@State private var imageScale = Constants.initialImageScale
12+
@State private var imageBottomSpace = Constants.initialImageBottomSpacing
13+
@State private var textOpacity = Constants.initialTextOpacity
14+
@State private var buttonsVerticalOffset = Constants.initialButtonsVerticalOffset
15+
16+
var body: some View {
17+
VStack(alignment: .center, spacing: 0) {
18+
Spacer()
19+
20+
VStack(alignment: .leading, spacing: 0) {
21+
Image(uiImage: UIImage.checkSuccessImage)
22+
.padding(.bottom, imageBottomSpace)
23+
.scaleEffect(imageScale)
24+
Text(Localization.successMessage)
25+
.font(.largeTitle)
26+
.bold()
27+
.opacity(textOpacity)
28+
Text(couponCode)
29+
.font(.largeTitle)
30+
.opacity(textOpacity)
31+
}
32+
.padding(Constants.contentPadding)
33+
34+
Spacer()
35+
36+
VStack(alignment: .center, spacing: Constants.contentPadding) {
37+
Button(Localization.shareCoupon) {
38+
showingShareSheet = true
39+
// TODO: add analytics
40+
}
41+
.buttonStyle(PrimaryButtonStyle())
42+
.shareSheet(isPresented: $showingShareSheet) {
43+
ShareSheet(activityItems: [shareMessage])
44+
}
45+
46+
Button(Localization.close) {
47+
onDismiss()
48+
}
49+
.buttonStyle(SecondaryButtonStyle())
50+
}
51+
.padding(Constants.contentPadding)
52+
.offset(x: 0, y: buttonsVerticalOffset)
53+
}
54+
.onAppear {
55+
animateEntry()
56+
}
57+
}
58+
59+
private func animateEntry() {
60+
let buttonGroupAnimation = Animation.easeIn(duration: Constants.buttonGroupAnimationDuration)
61+
62+
let imageAnimation = Animation
63+
.interpolatingSpring(stiffness: Constants.imageAnimationStiffness,
64+
damping: Constants.imageAnimationDamping,
65+
initialVelocity: Constants.imageAnimationInitialVelocity)
66+
.delay(Constants.imageAnimationDelay)
67+
68+
let textAnimation = Animation
69+
.easeIn(duration: Constants.textAnimationDuration)
70+
.delay(Constants.textAnimationDelay)
71+
72+
withAnimation(buttonGroupAnimation) {
73+
buttonsVerticalOffset = Constants.finalButtonsVerticalOffset
74+
}
75+
76+
withAnimation(imageAnimation) {
77+
imageScale = Constants.finalImageScale
78+
}
79+
80+
withAnimation(textAnimation) {
81+
imageBottomSpace = Constants.finalImageBottomSpacing
82+
textOpacity = Constants.finalTextOpacity
83+
}
84+
}
85+
}
86+
87+
private extension CouponCreationSuccess {
88+
enum Constants {
89+
static let contentPadding: CGFloat = 16
90+
91+
static let initialImageBottomSpacing: CGFloat = 80
92+
static let finalImageBottomSpacing: CGFloat = 40
93+
static let initialImageScale: CGFloat = 0
94+
static let finalImageScale: CGFloat = 1
95+
96+
static let initialTextOpacity: CGFloat = 0
97+
static let finalTextOpacity: CGFloat = 1
98+
99+
static let initialButtonsVerticalOffset: CGFloat = 300
100+
static let finalButtonsVerticalOffset: CGFloat = 0
101+
102+
static let buttonGroupAnimationDuration: CGFloat = 0.3
103+
static let imageAnimationStiffness: CGFloat = 150
104+
static let imageAnimationDamping: CGFloat = 15
105+
static let imageAnimationInitialVelocity: CGFloat = 3
106+
static let imageAnimationDelay: CGFloat = 0.7
107+
static let textAnimationDuration: CGFloat = 0.3
108+
static let textAnimationDelay: CGFloat = 0.5
109+
}
110+
111+
enum Localization {
112+
static let successMessage = NSLocalizedString("Your new coupon was created!", comment: "Message displayed when a coupon was successfully created")
113+
static let shareCoupon = NSLocalizedString("Share Coupon", comment: "Button to share coupon from the Coupon Creation Success screen.")
114+
static let close = NSLocalizedString("Close", comment: "Button to dismiss the Coupon Creation Success screen")
115+
}
116+
}
117+
118+
struct CouponCreationSuccess_Previews: PreviewProvider {
119+
static var previews: some View {
120+
CouponCreationSuccess(couponCode: "34sdfg", shareMessage: "Use this coupon to get 10% off all products") {}
121+
}
122+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"images" : [
3+
{
4+
"filename" : "check-success.pdf",
5+
"idiom" : "universal"
6+
}
7+
],
8+
"info" : {
9+
"author" : "xcode",
10+
"version" : 1
11+
}
12+
}
Binary file not shown.

WooCommerce/WooCommerce.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,6 +1585,7 @@
15851585
DE4B3B2E269455D400EEF2D8 /* MockShipmentActionStoresManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4B3B2D269455D400EEF2D8 /* MockShipmentActionStoresManager.swift */; };
15861586
DE4B3B5626A68DD000EEF2D8 /* View+InsetPaddings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4B3B5526A68DD000EEF2D8 /* View+InsetPaddings.swift */; };
15871587
DE4B3B5826A7041800EEF2D8 /* EdgeInsets+Woo.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4B3B5726A7041800EEF2D8 /* EdgeInsets+Woo.swift */; };
1588+
DE4D308928507B5B00E36ADD /* CouponCreationSuccess.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4D308828507B5B00E36ADD /* CouponCreationSuccess.swift */; };
15881589
DE4FB7732812AE96003D20D6 /* FilterListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4FB7722812AE96003D20D6 /* FilterListView.swift */; };
15891590
DE525499268C8B32007A5829 /* UIRefreshControl+Woo.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE525498268C8B32007A5829 /* UIRefreshControl+Woo.swift */; };
15901591
DE67D46726B98FD000EFE8DB /* Publisher+WithLatestFrom.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE67D46626B98FD000EFE8DB /* Publisher+WithLatestFrom.swift */; };
@@ -3360,6 +3361,7 @@
33603361
DE4B3B2D269455D400EEF2D8 /* MockShipmentActionStoresManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockShipmentActionStoresManager.swift; sourceTree = "<group>"; };
33613362
DE4B3B5526A68DD000EEF2D8 /* View+InsetPaddings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+InsetPaddings.swift"; sourceTree = "<group>"; };
33623363
DE4B3B5726A7041800EEF2D8 /* EdgeInsets+Woo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EdgeInsets+Woo.swift"; sourceTree = "<group>"; };
3364+
DE4D308828507B5B00E36ADD /* CouponCreationSuccess.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CouponCreationSuccess.swift; sourceTree = "<group>"; };
33633365
DE4FB7722812AE96003D20D6 /* FilterListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterListView.swift; sourceTree = "<group>"; };
33643366
DE525498268C8B32007A5829 /* UIRefreshControl+Woo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIRefreshControl+Woo.swift"; sourceTree = "<group>"; };
33653367
DE67D46626B98FD000EFE8DB /* Publisher+WithLatestFrom.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Publisher+WithLatestFrom.swift"; sourceTree = "<group>"; };
@@ -5271,6 +5273,7 @@
52715273
DE69C54B27BB7163000BB888 /* UsageDetails */,
52725274
4535EE78281ADD1F004212B4 /* Coupon Text Validators */,
52735275
DE3877DF283B68CF0075D87E /* DiscountTypeBottomSheetListSelectorCommand.swift */,
5276+
DE4D308828507B5B00E36ADD /* CouponCreationSuccess.swift */,
52745277
);
52755278
path = "Add and Edit Coupons";
52765279
sourceTree = "<group>";
@@ -8793,6 +8796,7 @@
87938796
26ED9660274328BC00FA00A1 /* SimplePaymentsSummaryViewModel.swift in Sources */,
87948797
024DF31E23743045006658FE /* TextList+AztecFormatting.swift in Sources */,
87958798
0260F40123224E8100EDA10A /* ProductsViewController.swift in Sources */,
8799+
DE4D308928507B5B00E36ADD /* CouponCreationSuccess.swift in Sources */,
87968800
7E6A019F2725CD76001668D5 /* FilterProductCategoryListViewModel.swift in Sources */,
87978801
CC53FB3C2757EC7200C4CA4F /* ProductSelectorViewModel.swift in Sources */,
87988802
4569D3C325DC008700CDC3E2 /* SiteAddress.swift in Sources */,

WooCommerce/WooCommerceTests/Extensions/IconsTests.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ final class IconsTests: XCTestCase {
7171
XCTAssertNotNil(UIImage.checkPartialCircleImage)
7272
}
7373

74+
func test_check_success_image_icon_is_not_nil() {
75+
XCTAssertNotNil(UIImage.checkSuccessImage)
76+
}
77+
7478
func testChevronImageIconIsNotNil() {
7579
XCTAssertNotNil(UIImage.chevronImage)
7680
}

0 commit comments

Comments
 (0)