Skip to content

Commit a572441

Browse files
authored
Merge pull request #279 from mikecao/dev
v0.80.0
2 parents 82b41f9 + dca5105 commit a572441

17 files changed

Lines changed: 118 additions & 34 deletions

assets/exclamation-triangle.svg

Lines changed: 1 addition & 0 deletions
Loading

components/common/ErrorMessage.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import React from 'react';
2+
import { FormattedMessage } from 'react-intl';
3+
import Icon from './Icon';
4+
import Exclamation from 'assets/exclamation-triangle.svg';
5+
import styles from './ErrorMessage.module.css';
6+
7+
export default function ErrorMessage() {
8+
return (
9+
<div className={styles.error}>
10+
<Icon icon={<Exclamation />} className={styles.icon} size="large" />
11+
<FormattedMessage id="message.failure" defaultMessage="Something went wrong." />
12+
</div>
13+
);
14+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.error {
2+
position: absolute;
3+
top: 50%;
4+
left: 50%;
5+
transform: translate(-50%, -50%);
6+
margin: auto;
7+
display: flex;
8+
z-index: 1;
9+
}
10+
11+
.icon {
12+
margin-right: 10px;
13+
}

components/common/MenuButton.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ export default function MenuButton({
99
icon,
1010
value,
1111
options,
12-
menuClassname,
12+
buttonClassName,
13+
menuClassName,
1314
menuPosition = 'bottom',
1415
menuAlign = 'right',
1516
onSelect,
@@ -38,15 +39,15 @@ export default function MenuButton({
3839
<div className={styles.container} ref={ref}>
3940
<Button
4041
icon={icon}
41-
className={classNames(styles.button, { [styles.open]: showMenu })}
42+
className={classNames(styles.button, buttonClassName, { [styles.open]: showMenu })}
4243
onClick={toggleMenu}
4344
variant="light"
4445
>
4546
<div className={styles.text}>{renderValue ? renderValue(selectedOption) : value}</div>
4647
</Button>
4748
{showMenu && (
4849
<Menu
49-
className={menuClassname}
50+
className={menuClassName}
5051
options={options}
5152
selectedOption={selectedOption}
5253
onSelect={handleSelect}

components/metrics/MetricsBar.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, { useState } from 'react';
22
import { FormattedMessage } from 'react-intl';
33
import classNames from 'classnames';
44
import Loading from 'components/common/Loading';
5+
import ErrorMessage from 'components/common/ErrorMessage';
56
import useFetch from 'hooks/useFetch';
67
import useDateRange from 'hooks/useDateRange';
78
import { formatShortTime, formatNumber, formatLongNumber } from 'lib/format';
@@ -17,7 +18,7 @@ export default function MetricsBar({ websiteId, token, className }) {
1718
query: { url },
1819
} = usePageQuery();
1920

20-
const { data } = useFetch(
21+
const { data, error, loading } = useFetch(
2122
`/api/website/${websiteId}/metrics`,
2223
{
2324
start_at: +startDate,
@@ -40,9 +41,9 @@ export default function MetricsBar({ websiteId, token, className }) {
4041

4142
return (
4243
<div className={classNames(styles.bar, className)} onClick={handleSetFormat}>
43-
{!data ? (
44-
<Loading />
45-
) : (
44+
{!data && loading && <Loading />}
45+
{error && <ErrorMessage />}
46+
{data && !error && (
4647
<>
4748
<MetricCard
4849
label={<FormattedMessage id="metrics.views" defaultMessage="Views" />}

components/metrics/MetricsTable.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { formatNumber, formatLongNumber } from 'lib/format';
1313
import useDateRange from 'hooks/useDateRange';
1414
import usePageQuery from 'hooks/usePageQuery';
1515
import styles from './MetricsTable.module.css';
16+
import ErrorMessage from '../common/ErrorMessage';
1617

1718
export default function MetricsTable({
1819
websiteId,
@@ -36,7 +37,7 @@ export default function MetricsTable({
3637
query: { url },
3738
} = usePageQuery();
3839

39-
const { data } = useFetch(
40+
const { data, loading, error } = useFetch(
4041
`/api/website/${websiteId}/rankings`,
4142
{
4243
type,
@@ -61,7 +62,7 @@ export default function MetricsTable({
6162
return items;
6263
}
6364
return [];
64-
}, [data, dataFilter, filterOptions]);
65+
}, [data, error, dataFilter, filterOptions]);
6566

6667
const handleSetFormat = () => setFormat(state => !state);
6768

@@ -86,8 +87,9 @@ export default function MetricsTable({
8687

8788
return (
8889
<div className={classNames(styles.container, className)}>
89-
{!data && <Loading />}
90-
{data && (
90+
{!data && loading && <Loading />}
91+
{error && <ErrorMessage />}
92+
{data && !error && (
9193
<>
9294
<div className={styles.header}>
9395
<div className={styles.title}>{title}</div>

components/metrics/WebsiteChart.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import usePageQuery from 'hooks/usePageQuery';
1313
import { getDateArray, getDateLength } from 'lib/date';
1414
import Times from 'assets/times.svg';
1515
import styles from './WebsiteChart.module.css';
16+
import ErrorMessage from '../common/ErrorMessage';
1617

1718
export default function WebsiteChart({
1819
websiteId,
@@ -31,7 +32,7 @@ export default function WebsiteChart({
3132
query: { url },
3233
} = usePageQuery();
3334

34-
const { data, loading } = useFetch(
35+
const { data, loading, error } = useFetch(
3536
`/api/website/${websiteId}/pageviews`,
3637
{
3738
start_at: +startDate,
@@ -83,6 +84,7 @@ export default function WebsiteChart({
8384
</div>
8485
<div className="row">
8586
<div className="col">
87+
{error && <ErrorMessage />}
8688
<PageviewsChart
8789
websiteId={websiteId}
8890
data={{ pageviews, uniques }}

components/settings/LanguageButton.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export default function LanguageButton() {
3333
icon={<Globe />}
3434
options={menuOptions}
3535
value={locale}
36-
menuClassname={styles.menu}
36+
menuClassName={styles.menu}
3737
renderValue={option => option?.display}
3838
onSelect={handleSelect}
3939
/>

hooks/useFetch.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,13 @@ export default function useFetch(url, params = {}, options = {}) {
2525

2626
dispatch(updateQuery({ url, time: performance.now() - time, completed: Date.now() }));
2727

28-
setData(data);
28+
if (status >= 400) {
29+
setError(data);
30+
setData(null);
31+
} else {
32+
setData(data);
33+
}
34+
2935
setStatus(status);
3036
onDataLoad(data);
3137
} catch (e) {

hooks/useForceSSL.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { useEffect } from 'react';
2+
import { useRouter } from 'next/router';
3+
4+
export default function useForceSSL(enabled) {
5+
const router = useRouter();
6+
7+
useEffect(() => {
8+
if (enabled && typeof window !== 'undefined' && /^http:\/\//.test(location.href)) {
9+
router.push(location.href.replace(/^http:\/\//, 'https://'));
10+
}
11+
}, [enabled]);
12+
13+
return null;
14+
}

0 commit comments

Comments
 (0)