- {(data as any[]).map((item, index) => (
-
-
-
{getFlagComponent(item.country)}
-
- {activeTab === 'countries' ? getCountryName(item.country) :
- activeTab === 'regions' ? getRegionName(item.region, item.country) :
- getCityName(item.city)}
-
+ {isLoadingFull ? (
+
Loading...
+ ) : (
+ (fullData.length > 0 ? fullData : data as any[]).map((item, index) => (
+
+
+ {getFlagComponent(item.country)}
+
+ {activeTab === 'countries' ? getCountryName(item.country) :
+ activeTab === 'regions' ? getRegionName(item.region, item.country) :
+ getCityName(item.city)}
+
+
+
+ {formatNumber(item.pageviews)}
+
-
- {formatNumber(item.pageviews)}
-
-
- ))}
+ ))
+ )}
>
)
-}
+}
\ No newline at end of file
diff --git a/components/dashboard/TechSpecs.tsx b/components/dashboard/TechSpecs.tsx
index dcef5a6..d3f025b 100644
--- a/components/dashboard/TechSpecs.tsx
+++ b/components/dashboard/TechSpecs.tsx
@@ -1,10 +1,11 @@
'use client'
-import { useState } from 'react'
+import { useState, useEffect } from 'react'
import { formatNumber } from '@/lib/utils/format'
import { getBrowserIcon, getOSIcon, getDeviceIcon } from '@/lib/utils/icons'
import { MdMonitor } from 'react-icons/md'
import { Modal } from '@ciphera-net/ui'
+import { getBrowsers, getOS, getDevices, getScreenResolutions } from '@/lib/api/stats'
interface TechSpecsProps {
browsers: Array<{ browser: string; pageviews: number }>
@@ -13,21 +14,57 @@ interface TechSpecsProps {
screenResolutions: Array<{ screen_resolution: string; pageviews: number }>
collectDeviceInfo?: boolean
collectScreenResolution?: boolean
+ siteId: string
+ dateRange: { start: string, end: string }
}
type Tab = 'browsers' | 'os' | 'devices' | 'screens'
const LIMIT = 7
-export default function TechSpecs({ browsers, os, devices, screenResolutions, collectDeviceInfo = true, collectScreenResolution = true }: TechSpecsProps) {
+export default function TechSpecs({ browsers, os, devices, screenResolutions, collectDeviceInfo = true, collectScreenResolution = true, siteId, dateRange }: TechSpecsProps) {
const [activeTab, setActiveTab] = useState
('browsers')
const [isModalOpen, setIsModalOpen] = useState(false)
+ const [fullData, setFullData] = useState([])
+ const [isLoadingFull, setIsLoadingFull] = useState(false)
// Filter out "Unknown" entries that result from disabled collection
const filterUnknown = (items: Array<{ name: string; pageviews: number; icon: React.ReactNode }>) => {
return items.filter(item => item.name && item.name !== 'Unknown' && item.name !== '')
}
+ useEffect(() => {
+ if (isModalOpen) {
+ const fetchData = async () => {
+ setIsLoadingFull(true)
+ try {
+ let data: any[] = []
+ if (activeTab === 'browsers') {
+ const res = await getBrowsers(siteId, dateRange.start, dateRange.end, 100)
+ data = res.map(b => ({ name: b.browser, pageviews: b.pageviews, icon: getBrowserIcon(b.browser) }))
+ } else if (activeTab === 'os') {
+ const res = await getOS(siteId, dateRange.start, dateRange.end, 100)
+ data = res.map(o => ({ name: o.os, pageviews: o.pageviews, icon: getOSIcon(o.os) }))
+ } else if (activeTab === 'devices') {
+ const res = await getDevices(siteId, dateRange.start, dateRange.end, 100)
+ data = res.map(d => ({ name: d.device, pageviews: d.pageviews, icon: getDeviceIcon(d.device) }))
+ } else if (activeTab === 'screens') {
+ const res = await getScreenResolutions(siteId, dateRange.start, dateRange.end, 100)
+ data = res.map(s => ({ name: s.screen_resolution, pageviews: s.pageviews, icon: }))
+ }
+ setFullData(filterUnknown(data))
+ } catch (e) {
+ console.error(e)
+ } finally {
+ setIsLoadingFull(false)
+ }
+ }
+ fetchData()
+ } else {
+ setFullData([])
+ }
+ }, [isModalOpen, activeTab, siteId, dateRange])
+
const getRawData = () => {
switch (activeTab) {
case 'browsers':
@@ -141,19 +178,23 @@ export default function TechSpecs({ browsers, os, devices, screenResolutions, co
title={`Technology - ${activeTab.charAt(0).toUpperCase() + activeTab.slice(1)}`}
>
- {data.map((item, index) => (
-
-
- {item.icon &&
{item.icon}}
-
{item.name === 'Unknown' ? 'Unknown' : item.name}
+ {isLoadingFull ? (
+
Loading...
+ ) : (
+ (fullData.length > 0 ? fullData : data).map((item, index) => (
+
+
+ {item.icon && {item.icon}}
+ {item.name === 'Unknown' ? 'Unknown' : item.name}
+
+
+ {formatNumber(item.pageviews)}
+
-
- {formatNumber(item.pageviews)}
-
-
- ))}
+ ))
+ )}
>
)
-}
+}
\ No newline at end of file
diff --git a/components/dashboard/TopReferrers.tsx b/components/dashboard/TopReferrers.tsx
index 90c0e28..b5cabe5 100644
--- a/components/dashboard/TopReferrers.tsx
+++ b/components/dashboard/TopReferrers.tsx
@@ -1,19 +1,24 @@
'use client'
-import { useState } from 'react'
+import { useState, useEffect } from 'react'
import { formatNumber } from '@/lib/utils/format'
import { getReferrerIcon } from '@/lib/utils/icons'
import { Modal } from '@ciphera-net/ui'
+import { getTopReferrers, TopReferrer } from '@/lib/api/stats'
interface TopReferrersProps {
referrers: Array<{ referrer: string; pageviews: number }>
collectReferrers?: boolean
+ siteId: string
+ dateRange: { start: string, end: string }
}
const LIMIT = 7
-export default function TopReferrers({ referrers, collectReferrers = true }: TopReferrersProps) {
+export default function TopReferrers({ referrers, collectReferrers = true, siteId, dateRange }: TopReferrersProps) {
const [isModalOpen, setIsModalOpen] = useState(false)
+ const [fullData, setFullData] = useState
([])
+ const [isLoadingFull, setIsLoadingFull] = useState(false)
// Filter out empty/unknown referrers
const filteredReferrers = (referrers || []).filter(
@@ -25,6 +30,29 @@ export default function TopReferrers({ referrers, collectReferrers = true }: Top
const emptySlots = Math.max(0, LIMIT - displayedReferrers.length)
const showViewAll = hasData && filteredReferrers.length > LIMIT
+ useEffect(() => {
+ if (isModalOpen) {
+ const fetchData = async () => {
+ setIsLoadingFull(true)
+ try {
+ const data = await getTopReferrers(siteId, dateRange.start, dateRange.end, 100)
+ // Filter fetched data too
+ const filtered = (data || []).filter(
+ ref => ref.referrer && ref.referrer !== 'Unknown' && ref.referrer !== ''
+ )
+ setFullData(filtered)
+ } catch (e) {
+ console.error(e)
+ } finally {
+ setIsLoadingFull(false)
+ }
+ }
+ fetchData()
+ } else {
+ setFullData([])
+ }
+ }, [isModalOpen, siteId, dateRange])
+
return (
<>
@@ -78,19 +106,23 @@ export default function TopReferrers({ referrers, collectReferrers = true }: Top
title="Top Referrers"
>
- {referrers?.map((ref, index) => (
-
-
-
{getReferrerIcon(ref.referrer)}
-
{ref.referrer}
+ {isLoadingFull ? (
+
Loading...
+ ) : (
+ (fullData.length > 0 ? fullData : filteredReferrers).map((ref, index) => (
+
+
+ {getReferrerIcon(ref.referrer)}
+ {ref.referrer}
+
+
+ {formatNumber(ref.pageviews)}
+
-
- {formatNumber(ref.pageviews)}
-
-
- ))}
+ ))
+ )}
>
)
-}
+}
\ No newline at end of file