From c2e921f559ae12efa1c7370ab23be76538391114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Carri=C3=B3n?= Date: Tue, 22 Nov 2022 17:49:58 -0500 Subject: [PATCH 1/5] Adds type to transmit report card data --- .../Analytics Hub/AnalyticsHubViewModel.swift | 30 +++++++++++++ .../AnalyticsReportCardViewModel.swift | 43 +++++++++++++++++++ .../WooCommerce.xcodeproj/project.pbxproj | 8 ++++ 3 files changed, 81 insertions(+) create mode 100644 WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsHubViewModel.swift create mode 100644 WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsReportCardViewModel.swift diff --git a/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsHubViewModel.swift b/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsHubViewModel.swift new file mode 100644 index 00000000000..986f56414c1 --- /dev/null +++ b/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsHubViewModel.swift @@ -0,0 +1,30 @@ +import Foundation + +/// Main View Model for the Analytics Hub. +/// +final class AnalyticsHubViewModel: ObservableObject { + + /// Revenue Card ViewModel + /// + @Published var revenueCard = ReportCardViewModel(title: "REVENUE", + leadingTitle: "Total Sales", + leadingValue: "$3.234", + leadingDelta: "+23%", + leadingDeltaColor: .withColorStudio(.green, shade: .shade50), + trailingTitle: "Net Sales", + trailingValue: "$2.324", + trailingDelta: "-4%", + trailingDeltaColor: .withColorStudio(.red, shade: .shade40)) + + /// Orders Card ViewModel + /// + @Published var ordersCard = ReportCardViewModel(title: "ORDERS", + leadingTitle: "Total Orders", + leadingValue: "145", + leadingDelta: "+36%", + leadingDeltaColor: .withColorStudio(.green, shade: .shade50), + trailingTitle: "Average Order Value", + trailingValue: "$57,99", + trailingDelta: "-16%", + trailingDeltaColor: .withColorStudio(.red, shade: .shade40)) +} diff --git a/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsReportCardViewModel.swift b/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsReportCardViewModel.swift new file mode 100644 index 00000000000..27561615894 --- /dev/null +++ b/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsReportCardViewModel.swift @@ -0,0 +1,43 @@ +import Foundation +import class UIKit.UIColor + +/// Analytics Hub Report Card ViewModel. +/// Used to transmit analytics report data. +/// +struct ReportCardViewModel { + /// Report Card Title. + /// + let title: String + + /// First Column Title + /// + let leadingTitle: String + + /// First Column Value + /// + let leadingValue: String + + /// First Column Delta Value + /// + let leadingDelta: String + + /// First Column delta background color. + /// + let leadingDeltaColor: UIColor + + /// Second Column Titlke + /// + let trailingTitle: String + + /// Second Column Value + /// + let trailingValue: String + + /// Second Column Delta Value + /// + let trailingDelta: String + + /// Second Column Delta Background Color + /// + let trailingDeltaColor: UIColor +} diff --git a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj index 142ac632168..0dd787d4f0b 100644 --- a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj +++ b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj @@ -642,6 +642,8 @@ 26E1BECA251BE5390096D0A1 /* RefundItemTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E1BEC9251BE5390096D0A1 /* RefundItemTableViewCell.swift */; }; 26E1BECC251BE5570096D0A1 /* RefundItemTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 26E1BECB251BE5570096D0A1 /* RefundItemTableViewCell.xib */; }; 26E1BECE251CD9F80096D0A1 /* RefundItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E1BECD251CD9F80096D0A1 /* RefundItemViewModel.swift */; }; + 26E7EE6A292D688900793045 /* AnalyticsHubViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E7EE69292D688900793045 /* AnalyticsHubViewModel.swift */; }; + 26E7EE6C292D894100793045 /* AnalyticsReportCardViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E7EE6B292D894100793045 /* AnalyticsReportCardViewModel.swift */; }; 26ED9660274328BC00FA00A1 /* SimplePaymentsSummaryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26ED965F274328BC00FA00A1 /* SimplePaymentsSummaryViewModel.swift */; }; 26F65C9825DEDAF0008FAE29 /* GenerateVariationUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26F65C9725DEDAF0008FAE29 /* GenerateVariationUseCase.swift */; }; 26F65C9E25DEDE67008FAE29 /* GenerateVariationUseCaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26F65C9D25DEDE67008FAE29 /* GenerateVariationUseCaseTests.swift */; }; @@ -2604,6 +2606,8 @@ 26E1BEC9251BE5390096D0A1 /* RefundItemTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefundItemTableViewCell.swift; sourceTree = ""; }; 26E1BECB251BE5570096D0A1 /* RefundItemTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RefundItemTableViewCell.xib; sourceTree = ""; }; 26E1BECD251CD9F80096D0A1 /* RefundItemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefundItemViewModel.swift; sourceTree = ""; }; + 26E7EE69292D688900793045 /* AnalyticsHubViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsHubViewModel.swift; sourceTree = ""; }; + 26E7EE6B292D894100793045 /* AnalyticsReportCardViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsReportCardViewModel.swift; sourceTree = ""; }; 26ED965F274328BC00FA00A1 /* SimplePaymentsSummaryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimplePaymentsSummaryViewModel.swift; sourceTree = ""; }; 26F65C9725DEDAF0008FAE29 /* GenerateVariationUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenerateVariationUseCase.swift; sourceTree = ""; }; 26F65C9D25DEDE67008FAE29 /* GenerateVariationUseCaseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenerateVariationUseCaseTests.swift; sourceTree = ""; }; @@ -5239,7 +5243,9 @@ isa = PBXGroup; children = ( 2647F7B429280A7F00D59FDF /* AnalyticsHubView.swift */, + 26E7EE69292D688900793045 /* AnalyticsHubViewModel.swift */, 2647F7B9292BE2F900D59FDF /* StatsCard.swift */, + 26E7EE6B292D894100793045 /* AnalyticsReportCardViewModel.swift */, ); path = "Analytics Hub"; sourceTree = ""; @@ -9757,6 +9763,7 @@ 57896D6625362B0C000E8C4D /* TitleAndEditableValueTableViewCellViewModel.swift in Sources */, 0205021E27C8B6C600FB1C6B /* InboxEligibilityUseCase.swift in Sources */, 26E1BECE251CD9F80096D0A1 /* RefundItemViewModel.swift in Sources */, + 26E7EE6C292D894100793045 /* AnalyticsReportCardViewModel.swift in Sources */, 6827141128A5410D00E6E3F6 /* NewSimplePaymentsLocationNoticeViewModel.swift in Sources */, DE7B479027A153C20018742E /* CouponSearchUICommand.swift in Sources */, DE50294D28BEF8F100551736 /* JetpackConnectionWebViewModel.swift in Sources */, @@ -10557,6 +10564,7 @@ 020F41E623163C0100776C4D /* TopBannerView.swift in Sources */, DE6906E327D7121800735E3B /* GhostTableViewController.swift in Sources */, 02EEB5C42424AFAA00B8A701 /* TextFieldTableViewCell.swift in Sources */, + 26E7EE6A292D688900793045 /* AnalyticsHubViewModel.swift in Sources */, AE457813275644590092F687 /* OrderStatusSection.swift in Sources */, B57C744E20F56E3800EEFC87 /* UITableViewCell+Helpers.swift in Sources */, 0295355B245ADF8100BDC42B /* FilterType+Products.swift in Sources */, From fc414524ca9ffd35225abfae2636365b4ce9a329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Carri=C3=B3n?= Date: Tue, 22 Nov 2022 17:50:24 -0500 Subject: [PATCH 2/5] Rename StartCards filename to AnalyticsReportCardData --- .../{StatsCard.swift => AnalyticsReportCard.swift} | 0 WooCommerce/WooCommerce.xcodeproj/project.pbxproj | 8 ++++---- 2 files changed, 4 insertions(+), 4 deletions(-) rename WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/{StatsCard.swift => AnalyticsReportCard.swift} (100%) diff --git a/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/StatsCard.swift b/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsReportCard.swift similarity index 100% rename from WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/StatsCard.swift rename to WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsReportCard.swift diff --git a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj index 0dd787d4f0b..386e15c8507 100644 --- a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj +++ b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj @@ -559,7 +559,7 @@ 263E38472641FF3400260D3B /* Codegen in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 263E38452641FF3400260D3B /* Codegen */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 263EB409242C58EA00F3A15F /* ProductFormActionsFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 263EB408242C58EA00F3A15F /* ProductFormActionsFactoryTests.swift */; }; 2647F7B529280A7F00D59FDF /* AnalyticsHubView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2647F7B429280A7F00D59FDF /* AnalyticsHubView.swift */; }; - 2647F7BA292BE2F900D59FDF /* StatsCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2647F7B9292BE2F900D59FDF /* StatsCard.swift */; }; + 2647F7BA292BE2F900D59FDF /* AnalyticsReportCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2647F7B9292BE2F900D59FDF /* AnalyticsReportCard.swift */; }; 265284022624937600F91BA1 /* AddOnCrossreferenceUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 265284012624937600F91BA1 /* AddOnCrossreferenceUseCase.swift */; }; 265284092624ACE900F91BA1 /* AddOnCrossreferenceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 265284082624ACE900F91BA1 /* AddOnCrossreferenceTests.swift */; }; 2655905B27863D1300BB8457 /* MockCollectOrderPaymentUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2655905A27863D1300BB8457 /* MockCollectOrderPaymentUseCase.swift */; }; @@ -2525,7 +2525,7 @@ 26309F16277D0AEA0012797F /* SafeAreaInsetsKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafeAreaInsetsKey.swift; sourceTree = ""; }; 263EB408242C58EA00F3A15F /* ProductFormActionsFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductFormActionsFactoryTests.swift; sourceTree = ""; }; 2647F7B429280A7F00D59FDF /* AnalyticsHubView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsHubView.swift; sourceTree = ""; }; - 2647F7B9292BE2F900D59FDF /* StatsCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsCard.swift; sourceTree = ""; }; + 2647F7B9292BE2F900D59FDF /* AnalyticsReportCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsReportCard.swift; sourceTree = ""; }; 265284012624937600F91BA1 /* AddOnCrossreferenceUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddOnCrossreferenceUseCase.swift; sourceTree = ""; }; 265284082624ACE900F91BA1 /* AddOnCrossreferenceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddOnCrossreferenceTests.swift; sourceTree = ""; }; 2655905A27863D1300BB8457 /* MockCollectOrderPaymentUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCollectOrderPaymentUseCase.swift; sourceTree = ""; }; @@ -5244,7 +5244,7 @@ children = ( 2647F7B429280A7F00D59FDF /* AnalyticsHubView.swift */, 26E7EE69292D688900793045 /* AnalyticsHubViewModel.swift */, - 2647F7B9292BE2F900D59FDF /* StatsCard.swift */, + 2647F7B9292BE2F900D59FDF /* AnalyticsReportCard.swift */, 26E7EE6B292D894100793045 /* AnalyticsReportCardViewModel.swift */, ); path = "Analytics Hub"; @@ -10180,7 +10180,7 @@ 02482A8B237BE8C7007E73ED /* LinkSettingsViewController.swift in Sources */, CE227097228F152400C0626C /* WooBasicTableViewCell.swift in Sources */, 02C27BCE282CB52F0065471A /* CardPresentPaymentReceiptEmailCoordinator.swift in Sources */, - 2647F7BA292BE2F900D59FDF /* StatsCard.swift in Sources */, + 2647F7BA292BE2F900D59FDF /* AnalyticsReportCard.swift in Sources */, 451526392577D89E0076B03C /* AddAttributeViewModel.swift in Sources */, DE0A2EAF281BA278007A8015 /* ProductCategorySelectorViewModel.swift in Sources */, 45B9C64323A91CB6007FC4C5 /* PriceInputFormatter.swift in Sources */, From 9284344d66de2d91807f8b6eb5671990b58c1eb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Carri=C3=B3n?= Date: Tue, 22 Nov 2022 17:55:41 -0500 Subject: [PATCH 3/5] Adds convinience extension for the VM --- .../AnalyticsReportCardViewModel.swift | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsReportCardViewModel.swift b/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsReportCardViewModel.swift index 27561615894..f8bb8690157 100644 --- a/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsReportCardViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsReportCardViewModel.swift @@ -4,7 +4,7 @@ import class UIKit.UIColor /// Analytics Hub Report Card ViewModel. /// Used to transmit analytics report data. /// -struct ReportCardViewModel { +struct AnalyticsReportCardViewModel { /// Report Card Title. /// let title: String @@ -41,3 +41,19 @@ struct ReportCardViewModel { /// let trailingDeltaColor: UIColor } + +/// Convenience extension to create an `AnalyticsReportCard` from a view model. +/// +extension AnalyticsReportCard { + init(viewModel: AnalyticsReportCardViewModel) { + self.title = viewModel.title + self.leadingTitle = viewModel.leadingTitle + self.leadingValue = viewModel.leadingValue + self.leadingDelta = viewModel.leadingDelta + self.leadingDeltaColor = viewModel.leadingDeltaColor + self.trailingTitle = viewModel.trailingTitle + self.trailingValue = viewModel.trailingValue + self.trailingDelta = viewModel.trailingDelta + self.trailingDeltaColor = viewModel.trailingDeltaColor + } +} From 3bd7d4d205c279deae037b0d1decfbbbca900b33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Carri=C3=B3n?= Date: Tue, 22 Nov 2022 18:01:15 -0500 Subject: [PATCH 4/5] Link viewmodel into existing code --- .../Analytics Hub/AnalyticsHubView.swift | 27 ++++---------- .../Analytics Hub/AnalyticsHubViewModel.swift | 36 +++++++++---------- 2 files changed, 25 insertions(+), 38 deletions(-) diff --git a/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsHubView.swift b/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsHubView.swift index b7828f3a5a4..2f3f1bb950e 100644 --- a/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsHubView.swift +++ b/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsHubView.swift @@ -6,7 +6,8 @@ import SwiftUI /// final class AnalyticsHubHostingViewController: UIHostingController { init(timeRange: StatsTimeRangeV4) { - super.init(rootView: AnalyticsHubView()) + let viewModel = AnalyticsHubViewModel() + super.init(rootView: AnalyticsHubView(viewModel: viewModel)) } @available(*, unavailable) @@ -19,6 +20,8 @@ final class AnalyticsHubHostingViewController: UIHostingController Date: Tue, 22 Nov 2022 18:02:29 -0500 Subject: [PATCH 5/5] Move divider spacing into constants --- .../Dashboard/Analytics Hub/AnalyticsHubView.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsHubView.swift b/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsHubView.swift index 2f3f1bb950e..6bd2b581793 100644 --- a/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsHubView.swift +++ b/WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsHubView.swift @@ -25,7 +25,7 @@ struct AnalyticsHubView: View { var body: some View { ScrollView { VStack(alignment: .leading, spacing: Layout.vertialSpacing) { - VStack(spacing: 0) { + VStack(spacing: Layout.dividerSpacing) { Divider() Text("Placeholder for Time Range Selection") .padding(.leading) @@ -36,7 +36,7 @@ struct AnalyticsHubView: View { } - VStack(spacing: 0) { + VStack(spacing: Layout.dividerSpacing) { Divider() AnalyticsReportCard(viewModel: viewModel.revenueCard) @@ -45,7 +45,7 @@ struct AnalyticsHubView: View { Divider() } - VStack(spacing: 0) { + VStack(spacing: Layout.dividerSpacing) { Divider() AnalyticsReportCard(viewModel: viewModel.ordersCard) @@ -72,6 +72,7 @@ private extension AnalyticsHubView { struct Layout { static let vertialSpacing: CGFloat = 24.0 + static let dividerSpacing: CGFloat = .zero } }