Skip to content

Commit

Permalink
Merge pull request #111 from mikecao/dev
Browse files Browse the repository at this point in the history
v0.24.0
  • Loading branch information
mikecao authored Sep 8, 2020
2 parents a60cdc8 + ccca5d2 commit 8df3c21
Show file tree
Hide file tree
Showing 52 changed files with 1,566 additions and 248 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# production
/build
/public/umami.js
/lang-compiled

# misc
.DS_Store
Expand Down
1 change: 1 addition & 0 deletions assets/globe.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
47 changes: 39 additions & 8 deletions components/WebsiteDetails.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useState } from 'react';
import { FormattedMessage } from 'react-intl';
import classNames from 'classnames';
import WebsiteChart from 'components/metrics/WebsiteChart';
import WorldMap from 'components/common/WorldMap';
Expand Down Expand Up @@ -32,21 +33,51 @@ export default function WebsiteDetails({ websiteId }) {
size="xsmall"
onClick={() => setExpand(null)}
>
<div>Back</div>
<div>
<FormattedMessage id="button.back" defaultMessage="Back" />
</div>
</Button>
);

const menuOptions = [
{
render: BackButton,
},
{ label: 'Pages', value: 'url', component: PagesTable },
{ label: 'Referrers', value: 'referrer', component: ReferrersTable },
{ label: 'Browsers', value: 'browser', component: BrowsersTable },
{ label: 'Operating system', value: 'os', component: OSTable },
{ label: 'Devices', value: 'device', component: DevicesTable },
{ label: 'Countries', value: 'country', component: CountriesTable },
{ label: 'Events', value: 'event', component: EventsTable },
{
label: <FormattedMessage id="metrics.pages" defaultMessage="Pages" />,
value: 'url',
component: PagesTable,
},
{
label: <FormattedMessage id="metrics.browsers" defaultMessage="Browsers" />,
value: 'referrer',
component: ReferrersTable,
},
{
label: <FormattedMessage id="metrics.referrers" defaultMessage="Referrers" />,
value: 'browser',
component: BrowsersTable,
},
{
label: <FormattedMessage id="metrics.operating-system" defaultMessage="Operating system" />,
value: 'os',
component: OSTable,
},
{
label: <FormattedMessage id="metrics.devices" defaultMessage="Devices" />,
value: 'device',
component: DevicesTable,
},
{
label: <FormattedMessage id="metrics.countries" defaultMessage="Countries" />,
value: 'country',
component: CountriesTable,
},
{
label: <FormattedMessage id="metrics.events" defaultMessage="Events" />,
value: 'event',
component: EventsTable,
},
];

const tableProps = {
Expand Down
17 changes: 15 additions & 2 deletions components/WebsiteList.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import { FormattedMessage } from 'react-intl';
import { useRouter } from 'next/router';
import WebsiteChart from 'components/metrics/WebsiteChart';
import Page from 'components/layout/Page';
Expand All @@ -24,9 +25,21 @@ export default function WebsiteList() {
</div>
))}
{data.length === 0 && (
<EmptyPlaceholder msg={"You don't have any websites configured."}>
<EmptyPlaceholder
msg={
<FormattedMessage
id="placeholder.message.no-websites-configured"
defaultMessage="You don't have any websites configured."
/>
}
>
<Button icon={<Arrow />} size="medium" onClick={() => router.push('/settings')}>
<div>Go to settings</div>
<div>
<FormattedMessage
id="placeholder.message.go-to-settings"
defaultMessage="Go to settings"
/>
</div>
</Button>
</EmptyPlaceholder>
)}
Expand Down
25 changes: 14 additions & 11 deletions components/common/ButtonGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,20 @@ export default function ButtonGroup({
}) {
return (
<div className={classNames(styles.group, className)}>
{items.map(item => (
<Button
key={item}
className={classNames(styles.button, { [styles.selected]: selectedItem === item })}
size={size}
icon={icon}
onClick={() => onClick(item)}
>
{item}
</Button>
))}
{items.map(item => {
const { label, value } = item;
return (
<Button
key={value}
className={classNames(styles.button, { [styles.selected]: selectedItem === value })}
size={size}
icon={icon}
onClick={() => onClick(value)}
>
{label}
</Button>
);
})}
</div>
);
}
7 changes: 5 additions & 2 deletions components/common/CopyButton.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import React, { useState } from 'react';
import Button from './Button';
import { FormattedMessage } from 'react-intl';

const defaultText = 'Copy to clipboard';
const defaultText = (
<FormattedMessage id="button.copy-to-clipboard" defaultMessage="Copy to clipboard" />
);

export default function CopyButton({ element, ...props }) {
const [text, setText] = useState(defaultText);
Expand All @@ -10,7 +13,7 @@ export default function CopyButton({ element, ...props }) {
if (element?.current) {
element.current.select();
document.execCommand('copy');
setText('Copied!');
setText(<FormattedMessage id="message.copied" defaultMessage="Copied!" />);
window.getSelection().removeAllRanges();
}
}
Expand Down
40 changes: 32 additions & 8 deletions components/common/DateFilter.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,40 @@
import React from 'react';
import { getDateRange } from 'lib/date';
import DropDown from './DropDown';
import { FormattedMessage } from 'react-intl';

const filterOptions = [
{ label: 'Last 24 hours', value: '24hour' },
{ label: 'Last 7 days', value: '7day' },
{ label: 'Last 30 days', value: '30day' },
{ label: 'Last 90 days', value: '90day' },
{ label: 'Today', value: '1day' },
{ label: 'This week', value: '1week' },
{ label: 'This month', value: '1month' },
{ label: 'This year', value: '1year' },
{
label: (
<FormattedMessage id="label.last-hours" defaultMessage="Last {x} hours" values={{ x: 24 }} />
),
value: '24hour',
},
{
label: (
<FormattedMessage id="label.last-days" defaultMessage="Last {x} days" values={{ x: 7 }} />
),
value: '7day',
},
{
label: (
<FormattedMessage id="label.last-days" defaultMessage="Last {x} days" values={{ x: 30 }} />
),
value: '30day',
},
{
label: (
<FormattedMessage id="label.last-days" defaultMessage="Last {x} days" values={{ x: 90 }} />
),
value: '90day',
},
{ label: <FormattedMessage id="label.today" defaultMessage="Today" />, value: '1day' },
{ label: <FormattedMessage id="label.this-week" defaultMessage="This week" />, value: '1week' },
{
label: <FormattedMessage id="label.this-month" defaultMessage="This month" />,
value: '1month',
},
{ label: <FormattedMessage id="label.this-year" defaultMessage="This year" />, value: '1year' },
];

export default function DateFilter({ value, onChange, className }) {
Expand Down
45 changes: 45 additions & 0 deletions components/common/LanguageButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React, { useState, useRef } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import Globe from 'assets/globe.svg';
import useDocumentClick from 'hooks/useDocumentClick';
import { updateApp } from 'redux/actions/app';
import Menu from './Menu';
import Button from './Button';
import { menuOptions } from 'lib/lang';
import styles from './LanguageButton.module.css';

export default function LanguageButton({ menuPosition = 'bottom', menuAlign = 'left' }) {
const dispatch = useDispatch();
const [showMenu, setShowMenu] = useState(false);
const locale = useSelector(state => state.app.locale);
const ref = useRef();
const selectedLocale = menuOptions.find(e => e.value === locale)?.display;

function handleSelect(value) {
dispatch(updateApp({ locale: value }));
window.localStorage.setItem('locale', value);
setShowMenu(false);
}

useDocumentClick(e => {
if (!ref.current.contains(e.target)) {
setShowMenu(false);
}
});

return (
<div ref={ref} className={styles.container}>
<Button icon={<Globe />} onClick={() => setShowMenu(true)} size="small">
<div className={locale}>{selectedLocale}</div>
</Button>
{showMenu && (
<Menu
options={menuOptions}
onSelect={handleSelect}
float={menuPosition}
align={menuAlign}
/>
)}
</div>
);
}
5 changes: 5 additions & 0 deletions components/common/LanguageButton.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.container {
display: flex;
position: relative;
cursor: pointer;
}
2 changes: 1 addition & 1 deletion components/common/Modal.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
left: 50%;
transform: translate(-50%, -50%);
background: var(--gray50);
min-width: 200px;
min-width: 400px;
min-height: 100px;
z-index: 1;
border: 1px solid var(--gray300);
Expand Down
11 changes: 7 additions & 4 deletions components/common/UserButton.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useState, useRef } from 'react';
import { FormattedMessage } from 'react-intl';
import { useSelector } from 'react-redux';
import { useRouter } from 'next/router';
import Menu from './Menu';
Expand All @@ -17,14 +18,16 @@ export default function UserButton() {
const menuOptions = [
{
label: (
<>
Logged in as <b>{user.username}</b>
</>
<FormattedMessage
id="label.logged-in-as"
defaultMessage="Logged in as {username}"
values={{ username: <b>{user.username}</b> }}
/>
),
value: 'username',
className: styles.username,
},
{ label: 'Logout', value: 'logout' },
{ label: <FormattedMessage id="label.logout" defaultMessage="Logout" />, value: 'logout' },
];

function handleSelect(value) {
Expand Down
25 changes: 18 additions & 7 deletions components/forms/AccountEditForm.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useState } from 'react';
import { FormattedMessage } from 'react-intl';
import { Formik, Form, Field } from 'formik';
import { post } from 'lib/web';
import Button from 'components/common/Button';
Expand All @@ -18,10 +19,10 @@ const validate = ({ user_id, username, password }) => {
const errors = {};

if (!username) {
errors.username = 'Required';
errors.username = <FormattedMessage id="label.required" defaultMessage="Required" />;
}
if (!user_id && !password) {
errors.password = 'Required';
errors.password = <FormattedMessage id="label.required" defaultMessage="Required" />;
}

return errors;
Expand All @@ -36,7 +37,11 @@ export default function AccountEditForm({ values, onSave, onClose }) {
if (typeof response !== 'string') {
onSave();
} else {
setMessage(response || 'Something went wrong');
setMessage(
response || (
<FormattedMessage id="message.failure" defaultMessage="Something went wrong." />
),
);
}
};

Expand All @@ -50,20 +55,26 @@ export default function AccountEditForm({ values, onSave, onClose }) {
{() => (
<Form>
<FormRow>
<label htmlFor="username">Username</label>
<label htmlFor="username">
<FormattedMessage id="label.username" defaultMessage="Username" />
</label>
<Field name="username" type="text" />
<FormError name="username" />
</FormRow>
<FormRow>
<label htmlFor="password">Password</label>
<label htmlFor="password">
<FormattedMessage id="label.password" defaultMessage="Password" />
</label>
<Field name="password" type="password" />
<FormError name="password" />
</FormRow>
<FormButtons>
<Button type="submit" variant="action">
Save
<FormattedMessage id="button.save" defaultMessage="Save" />
</Button>
<Button onClick={onClose}>
<FormattedMessage id="button.cancel" defaultMessage="Cancel" />
</Button>
<Button onClick={onClose}>Cancel</Button>
</FormButtons>
<FormMessage>{message}</FormMessage>
</Form>
Expand Down
Loading

1 comment on commit 8df3c21

@vercel
Copy link

@vercel vercel bot commented on 8df3c21 Sep 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.