File "site-selector-popup.js"

Full Path: /home/fresvfqn/waterdamagerestorationandrepairsmithtown.com/wp-content/plugins/surerank/src/apps/admin-dashboard/site-selector-popup.js
File size: 10.13 KB
MIME-type: text/x-java
Charset: utf-8

import apiFetch from '@wordpress/api-fetch';
import {
	Button,
	toast,
	Loader,
	Skeleton,
	Container,
	Alert,
	Text,
} from '@bsf/force-ui';
import { useDispatch, useSuspenseSelect, useSelect } from '@wordpress/data';
import { STORE_NAME } from '@/admin-store/constants';
import { __ } from '@wordpress/i18n';
import { useState, Suspense } from '@wordpress/element';
import { handleDisconnectConfirm } from '../admin-components/user-dropdown';
import { X } from 'lucide-react';
import ModalWrapper from '@AdminComponents/modal-wrapper';
import useSiteVerificationStatus, {
	normalizeUrl,
} from './use-site-verification-status';
import SiteSelector from './site-selector';

const SiteSelectorPopup = () => {
	const { toggleSiteSelectorModal } = useDispatch( STORE_NAME );
	const searchConsole = useSelect(
		( select ) => select( STORE_NAME ).getSearchConsole(),
		[]
	);

	const isSiteSelected = () => {
		return !! searchConsole?.hasSiteSelected;
	};

	return (
		<ModalWrapper
			maxWidth="max-w-[480px]"
			isOpen={ toggleSiteSelectorModal }
		>
			<Container
				className="relative bg-white rounded-lg shadow-lg max-w-md w-full"
				direction="column"
				gap="xs"
			>
				{ /* Header */ }
				<Container
					className="border-b border-gray-200 p-5 pb-2"
					justify="between"
					align="start"
					gap="xs"
					direction="column"
				>
					<Container
						justify="between"
						align="start"
						gap="xs"
						className="w-full"
					>
						<Text className="text-lg font-semibold">
							{ __( 'Search Console Account', 'surerank' ) }
						</Text>
						{ isSiteSelected() && (
							<Button
								icon={ <X /> }
								onClick={ toggleSiteSelectorModal }
								variant="ghost"
								className="p-0"
							/>
						) }
					</Container>
					<Container direction="column" gap="xs">
						<Text className="text-sm text-gray-600">
							{ __(
								'Please select a site below to view its data.',
								'surerank'
							) }
						</Text>
					</Container>
				</Container>

				{ /* Body */ }
				<Suspense
					fallback={
						<Container direction="column" className="gap-5">
							<Container
								direction="column"
								className="gap-1.5 px-5 pt-2"
							>
								<Skeleton className="h-5 w-1/4" />
								<Skeleton className="h-10 w-full" />
							</Container>
							<Container justify="end" className="p-4 gap-3">
								<Skeleton className="h-10 w-20" />
								<Skeleton className="h-10 w-20" />
							</Container>
						</Container>
					}
				>
					<SiteSelectorInputs />
				</Suspense>
			</Container>
		</ModalWrapper>
	);
};

const SiteSelectorInputs = () => {
	const searchConsole = useSuspenseSelect(
		( select ) => select( STORE_NAME ).getSearchConsole(),
		[]
	);
	const { toggleSiteSelectorModal, setSearchConsole, setConfirmationModal } =
		useDispatch( STORE_NAME );
	const [ isLoading, setIsLoading ] = useState( false );
	const [ isCreatingProperty, setIsCreatingProperty ] = useState( false );

	// Check if current site is in the available sites list
	const getCurrentSiteUrl = () => {
		// Get current site URL from window location or WordPress localized data
		return window.location.origin;
	};

	const currentSiteUrl = getCurrentSiteUrl();

	// Set default selected site - if current site is not in list, use current site URL
	const [ selectedSite, setSelectedSite ] = useState( () => {
		const isCurrentSiteInList = searchConsole?.sites?.some(
			( site ) =>
				site.siteUrl === currentSiteUrl ||
				site.siteUrl === `${ currentSiteUrl }/` ||
				normalizeUrl( site.siteUrl ) === normalizeUrl( currentSiteUrl )
		);
		return ! isCurrentSiteInList
			? currentSiteUrl
			: searchConsole?.selectedSite ||
					searchConsole?.tempSelectedSite ||
					currentSiteUrl;
	} );

	// Use the custom hook for site verification status
	const {
		isSelectedSiteVerified,
		currentSiteInListButNotVerified,
		shouldShowConnectAlert,
	} = useSiteVerificationStatus(
		selectedSite,
		currentSiteUrl,
		searchConsole
	);

	const handleSelectSite = ( site ) => {
		setSelectedSite( site );
	};

	const handleDisconnect = () => {
		setConfirmationModal( {
			open: true,
			title: __( 'Disconnect Search Console Account', 'surerank' ),
			description: __(
				'Are you sure you want to disconnect your Search Console account from SureRank?',
				'surerank'
			),
			onConfirm: handleDisconnectConfirm,
			confirmButtonText: __( 'Disconnect', 'surerank' ),
		} );
	};

	const handleCreateProperty = async () => {
		if ( isCreatingProperty ) {
			return;
		}

		setIsCreatingProperty( true );

		try {
			// Use different endpoints based on whether site exists or not
			const endpoint = currentSiteInListButNotVerified
				? '/surerank/v1/google-search-console/verify-site'
				: '/surerank/v1/google-search-console/add-site';

			const response = await apiFetch( {
				path: endpoint,
				method: 'POST',
			} );

			if ( ! response.success ) {
				throw new Error(
					response.message ??
						__( 'Failed to create property', 'surerank' )
				);
			}

			// Handle pending verification case
			if ( response.pending ) {
				toast.success(
					currentSiteInListButNotVerified
						? __( 'Verification started successfully!', 'surerank' )
						: __( 'Property created successfully!', 'surerank' ),
					{
						description: __(
							'Verification is pending and may take 1-2 hours or up to 2 days. Your site has been added to Search Console. Reloading in 2 seconds…',
							'surerank'
						),
					}
				);
			} else {
				toast.success(
					currentSiteInListButNotVerified
						? __( 'Property verified successfully!', 'surerank' )
						: __(
								'Property created and verified successfully!',
								'surerank'
						  ),
					{
						description: __(
							'The changes will take effect after a page refresh. Reloading in 2 seconds…',
							'surerank'
						),
					}
				);
			}

			// Reload page after 2 seconds
			setTimeout( () => {
				window.location.reload();
			}, 2000 );
		} catch ( error ) {
			toast.error( error.message );
		} finally {
			setIsCreatingProperty( false );
		}
	};

	const handleProceed = async () => {
		if ( isLoading ) {
			return;
		}

		// Proceed with site selection only
		if ( ! selectedSite ) {
			toast.error( __( 'Please select a site', 'surerank' ) );
			return;
		}

		setIsLoading( true );
		try {
			const response = await apiFetch( {
				path: '/surerank/v1/google-search-console/site',
				method: 'PUT',
				data: { url: selectedSite },
			} );
			if ( ! response.success ) {
				throw new Error(
					response.message ?? __( 'Failed to proceed', 'surerank' )
				);
			}
			toast.success( __( 'Site selected successfully', 'surerank' ) );
			toggleSiteSelectorModal();
			setSearchConsole( {
				selectedSite,
				hasSiteSelected: true,
			} );
		} catch ( error ) {
			toast.error( error.message );
		} finally {
			setIsLoading( false );
		}
	};

	return (
		<>
			<Container direction="column" gap="xs" className="p-5 pt-2 pb-3">
				<SiteSelector
					sites={ searchConsole?.sites || [] }
					currentSiteUrl={ currentSiteUrl }
					selectedSite={ selectedSite }
					onSiteSelect={ handleSelectSite }
					placeholder={ __( 'Select a site', 'surerank' ) }
				/>

				{ shouldShowConnectAlert && (
					<Container className="mt-4">
						<div>
							<Alert
								variant="info"
								className="shadow-none m-0 [&>div>p]:mr-0"
								content={
									<div className="flex flex-col gap-3">
										<div className="flex flex-col gap-1">
											<span className="text-text-primary text-sm font-semibold">
												{ __(
													"Let's Get Your Site Connected",
													'surerank'
												) }
											</span>

											<p className="text-text-primary text-sm">
												{ __(
													'Connect it now to see SureRank insights. Your site will usually be verified instantly, though Google may take up to 1-2 days in some situations.',
													'surerank'
												) }{ ' ' }
												<a
													href="https://support.google.com/webmasters/answer/34592?hl=en"
													target="_blank"
													rel="noopener noreferrer"
													className="text-text-secondary"
												>
													{ __(
														'Learn more',
														'surerank'
													) }
												</a>
											</p>
										</div>
									</div>
								}
							/>
						</div>
					</Container>
				) }
			</Container>
			{ /* Footer */ }
			<SiteSelectorFooter
				currentSiteUrl={ currentSiteUrl }
				isLoading={ isLoading }
				isCreatingProperty={ isCreatingProperty }
				selectedSite={ selectedSite }
				isSelectedSiteVerified={ isSelectedSiteVerified }
				handleDisconnect={ handleDisconnect }
				handleProceed={ handleProceed }
				handleCreateProperty={ handleCreateProperty }
			/>
		</>
	);
};

const SiteSelectorFooter = ( {
	currentSiteUrl,
	isLoading,
	isCreatingProperty,
	selectedSite,
	isSelectedSiteVerified,
	handleDisconnect,
	handleProceed,
	handleCreateProperty,
} ) => {
	// Check if current site is selected and not verified
	const isCurrentSiteSelectedAndUnverified =
		normalizeUrl( selectedSite ) === normalizeUrl( currentSiteUrl ) &&
		! isSelectedSiteVerified;

	return (
		<Container
			className="border-0 border-solid border-t border-gray-200 gap-3 p-4"
			justify="between"
		>
			<Button
				destructive
				iconPosition="left"
				size="md"
				tag="button"
				type="button"
				variant="link"
				onClick={ handleDisconnect }
			>
				{ __( 'Disconnect', 'surerank' ) }
			</Button>

			{ isCurrentSiteSelectedAndUnverified ? (
				<Button
					variant="primary"
					size="md"
					onClick={ handleCreateProperty }
					icon={
						isCreatingProperty && <Loader variant="secondary" />
					}
					iconPosition="left"
					disabled={ isCreatingProperty || isLoading }
				>
					{ isCreatingProperty
						? __( 'Connecting your site…', 'surerank' )
						: __( 'Connect Site', 'surerank' ) }
				</Button>
			) : (
				<Button
					variant="primary"
					size="md"
					onClick={ handleProceed }
					icon={ isLoading && <Loader variant="secondary" /> }
					iconPosition="left"
					disabled={
						isLoading ||
						isCreatingProperty ||
						! selectedSite ||
						! isSelectedSiteVerified
					}
				>
					{ __( 'Select Site', 'surerank' ) }
				</Button>
			) }
		</Container>
	);
};

export default SiteSelectorPopup;