Implement `background-toggle` setup for Visitor groups
- Dominant language
- JavaScript
- Stars
- 1.4k
- Forks
- 383
- Avg merge
- 4d 14h
- Merged PRs (30d)
- 77
Description
## Feature Description
Visitor groups is the hub's second feature that's switched on where the user clicks, without leaving the page. Unlike Enhanced measurement (#13341), though, it isn't one setting: turning it on creates the visitor groups themselves and the custom dimensions behind them in Analytics, which takes a moment and can partly succeed — some groups created, some not.
Site Kit already does all of this on the dashboard, with its own handling for the permission trip out to Google, for a setup that has to be picked up again on return, and for the partial failure. Reproducing any of that in the hub would mean a second version of it to keep in step. So instead the hub lets a feature bring its own setup UI, which stands in the place its card would take, and Visitor groups uses that to reuse what the dashboard already has.
Visitor groups is the only feature in this release that needs it. The point of doing it this way is that the next feature with a setup of its own can be added by its own module, without the hub having to learn anything about it.
For reference, see the [Bespoke setup components](https://docs.google.com/document/d/1sLWcimi6eZqbK4YXVCZtO0ZrfrDV7Ub218Hu_vpwmyI/edit?tab=t.0#heading=h.skbts0rjsv3g) and [`background-toggle` — enable in place](https://docs.google.com/document/d/1sLWcimi6eZqbK4YXVCZtO0ZrfrDV7Ub218Hu_vpwmyI/edit?tab=t.0#heading=h.q8l6vebw4hp9) sections in the design doc.
---------------
_Do not alter or remove anything below. The following sections will be managed by moderators only._
## Acceptance criteria
- Visitor groups is set up from its card's CTA (#13322) without the user leaving the hub, and the CTA shows its in-progress state while the visitor groups and the custom dimensions behind them are created.
- Where Site Kit doesn't have permission to update the site's Analytics property, clicking the CTA takes the user to Google's permission screen. Granting permission returns them to the hub, on the tab they started from (#13338), where the setup continues on its own — they don't have to click the CTA again.
- If the permission isn't granted, visitor groups aren't set up and the card is left as it was.
- If the setup fails, the failure is reported in the feature's place in the list, saying exactly what the dashboard says today for the same failure — its own wording for a setup that couldn't be completed and for visitor groups that couldn't be created, each with a version for a user who lacks the permissions to create them, and each with its *Learn more* link.
- **Retry** on that failure attempts the setup again — after a partial failure retrying picks up only the visitor groups that failed, as it does on the dashboard.
- Dismissing the failure returns the feature's card to its normal pre-setup state. In the hub the dismiss reads *"Got it"*, matching the other features that are switched on in place, while on the dashboard it stays *"No thanks"* as it is today.
- A feature that brings its own setup UI this way is indistinguishable from any other in the list: the same card, with a CTA that looks and behaves like every other feature's, until something happens that only that feature can report.
- The setup UI a feature brings is loaded only when its card is actually shown, so a screen that reads the hub's catalog without displaying it — the dashboards and the WordPress dashboard widget — doesn't load it at all. While it's being loaded the feature's card is shown with its CTA not yet clickable.
- Visitor groups is set up from the detail panel's CTA (#13330) exactly as from the card: the panel closes and everything above happens in the list behind it.
- Visitor groups counts as set up once its visitor groups are configured for the site, and from that point the hub stops listing the feature.
- The confirmation the user sees when a feature is set up in place is covered by #13346.
- Site Kit's existing way of setting up visitor groups from the dashboard is unchanged, including the wording of the failure it shows there.
## Implementation Brief
- [ ] In `assets/js/components/feature-discovery/FeatureCTA.tsx` (added in #13322), add the descriptor's `SetupComponent`, so a feature can bring its own setup UI into the CTA slot:
- When `feature.setup.SetupComponent` is set, render `SetupComponent` instead of the default ``, wrapped in `{ feature.setup.ctaLabel } }>` — this is what leaves the CTA shown but not clickable while the component's chunk is loading.
- Pass `SetupComponent` the four props: `slug`, `isTertiary`, `isBusy`, `setIsBusy`, so a bespoke component can drive the shared busy indicator without owning its own copy of it.
- `feature.setup.SetupComponent` should itself be a `React.lazy()` reference, so that it is only loaded when required to keep the overall bundle size to minimal.
- When `SetupComponent` is present, it has its own click handling and survey trigger, so `FeatureCTA`'s `onClick` will be skipped.
- [ ] Create `assets/js/modules/analytics-4/components/feature-discovery/VisitorGroupsFeatureSetup.tsx` — Visitor groups' `SetupComponent`:
- Accept the four props above: `slug`, `isTertiary`, `isBusy`, `setIsBusy`.
- Wrap the component with `withWidgetComponentProps( 'visitorGroupsFeatureSetup' )` to obtain a `Widget` to hand to `AudienceSegmentationSetupErrorWidget` below — no widget area registration is needed, since this isn't rendered through `WidgetContextRenderer`.
- Drive the whole setup through the existing `useEnableAudienceGroup` hook (`assets/js/modules/analytics-4/hooks/useEnableAudienceGroup.js`) - It already runs through, the scope handshake and OAuth handoff, resuming automatically on return (`autoSubmit` + `hasAnalytics4EditScope` effect), and retrying only the audiences that failed (`failedAudiences`).
- Model on `SetupCTABanner.js`'s wiring, with two differences: report failure and success into local state instead of a dashboard notification, and use the hub's return trip instead of the dashboard's.
- `onOAuthNavigation`: call `setPendingSetup( slug, getCurrentFeatureDiscoveryTab() )` (from `pending-setup.ts`, #13338) so the scope round-trip returns the user to the tab they started from. Leave the hook's default `redirectURL` as is; the tab is restored from the pending-setup record, not the redirect URL.
- `useEffect` to mirror the hook's `isSaving` into `setIsBusy`.
- On click: trigger `setup:feature_setup_{slug}` via `useDispatch( CORE_USER ).triggerSurvey()`, then call the hook's `onEnableGroups`, wrap this in `handleClick` callback.
- Render:
- Normal state — `` with the feature's own `setup.ctaLabel` (read via `useSelect( ( select ) => select( CORE_FEATURE_DISCOVERY ).getFeature( slug ) )`).
- Failure state (`apiErrors.length || failedAudiences.length`, and not locally dismissed) — ``, passing `Widget`, `errors={ apiErrors.length ? apiErrors : failedAudiences }`, `isAudienceCreationVariant={ isAudienceCreationError }`, `onRetry={ onEnableGroups }`, and `onDismiss` clearing local dismissed state.
- Because the hook already carries `failedAudiences` across calls, clicking Retry from the widget naturally repeats `onEnableGroups()` with only the audiences that failed.
- [ ] In `assets/js/modules/analytics-4/components/audience-segmentation/dashboard/AudienceSegmentationSetupErrorWidget.tsx`, add an optional `dismissLabel` prop, default `__( 'No thanks', 'google-site-kit' )`, preserving present dashboard wording, and use it in place of the hard-coded dismiss button label.
- The hub instance below passes `dismissLabel={ __( 'Got it', 'google-site-kit' ) }`.
- [ ] In `assets/js/modules/analytics-4/feature-discovery/index.ts`
- `Visitor groups` catalog entry (added in #13247), set `setup.SetupComponent` to a `React.lazy( () => import( '@/js/modules/analytics-4/components/feature-discovery/VisitorGroupsFeatureSetup' ) )` reference, leaving its existing `type: FEATURE_SETUP_TYPES.BACKGROUND_TOGGLE`, `ctaLabel` and `isEnabled` as registered.
### Test Coverage
- Add unit tests for `VisitorGroupsFeatureSetup`: idle CTA click enabling groups, the OAuth scope round-trip writing a pending-setup record and resuming on return, partial-failure retry picking up only failed audiences, and dismiss returning to the idle CTA.
- Extend `FeatureCTA.test.tsx` (#13322) to cover the `SetupComponent` branch: it renders in place of `FeatureCTAButton`, the `Suspense` fallback while its chunk loads, and that `onClick`/the survey trigger aren't fired by `FeatureCTA` itself in this branch.
- Extend `AudienceSegmentationSetupErrorWidget.test.tsx` for the new `dismissLabel` prop, including its default.
## QA Brief
-
## Changelog entry
-
Contributor guide
Research direction
Start with assets/js/components/feature-discovery/FeatureCTA.tsx, its FeatureCTA.test.tsx coverage, and the existing SetupCTABanner.js wiring. Then read useEnableAudienceGroup.js, pending-setup.ts, VisitorGroupsFeatureSetup.tsx's specified integration points, and AudienceSegmentationSetupErrorWidget.tsx with its tests. Done means the card and detail-panel CTAs support loading, OAuth return, partial-failure retry, dismissal, and existing dashboard wording without loading setup UI when the card is absent.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, react
- Domain
- frontend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100