Update rankings view.

This commit is contained in:
Mike Cao 2020-07-31 20:37:29 -07:00
parent ac2612924e
commit 65d44ff6a1
5 changed files with 94 additions and 24 deletions

View File

@ -1,6 +1,6 @@
.dropdown { .dropdown {
position: relative; position: relative;
font-size: 12px; font-size: 14px;
min-width: 140px; min-width: 140px;
} }
@ -19,7 +19,7 @@
border: 1px solid #b3b3b3; border: 1px solid #b3b3b3;
border-radius: 4px; border-radius: 4px;
overflow: hidden; overflow: hidden;
z-index: 1; z-index: 2;
} }
.option { .option {

View File

@ -6,7 +6,7 @@
opacity: 0; opacity: 0;
position: absolute; position: absolute;
pointer-events: none; pointer-events: none;
z-index: 2; z-index: 1;
} }
.content { .content {

View File

@ -10,12 +10,13 @@ export default function RankingsChart({
startDate, startDate,
endDate, endDate,
type, type,
heading,
className, className,
filterData, dataFilter,
}) { }) {
const [data, setData] = useState(); const [data, setData] = useState();
const rankings = useMemo(() => (data && filterData ? filterData(data) : data), [data]); const rankings = useMemo(() => (data && dataFilter ? dataFilter(data) : data), [data]);
const total = useMemo(() => rankings?.reduce((n, { y }) => n + y, 0) || 0, [rankings]); const total = useMemo(() => rankings?.reduce((n, { y }) => n + y, 0) || 0, [rankings]);
@ -41,14 +42,17 @@ export default function RankingsChart({
return ( return (
<div className={classNames(styles.container, className)}> <div className={classNames(styles.container, className)}>
<div className={styles.title}>{title}</div> <div className={styles.header}>
<div className={styles.title}>{title}</div>
<div className={styles.heading}>{heading}</div>
</div>
{rankings.map(({ x, y }, i) => (i <= 10 ? <Row label={x} value={y} total={total} /> : null))} {rankings.map(({ x, y }, i) => (i <= 10 ? <Row label={x} value={y} total={total} /> : null))}
</div> </div>
); );
} }
const Row = ({ label, value, total }) => { const Row = ({ label, value, total }) => {
const props = useSpring({ width: `${(value / total) * 100}%`, from: { width: '0%' } }); const props = useSpring({ width: (value / total) * 100, from: { width: 0 } });
const valueProps = useSpring({ y: value, from: { y: 0 } }); const valueProps = useSpring({ y: value, from: { y: 0 } });
return ( return (
@ -57,7 +61,10 @@ const Row = ({ label, value, total }) => {
<animated.div className={styles.value}> <animated.div className={styles.value}>
{valueProps.y.interpolate(y => y.toFixed(0))} {valueProps.y.interpolate(y => y.toFixed(0))}
</animated.div> </animated.div>
<animated.div className={styles.bar} style={{ ...props }} /> <div className={styles.percent}>
<animated.div>{props.width.interpolate(y => `${y.toFixed(0)}%`)}</animated.div>
<animated.div className={styles.bar} style={{ ...props }} />
</div>
</div> </div>
); );
}; };

View File

@ -1,6 +1,24 @@
.container { .container {
position: relative; position: relative;
min-height: 390px; min-height: 390px;
font-size: 14px;
}
.header {
display: flex;
line-height: 40px;
}
.title {
flex: 1;
font-weight: 600;
font-size: 16px;
}
.heading {
font-size: 14px;
text-align: center;
width: 100px;
} }
.row { .row {
@ -13,25 +31,32 @@
margin-bottom: 5px; margin-bottom: 5px;
} }
.title {
font-weight: 600;
line-height: 40px;
}
.label { .label {
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
flex: 1; flex: 2;
z-index: 1;
} }
.value { .value {
width: 50px;
text-align: right; text-align: right;
margin-right: 10px;
font-weight: 600;
}
.percent {
width: 50px;
color: #6e6e6e;
position: relative;
border-left: 1px solid #6e6e6e;
padding-left: 10px;
} }
.bar { .bar {
position: absolute; position: absolute;
top: 0;
left: 0;
height: 30px; height: 30px;
opacity: 0.1; opacity: 0.1;
background: #2680eb; background: #2680eb;

View File

@ -18,22 +18,54 @@ const deviceFilter = data => {
(obj, { x, y }) => { (obj, { x, y }) => {
const [width] = x.split('x'); const [width] = x.split('x');
if (width >= 1920) { if (width >= 1920) {
obj.desktop += +y; obj.Desktop += +y;
} else if (width >= 1024) { } else if (width >= 1024) {
obj.laptop += +y; obj.Laptop += +y;
} else if (width >= 767) { } else if (width >= 767) {
obj.tablet += +y; obj.Tablet += +y;
} else { } else {
obj.mobile += +y; obj.Mobile += +y;
} }
return obj; return obj;
}, },
{ desktop: 0, laptop: 0, tablet: 0, mobile: 0 }, { Desktop: 0, Laptop: 0, Tablet: 0, Mobile: 0 },
); );
return Object.keys(devices).map(key => ({ x: key, y: devices[key] })); return Object.keys(devices).map(key => ({ x: key, y: devices[key] }));
}; };
const browsers = {
aol: 'AOL',
edge: 'Edge',
'edge-ios': 'Edge (iOS)',
yandexbrowser: 'Yandex',
kakaotalk: 'KKaoTalk',
samsung: 'Samsung',
silk: 'Silk',
miui: 'MIUI',
beaker: 'Beaker',
'edge-chromium': 'Edge (Chromium)',
chrome: 'Chrome',
'chromium-webview': 'Chrome (webview)',
phantomjs: 'PhantomJS',
crios: 'CriOS',
firefox: 'Firefox',
fxios: 'Firefox (iOS)',
'opera-mini': 'Opera Mini',
opera: 'Opera',
ie: 'IE',
bb10: 'BlackBerry 10',
android: 'Android',
ios: 'iOS',
safari: 'Safari',
facebook: 'Facebook',
instagram: 'Instagram',
'ios-webview': 'iOS (webview)',
searchbot: 'Searchbot',
};
const browserFilter = data => data.map(({ x, y }) => ({ x: browsers[x] || x, y }));
export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' }) { export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' }) {
const [data, setData] = useState(); const [data, setData] = useState();
const [dateRange, setDateRange] = useState(getDateRange(defaultDateRange)); const [dateRange, setDateRange] = useState(getDateRange(defaultDateRange));
@ -69,48 +101,54 @@ export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' })
<RankingsChart <RankingsChart
title="Top URLs" title="Top URLs"
type="url" type="url"
heading="Views"
className="col-12 col-md-8 col-lg-6" className="col-12 col-md-8 col-lg-6"
websiteId={data.website_id} websiteId={data.website_id}
startDate={startDate} startDate={startDate}
endDate={endDate} endDate={endDate}
filterData={urlFilter} dataFilter={urlFilter}
/> />
<RankingsChart <RankingsChart
title="Top referrers" title="Top referrers"
type="referrer" type="referrer"
heading="Views"
className="col-12 col-md-8 col-lg-6" className="col-12 col-md-8 col-lg-6"
websiteId={data.website_id} websiteId={data.website_id}
startDate={startDate} startDate={startDate}
endDate={endDate} endDate={endDate}
filterData={refFilter} dataFilter={refFilter}
/> />
</div> </div>
<div className={classNames(styles.row, 'row justify-content-between')}> <div className={classNames(styles.row, 'row justify-content-between')}>
<RankingsChart <RankingsChart
title="Browsers" title="Browsers"
type="browser" type="browser"
heading="Visitors"
className="col-12 col-md-8 col-lg-4" className="col-12 col-md-8 col-lg-4"
websiteId={data.website_id} websiteId={data.website_id}
startDate={startDate} startDate={startDate}
endDate={endDate} endDate={endDate}
dataFilter={browserFilter}
/> />
<RankingsChart <RankingsChart
title="Operating system" title="Operating system"
type="os" type="os"
heading="Visitors"
className="col-12 col-md-8 col-lg-4" className="col-12 col-md-8 col-lg-4"
websiteId={data.website_id} websiteId={data.website_id}
startDate={startDate} startDate={startDate}
endDate={endDate} endDate={endDate}
filterData={osFilter} dataFilter={osFilter}
/> />
<RankingsChart <RankingsChart
title="Devices" title="Devices"
type="screen" type="screen"
heading="Visitors"
className="col-12 col-md-8 col-lg-4" className="col-12 col-md-8 col-lg-4"
websiteId={data.website_id} websiteId={data.website_id}
startDate={startDate} startDate={startDate}
endDate={endDate} endDate={endDate}
filterData={deviceFilter} dataFilter={deviceFilter}
/> />
</div> </div>
</> </>