HEX
Server: LiteSpeed
System: Linux server902.web-hosting.com 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
User: deshuvsd (2181)
PHP: 8.1.33
Disabled: NONE
Upload Files
File: /home/deshuvsd/www/wp-content/plugins/surerank/src/apps/search-console-widget/widget.js
import { useEffect, useCallback } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import apiFetch from '@wordpress/api-fetch';
import { addQueryArgs } from '@wordpress/url';
import { toast } from '@bsf/force-ui';
import {
	formatToISOPreserveDate,
	getLastNDays,
	formatDateRange,
} from '@/functions/utils';
import { useWidgetDispatch, ACTIONS } from './context/widget-context';
import EmptyState from './empty-state';
import TrafficDisplay from './traffic-display';
import UpgradeCtaAlert from '@AdminComponents/upgrade-cta-alert';
import { DEFAULT_DATE_RANGE } from './constants';

/**
 * Main Widget Component
 * Handles data fetching and conditional rendering
 *
 * @return {JSX.Element} Widget component
 */
const Widget = () => {
	const dispatch = useWidgetDispatch();

	const {
		is_gsc_connected: isConnected,
		has_gsc_site_selected: hasSiteSelected,
	} = window.surerank_search_console_widget || {};

	const isAuthenticated = isConnected === '1' || isConnected === 1;
	const isSiteSelected = hasSiteSelected === '1' || hasSiteSelected === 1;

	/**
	 * Fetch clicks and impressions data
	 */
	const fetchClicksAndImpressions = useCallback(
		async ( from, to ) => {
			const formattedStartDate = formatToISOPreserveDate( from );
			const formattedEndDate = formatToISOPreserveDate( to );

			try {
				const response = await apiFetch( {
					path: '/surerank/v1/google-search-console/clicks-and-impressions',
					method: 'POST',
					data: {
						startDate: formattedStartDate,
						endDate: formattedEndDate,
					},
				} );

				if ( ! response.success ) {
					throw new Error(
						response.message ??
							__(
								'Failed to fetch clicks and impressions',
								'surerank'
							)
					);
				}

				const clicks = response?.data?.clicks;
				const impressions = response?.data?.impressions;

				const getPercentageType = ( percentage ) => {
					if ( percentage === 0 ) {
						return 'neutral';
					}
					return percentage > 0 ? 'success' : 'danger';
				};

				dispatch( {
					type: ACTIONS.SET_CLICKS_DATA,
					payload: [
						{
							label: __( 'Clicks', 'surerank' ),
							value: clicks?.current,
							previous: clicks?.previous,
							percentage: clicks?.percentage,
							percentageType: getPercentageType(
								clicks?.percentage
							),
							color: 'bg-[#72AEE6]',
						},
						{
							label: __( 'Impressions', 'surerank' ),
							value: impressions?.current,
							percentage: impressions?.percentage,
							previous: impressions?.previous,
							percentageType: getPercentageType(
								impressions?.percentage
							),
							color: 'bg-[#2171B1]',
						},
					],
				} );
			} catch ( error ) {
				toast.error( error.message );
				dispatch( {
					type: ACTIONS.SET_ERROR,
					payload: error.message,
				} );
			}
		},
		[ dispatch ]
	);

	/**
	 * Fetch site traffic data
	 */
	const fetchSiteTraffic = useCallback(
		async ( from, to ) => {
			const formattedStartDate = formatToISOPreserveDate( from );
			const formattedEndDate = formatToISOPreserveDate( to );

			try {
				const response = await apiFetch( {
					path: addQueryArgs(
						'/surerank/v1/google-search-console/site-traffic',
						{
							startDate: formattedStartDate,
							endDate: formattedEndDate,
						}
					),
					method: 'GET',
				} );

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

				dispatch( {
					type: ACTIONS.SET_SITE_TRAFFIC,
					payload: response?.data?.length
						? response?.data?.map( ( item ) => ( {
								...item,
								readableDate: formatDateRange(
									item.date,
									null,
									null,
									'dd/MM'
								),
						  } ) )
						: [],
				} );
			} catch ( error ) {
				toast.error( error.message );
				dispatch( {
					type: ACTIONS.SET_ERROR,
					payload: error.message,
				} );
			}
		},
		[ dispatch ]
	);

	/**
	 * Initiate API calls to fetch data
	 */
	const initiateAPICalls = useCallback( async () => {
		if ( ! isAuthenticated || ! isSiteSelected ) {
			return;
		}

		dispatch( { type: ACTIONS.SET_LOADING, payload: true } );

		const { from, to } = getLastNDays( DEFAULT_DATE_RANGE );

		try {
			await fetchClicksAndImpressions( from, to );
			await fetchSiteTraffic( from, to );
		} catch ( error ) {
			// Errors are already handled in individual fetch functions
		} finally {
			dispatch( { type: ACTIONS.SET_LOADING, payload: false } );
		}
	}, [
		isAuthenticated,
		isSiteSelected,
		fetchClicksAndImpressions,
		fetchSiteTraffic,
		dispatch,
	] );

	// Fetch data on mount if authenticated and site selected
	useEffect( () => {
		if ( isAuthenticated && isSiteSelected ) {
			initiateAPICalls();
		}
	}, [ isAuthenticated, isSiteSelected, initiateAPICalls ] );

	// Render empty state if not connected or no site selected
	if ( ! isAuthenticated || ! isSiteSelected ) {
		return <EmptyState />;
	}

	// Render traffic display
	return (
		<>
			<TrafficDisplay />
			<UpgradeCtaAlert
				isProActive={ !! window?.surerank_globals?.is_pro_active }
			/>
		</>
	);
};

export default Widget;