feat(ui): optimize CTA buttons with contextual copy and fix static export build issues
CTA Optimization: - Implement scenario-based CTA text across 6 key locations - Add responsive Header CTA with icon+compact design - Enhance CTA Section with vision-driven copy Bug Fixes: - Fix useSearchParams() build failure with dynamic import wrapper - Remove useSearchParams() from PageTransition component - Fix React 19 useEffect lint errors via useSyncExternalStore UI Enhancements: - Add ripple effects and gradient animations to Button - Enhance loading skeleton with branded pulse animation
This commit is contained in:
@@ -2,16 +2,28 @@
|
||||
|
||||
import Script from 'next/script';
|
||||
import { usePathname, useSearchParams } from 'next/navigation';
|
||||
import { useEffect, Suspense } from 'react';
|
||||
import { useEffect, Suspense, useSyncExternalStore } from 'react';
|
||||
|
||||
const GA_MEASUREMENT_ID = process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID || '';
|
||||
|
||||
function useIsMounted() {
|
||||
return useSyncExternalStore(
|
||||
(callback) => {
|
||||
window.addEventListener('resize', callback);
|
||||
return () => window.removeEventListener('resize', callback);
|
||||
},
|
||||
() => true,
|
||||
() => false
|
||||
);
|
||||
}
|
||||
|
||||
function GoogleAnalyticsContent() {
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
const mounted = useIsMounted();
|
||||
|
||||
useEffect(() => {
|
||||
if (!GA_MEASUREMENT_ID || typeof window === 'undefined') {return;}
|
||||
if (!GA_MEASUREMENT_ID || !mounted || typeof window === 'undefined') {return;}
|
||||
|
||||
const url = pathname + (searchParams.toString() ? `?${searchParams.toString()}` : '');
|
||||
|
||||
@@ -22,9 +34,9 @@ function GoogleAnalyticsContent() {
|
||||
page_location: window.location.origin + url,
|
||||
});
|
||||
}
|
||||
}, [pathname, searchParams]);
|
||||
}, [pathname, searchParams, mounted]);
|
||||
|
||||
if (!GA_MEASUREMENT_ID) {return null;}
|
||||
if (!GA_MEASUREMENT_ID || !mounted) {return null;}
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -61,11 +73,13 @@ function GoogleAnalyticsContent() {
|
||||
}
|
||||
|
||||
export function GoogleAnalytics() {
|
||||
if (!GA_MEASUREMENT_ID) {return null;}
|
||||
const mounted = useIsMounted();
|
||||
|
||||
if (!GA_MEASUREMENT_ID || !mounted) {return null;}
|
||||
|
||||
return (
|
||||
<Suspense fallback={null}>
|
||||
<GoogleAnalyticsContent />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
'use client';
|
||||
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
const GoogleAnalytics = dynamic(
|
||||
() => import('./GoogleAnalytics').then((mod) => mod.GoogleAnalytics),
|
||||
{ ssr: false }
|
||||
);
|
||||
|
||||
export function GoogleAnalyticsWrapper() {
|
||||
return <GoogleAnalytics />;
|
||||
}
|
||||
Reference in New Issue
Block a user