Initial expanded view in details.

This commit is contained in:
Mike Cao 2020-08-09 03:04:48 -07:00
parent b392a51676
commit f535dca7b9
14 changed files with 108 additions and 39 deletions

View File

@ -1,4 +1,4 @@
import React from 'react'; import React, { useState } from 'react';
import Page from 'components/layout/Page'; import Page from 'components/layout/Page';
import MenuLayout from 'components/layout/MenuLayout'; import MenuLayout from 'components/layout/MenuLayout';
import WebsiteSettings from './WebsiteSettings'; import WebsiteSettings from './WebsiteSettings';
@ -8,21 +8,16 @@ import { useSelector } from 'react-redux';
export default function Settings() { export default function Settings() {
const user = useSelector(state => state.user); const user = useSelector(state => state.user);
const [option, setOption] = useState('Websites');
const menuOptions = ['Websites', user.is_admin && 'Accounts', 'Profile']; const menuOptions = ['Websites', user.is_admin && 'Accounts', 'Profile'];
return ( return (
<Page> <Page>
<MenuLayout menu={menuOptions} selectedOption="Websites"> <MenuLayout menu={menuOptions} selectedOption={option} onMenuSelect={setOption}>
{option => { {option === 'Websites' && <WebsiteSettings />}
if (option === 'Websites') { {option === 'Accounts' && <AccountSettings />}
return <WebsiteSettings />; {option === 'Profile' && <ProfileSettings />}
} else if (option === 'Accounts') {
return <AccountSettings />;
} else if (option === 'Profile') {
return <ProfileSettings />;
}
}}
</MenuLayout> </MenuLayout>
</Page> </Page>
); );

View File

@ -9,15 +9,18 @@ import { get } from 'lib/web';
import { browserFilter, urlFilter, refFilter, deviceFilter, countryFilter } from 'lib/filters'; import { browserFilter, urlFilter, refFilter, deviceFilter, countryFilter } from 'lib/filters';
import styles from './WebsiteDetails.module.css'; import styles from './WebsiteDetails.module.css';
import PageHeader from './layout/PageHeader'; import PageHeader from './layout/PageHeader';
import MenuLayout from './layout/MenuLayout';
const pageviewClasses = 'col-md-12 col-lg-6'; const pageviewClasses = 'col-md-12 col-lg-6';
const sessionClasses = 'col-12 col-lg-4'; const sessionClasses = 'col-12 col-lg-4';
const menuOptions = ['Pages', 'Referrers', 'Browsers', 'Operating system', 'Devices', 'Countries'];
export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' }) { export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' }) {
const [data, setData] = useState(); const [data, setData] = useState();
const [chartLoaded, setChartLoaded] = useState(false); const [chartLoaded, setChartLoaded] = useState(false);
const [countryData, setCountryData] = useState(); const [countryData, setCountryData] = useState();
const [dateRange, setDateRange] = useState(getDateRange(defaultDateRange)); const [dateRange, setDateRange] = useState(getDateRange(defaultDateRange));
const [expand, setExpand] = useState();
const { startDate, endDate } = dateRange; const { startDate, endDate } = dateRange;
async function loadData() { async function loadData() {
@ -32,6 +35,14 @@ export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' })
setTimeout(() => setDateRange(values), 300); setTimeout(() => setDateRange(values), 300);
} }
function handleExpand(title) {
setExpand(title);
}
function handleMenuSelect(title) {
setExpand(title);
}
useEffect(() => { useEffect(() => {
if (websiteId) { if (websiteId) {
loadData(); loadData();
@ -55,7 +66,7 @@ export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' })
/> />
</div> </div>
</div> </div>
{chartLoaded && ( {chartLoaded && !expand && (
<> <>
<div className={classNames(styles.row, 'row')}> <div className={classNames(styles.row, 'row')}>
<div className={pageviewClasses}> <div className={pageviewClasses}>
@ -67,6 +78,7 @@ export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' })
startDate={startDate} startDate={startDate}
endDate={endDate} endDate={endDate}
dataFilter={urlFilter} dataFilter={urlFilter}
onExpand={handleExpand}
/> />
</div> </div>
<div className={pageviewClasses}> <div className={pageviewClasses}>
@ -78,6 +90,7 @@ export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' })
startDate={startDate} startDate={startDate}
endDate={endDate} endDate={endDate}
dataFilter={refFilter(data.domain)} dataFilter={refFilter(data.domain)}
onExpand={handleExpand}
/> />
</div> </div>
</div> </div>
@ -91,6 +104,7 @@ export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' })
startDate={startDate} startDate={startDate}
endDate={endDate} endDate={endDate}
dataFilter={browserFilter} dataFilter={browserFilter}
onExpand={handleExpand}
/> />
</div> </div>
<div className={sessionClasses}> <div className={sessionClasses}>
@ -101,6 +115,7 @@ export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' })
websiteId={websiteId} websiteId={websiteId}
startDate={startDate} startDate={startDate}
endDate={endDate} endDate={endDate}
onExpand={handleExpand}
/> />
</div> </div>
<div className={sessionClasses}> <div className={sessionClasses}>
@ -112,6 +127,7 @@ export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' })
startDate={startDate} startDate={startDate}
endDate={endDate} endDate={endDate}
dataFilter={deviceFilter} dataFilter={deviceFilter}
onExpand={handleExpand}
/> />
</div> </div>
</div> </div>
@ -129,11 +145,21 @@ export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' })
endDate={endDate} endDate={endDate}
dataFilter={countryFilter} dataFilter={countryFilter}
onDataLoad={data => setCountryData(data)} onDataLoad={data => setCountryData(data)}
onExpand={handleExpand}
/> />
</div> </div>
</div> </div>
</> </>
)} )}
{expand && (
<MenuLayout
className={styles.expand}
menuClassName={styles.menu}
menu={menuOptions}
selectedOption={expand}
onMenuSelect={handleMenuSelect}
/>
)}
</Page> </Page>
); );
} }

View File

@ -2,6 +2,14 @@
margin-bottom: 30px; margin-bottom: 30px;
} }
.expand {
border-top: 1px solid var(--gray300);
}
.menu {
font-size: var(--font-size-small);
}
.row { .row {
border-top: 1px solid var(--gray300); border-top: 1px solid var(--gray300);
min-height: 430px; min-height: 430px;

View File

@ -27,6 +27,7 @@ export default function WebsiteList() {
{data?.map(({ website_id, name }) => ( {data?.map(({ website_id, name }) => (
<div key={website_id} className={styles.website}> <div key={website_id} className={styles.website}>
<PageHeader> <PageHeader>
<div>
<Link <Link
href="/website/[...id]" href="/website/[...id]"
as={`/website/${website_id}/${name}`} as={`/website/${website_id}/${name}`}
@ -34,6 +35,7 @@ export default function WebsiteList() {
> >
{name} {name}
</Link> </Link>
</div>
<Button <Button
icon={<Arrow />} icon={<Arrow />}
onClick={() => onClick={() =>

View File

@ -1,5 +1,6 @@
.buttons { .buttons {
display: flex; display: flex;
align-content: center;
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
@ -10,7 +11,7 @@
margin-left: 10px; margin-left: 10px;
} }
.button { .buttons .button {
font-size: var(--font-size-xsmall); font-size: var(--font-size-xsmall);
padding: 4px 8px; padding: 4px 8px;
} }

View File

@ -1,7 +1,9 @@
import React, { useState, useEffect, useMemo } from 'react'; import React, { useState, useEffect, useMemo } from 'react';
import { useSpring, animated, config } from 'react-spring'; import { useSpring, animated, config } from 'react-spring';
import classNames from 'classnames'; import classNames from 'classnames';
import CheckVisible from '../helpers/CheckVisible'; import CheckVisible from 'components/helpers/CheckVisible';
import Button from 'components/common/Button';
import Arrow from 'assets/arrow-right.svg';
import { get } from 'lib/web'; import { get } from 'lib/web';
import { percentFilter } from 'lib/filters'; import { percentFilter } from 'lib/filters';
import styles from './RankingsChart.module.css'; import styles from './RankingsChart.module.css';
@ -16,6 +18,7 @@ export default function RankingsChart({
className, className,
dataFilter, dataFilter,
onDataLoad = () => {}, onDataLoad = () => {},
onExpand = () => {},
}) { }) {
const [data, setData] = useState(); const [data, setData] = useState();
@ -62,6 +65,11 @@ export default function RankingsChart({
<Row key={x} label={x} value={y} percent={z} animate={visible} /> <Row key={x} label={x} value={y} percent={z} animate={visible} />
))} ))}
</div> </div>
<div className={styles.footer}>
<Button icon={<Arrow />} size="xsmall" onClick={() => onExpand(title)}>
<div>More</div>
</Button>
</div>
</div> </div>
)} )}
</CheckVisible> </CheckVisible>

View File

@ -1,6 +1,6 @@
.container { .container {
position: relative; position: relative;
min-height: 430px; min-height: 460px;
font-size: var(--font-size-small); font-size: var(--font-size-small);
padding: 20px 0; padding: 20px 0;
display: flex; display: flex;
@ -90,6 +90,11 @@
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
} }
.footer {
display: flex;
justify-content: center;
}
@media only screen and (max-width: 992px) { @media only screen and (max-width: 992px) {
.container { .container {
min-height: auto; min-height: auto;

View File

@ -16,8 +16,9 @@ export default function Button({
<button <button
type={type} type={type}
className={classNames(styles.button, className, { className={classNames(styles.button, className, {
[styles.small]: size === 'small',
[styles.large]: size === 'large', [styles.large]: size === 'large',
[styles.small]: size === 'small',
[styles.xsmall]: size === 'xsmall',
[styles.action]: variant === 'action', [styles.action]: variant === 'action',
[styles.danger]: variant === 'danger', [styles.danger]: variant === 'danger',
})} })}

View File

@ -20,12 +20,20 @@
margin-left: 10px; margin-left: 10px;
} }
.large {
font-size: var(--font-size-large);
}
.medium {
font-size: var(--font-size-normal);
}
.small { .small {
font-size: var(--font-size-small); font-size: var(--font-size-small);
} }
.large { .xsmall {
font-size: var(--font-size-large); font-size: var(--font-size-xsmall);
} }
.action { .action {

View File

@ -2,7 +2,7 @@ import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import styles from './Icon.module.css'; import styles from './Icon.module.css';
export default function Icon({ icon, className, size = 'M' }) { export default function Icon({ icon, className, size = 'medium' }) {
return ( return (
<div <div
className={classNames(styles.icon, className, { className={classNames(styles.icon, className, {
@ -10,6 +10,7 @@ export default function Icon({ icon, className, size = 'M' }) {
[styles.large]: size === 'large', [styles.large]: size === 'large',
[styles.medium]: size === 'medium', [styles.medium]: size === 'medium',
[styles.small]: size === 'small', [styles.small]: size === 'small',
[styles.xsmall]: size === 'xsmall',
})} })}
> >
{icon} {icon}

View File

@ -32,3 +32,8 @@
width: 12px; width: 12px;
height: 12px; height: 12px;
} }
.xsmall > svg {
width: 10px;
height: 10px;
}

View File

@ -2,26 +2,34 @@ import React, { useState } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import styles from './MenuLayout.module.css'; import styles from './MenuLayout.module.css';
export default function MenuLayout({ menu, selectedOption, onMenuSelect, children }) { export default function MenuLayout({
const [option, setOption] = useState(selectedOption); menu,
selectedOption,
onMenuSelect,
className,
menuClassName,
contentClassName,
children,
}) {
function handleMenuSelect(option) {
onMenuSelect(option);
}
return ( return (
<div className={styles.container}> <div className={classNames(styles.container, className)}>
<div className={styles.menu}> <div className={classNames(styles.menu, menuClassName)}>
{menu.map(item => {menu.map(option =>
item ? ( option ? (
<div <div
className={classNames(styles.option, { [styles.active]: option === item })} className={classNames(styles.option, { [styles.active]: option === selectedOption })}
onClick={() => setOption(item)} onClick={() => handleMenuSelect(option)}
> >
{item} {option}
</div> </div>
) : null, ) : null,
)} )}
</div> </div>
<div className={styles.content}> <div className={classNames(styles.content, contentClassName)}>{children}</div>
{typeof children === 'function' ? children(option) : children}
</div>
</div> </div>
); );
} }

View File

@ -20,7 +20,7 @@
.option { .option {
padding: 8px 16px; padding: 8px 16px;
cursor: pointer; cursor: pointer;
min-width: 140px; min-width: 160px;
margin-right: 30px; margin-right: 30px;
border-radius: 4px; border-radius: 4px;
} }

View File

@ -2,6 +2,7 @@
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
align-content: center;
line-height: 80px; line-height: 80px;
font-size: var(--font-size-large); font-size: var(--font-size-large);
} }