import { Container, Label, toast } from '@bsf/force-ui'; import { __ } from '@wordpress/i18n'; import { useEffect, useCallback } from '@wordpress/element'; import { usePluginsAndThemes } from './use-plugins-and-themes'; import { PluginCard } from './plugin-card'; import { themesAndPlugins, dashboard_plugins_sequence, } from './dashboard-constants'; import { Ticket, MessageSquare, Star, Info } from 'lucide-react'; import { SureRankMonoLogo } from '@/global/components/icons'; import { SiteSeoChecksSummary } from './site-seo-checks'; import { useNavigate } from '@tanstack/react-router'; const quickLinks = [ { label: __( 'Open Support Ticket', 'surerank' ), icon: <Ticket className="size-4" />, link: surerank_globals.support_link, external: true, }, { label: __( 'Help Center', 'surerank' ), icon: <Info className="size-4" />, link: surerank_globals.help_link, external: true, }, { label: __( 'Join our Community on Facebook', 'surerank' ), icon: <MessageSquare className="size-4" />, link: surerank_globals.community_link, external: true, }, { label: __( 'Leave Us a Review', 'surerank' ), icon: <Star className="size-4" />, link: surerank_globals.rating_link, external: true, }, ]; const onboardingSetup = [ { label: __( 'Launch Setup Wizard', 'surerank' ), icon: <SureRankMonoLogo className="size-4" />, link: surerank_globals.wp_dashboard_url + '?page=surerank_onboarding', external: false, }, ]; const quickAccessLinks = 'yes' !== surerank_admin_common?.onboarding_complete_status ? [ ...onboardingSetup, ...quickLinks ] : [ ...quickLinks ]; const SequencedThemesAndPlugins = dashboard_plugins_sequence .map( ( slug ) => themesAndPlugins.find( ( item ) => item.slug === slug ) ) .filter( Boolean ); const Dashboard = () => { const navigate = useNavigate(); const { fetchStatus, fetchInstalledPluginsAndThemes, handleInstallThemeOrPlugin, getProgressStatus, getPluginStatus, } = usePluginsAndThemes(); useEffect( () => { checkForGCError(); fetchInstalledPluginsAndThemes(); }, [] ); const getErrorMessages = ( errorCode ) => { switch ( String( errorCode ) ) { case '400': return __( 'The request is malformed or invalid. Please check the request parameters and try again.', 'surerank' ); case '401': return __( 'Authentication failed. Please provide valid credentials or re-authenticate.', 'surerank' ); case '403': return __( 'Access is denied. You lack the necessary permissions to perform this action.', 'surerank' ); case '404': return __( 'The requested resource was not found. Please verify the URL or resource ID.', 'surerank' ); case '429': return __( 'You have exceeded your API quota. Please wait or upgrade your plan.', 'surerank' ); case '500': return __( `A server error occurred on Google's end. Please try again later.`, 'surerank' ); default: return __( 'An error occurred. Please try again.', 'surerank' ); } }; const checkForGCError = () => { const link = 'https://developers.google.com/webmaster-tools/v1/errors'; const params = new URLSearchParams( window.location.search ); const errorCode = params.get( 'gcp_error_code' ); if ( ! errorCode ) { return; } const errorMessage = getErrorMessages( errorCode ); const content = ( <div> <p>{ errorMessage }</p> <p> { __( 'Error code: ', 'surerank' ) } { errorCode } </p> <a href={ link } target="_blank" rel="noopener noreferrer" className="text-link-primary no-underline" > { __( 'Learn more', 'surerank' ) } </a> </div> ); if ( errorMessage ) { toast.error( content, { dangerouslySetInnerHTML: true, autoDismiss: false, } ); } //remove error code parameter and navigate directly to search-console const url = new URL( window.location.href ); url.searchParams.delete( 'gcp_error_code' ); url.searchParams.delete( 'action' ); url.searchParams.delete( 'nonce' ); url.searchParams.delete( 'status' ); window.history.replaceState( {}, '', url.toString() ); navigate( { to: '/search-console' } ); }; const renderInstallButtonText = useCallback( ( item ) => { const status = getPluginStatus( item ); switch ( status ) { case 'active': return __( 'Activated', 'surerank' ); case 'activate': return __( 'Activate', 'surerank' ); default: return __( 'Install & Activate', 'surerank' ); } }, [ getPluginStatus ] ); return ( <> <Container className="h-full p-5 pb-8 xl:p-8 max-[1920px]:max-w-full mx-auto box-content bg-background-secondary gap-6" cols={ 12 } containerType="grid" gap="2xl" > <Container.Item className="col-span-8"> <Container direction="column" className="gap-8 relative"> <SiteSeoChecksSummary limit={ 10 } showViewAll={ true } /> </Container> </Container.Item> <Container.Item className="col-span-4 flex flex-col gap-6"> { /* Plugins and Themes */ } <Container className="w-full h-fit bg-background-primary border-0.5 border-solid rounded-xl border-border-subtle p-3 shadow-sm" containerType="flex" direction="column" gap="xs" > <Container.Item className="md:w-full lg:w-full"> <Container align="center" className="p-1" gap="xs" justify="between" > <Label className="font-semibold text-text-primary"> { __( 'Extend Your Website', 'surerank' ) } </Label> </Container> </Container.Item> <Container.Item className="md:w-full lg:w-full bg-field-primary-background rounded-lg"> <Container containerType="grid" className="p-1 gap-1 grid-cols-1 min-[425px]:grid-cols-2 md:grid-cols-2 xl:grid-cols-2" > { SequencedThemesAndPlugins.map( ( item ) => ( <PluginCard key={ item.name } item={ item } onInstall={ handleInstallThemeOrPlugin } fetchStatus={ fetchStatus } getPluginStatus={ getPluginStatus } getProgressStatus={ getProgressStatus } renderInstallButtonText={ renderInstallButtonText } /> ) ) } </Container> </Container.Item> </Container> { /* Quick Access */ } <Container className="w-full h-fit bg-background-primary border-0.5 border-solid rounded-xl border-border-subtle p-3 shadow-sm" containerType="flex" direction="column" gap="xs" > <Container.Item className="md:w-full lg:w-full p-1"> <Label className="font-semibold text-text-primary"> { __( 'Quick Access', 'surerank' ) } </Label> </Container.Item> <Container.Item className="flex flex-col md:w-full lg:w-full bg-field-primary-background gap-1 p-1 rounded-lg"> { quickAccessLinks.map( ( link ) => ( <div key={ link.label } className="p-2 gap-1 items-center bg-background-primary rounded-md shadow-sm cursor-pointer" onClick={ () => { if ( link.external ) { window.open( link.link, '_blank', 'noopener,noreferrer' ); } else { window.location.href = link.link; } } } > <Container align="center" className="gap-1 p-1" containerType="flex" direction="row" > <Container.Item className="flex"> { link.icon } </Container.Item> <Container.Item className="flex"> <Label className="py-0 px-1 font-normal cursor-pointer hover:text-link-primary"> { link.label } </Label> </Container.Item> </Container> </div> ) ) } </Container.Item> </Container> </Container.Item> </Container> </> ); }; export default Dashboard;