@@ -71,6 +71,14 @@ final class DashboardViewController: UIViewController {
7171 } )
7272 } ( )
7373
74+ /// Bottom Jetpack benefits banner, shown when the site is connected to Jetpack without Jetpack-the-plugin.
75+ private lazy var bottomJetpackBenefitsBannerController = JetpackBenefitsBannerHostingController ( )
76+ private var contentBottomToJetpackBenefitsBannerConstraint : NSLayoutConstraint ?
77+ private var contentBottomToContainerConstraint : NSLayoutConstraint ?
78+ private var isJetpackBenefitsBannerShown : Bool {
79+ bottomJetpackBenefitsBannerController. view? . superview != nil
80+ }
81+
7482 /// A spacer view to add a margin below the top banner (between the banner and dashboard UI)
7583 ///
7684 private lazy var spacerView : UIView = {
@@ -100,6 +108,7 @@ final class DashboardViewController: UIViewController {
100108 configureNavigation ( )
101109 configureView ( )
102110 configureDashboardUIContainer ( )
111+ configureBottomJetpackBenefitsBanner ( )
103112 observeSiteForUIUpdates ( )
104113 }
105114
@@ -174,8 +183,8 @@ private extension DashboardViewController {
174183 contentView. topAnchor. constraint ( equalTo: headerStackView. bottomAnchor) ,
175184 contentView. leadingAnchor. constraint ( equalTo: containerView. leadingAnchor) ,
176185 contentView. trailingAnchor. constraint ( equalTo: containerView. trailingAnchor) ,
177- contentView. bottomAnchor. constraint ( equalTo: containerView. bottomAnchor)
178186 ] )
187+ contentBottomToContainerConstraint = contentView. bottomAnchor. constraint ( equalTo: containerView. bottomAnchor)
179188 }
180189
181190 private func configureNavigationItem( ) {
@@ -210,6 +219,22 @@ private extension DashboardViewController {
210219 view. pinSubviewToSafeArea ( containerView)
211220 }
212221
222+ func configureBottomJetpackBenefitsBanner( ) {
223+ bottomJetpackBenefitsBannerController. setActions { [ weak self] in
224+ guard let self = self else { return }
225+ let benefitsController = JetpackBenefitsHostingController ( )
226+ benefitsController. setActions {
227+ // TODO: 5370 - Navigate to install Jetpack
228+ } dismissAction: { [ weak self] in
229+ self ? . dismiss ( animated: true , completion: nil )
230+ }
231+ self . present ( benefitsController, animated: true , completion: nil )
232+ } dismissAction: { [ weak self] in
233+ // TODO: 5362 - Persist dismiss state per site
234+ self ? . hideJetpackBenefitsBanner ( )
235+ }
236+ }
237+
213238 func reloadDashboardUIStatsVersion( forced: Bool ) {
214239 dashboardUIFactory. reloadDashboardUI ( onUIUpdate: { [ weak self] dashboardUI in
215240 if ServiceLocator . featureFlagService. isFeatureFlagEnabled ( . largeTitles) {
@@ -303,6 +328,50 @@ private extension DashboardViewController {
303328 updatedDashboardUI. displaySyncingError = { [ weak self] in
304329 self ? . showTopBannerView ( )
305330 }
331+
332+ // Bottom banner
333+ // TODO: 5362 & 5368 - Display banner for JCP sites and if the banner has not been dismissed before.
334+ let shouldShowJetpackBenefitsBanner = ServiceLocator . featureFlagService. isFeatureFlagEnabled ( . jetpackConnectionPackageSupport)
335+ if shouldShowJetpackBenefitsBanner {
336+ showJetpackBenefitsBanner ( contentView: contentView)
337+ } else {
338+ hideJetpackBenefitsBanner ( )
339+ }
340+ }
341+
342+ func showJetpackBenefitsBanner( contentView: UIView ) {
343+ hideJetpackBenefitsBanner ( )
344+ guard let banner = bottomJetpackBenefitsBannerController. view else {
345+ return
346+ }
347+ contentBottomToContainerConstraint? . isActive = false
348+
349+ addChild ( bottomJetpackBenefitsBannerController)
350+ containerView. addSubview ( banner)
351+ bottomJetpackBenefitsBannerController. didMove ( toParent: self )
352+
353+ banner. translatesAutoresizingMaskIntoConstraints = false
354+
355+ // The banner height is calculated in `viewDidLayoutSubviews` to support rotation.
356+ let contentBottomToJetpackBenefitsBannerConstraint = banner. topAnchor. constraint ( equalTo: contentView. bottomAnchor)
357+ self . contentBottomToJetpackBenefitsBannerConstraint = contentBottomToJetpackBenefitsBannerConstraint
358+
359+ NSLayoutConstraint . activate ( [
360+ contentBottomToJetpackBenefitsBannerConstraint,
361+ banner. leadingAnchor. constraint ( equalTo: containerView. leadingAnchor) ,
362+ banner. trailingAnchor. constraint ( equalTo: containerView. trailingAnchor) ,
363+ // Pins from the safe area layout bottom to accommodate offline banner.
364+ banner. safeAreaLayoutGuide. bottomAnchor. constraint ( equalTo: containerView. bottomAnchor) ,
365+ ] )
366+ }
367+
368+ func hideJetpackBenefitsBanner( ) {
369+ contentBottomToJetpackBenefitsBannerConstraint? . isActive = false
370+ contentBottomToContainerConstraint? . isActive = true
371+ if isJetpackBenefitsBannerShown {
372+ bottomJetpackBenefitsBannerController. view? . removeFromSuperview ( )
373+ remove ( bottomJetpackBenefitsBannerController)
374+ }
306375 }
307376}
308377
0 commit comments