Skip to content

Commit 8c78069

Browse files
authored
Merge pull request #306 from AmbireTech/advanced-stats
Advanced stats
2 parents 3b4ebc3 + c39f1b2 commit 8c78069

File tree

5 files changed

+227
-99
lines changed

5 files changed

+227
-99
lines changed

src/components/AdminPanel/SSPsAnalytics.tsx

+174-37
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,27 @@
11
import { useEffect, useState, useMemo } from 'react'
2-
import { Select, Stack, Group, Badge, Text, Loader, Code, NumberFormatter } from '@mantine/core'
2+
import {
3+
Select,
4+
Stack,
5+
Group,
6+
Badge,
7+
Text,
8+
Loader,
9+
Code,
10+
NumberFormatter,
11+
MultiSelect,
12+
Fieldset,
13+
Divider
14+
} from '@mantine/core'
315
import { SSPs, RequestStatPlacement, SSPsAnalyticsDataQuery } from 'types'
416
import useSSPsAnalytics from 'hooks/useCampaignAnalytics/useSSPsAnalytics'
517
import CustomTable, { DataElement } from 'components/common/CustomTable'
6-
import { removeOptionalEmptyStringProps } from 'helpers'
18+
import { removeOptionalEmptyStringProps, getEnumKeyByValue } from 'helpers'
719
import DownloadCSV from 'components/common/DownloadCSV'
20+
import { CountryData } from 'helpers/countries'
21+
import { IabTaxonomyV3 } from 'adex-common'
22+
import { CATEGORIES, CAT_GROUPS, COUNTRIES, REGION_GROUPS } from 'constants/createCampaign'
23+
import MultiSelectAndRadioButtons from 'components/CreateCampaign/StepTwo/MultiSelectAndRadioButtons'
24+
import useCreateCampaignContext from 'hooks/useCreateCampaignContext'
825

926
const sspsData: Array<{ value: SSPs | ''; label: string }> = [
1027
{ value: '', label: 'All SSPs' },
@@ -31,6 +48,38 @@ const groupByData: Array<{ value: string; label: string }> = [
3148
{ value: 'format', label: 'format' }
3249
]
3350

51+
const mapSegmentLabel = (
52+
type: SSPsAnalyticsDataQuery['groupBy'],
53+
segment: string | number
54+
): { label: string } => {
55+
let label = (segment || '').toString()
56+
57+
switch (type) {
58+
case 'country':
59+
label = `${CountryData.get(segment.toString().toUpperCase())?.name} (${segment
60+
.toString()
61+
.toUpperCase()})`
62+
break
63+
case 'category':
64+
label = `${getEnumKeyByValue(
65+
IabTaxonomyV3,
66+
segment.toString().toUpperCase() || ''
67+
)} (${segment.toString().toUpperCase()})`
68+
break
69+
70+
case 'placement':
71+
label = getEnumKeyByValue(RequestStatPlacement, segment)
72+
break
73+
74+
default:
75+
break
76+
}
77+
78+
return {
79+
label
80+
}
81+
}
82+
3483
const SSPsAnalytics = ({
3584
country,
3685
category,
@@ -40,6 +89,10 @@ const SSPsAnalytics = ({
4089
country?: SSPsAnalyticsDataQuery['country']
4190
format?: string[]
4291
}) => {
92+
// TODO: get all formats once then use it for src
93+
// NOTE: temp
94+
const { allowedBannerSizes } = useCreateCampaignContext()
95+
4396
const [analyticsKey, setAnalyticsKey] = useState<
4497
| {
4598
key: string
@@ -51,16 +104,20 @@ const SSPsAnalytics = ({
51104
const [groupBy, setGrop] = useState<SSPsAnalyticsDataQuery['groupBy']>('country')
52105
const [placement, setPlacement] = useState<RequestStatPlacement | ''>('')
53106
const { analyticsData, getAnalyticsKeyAndUpdate } = useSSPsAnalytics()
107+
const [selectedCountries, setCountries] = useState<SSPsAnalyticsDataQuery['country']>(
108+
country || { values: [], operator: 'in' }
109+
)
110+
const [selectedCategories, setCategories] = useState<SSPsAnalyticsDataQuery['category']>(
111+
category || { values: [], operator: 'in' }
112+
)
113+
114+
const [selectedFormats, setFormats] = useState<string[]>(format || [])
54115

55116
const analytics = useMemo(
56117
() => analyticsData.get(analyticsKey?.key || ''),
57118
[analyticsData, analyticsKey]
58119
)
59120

60-
useEffect(() => {
61-
console.log({ analytics })
62-
}, [analytics])
63-
64121
useEffect(() => {
65122
setAnalyticsKey(undefined)
66123

@@ -69,9 +126,9 @@ const SSPsAnalytics = ({
69126
...removeOptionalEmptyStringProps({
70127
ssp,
71128
placement,
72-
category,
73-
country,
74-
format
129+
category: selectedCategories,
130+
country: selectedCountries,
131+
format: selectedFormats
75132
}),
76133
groupBy
77134
})
@@ -80,7 +137,18 @@ const SSPsAnalytics = ({
80137
}
81138

82139
checkAnalytics()
83-
}, [category, country, format, getAnalyticsKeyAndUpdate, groupBy, placement, ssp])
140+
}, [
141+
category,
142+
country,
143+
format,
144+
getAnalyticsKeyAndUpdate,
145+
groupBy,
146+
placement,
147+
selectedCategories,
148+
selectedCountries,
149+
selectedFormats,
150+
ssp
151+
])
84152

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

@@ -91,45 +159,103 @@ const SSPsAnalytics = ({
91159
return {
92160
id: value.toString() + count.toString(),
93161
columns: [
94-
{ value: value.toString(), label: value.toString() },
162+
{
163+
value: value.toString(),
164+
element: mapSegmentLabel(groupBy, value).label
165+
},
95166
{ value: count, element: <NumberFormatter value={count} thousandSeparator /> }
96167
]
97168
}
98169
}) || [],
99170
totalRequests: analytics?.data.reduce((sum, i) => sum + i.count, 0) || 0
100171
}
101-
}, [analytics])
172+
}, [analytics?.data, groupBy])
102173

103174
return (
104175
<Stack gap="xs">
105176
<Text size="sm" inline c="purple">
106177
* This analytics are for the actual processed request from our SSRs (oRtb: BidRequest) for
107178
the <strong>48 hours</strong>
108179
</Text>
109-
<Group align="start" justify="left" gap="xs">
110-
<Select
111-
label="Group by"
112-
value={groupBy}
113-
onChange={(val) => setGrop(val as SSPsAnalyticsDataQuery['groupBy'])}
114-
data={groupByData}
115-
size="md"
116-
/>
117-
<Select
118-
label="SSP"
119-
value={ssp}
120-
onChange={(val) => setSsp(val as SSPs)}
121-
data={sspsData}
122-
size="md"
123-
/>
124-
<Select
125-
label="Placement"
126-
value={placement?.toString()}
127-
// @ts-ignore
128-
onChange={(val) => setPlacement(val !== '' ? Number(val) : val)}
129-
data={placementsData}
130-
size="md"
131-
/>
132-
</Group>
180+
<Fieldset>
181+
<Stack>
182+
<Group align="start" justify="left" gap="xl" grow>
183+
<Stack gap="xs">
184+
<Select
185+
label="Group by"
186+
value={groupBy}
187+
onChange={(val) => setGrop(val as SSPsAnalyticsDataQuery['groupBy'])}
188+
data={groupByData}
189+
searchable
190+
size="sm"
191+
/>
192+
<MultiSelect
193+
label="Formats"
194+
value={selectedFormats}
195+
onChange={setFormats}
196+
data={allowedBannerSizes}
197+
clearable
198+
searchable
199+
size="sm"
200+
/>
201+
</Stack>
202+
<Stack>
203+
<Select
204+
label="SSP"
205+
value={ssp}
206+
onChange={(val) => setSsp(val as SSPs)}
207+
data={sspsData}
208+
searchable
209+
size="sm"
210+
/>
211+
<Select
212+
label="Placement"
213+
value={placement?.toString()}
214+
// @ts-ignore
215+
onChange={(val) => setPlacement(val !== '' ? Number(val) : val)}
216+
data={placementsData}
217+
size="sm"
218+
/>
219+
</Stack>
220+
</Group>
221+
222+
<Group grow gap="xl" align="baseline">
223+
<Stack>
224+
<Divider size="md" label="Categories" color="mainText" />
225+
<MultiSelectAndRadioButtons
226+
onCategoriesChange={(selectedRadio, values) =>
227+
setCategories({
228+
values: values as IabTaxonomyV3[],
229+
operator: selectedRadio === 'all' ? undefined : selectedRadio
230+
})
231+
}
232+
multiSelectData={CATEGORIES}
233+
defaultRadioValue={selectedCategories?.operator}
234+
defaultSelectValue={selectedCategories?.values}
235+
groups={CAT_GROUPS}
236+
label="Categories"
237+
/>
238+
</Stack>
239+
<Stack>
240+
<Divider size="md" label="Countries" color="mainText" />
241+
242+
<MultiSelectAndRadioButtons
243+
onCategoriesChange={(selectedRadio, values) =>
244+
setCountries({
245+
values,
246+
operator: selectedRadio === 'all' ? undefined : selectedRadio
247+
})
248+
}
249+
defaultRadioValue={selectedCountries?.operator}
250+
defaultSelectValue={selectedCountries?.values}
251+
multiSelectData={COUNTRIES}
252+
groups={REGION_GROUPS}
253+
label="Countries"
254+
/>
255+
</Stack>
256+
</Group>
257+
</Stack>
258+
</Fieldset>
133259
<Group align="center" justify="left" gap="xs" pos="relative">
134260
<Badge size="lg" leftSection="Total requests">
135261
{loading ? <Loader type="dots" color="white" /> : data.totalRequests.toLocaleString()}
@@ -156,7 +282,18 @@ const SSPsAnalytics = ({
156282
loading={loading}
157283
/>
158284
<Code block>
159-
{JSON.stringify({ ssp, placement, category, country, format, groupBy }, null, 2)}
285+
{JSON.stringify(
286+
{
287+
ssp,
288+
placement,
289+
category: selectedCategories,
290+
country: selectedCountries,
291+
format,
292+
groupBy
293+
},
294+
null,
295+
2
296+
)}
160297
</Code>
161298
</Stack>
162299
</Stack>

src/components/CreateCampaign/StepTwo/MultiSelectAndRadioButtons.tsx

+17-24
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useCallback, useMemo, useState } from 'react'
2-
import { MantineTheme, MultiSelect, Radio, Stack, Text, getPrimaryShade } from '@mantine/core'
2+
import { MantineTheme, MultiSelect, SegmentedControl, Stack, getPrimaryShade } from '@mantine/core'
33
import { TargetingInputApplyProp } from 'adex-common/dist/types'
44
import { useColorScheme } from '@mantine/hooks'
55
import { createStyles } from '@mantine/emotion'
@@ -118,33 +118,26 @@ const MultiSelectAndRadioButtons = ({
118118
[groups, onCategoriesChange, selectedRadio]
119119
)
120120

121-
const labelText = useMemo(() => {
122-
if (selectedRadio === 'in') return `Select ${label}`
123-
if (selectedRadio === 'nin') return `Select ${label} to exclude`
124-
if (selectedRadio === 'all') return 'All selected'
125-
return ''
126-
}, [selectedRadio, label])
127-
128121
return (
129-
<>
130-
<Radio.Group value={selectedRadio} onChange={handleRadioChange} mb="md">
131-
<Stack gap="xs">
132-
<Radio label="Select All" value="all" />
133-
<Radio label={`Select ${label}`} value="in" />
134-
<Radio label={`Select All ${label} Except`} value="nin" />
135-
</Stack>
136-
</Radio.Group>
122+
<Stack gap="xs">
123+
<SegmentedControl
124+
color={selectedRadio === 'nin' ? 'warning' : 'brand'}
125+
size="sm"
126+
value={selectedRadio}
127+
onChange={handleRadioChange}
128+
withItemsBorders={false}
129+
data={[
130+
{ label: 'All selected', value: 'all' },
131+
{ label: 'Include selected', value: 'in' },
132+
{ label: 'Exclude selected', value: 'nin' }
133+
]}
134+
/>
137135
<MultiSelect
138-
label={
139-
<Text c="secondaryText" size="sm" fw="bold" mb="xs">
140-
{labelText}
141-
</Text>
142-
}
143136
clearable
144137
searchable
145138
variant="filled"
146-
size="lg"
147-
radius="lg"
139+
size="md"
140+
radius="md"
148141
// NOTE: just visually show the nothing but keeps the value in case of change - will not need to select again
149142
value={selectedRadio === 'all' ? [] : selectedValue}
150143
disabled={selectedRadio === 'all'}
@@ -157,7 +150,7 @@ const MultiSelectAndRadioButtons = ({
157150
pill: classes.pill
158151
}}
159152
/>
160-
</>
153+
</Stack>
161154
)
162155
}
163156

0 commit comments

Comments
 (0)