Skip to content

Commit

Permalink
Merge pull request #305 from AmbireTech/advanced-stats
Browse files Browse the repository at this point in the history
wip: Advanced stats
  • Loading branch information
ivopaunov authored Oct 18, 2024
2 parents f5a375a + 4bbe656 commit 6feedfa
Show file tree
Hide file tree
Showing 10 changed files with 430 additions and 10 deletions.
14 changes: 10 additions & 4 deletions src/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import useAccount from 'hooks/useAccount'
import Deposit from 'components/Deposit'
import CreateCampaign from 'components/CreateCampaign'
import { CreateCampaignContextProvider } from 'contexts/CreateCampaignContext/CreateCampaignContext'
import { CampaignsDataProvider, CampaignsAnalyticsProvider } from 'contexts/CampaignsContext'
import {
CampaignsDataProvider,
CampaignsAnalyticsProvider,
SSPsAnalyticsProvider
} from 'contexts/CampaignsContext'
import NotFound404 from 'components/404/404'
// import AdminPanel from './admin/Admin'
import { AccountDetails } from 'components/AdminPanel/AccountDetails'
Expand Down Expand Up @@ -78,9 +82,11 @@ export const router = createBrowserRouter(
<RequireAuth>
<CampaignsDataProvider type="user">
<CampaignsAnalyticsProvider>
<CreateCampaignContextProvider>
<UserPanel />
</CreateCampaignContextProvider>
<SSPsAnalyticsProvider>
<CreateCampaignContextProvider>
<UserPanel />
</CreateCampaignContextProvider>
</SSPsAnalyticsProvider>
</CampaignsAnalyticsProvider>
</CampaignsDataProvider>
</RequireAuth>
Expand Down
6 changes: 6 additions & 0 deletions src/components/AdminPanel/AdminPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { StickyPanel } from 'components/TopBar/TopBarStickyPanel'
import Invoices from 'components/Billing/Invoices'
import AdminAnalytics from './AdminAnalytics'
import Accounts from './Accounts'
import SSPsAnalytics from './SSPsAnalytics'
import { SspStats } from './SspStats'
// import { AccountDetails } from './AccountDetails'

Expand All @@ -29,6 +30,7 @@ const AdminPanel = () => {
<Tabs.Tab value="campaigns">All Campaigns</Tabs.Tab>
<Tabs.Tab value="invoices">Invoices</Tabs.Tab>
<Tabs.Tab value="validatorAnalytics">Validator Analytics</Tabs.Tab>
<Tabs.Tab value="sspAnalytics">SSPs Analytics</Tabs.Tab>
<Tabs.Tab value="sspStats">SSP stats</Tabs.Tab>
<Tabs.Tab value="accounts">Accounts</Tabs.Tab>
<Tabs.Tab value="user-account" disabled>
Expand All @@ -49,6 +51,10 @@ const AdminPanel = () => {
<AdminAnalytics />
</Tabs.Panel>

<Tabs.Panel value="sspAnalytics" pt="xs">
<SSPsAnalytics />
</Tabs.Panel>

<Tabs.Panel value="sspStats" pt="xs">
<SspStats />
</Tabs.Panel>
Expand Down
166 changes: 166 additions & 0 deletions src/components/AdminPanel/SSPsAnalytics.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import { useEffect, useState, useMemo } from 'react'
import { Select, Stack, Group, Badge, Text, Loader, Code, NumberFormatter } from '@mantine/core'
import { SSPs, RequestStatPlacement, SSPsAnalyticsDataQuery } from 'types'
import useSSPsAnalytics from 'hooks/useCampaignAnalytics/useSSPsAnalytics'
import CustomTable, { DataElement } from 'components/common/CustomTable'
import { removeOptionalEmptyStringProps } from 'helpers'
import DownloadCSV from 'components/common/DownloadCSV'

const sspsData: Array<{ value: SSPs | ''; label: string }> = [
{ value: '', label: 'All SSPs' },
{ value: 'Eskimi', label: 'Eskimi' },
{ value: 'Epom', label: 'Epom' },
{ value: 'Qortex', label: 'Qortex' }
]

const placementsData: Array<{ value: string; label: string }> = [
{ value: '', label: 'All placements' },
{ value: RequestStatPlacement.app.toString(), label: 'App' },
{ value: RequestStatPlacement.siteMobile.toString(), label: 'Site - Mobile' },
{ value: RequestStatPlacement.siteDesktop.toString(), label: 'Site - Desktop' },
{ value: RequestStatPlacement.other.toString(), label: 'Site - other' }
]

const groupByData: Array<{ value: string; label: string }> = [
{ value: 'bidfloor', label: 'bid Floor' },
{ value: 'date', label: 'date' },
{ value: 'category', label: 'category' },
{ value: 'placement', label: 'placement' },
{ value: 'country', label: 'country' },
{ value: 'ssp', label: 'ssp' },
{ value: 'format', label: 'format' }
]

const SSPsAnalytics = ({
country,
category,
format
}: {
category?: SSPsAnalyticsDataQuery['category']
country?: SSPsAnalyticsDataQuery['country']
format?: string[]
}) => {
const [analyticsKey, setAnalyticsKey] = useState<
| {
key: string
}
| undefined
>()

const [ssp, setSsp] = useState<SSPs>('')
const [groupBy, setGrop] = useState<SSPsAnalyticsDataQuery['groupBy']>('country')
const [placement, setPlacement] = useState<RequestStatPlacement | ''>('')
const { analyticsData, getAnalyticsKeyAndUpdate } = useSSPsAnalytics()

const analytics = useMemo(
() => analyticsData.get(analyticsKey?.key || ''),
[analyticsData, analyticsKey]
)

useEffect(() => {
console.log({ analytics })
}, [analytics])

useEffect(() => {
setAnalyticsKey(undefined)

const checkAnalytics = async () => {
const key = await getAnalyticsKeyAndUpdate({
...removeOptionalEmptyStringProps({
ssp,
placement,
category,
country,
format
}),
groupBy
})
setAnalyticsKey(key)
console.log('key', key)
}

checkAnalytics()
}, [category, country, format, getAnalyticsKeyAndUpdate, groupBy, placement, ssp])

const loading = useMemo(() => analytics?.status === 'loading', [analytics])

const data: { elements: DataElement[]; totalRequests: number } = useMemo(() => {
return {
elements:
analytics?.data.map(({ count, value }) => {
return {
id: value.toString() + count.toString(),
columns: [
{ value: value.toString(), label: value.toString() },
{ value: count, element: <NumberFormatter value={count} thousandSeparator /> }
]
}
}) || [],
totalRequests: analytics?.data.reduce((sum, i) => sum + i.count, 0) || 0
}
}, [analytics])

return (
<Stack gap="xs">
<Text size="sm" inline c="purple">
* This analytics are for the actual processed request from our SSRs (oRtb: BidRequest) for
the <strong>48 hours</strong>
</Text>
<Group align="start" justify="left" gap="xs">
<Select
label="Group by"
value={groupBy}
onChange={(val) => setGrop(val as SSPsAnalyticsDataQuery['groupBy'])}
data={groupByData}
size="md"
/>
<Select
label="SSP"
value={ssp}
onChange={(val) => setSsp(val as SSPs)}
data={sspsData}
size="md"
/>
<Select
label="Placement"
value={placement?.toString()}
// @ts-ignore
onChange={(val) => setPlacement(val !== '' ? Number(val) : val)}
data={placementsData}
size="md"
/>
</Group>
<Group align="center" justify="left" gap="xs" pos="relative">
<Badge size="lg" leftSection="Total requests">
{loading ? <Loader type="dots" color="white" /> : data.totalRequests.toLocaleString()}
</Badge>

<DownloadCSV
// TODO: fix anal type
// @ts-ignore
data={analytics?.data?.map((x) => ({
value: x.count,
segment: x.value.toString()
}))}
// mapHeadersToDataProperties={{ [analType]: 'segment', ...csvHeaders }}
filename={`${analyticsKey?.key || 'admin-data-export'}.csv`}
// disabled={loading}
disabled
/>
</Group>
<Stack>
<CustomTable
pageSize={10}
headings={[groupBy?.toString() || 'data', 'count']}
data={data.elements}
loading={loading}
/>
<Code block>
{JSON.stringify({ ssp, placement, category, country, format, groupBy }, null, 2)}
</Code>
</Stack>
</Stack>
)
}

export default SSPsAnalytics
32 changes: 32 additions & 0 deletions src/components/CampaignAnalytics/CampaignAnalytics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import GoBack from 'components/common/GoBack/GoBack'
import { StickyPanel } from 'components/TopBar/TopBarStickyPanel'
import { AdminBadge } from 'components/common/AdminBadge'
import { useCampaignsData } from 'hooks/useCampaignsData'
import SSPsAnalytics from 'components/AdminPanel/SSPsAnalytics'
import { IabTaxonomyV3 } from 'adex-common'
import Placements from './Placements'
import Creatives from './Creatives'
import SSPs from './SSPs'
Expand Down Expand Up @@ -70,6 +72,7 @@ const CampaignAnalytics = ({ isAdminPanel = false }: { isAdminPanel?: boolean })
<Tabs.Tab value="country">REGIONS</Tabs.Tab>
<Tabs.Tab value="adUnit">CREATIVES</Tabs.Tab>
{isAdminPanel && <Tabs.Tab value="ssp">SSPs</Tabs.Tab>}
{isAdminPanel && <Tabs.Tab value="sspAnalytics">SSPs request analytics</Tabs.Tab>}
</Tabs.List>
</Flex>
<Tabs.Panel value="timeframe">
Expand All @@ -87,6 +90,35 @@ const CampaignAnalytics = ({ isAdminPanel = false }: { isAdminPanel?: boolean })
<Tabs.Panel value="ssp">
<SSPs campaignId={id} forAdmin={isAdminPanel} />
</Tabs.Panel>
<Tabs.Panel value="sspAnalytics">
<SSPsAnalytics
category={{
values:
campaign?.targetingInput.inputs.categories.apply === 'all'
? []
: (campaign?.targetingInput.inputs.categories[
campaign?.targetingInput.inputs.categories.apply
] as IabTaxonomyV3[]),
operator:
campaign?.targetingInput.inputs.categories.apply === 'all'
? undefined
: campaign?.targetingInput.inputs.categories.apply
}}
country={{
values:
campaign?.targetingInput.inputs.location.apply === 'all'
? []
: campaign?.targetingInput.inputs.location[
campaign?.targetingInput.inputs.location.apply
],
operator:
campaign?.targetingInput.inputs.location.apply === 'all'
? undefined
: campaign?.targetingInput.inputs.location.apply
}}
format={campaign?.adUnits.map((x) => `${x.banner?.format.h}x${x.banner?.format.w}`)}
/>
</Tabs.Panel>
</Tabs>
</Container>
)
Expand Down
3 changes: 0 additions & 3 deletions src/components/CampaignAnalytics/SSPs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@ const SSPs = ({ forAdmin, campaignId }: { forAdmin: boolean; campaignId: string
[campaignMappedAnalytics, currencyName]
)

if (!campaignMappedAnalytics?.length) {
return <div>No placement found</div>
}
return <CustomTable headings={headings} data={elements} error={error} loading={loading} />
}

Expand Down
6 changes: 4 additions & 2 deletions src/contexts/CampaignsContext/CampaignsAnalyticsContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,10 @@ const CampaignsAnalyticsProvider: FC<PropsWithChildren> = ({ children }) => {

setAnalyticsData((prev) => {
const next = new Map(prev)
const nextAggr: { status: DataStatus; data: AnalyticsData[] } =
{ status: 'processed', data: analyticsDataRes?.aggr } || prev.get(dataKey)
const nextAggr: { status: DataStatus; data: AnalyticsData[] } = {
status: 'processed',
data: analyticsDataRes?.aggr || prev.get(dataKey)?.data
}
next.set(dataKey, nextAggr)
return next
})
Expand Down
Loading

0 comments on commit 6feedfa

Please sign in to comment.