@@ -98,14 +98,17 @@ export default function SetupMain( { finishSetup } ) {
 	// Get additional information to determine account and site status.
 	const alerts = useSelect( ( select ) => select( STORE_NAME ).getAlerts( accountID ) );
 	const urlChannels = useSelect( ( select ) => select( STORE_NAME ).getURLChannels( accountID, clientID ) );
-	const error = useSelect( ( select ) => select( STORE_NAME ).getError() );
+	const accountsError = useSelect( ( select ) => select( STORE_NAME ).getError( 'getAccounts', [] ) );
+	const alertsError = useSelect( ( select ) => select( STORE_NAME ).getError( 'getAlerts', [ accountID ] ) );
+	const error = accountsError || alertsError;
 
 	// Determine account and site status.
 	const accountStatus = determineAccountStatus( {
 		accounts,
 		clients,
 		alerts,
-		error,
+		accountsError,
+		alertsError,
 		previousAccountID,
 		previousClientID,
 	} );
/**
 * AdSense Main setup component.
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';

/**
 * WordPress dependencies
 */
import { useEffect, useState } from '@wordpress/element';
import { __, _x, sprintf } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import ProgressBar from '../../../../components/progress-bar';
import ErrorText from '../../../../components/error-text';
import { SvgIcon } from '../../../../util';
import { STORE_NAME } from '../../datastore/constants';
import { STORE_NAME as siteStoreName } from '../../../../googlesitekit/datastore/site/constants';
import {
	ACCOUNT_STATUS_NONE,
	ACCOUNT_STATUS_MULTIPLE,
	ACCOUNT_STATUS_DISAPPROVED,
	ACCOUNT_STATUS_GRAYLISTED,
	ACCOUNT_STATUS_PENDING,
	ACCOUNT_STATUS_NO_CLIENT,
	ACCOUNT_STATUS_APPROVED,
	SITE_STATUS_NONE,
	SITE_STATUS_ADDED,
	determineAccountID,
	determineClientID,
	determineAccountStatus,
	determineSiteStatus,
} from '../../util/status';
import SetupAccountCreate from './SetupAccountCreate';
import SetupAccountSelect from './SetupAccountSelect';
import SetupAccountDisapproved from './SetupAccountDisapproved';
import SetupAccountPending from './SetupAccountPending';
import SetupAccountNoClient from './SetupAccountNoClient';
import SetupAccountApproved from './SetupAccountApproved';
import SetupSiteAdd from './SetupSiteAdd';
import SetupSiteAdded from './SetupSiteAdded';
import {
	AdBlockerWarning,
	ErrorNotice,
} from '../common';
const { useSelect, useDispatch } = Data;

export default function SetupMain( { finishSetup } ) {
	// Get settings.
	const siteURL = useSelect( ( select ) => select( siteStoreName ).getReferenceSiteURL() );
	const previousAccountID = useSelect( ( select ) => select( STORE_NAME ).getAccountID() );
	const previousClientID = useSelect( ( select ) => select( STORE_NAME ).getClientID() );
	const previousAccountStatus = useSelect( ( select ) => select( STORE_NAME ).getAccountStatus() );
	const previousSiteStatus = useSelect( ( select ) => select( STORE_NAME ).getSiteStatus() );
	const accountSetupComplete = useSelect( ( select ) => select( STORE_NAME ).getAccountSetupComplete() );
	const siteSetupComplete = useSelect( ( select ) => select( STORE_NAME ).getSiteSetupComplete() );

	// Check whether a change submission is in progress.
	const isDoingSubmitChanges = useSelect( ( select ) => select( STORE_NAME ).isDoingSubmitChanges() );

	// Check whether settings differ from server and are valid.
	const canSubmitChanges = useSelect( ( select ) => select( STORE_NAME ).canSubmitChanges() );

	// Determine account.
	const accounts = useSelect( ( select ) => select( STORE_NAME ).getAccounts() );
	const accountID = determineAccountID( {
		accounts,
		previousAccountID,
	} );

	// Determine client.
	const clients = useSelect( ( select ) => select( STORE_NAME ).getClients( accountID ) );
	const clientID = determineClientID( {
		clients,
		previousClientID,
	} );

	// Get additional information to determine account and site status.
	const alerts = useSelect( ( select ) => select( STORE_NAME ).getAlerts( accountID ) );
	const urlChannels = useSelect( ( select ) => select( STORE_NAME ).getURLChannels( accountID, clientID ) );
	const error = useSelect( ( select ) => select( STORE_NAME ).getError() );

	// Determine account and site status.
	const accountStatus = determineAccountStatus( {
		accounts,
		clients,
		alerts,
		error,
		previousAccountID,
		previousClientID,
	} );
	const siteStatus = determineSiteStatus( {
		urlChannels,
		siteURL,
	} );

	const {
		setAccountID,
		setClientID,
		setAccountStatus,
		setSiteStatus,
		setAccountSetupComplete,
		setSiteSetupComplete,
		setUseSnippet,
		submitChanges,
		resetAccounts,
		resetAlerts,
		resetClients,
		resetURLChannels,
		receiveError,
	} = useDispatch( STORE_NAME );

	// Allow flagging when a background submission should happen.
	const [ isAwaitingBackgroundSubmit, setIsAwaitingBackgroundSubmit ] = useState( false );

	// Update current account ID setting on-the-fly.
	useEffect( () => {
		// Don't do anything if setting has not loaded yet, if account ID
		// cannot be determined, or if nothing has changed.
		if ( undefined === previousAccountID || undefined === accountID || previousAccountID === accountID ) {
			return;
		}
		setAccountID( accountID );
		// Set flag to await background submission.
		setIsAwaitingBackgroundSubmit( true );
	}, [ previousAccountID, accountID ] );

	// Update current client ID setting on-the-fly.
	useEffect( () => {
		// Don't do anything if setting has not loaded yet, if client ID cannot
		// be determined, or if nothing has changed.
		if ( undefined === previousClientID || undefined === clientID || previousClientID === clientID ) {
			return;
		}
		setClientID( clientID );
		// Set flag to await background submission.
		setIsAwaitingBackgroundSubmit( true );
	}, [ previousClientID, clientID ] );

	// Update account status setting on-the-fly.
	useEffect( () => {
		// Don't do anything if setting has not loaded yet, if account status
		// cannot be determined, or if nothing has changed.
		if ( undefined === previousAccountStatus || undefined === accountStatus || previousAccountStatus === accountStatus ) {
			return;
		}
		// Force setup completion flags to false in case it had been set
		// before, and enforce snippet placement until the account is
		// approved.
		if ( accountStatus !== ACCOUNT_STATUS_APPROVED ) {
			setAccountSetupComplete( false );
			setSiteSetupComplete( false );
			setUseSnippet( true );
		}
		setAccountStatus( accountStatus );
		// Set flag to await background submission.
		setIsAwaitingBackgroundSubmit( true );
	}, [ previousAccountStatus, accountStatus ] );

	// Update site status setting on-the-fly.
	useEffect( () => {
		// Don't do anything if setting has not loaded yet, if site status
		// cannot be determined, or if nothing has changed.
		if ( undefined === previousSiteStatus || undefined === siteStatus || previousSiteStatus === siteStatus ) {
			return;
		}
		// Force site setup completion flag to false in case it had been set before.
		if ( siteStatus !== SITE_STATUS_ADDED ) {
			setSiteSetupComplete( false );
		}
		setSiteStatus( siteStatus );
		// Set flag to await background submission.
		setIsAwaitingBackgroundSubmit( true );
	}, [ previousSiteStatus, siteStatus ] );

	// Submit changes for determined parameters in the background when they are valid.
	const [ isSubmittingInBackground, setIsSubmittingInBackground ] = useState( false );
	// If a background submission should happen and changes are valid to be
	// submitted, do that here. This is wrapped in a separate useEffect hook
	// and relies on isAwaitingBackgroundSubmit since the above useEffect hook
	// must not depend on canSubmitChanges, since that is also updated when
	// other than the above four settings are updated.
	useEffect( () => {
		if ( ! isAwaitingBackgroundSubmit || isSubmittingInBackground || ! canSubmitChanges ) {
			return;
		}

		// Set flag to false since we are gonna run the background submission
		// right now.
		setIsAwaitingBackgroundSubmit( false );

		// Set internal state for submitting in background to avoid sudden
		// rendering of a progress bar.
		( async () => {
			setIsSubmittingInBackground( true );
			await submitChanges();
			setIsSubmittingInBackground( false );
		} )();
	}, [ isAwaitingBackgroundSubmit, isSubmittingInBackground, canSubmitChanges ] );

	const isAdBlockerActive = useSelect( ( select ) => select( STORE_NAME ).isAdBlockerActive() );

	// Reset all fetched data when user re-focuses tab.
	useEffect( () => {
		let timeout;
		let idleSeconds = 0;
		// Count seconds once user focuses elsewhere.
		const countIdleTime = () => {
			timeout = global.setInterval( () => {
				idleSeconds++;
			}, 1000 );
		};
		// Reset when user re-focuses after 15 seconds or more.
		const reset = () => {
			global.clearTimeout( timeout );
			// Do not reset if user has been away for less than 15 seconds.
			if ( idleSeconds < 15 ) {
				idleSeconds = 0;
				return;
			}
			idleSeconds = 0;
			// Do not reset if account status has not been determined yet, or
			// if the account is approved.
			if ( undefined === accountStatus || ACCOUNT_STATUS_APPROVED === accountStatus ) {
				return;
			}

			// Unset any potential error.
			receiveError( undefined );
			// Reset all data to force re-fetch.
			resetAccounts();
			resetAlerts();
			resetClients();
			resetURLChannels();
		};
		global.addEventListener( 'focus', reset );
		global.addEventListener( 'blur', countIdleTime );
		return () => {
			global.removeEventListener( 'focus', reset );
			global.removeEventListener( 'blur', countIdleTime );
			global.clearTimeout( timeout );
		};
	}, [ accountStatus ] );

	// When `finishSetup` is called, flag that we are navigating to keep the progress bar going.
	const [ isNavigating, setIsNavigating ] = useState( false );
	const finishSetupAndNavigate = ( ...args ) => {
		finishSetup( ...args );
		setIsNavigating( true );
	};

	// Fetch existing tag right here, to ensure the progress bar is still being
	// shown while this is being loaded. It is technically used only by child
	// components.
	const existingTag = useSelect( ( select ) => select( STORE_NAME ).getExistingTag() );

	let viewComponent;
	if ( ( undefined === accountStatus && ! error ) || undefined === existingTag || ( isDoingSubmitChanges && ! isSubmittingInBackground ) || isNavigating ) {
		// Show loading indicator if account status not determined yet or if
		// a submission is in progress that is not happening in background.
		viewComponent = <ProgressBar />;
	} else if ( accountStatus !== ACCOUNT_STATUS_APPROVED || ! accountSetupComplete ) {
		// Show relevant account status component.
		switch ( accountStatus ) {
			case ACCOUNT_STATUS_NONE:
				viewComponent = <SetupAccountCreate />;
				break;
			case ACCOUNT_STATUS_MULTIPLE:
				viewComponent = <SetupAccountSelect />;
				break;
			case ACCOUNT_STATUS_DISAPPROVED:
				viewComponent = <SetupAccountDisapproved />;
				break;
			case ACCOUNT_STATUS_GRAYLISTED:
			case ACCOUNT_STATUS_PENDING:
				viewComponent = <SetupAccountPending />;
				break;
			case ACCOUNT_STATUS_NO_CLIENT:
				viewComponent = <SetupAccountNoClient />;
				break;
			case ACCOUNT_STATUS_APPROVED:
				viewComponent = <SetupAccountApproved />;
				break;
			default:
				if ( error ) {
					viewComponent = <ErrorNotice />;
				} else {
					viewComponent = <ErrorText message={ sprintf(
						/* translators: %s: invalid account status identifier */
						__( 'Invalid account status: %s', 'google-site-kit' ),
						accountStatus
					) } />;
				}
		}
	} else if ( undefined === siteStatus ) {
		// Show loading indicator if site status not determined yet.
		viewComponent = <ProgressBar />;
	} else if ( siteStatus !== SITE_STATUS_ADDED || ! siteSetupComplete ) {
		// Show relevant site status component.
		switch ( siteStatus ) {
			case SITE_STATUS_NONE:
				viewComponent = <SetupSiteAdd />;
				break;
			case SITE_STATUS_ADDED:
				viewComponent = <SetupSiteAdded finishSetup={ finishSetupAndNavigate } />;
				break;
			default:
				if ( error ) {
					viewComponent = <ErrorNotice />;
				} else {
					viewComponent = <ErrorText message={ sprintf(
						/* translators: %s: invalid site status identifier */
						__( 'Invalid site status: %s', 'google-site-kit' ),
						siteStatus
					) } />;
				}
		}
	} else {
		// This should never be reached because the setup is not accessible
		// under these circumstances due to related PHP+/JS logic. But at
		// least in theory it should show the last step, just in case.
		viewComponent = <SetupSiteAdded finishSetup={ finishSetupAndNavigate } />;
	}

	return (
		<div className="googlesitekit-setup-module googlesitekit-setup-module--adsense">
			<div className="googlesitekit-setup-module__step">
				<div className="googlesitekit-setup-module__logo">
					<SvgIcon id="adsense" width="33" height="33" />
				</div>

				<h2 className="googlesitekit-heading-3 googlesitekit-setup-module__title">
					{ _x( 'AdSense', 'Service name', 'google-site-kit' ) }
				</h2>
			</div>

			<div className="googlesitekit-setup-module__step">
				<AdBlockerWarning />

				{ ! isAdBlockerActive && (
					viewComponent
				) }
			</div>
		</div>
	);
}

SetupMain.propTypes = {
	finishSetup: PropTypes.func,
};

SetupMain.defaultProps = {
	finishSetup: () => {},
};

The IB says that `error` would be removed in this component, but it looks like perhaps we could still use this for cases where it is still used where it only seems to care "if there is any error". In that case, I think it would be slightly better to name it something like `hasError` and cast it to a boolean, but that's a bit of a nitpick. I'm okay with keeping it if @felixarntz is.