Skip to content

Commit

Permalink
Merge pull request #271 from AmbireTech/selectable-table
Browse files Browse the repository at this point in the history
Selectable table
  • Loading branch information
ivopaunov authored Aug 19, 2024
2 parents 2fa6737 + 8ddbf07 commit c4bbeb5
Show file tree
Hide file tree
Showing 10 changed files with 362 additions and 150 deletions.
10 changes: 5 additions & 5 deletions src/components/AdminPanel/AdminAnalytics.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect, useState, useMemo, useCallback } from 'react'
import { Select, Loader, Flex, Box, Text, Badge, ActionIcon } from '@mantine/core'
import { Select, Loader, Flex, Box, Text, Badge, ActionIcon, Stack, Group } from '@mantine/core'
import { BaseAnalyticsData, AnalyticsPeriod, Timeframe, AnalyticsType, SSPs } from 'types'
import useCampaignAnalytics from 'hooks/useCampaignAnalytics'
import CustomTable from 'components/common/CustomTable'
Expand Down Expand Up @@ -259,8 +259,8 @@ const AdminAnalytics = () => {
{loading ? (
<Loader size="xl" type="dots" color="violet" />
) : (
<Flex direction="column" mt="md">
<Flex direction="row" align="center" justify="left" gap="xs" mb="md">
<Stack>
<Group align="center" justify="left" gap="xs">
<Box>Totals: </Box>
<Badge
leftSection={
Expand Down Expand Up @@ -301,15 +301,15 @@ const AdminAnalytics = () => {
filename={`${analyticsKey?.key || 'admin-data-export'}.csv`}
disabled={loading}
/>
</Flex>
</Group>

<CustomTable
headings={headings}
elements={data.elements}
pageSize={10}
actions={analType === 'campaignId' ? actions : undefined}
/>
</Flex>
</Stack>
)}
</>
)
Expand Down
14 changes: 8 additions & 6 deletions src/components/CampaignAnalytics/Creatives.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useMemo } from 'react'
import CustomTable from 'components/common/CustomTable'
import { Flex, Anchor, Stack, Group } from '@mantine/core'
import { Flex, Anchor } from '@mantine/core'
import UrlIcon from 'resources/icons/Url'
import { formatCurrency } from 'helpers'
import { getMediaUrlWithProvider } from 'helpers/createCampaignHelpers'
Expand Down Expand Up @@ -58,17 +58,19 @@ const Creatives = ({ forAdmin, campaignId }: { forAdmin: boolean; campaignId: st
}, [campaign, campaignMappedAnalytics, currencyName, loading])

return (
<Stack gap="xs">
<Group align="center" justify="end">
<CustomTable
headings={headings}
elements={elements}
loading={loading}
tableActions={
<DownloadCSV
data={campaignMappedAnalytics}
mapHeadersToDataProperties={csvHeaders}
filename={`${analyticsKey?.key}.csv`}
disabled={loading}
/>
</Group>
<CustomTable headings={headings} elements={elements} loading={loading} />
</Stack>
}
/>
)
}

Expand Down
99 changes: 73 additions & 26 deletions src/components/CampaignAnalytics/Placements.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
import { CampaignStatus } from 'adex-common'
import CustomTable, { TableElement, TableRowAction } from 'components/common/CustomTable'
import { getHumneSrcName } from 'helpers'
import { useMemo } from 'react'
import IncludeIcon from 'resources/icons/Include'
import ExcludeIcon from 'resources/icons/Exclude'
import { ReactNode, useCallback, useMemo } from 'react'
import { useCampaignsData } from 'hooks/useCampaignsData'
import { useCampaignsAnalyticsData } from 'hooks/useCampaignAnalytics/useCampaignAnalyticsData'
import { Stack, Group } from '@mantine/core'
import { Group, ThemeIcon, Text } from '@mantine/core'
import DownloadCSV from 'components/common/DownloadCSV'
import BlockIcon from 'resources/icons/Block'

type PlacementsTableElement = Omit<TableElement, 'actionData'> & {
actionData: {
placementName: string
srcId: string
isBlocked: boolean
segment: string
srcName: string
}
id: string
placementName: string
placementName: string | ReactNode
impressions: string
clicks: string
ctr: string
Expand All @@ -31,7 +30,7 @@ const Placements = ({ forAdmin, campaignId }: { forAdmin: boolean; campaignId: s
forAdmin,
analyticsType: 'hostname'
})
const { toggleBlockedSource } = useCampaignsData()
const { filterSources } = useCampaignsData()

const placement = useMemo(
() => campaign?.targetingInput.inputs.placements.in[0] || 'site',
Expand Down Expand Up @@ -68,16 +67,25 @@ const Placements = ({ forAdmin, campaignId }: { forAdmin: boolean; campaignId: s
? []
: campaignMappedAnalytics.map((item) => {
const isBlocked = !!campaign.targetingInput.inputs.publishers.nin.includes(item.segment)
const placementName = getHumneSrcName(item.segment, placement)
const srcName = getHumneSrcName(item.segment, placement)
const data: PlacementsTableElement = {
rowColor: isBlocked ? 'red' : 'inherit',
rowColor: isBlocked ? 'warning' : 'inherit',
actionData: {
placementName,
srcName,
isBlocked,
segment: item.segment
srcId: item.segment
},
id: item.segment,
placementName,
placementName: isBlocked ? (
<Group align="center">
<ThemeIcon size="xs" variant="transparent" c="inherit">
<BlockIcon size="100%" />
</ThemeIcon>{' '}
<Text c="inherit">{srcName}</Text>
</Group>
) : (
srcName
),
impressions: item.impressions.toLocaleString(),
clicks: item.clicks.toLocaleString(),
ctr: `${item.ctr} %`,
Expand All @@ -96,39 +104,78 @@ const Placements = ({ forAdmin, campaignId }: { forAdmin: boolean; campaignId: s
]
)

const actions = useMemo(() => {
const filterSrc = useCallback(
({
action,
sources
}: {
action: 'include' | 'exclude'
sources: { srcName: string; srcId: string }[]
}) => {
if (!campaign?.id) return
filterSources(action, campaign?.id, sources)
},
[campaign?.id, filterSources]
)

const selectedActions = useMemo(() => {
if (!campaign?.id) return []
const placementActions: TableRowAction[] = [
CampaignStatus.active,
CampaignStatus.paused
].includes(campaign.status)
? [
{
action: (props: PlacementsTableElement['actionData']) =>
toggleBlockedSource(campaign?.id, props.placementName, props.segment),
label: ({ isBlocked, placementName }: PlacementsTableElement['actionData']) =>
`${isBlocked ? 'Unblock' : 'Block'} "${placementName}"`,
icon: ({ isBlocked }: PlacementsTableElement['actionData']) =>
isBlocked ? <IncludeIcon /> : <ExcludeIcon />
action: (props: PlacementsTableElement['actionData'][]) =>
filterSrc({
action: 'exclude',
sources: props.map(({ srcId, srcName }) => ({
srcId,
srcName
}))
}),
label: (selectedElements) => `Block selected (${selectedElements?.size})`,
icon: (
<ThemeIcon variant="transparent" size="xs">
<BlockIcon size="14px" />
</ThemeIcon>
),
color: 'warning'
},
{
action: (props: PlacementsTableElement['actionData'][]) =>
filterSrc({
action: 'include',
sources: props.map(({ srcId, srcName }) => ({
srcId,
srcName
}))
}),
label: (selectedElements) => `Unblock selected (${selectedElements?.size})`,
// icon: () => <VisibilityIcon size="10px" />,
color: 'success'
}
]
: []

return placementActions
}, [campaign, toggleBlockedSource])
}, [campaign?.id, campaign?.status, filterSrc])

return (
<Stack gap="xs">
<Group align="center" justify="end">
<CustomTable
headings={headings}
elements={elements}
loading={loading}
selectedActions={selectedActions}
tableActions={
<DownloadCSV
data={campaignMappedAnalytics}
mapHeadersToDataProperties={csvHeaders}
filename={`${analyticsKey?.key}.csv`}
disabled={loading}
/>
</Group>
<CustomTable headings={headings} elements={elements} actions={actions} loading={loading} />
</Stack>
}
/>
)
}

Expand Down
51 changes: 29 additions & 22 deletions src/components/CampaignAnalytics/Regions.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useMemo, useState } from 'react'
import { Group, Modal, Button, Stack } from '@mantine/core'
import { Group, Modal, Button, Box } from '@mantine/core'
import { useViewportSize } from '@mantine/hooks'
import { CountryData } from 'helpers/countries'
import CustomTable from 'components/common/CustomTable'
Expand Down Expand Up @@ -50,26 +50,33 @@ const Regions = ({ forAdmin, campaignId }: { forAdmin: boolean; campaignId: stri
}, [campaignMappedAnalytics, currencyName])

return (
<Stack gap="xs">
<Group align="center" justify="end">
<Button
variant="transparent"
color="mainText"
size="sm"
onClick={() => setIsMapVisible((prev) => !prev)}
rightSection={<MapIcon size="1rem" />}
disabled={loading}
>
See on Map{' '}
</Button>
<DownloadCSV
data={campaignMappedAnalytics}
mapHeadersToDataProperties={csvHeaders}
filename={`${analyticsKey?.key}.csv`}
disabled={loading}
/>
<CustomTable headings={headings} elements={elements} loading={loading} />
</Group>
<Box>
<CustomTable
headings={headings}
elements={elements}
loading={loading}
tableActions={
<Group align="center" justify="end" gap="xs">
<Button
variant="transparent"
color="mainText"
size="sm"
onClick={() => setIsMapVisible((prev) => !prev)}
rightSection={<MapIcon size="1rem" />}
disabled={loading}
>
See on Map
</Button>
<DownloadCSV
data={campaignMappedAnalytics}
mapHeadersToDataProperties={csvHeaders}
filename={`${analyticsKey?.key}.csv`}
disabled={loading}
/>
</Group>
}
/>

<Modal
opened={isMapVisible}
onClose={() => setIsMapVisible(false)}
Expand All @@ -79,7 +86,7 @@ const Regions = ({ forAdmin, campaignId }: { forAdmin: boolean; campaignId: stri
>
<GeoCustom width={width} height={height} regions={campaignMappedAnalytics} />
</Modal>
</Stack>
</Box>
)
}

Expand Down
2 changes: 1 addition & 1 deletion src/components/CreateCampaign/CreateCampaignCommon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const UtmInfo = ({ title = '', placement }: { title: string; placement?:
<Group>
<Text size="inherit">{title}</Text>
<ActionIcon size="sm" variant="transparent">
<InfoIcon size="inherit" />
<InfoIcon size="100%" />
</ActionIcon>
</Group>
</HoverCard.Target>
Expand Down
7 changes: 3 additions & 4 deletions src/components/Dashboard/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import {
import { Container, Flex, Text, Loader, UnstyledButton, Anchor, Box } from '@mantine/core'
import { useCallback, useEffect, useMemo, useState } from 'react'
import CustomTable, { TableElement, TableRowAction } from 'components/common/CustomTable'
import { periodNumberToDate } from 'helpers'
import { useNavigate } from 'react-router-dom'
import { useCampaignsData } from 'hooks/useCampaignsData'
import { parseBigNumTokenAmountToDecimal } from 'helpers/balances'
import { parseBigNumTokenAmountToDecimal, maskAddress, periodNumberToDate } from 'helpers'
import useCreateCampaignContext from 'hooks/useCreateCampaignContext'
import useCustomNotifications from 'hooks/useCustomNotifications'
import { modals } from '@mantine/modals'
Expand Down Expand Up @@ -139,7 +138,7 @@ const Dashboard = ({ isAdminPanel, accountId }: { isAdminPanel?: boolean; accoun
rowColor: archived ? 'red' : undefined,
id: cmpData.campaignId,
title: (
<Text size="sm" truncate>
<Text truncate maw={256}>
{archived && (
<BadgeStatusCampaign type={cmpData.campaign.status} isArchived={archived} />
)}
Expand All @@ -152,7 +151,7 @@ const Dashboard = ({ isAdminPanel, accountId }: { isAdminPanel?: boolean; accoun
href={`/dashboard/admin/user-account/${campaign.owner}`}
c="secondaryText"
>
{campaign.owner}
{maskAddress(campaign.owner)}
</Anchor>
</Box>
)}
Expand Down
Loading

0 comments on commit c4bbeb5

Please sign in to comment.