diff --git a/assets/calendar-alt.svg b/assets/calendar-alt.svg
new file mode 100644
index 00000000..230c4e66
--- /dev/null
+++ b/assets/calendar-alt.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/components/common/Button.js b/components/common/Button.js
index d72fb662..b973b36e 100644
--- a/components/common/Button.js
+++ b/components/common/Button.js
@@ -29,6 +29,7 @@ export default function Button({
[styles.xsmall]: size === 'xsmall',
[styles.action]: variant === 'action',
[styles.danger]: variant === 'danger',
+ [styles.light]: variant === 'light',
[styles.disabled]: disabled,
})}
disabled={disabled}
diff --git a/components/common/Button.module.css b/components/common/Button.module.css
index 99c7168f..faae656b 100644
--- a/components/common/Button.module.css
+++ b/components/common/Button.module.css
@@ -55,7 +55,16 @@
background: var(--red400);
}
+.light {
+ background: var(--gray50);
+}
+
+.light:hover {
+ background: var(--gray75);
+}
+
.button:disabled {
+ cursor: default;
color: var(--gray500);
background: var(--gray75);
}
@@ -67,3 +76,7 @@
.button:disabled:hover {
background: var(--gray75);
}
+
+.button.light:disabled {
+ background: var(--gray50);
+}
diff --git a/components/common/Calendar.js b/components/common/Calendar.js
index 8ecf76a8..d9c281d3 100644
--- a/components/common/Calendar.js
+++ b/components/common/Calendar.js
@@ -160,7 +160,7 @@ const MonthSelector = ({ date, minDate, maxDate, locale, onSelect }) => {
const start = startOfYear(date);
const months = [];
for (let i = 0; i < 12; i++) {
- months.push(endOfMonth(addMonths(start, i)));
+ months.push(addMonths(start, i));
}
function handleSelect(value) {
@@ -173,7 +173,8 @@ const MonthSelector = ({ date, minDate, maxDate, locale, onSelect }) => {
{chunk(months, 3).map((row, i) => (
{row.map((month, j) => {
- const disabled = isBefore(month, minDate) || isAfter(month, maxDate);
+ const disabled =
+ isBefore(endOfMonth(month), minDate) || isAfter(startOfMonth(month), maxDate);
return (
{
}
- size="xsmall"
+ size="small"
className={styles.left}
onClick={handlePrevClick}
disabled={years[0] <= minYear}
+ variant="light"
/>
@@ -248,10 +250,11 @@ const YearSelector = ({ date, minDate, maxDate, onSelect }) => {
}
- size="xsmall"
+ size="small"
className={styles.right}
onClick={handleNextClick}
disabled={years[years.length - 1] > maxYear}
+ variant="light"
/>
);
diff --git a/components/common/Calendar.module.css b/components/common/Calendar.module.css
index ccfde683..ee5581bd 100644
--- a/components/common/Calendar.module.css
+++ b/components/common/Calendar.module.css
@@ -3,6 +3,7 @@
flex-direction: column;
font-size: var(--font-size-small);
flex: 1;
+ min-height: 285px;
}
.calendar table {
@@ -37,7 +38,7 @@
}
.calendar td.disabled {
- color: var(--gray300);
+ color: var(--gray400);
background: var(--gray75);
}
@@ -47,7 +48,7 @@
}
.calendar td.faded.disabled {
- color: var(--gray200);
+ background: var(--gray100);
}
.header {
diff --git a/components/common/DateFilter.js b/components/common/DateFilter.js
index a7ac6372..c43cb860 100644
--- a/components/common/DateFilter.js
+++ b/components/common/DateFilter.js
@@ -7,20 +7,33 @@ import DatePickerForm from 'components/forms/DatePickerForm';
import useLocale from 'hooks/useLocale';
import { getDateRange } from 'lib/date';
import { dateFormat } from 'lib/lang';
+import Calendar from 'assets/calendar-alt.svg';
+import Icon from './Icon';
const filterOptions = [
+ { label: , value: '1day' },
{
label: (
),
value: '24hour',
},
+ {
+ label: ,
+ value: '1week',
+ divider: true,
+ },
{
label: (
),
value: '7day',
},
+ {
+ label: ,
+ value: '1month',
+ divider: true,
+ },
{
label: (
@@ -33,26 +46,22 @@ const filterOptions = [
),
value: '90day',
},
- { label: , value: '1day' },
- { label: , value: '1week' },
- {
- label: ,
- value: '1month',
- },
{ label: , value: '1year' },
{
label: ,
value: 'custom',
+ divider: true,
},
];
export default function DateFilter({ value, startDate, endDate, onChange, className }) {
- const [locale] = useLocale();
const [showPicker, setShowPicker] = useState(false);
const displayValue =
- value === 'custom'
- ? `${dateFormat(startDate, 'd LLL y', locale)} — ${dateFormat(endDate, 'd LLL y', locale)}`
- : value;
+ value === 'custom' ? (
+ handleChange('custom')} />
+ ) : (
+ value
+ );
function handleChange(value) {
if (value === 'custom') {
@@ -90,3 +99,20 @@ export default function DateFilter({ value, startDate, endDate, onChange, classN
>
);
}
+
+const CustomRange = ({ startDate, endDate, onClick }) => {
+ const [locale] = useLocale();
+
+ function handleClick(e) {
+ e.stopPropagation();
+
+ onClick();
+ }
+
+ return (
+ <>
+ } className="mr-2" onClick={handleClick} />
+ {`${dateFormat(startDate, 'd LLL y', locale)} — ${dateFormat(endDate, 'd LLL y', locale)}`}
+ >
+ );
+};
diff --git a/components/common/DropDown.js b/components/common/DropDown.js
index 03fa8bb6..df559ef9 100644
--- a/components/common/DropDown.js
+++ b/components/common/DropDown.js
@@ -36,8 +36,8 @@ export default function DropDown({
return (
- {options.find(e => e.value === value)?.label || value}
- } size="small" />
+ {options.find(e => e.value === value)?.label || value}
+ } className={styles.icon} size="small" />
{showMenu && (
diff --git a/components/common/Dropdown.module.css b/components/common/Dropdown.module.css
index 958305e7..250e6c29 100644
--- a/components/common/Dropdown.module.css
+++ b/components/common/Dropdown.module.css
@@ -1,15 +1,24 @@
.dropdown {
- flex: 1;
position: relative;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
border: 1px solid var(--gray500);
border-radius: 4px;
cursor: pointer;
}
.value {
+ flex: 1;
display: flex;
justify-content: space-between;
font-size: var(--font-size-small);
- min-width: 140px;
+ flex-wrap: nowrap;
+ white-space: nowrap;
padding: 4px 16px;
+ min-width: 160px;
+}
+
+.icon {
+ padding-left: 10px;
}
diff --git a/components/common/LanguageButton.js b/components/common/LanguageButton.js
index 714ae7f6..0581a020 100644
--- a/components/common/LanguageButton.js
+++ b/components/common/LanguageButton.js
@@ -20,6 +20,10 @@ export default function LanguageButton({ menuPosition = 'bottom', menuAlign = 'l
setShowMenu(false);
}
+ function toggleMenu() {
+ setShowMenu(state => !state);
+ }
+
useDocumentClick(e => {
if (!ref.current.contains(e.target)) {
setShowMenu(false);
@@ -43,7 +47,7 @@ export default function LanguageButton({ menuPosition = 'bottom', menuAlign = 'l
)}
- } onClick={() => setShowMenu(true)} size="small">
+ } onClick={toggleMenu} size="small">
{selectedLocale}
{showMenu && (
diff --git a/components/common/Menu.js b/components/common/Menu.js
index 4cb5a885..283ee1fb 100644
--- a/components/common/Menu.js
+++ b/components/common/Menu.js
@@ -25,7 +25,7 @@ export default function Menu({
{options
.filter(({ hidden }) => !hidden)
.map(option => {
- const { label, value, className: customClassName, render } = option;
+ const { label, value, className: customClassName, render, divider } = option;
return render ? (
render(option)
@@ -34,6 +34,7 @@ export default function Menu({
key={value}
className={classNames(styles.option, optionClassName, customClassName, {
[selectedClassName]: selectedOption === value,
+ [styles.divider]: divider,
})}
onClick={e => onSelect(value, e)}
>
diff --git a/components/common/Menu.module.css b/components/common/Menu.module.css
index be394b71..9bcd642f 100644
--- a/components/common/Menu.module.css
+++ b/components/common/Menu.module.css
@@ -40,3 +40,7 @@
.right {
right: 0;
}
+
+.divider {
+ border-top: 1px solid var(--gray300);
+}
diff --git a/components/metrics/MetricCard.module.css b/components/metrics/MetricCard.module.css
index ed868f99..9c0d9e46 100644
--- a/components/metrics/MetricCard.module.css
+++ b/components/metrics/MetricCard.module.css
@@ -3,7 +3,7 @@
flex-direction: column;
justify-content: center;
min-width: 120px;
- margin-right: 20px;
+ padding-right: 20px;
}
.value {
@@ -16,4 +16,5 @@
.label {
font-size: var(--font-size-normal);
+ white-space: nowrap;
}
diff --git a/components/metrics/MetricsBar.module.css b/components/metrics/MetricsBar.module.css
index 4046634e..5f5cb1a7 100644
--- a/components/metrics/MetricsBar.module.css
+++ b/components/metrics/MetricsBar.module.css
@@ -4,6 +4,9 @@
}
@media only screen and (max-width: 992px) {
+ .bar {
+ justify-content: space-between;
+ }
.bar > div:last-child {
display: none;
}
diff --git a/components/metrics/WebsiteChart.js b/components/metrics/WebsiteChart.js
index 6b319a89..8cf01a5a 100644
--- a/components/metrics/WebsiteChart.js
+++ b/components/metrics/WebsiteChart.js
@@ -57,14 +57,17 @@ export default function WebsiteChart({
stickyClassName={styles.sticky}
enabled={stickyHeader}
>
-
-
+
+
+
+
+
+
diff --git a/components/metrics/WebsiteChart.module.css b/components/metrics/WebsiteChart.module.css
index 3bd9db19..ea0fcaee 100644
--- a/components/metrics/WebsiteChart.module.css
+++ b/components/metrics/WebsiteChart.module.css
@@ -29,3 +29,15 @@
border-bottom: 1px solid var(--gray300);
z-index: 3;
}
+
+.filter {
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+}
+
+@media only screen and (max-width: 992px) {
+ .filter {
+ display: block;
+ }
+}
diff --git a/lib/date.js b/lib/date.js
index e7e28036..363e68dd 100644
--- a/lib/date.js
+++ b/lib/date.js
@@ -88,14 +88,16 @@ export function getDateRange(value) {
}
export function getDateRangeValues(startDate, endDate) {
- if (differenceInHours(endDate, startDate) <= 48) {
- return { startDate: startOfHour(startDate), endDate: endOfHour(endDate), unit: 'hour' };
+ let unit = 'year';
+ if (differenceInHours(endDate, startDate) <= 72) {
+ unit = 'hour';
} else if (differenceInCalendarDays(endDate, startDate) <= 90) {
- return { startDate: startOfDay(startDate), endDate: endOfDay(endDate), unit: 'day' };
+ unit = 'day';
} else if (differenceInCalendarMonths(endDate, startDate) <= 24) {
- return { startDate: startOfMonth(startDate), endDate: endOfMonth(endDate), unit: 'month' };
+ unit = 'month';
}
- return { startDate: startOfYear(startDate), endDate: endOfYear(endDate), unit: 'year' };
+
+ return { startDate: startOfDay(startDate), endDate: endOfDay(endDate), unit };
}
const dateFuncs = {
@@ -112,11 +114,12 @@ export function getDateArray(data, startDate, endDate, unit) {
function findData(t) {
const x = data.find(e => {
- if (unit === 'day') {
- const [year, month, day] = e.t.split('-');
- return normalize(new Date(year, month - 1, day)).getTime() === t.getTime();
+ if (unit === 'hour') {
+ return normalize(new Date(e.t)).getTime() === t.getTime();
}
- return normalize(new Date(e.t)).getTime() === t.getTime();
+
+ const [year, month, day] = e.t.split('-');
+ return normalize(new Date(year, month - 1, day)).getTime() === t.getTime();
});
return x?.y || 0;
diff --git a/lib/lang.js b/lib/lang.js
index 3a91f118..f66aa0ac 100644
--- a/lib/lang.js
+++ b/lib/lang.js
@@ -37,9 +37,9 @@ export const menuOptions = [
{ label: 'Nederlands (Dutch)', value: 'nl-NL', display: 'NL' },
{ label: 'Deutsch (German)', value: 'de-DE', display: 'DE' },
{ label: '日本語 (Japanese)', value: 'ja-JP', display: '日本語' },
+ { label: 'Español (Mexicano)', value: 'es-MX', display: 'ES' },
{ label: 'Русский (Russian)', value: 'ru-RU', display: 'РУ' },
{ label: 'Turkish', value: 'tr-TR', display: 'TR' },
- { label: 'Español (Mexicano)', value: 'es-MX', display: 'ES' },
];
export function dateFormat(date, str, locale) {
diff --git a/pages/api/website/[id]/events.js b/pages/api/website/[id]/events.js
index c230acd1..143c745a 100644
--- a/pages/api/website/[id]/events.js
+++ b/pages/api/website/[id]/events.js
@@ -3,7 +3,7 @@ import { getEvents } from 'lib/queries';
import { ok, badRequest, methodNotAllowed } from 'lib/response';
import { useAuth } from 'lib/middleware';
-const unitTypes = ['month', 'hour', 'day'];
+const unitTypes = ['year', 'month', 'hour', 'day'];
export default async (req, res) => {
await useAuth(req, res);
|