diff --git a/.env.local.example b/.env.local.example index a23ef9dd..8f34bfe7 100644 --- a/.env.local.example +++ b/.env.local.example @@ -8,11 +8,11 @@ END_SESSION_URL=https://keycloakdomain.com/auth/realms/keycloakrealm/protocol/op REFRESH_TOKEN_URL=https://keycloakdomain.com/auth/realms/keycloakrealm/protocol/openid-connect/token # # Backend System variables -NEXT_PUBLIC_BACKEND_URL= https://backendurl -BACKEND_URL= https://backendurl +NEXT_PUBLIC_BACKEND_URL= http://backendurl +BACKEND_URL= http://backendurl -NEXT_PUBLIC_BACKEND_GRAPHQL_URL=https://backendurl/api/graphql -BACKEND_GRAPHQL_URL=https://backendurl/api/graphql +NEXT_PUBLIC_BACKEND_GRAPHQL_URL=http://backendurl/api/graphql +BACKEND_GRAPHQL_URL=http://backendurl/api/graphql NEXT_PUBLIC_ENABLE_ACCESSMODEL = 'false' NEXT_PUBLIC_ANALYTICS_URL ='https://analyticsurl' @@ -27,3 +27,11 @@ SENTRY_ORG_NAME='orgname' SENTRY_PROJECT_NAME='projectname' NEXT_PUBLIC_PLATFORM_URL = 'https://platformurl' +# Google Analytics +NEXT_PUBLIC_GA_ID='G-XXXXXXXXXX' + +FEATURE_SITEMAPS='false' +FEATURE_SITEMAP_BACKEND_BASE_URL= http://backendurl/api +FEATURE_SITEMAP_ITEMS_PER_PAGE=5 +FEATURE_SITEMAP_CACHE_DURATION=3600 +FEATURE_SITEMAP_CHILD_CACHE_DURATION=21600 \ No newline at end of file diff --git a/app/[locale]/(user)/datasets/[datasetIdentifier]/components/Details/index.tsx b/app/[locale]/(user)/datasets/[datasetIdentifier]/components/Details/index.tsx index 07e8213f..eb4430d1 100644 --- a/app/[locale]/(user)/datasets/[datasetIdentifier]/components/Details/index.tsx +++ b/app/[locale]/(user)/datasets/[datasetIdentifier]/components/Details/index.tsx @@ -20,6 +20,7 @@ import { } from 'opub-ui'; import { GraphQL } from '@/lib/api'; +import { useAnalytics } from '@/hooks/use-analytics'; import { Icons } from '@/components/icons'; const DetailsQuery: any = graphql(` @@ -52,12 +53,20 @@ const DetailsQuery: any = graphql(` const Details: React.FC = () => { const params = useParams(); const chartRef = useRef(null); + const { trackDataset } = useAnalytics(); const { data, isLoading }: { data: any; isLoading: any } = useQuery( [`chartDetails_${params.id}`], () => GraphQL(DetailsQuery, {}, { datasetId: params.datasetIdentifier }) ); + // Track dataset view when component mounts + useEffect(() => { + if (params.datasetIdentifier) { + trackDataset(params.datasetIdentifier as string); + } + }, [params.datasetIdentifier, trackDataset]); + const renderChart = (item: any) => { if (item.chartType === 'ASSAM_DISTRICT' || item.chartType === 'ASSAM_RC') { // Register the map diff --git a/app/[locale]/(user)/usecases/[useCaseSlug]/UsecaseDetailsClient.tsx b/app/[locale]/(user)/usecases/[useCaseSlug]/UsecaseDetailsClient.tsx index 111c83a8..ff52b638 100644 --- a/app/[locale]/(user)/usecases/[useCaseSlug]/UsecaseDetailsClient.tsx +++ b/app/[locale]/(user)/usecases/[useCaseSlug]/UsecaseDetailsClient.tsx @@ -3,6 +3,7 @@ import Image from 'next/image'; import Link from 'next/link'; import { useParams } from 'next/navigation'; +import { useEffect } from 'react'; import { graphql } from '@/gql'; import { TypeDataset, TypeUseCase } from '@/gql/generated/graphql'; import { useQuery } from '@tanstack/react-query'; @@ -10,6 +11,7 @@ import { Card, Text } from 'opub-ui'; import { GraphQLPublic } from '@/lib/api'; import { formatDate, generateJsonLd } from '@/lib/utils'; +import { useAnalytics } from '@/hooks/use-analytics'; import BreadCrumbs from '@/components/BreadCrumbs'; import { Icons } from '@/components/icons'; import JsonLd from '@/components/JsonLd'; @@ -141,6 +143,7 @@ const UseCasedetails = graphql(` const UseCaseDetailClient = () => { const params = useParams(); + const { trackUsecase } = useAnalytics(); const { data: UseCaseDetails, @@ -166,6 +169,14 @@ const UseCaseDetailClient = () => { }, } ); + + // Track usecase view when data is loaded + useEffect(() => { + if (UseCaseDetails?.useCase) { + trackUsecase(UseCaseDetails.useCase.id, UseCaseDetails.useCase.title || undefined); + } + }, [UseCaseDetails?.useCase, trackUsecase]); + const datasets = UseCaseDetails?.useCase?.datasets || []; // Fallback to an empty array const hasSupportingOrganizations = diff --git a/app/[locale]/layout.tsx b/app/[locale]/layout.tsx index 4478891c..ecb10ab1 100644 --- a/app/[locale]/layout.tsx +++ b/app/[locale]/layout.tsx @@ -4,8 +4,8 @@ import { notFound } from 'next/navigation'; import { NextIntlClientProvider } from 'next-intl'; import { unstable_setRequestLocale } from 'next-intl/server'; -import { siteConfig } from '@/config/site'; import Provider from '@/components/provider'; +import GoogleAnalytics from '@/components/GoogleAnalytics'; import locales from '../../config/locales'; const fontSans = FontSans({ subsets: ['latin'], display: 'swap' }); @@ -80,6 +80,7 @@ export default async function LocaleLayout({ return ( + {children} diff --git a/components/GoogleAnalytics/GoogleAnalytics.tsx b/components/GoogleAnalytics/GoogleAnalytics.tsx new file mode 100644 index 00000000..17c43a42 --- /dev/null +++ b/components/GoogleAnalytics/GoogleAnalytics.tsx @@ -0,0 +1,77 @@ +'use client'; + +import { useEffect, Suspense } from 'react'; +import { usePathname, useSearchParams } from 'next/navigation'; +import Script from 'next/script'; +import { GA_TRACKING_ID, pageview, trackEvent } from '@/lib/gtag'; + +function GoogleAnalyticsInner() { + const pathname = usePathname(); + const searchParams = useSearchParams(); + + useEffect(() => { + if (GA_TRACKING_ID && pathname) { + const url = pathname + (searchParams.toString() ? `?${searchParams.toString()}` : ''); + + // Track page view + pageview(url); + + // Track additional page metadata + trackEvent('page_view_detailed', { + page_path: pathname, + page_location: url, + page_title: document.title, + // Extract route information + route_type: getRouteType(pathname), + locale: pathname.split('/')[1] || 'en', + }); + } + }, [pathname, searchParams]); + + return null; +} + +export default function GoogleAnalytics() { + if (!GA_TRACKING_ID) { + return null; + } + + return ( + <> +