From 02a1438cfe79c7e3ddc05a238cc8d7653821f582 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Mon, 30 Jan 2023 21:44:07 -0800 Subject: [PATCH] More refactoring. --- components/buttons/LanguageButton.js | 6 +- components/buttons/ThemeButton.js | 6 +- components/buttons/UserButton.js | 2 +- components/common/Calendar.js | 280 ------------------ components/common/Calendar.module.css | 110 ------- components/common/CopyButton.js | 37 --- components/common/DropDown.js | 66 ----- components/common/Dropdown.module.css | 27 -- components/common/FilterLink.js | 5 +- components/common/HamburgerButton.js | 9 +- components/common/MobileMenu.js | 20 +- components/common/RefreshButton.js | 14 +- components/icons.js | 6 +- components/layout/AppLayout.js | 6 +- components/layout/Header.js | 2 +- components/layout/NavBar.js | 28 +- components/layout/PageHeader.js | 17 +- components/layout/PageHeader.module.css | 4 +- components/messages.js | 4 +- components/metrics/DatePickerForm.js | 65 ++-- components/metrics/DatePickerForm.module.css | 8 + components/metrics/MetricsTable.js | 5 +- components/metrics/RealtimeHeader.js | 17 +- components/pages/console/TestConsole.js | 57 ++-- .../pages/console/TestConsole.module.css | 6 + .../settings/profile/PasswordChangeButton.js | 4 +- .../pages/settings/profile/ProfileDetails.js | 6 +- .../pages/settings/teams/TeamEditForm.js | 2 +- .../pages/settings/teams/TeamMembersTable.js | 20 +- .../pages/settings/websites/WebsitesTable.js | 17 +- components/pages/websites/WebsiteDetails.js | 9 +- lib/middleware.ts | 20 +- package.json | 4 +- pages/console/[[...id]].js | 5 +- pages/settings/teams/[...id].js | 2 +- pages/settings/teams/index.js | 2 +- pages/settings/users/[...id].js | 2 +- pages/settings/users/index.js | 2 +- pages/settings/websites/[id]/index.js | 4 +- pages/sso.js | 3 +- yarn.lock | 8 +- 41 files changed, 196 insertions(+), 721 deletions(-) delete mode 100644 components/common/Calendar.js delete mode 100644 components/common/Calendar.module.css delete mode 100644 components/common/CopyButton.js delete mode 100644 components/common/DropDown.js delete mode 100644 components/common/Dropdown.module.css diff --git a/components/buttons/LanguageButton.js b/components/buttons/LanguageButton.js index ed9c6682..687f639f 100644 --- a/components/buttons/LanguageButton.js +++ b/components/buttons/LanguageButton.js @@ -1,9 +1,9 @@ -import { Icon, Button, PopupTrigger, Popup, Tooltip, Icons, Text } from 'react-basics'; +import { Icon, Button, PopupTrigger, Popup, Tooltip, Text } from 'react-basics'; import { useIntl } from 'react-intl'; import classNames from 'classnames'; import { languages } from 'lib/lang'; import useLocale from 'hooks/useLocale'; -import { Globe } from 'components/icons'; +import Icons from 'components/icons'; import { labels } from 'components/messages'; import styles from './LanguageButton.module.css'; @@ -21,7 +21,7 @@ export default function LanguageButton({ tooltipPosition = 'top' }) { {formatMessage(labels.language)} diff --git a/components/buttons/ThemeButton.js b/components/buttons/ThemeButton.js index f3d91e4f..4af80882 100644 --- a/components/buttons/ThemeButton.js +++ b/components/buttons/ThemeButton.js @@ -2,7 +2,7 @@ import { useTransition, animated } from 'react-spring'; import { Button, Icon, PopupTrigger, Tooltip } from 'react-basics'; import { useIntl } from 'react-intl'; import useTheme from 'hooks/useTheme'; -import { Sun, Moon } from 'components/icons'; +import Icons from 'components/icons'; import { labels } from 'components/messages'; import styles from './ThemeButton.module.css'; @@ -28,11 +28,11 @@ export default function ThemeButton({ tooltipPosition = 'top' }) { } return ( - + diff --git a/components/buttons/UserButton.js b/components/buttons/UserButton.js index e20e0dd3..f6b42d62 100644 --- a/components/buttons/UserButton.js +++ b/components/buttons/UserButton.js @@ -13,7 +13,7 @@ import styles from './UserButton.module.css'; export default function UserButton() { const [show, setShow] = useState(false); const ref = useRef(); - const user = useUser(); + const { user } = useUser(); const router = useRouter(); const { adminDisabled } = useConfig(); diff --git a/components/common/Calendar.js b/components/common/Calendar.js deleted file mode 100644 index dd771f28..00000000 --- a/components/common/Calendar.js +++ /dev/null @@ -1,280 +0,0 @@ -import { useState } from 'react'; -import classNames from 'classnames'; -import { - startOfWeek, - startOfMonth, - startOfYear, - endOfMonth, - addDays, - subDays, - addYears, - subYears, - addMonths, - setMonth, - setYear, - isSameDay, - isBefore, - isAfter, -} from 'date-fns'; -import { Button, Icon, Icons } from 'react-basics'; -import { chunkArray } from 'next-basics'; -import useLocale from 'hooks/useLocale'; -import { dateFormat } from 'lib/date'; -import { getDateLocale } from 'lib/lang'; -import styles from './Calendar.module.css'; - -export default function Calendar({ date, minDate, maxDate, onChange }) { - const { locale } = useLocale(); - const [selectMonth, setSelectMonth] = useState(false); - const [selectYear, setSelectYear] = useState(false); - - const month = dateFormat(date, 'MMMM', locale); - const year = date.getFullYear(); - - function toggleMonthSelect() { - setSelectYear(false); - setSelectMonth(state => !state); - } - - function toggleYearSelect() { - setSelectMonth(false); - setSelectYear(state => !state); - } - - function handleChange(value) { - setSelectMonth(false); - setSelectYear(false); - if (value) { - onChange(value); - } - } - - return ( -
-
-
{date.getDate()}
-
- {month} - - {selectMonth ? : } - -
-
- {year} - - {selectMonth ? : } - -
-
-
- {!selectMonth && !selectYear && ( - - )} - {selectMonth && ( - - )} - {selectYear && ( - - )} -
-
- ); -} - -const DaySelector = ({ date, minDate, maxDate, locale, onSelect }) => { - const dateLocale = getDateLocale(locale); - const weekStartsOn = dateLocale?.options?.weekStartsOn || 0; - const startWeek = startOfWeek(date, { - locale: dateLocale, - weekStartsOn, - }); - const startMonth = startOfMonth(date); - const startDay = subDays(startMonth, startMonth.getDay() - weekStartsOn); - const month = date.getMonth(); - const year = date.getFullYear(); - - const daysOfWeek = []; - for (let i = 0; i < 7; i++) { - daysOfWeek.push(addDays(startWeek, i)); - } - - const days = []; - for (let i = 0; i < 35; i++) { - days.push(addDays(startDay, i)); - } - - return ( - - - - {daysOfWeek.map((day, i) => ( - - ))} - - - - {chunkArray(days, 7).map((week, i) => ( - - {week.map((day, j) => { - const disabled = isBefore(day, minDate) || isAfter(day, maxDate); - return ( - - ); - })} - - ))} - -
- {dateFormat(day, 'EEE', locale)} -
onSelect(day) : null} - > - {day.getDate()} -
- ); -}; - -const MonthSelector = ({ date, minDate, maxDate, locale, onSelect }) => { - const start = startOfYear(date); - const months = []; - for (let i = 0; i < 12; i++) { - months.push(addMonths(start, i)); - } - - function handleSelect(value) { - onSelect(setMonth(date, value)); - } - - return ( - - - {chunkArray(months, 3).map((row, i) => ( - - {row.map((month, j) => { - const disabled = - isBefore(endOfMonth(month), minDate) || isAfter(startOfMonth(month), maxDate); - return ( - - ); - })} - - ))} - -
handleSelect(month.getMonth()) : null} - > - {dateFormat(month, 'MMMM', locale)} -
- ); -}; - -const YearSelector = ({ date, minDate, maxDate, onSelect }) => { - const [currentDate, setCurrentDate] = useState(date); - const year = date.getFullYear(); - const currentYear = currentDate.getFullYear(); - const minYear = minDate.getFullYear(); - const maxYear = maxDate.getFullYear(); - const years = []; - for (let i = 0; i < 15; i++) { - years.push(currentYear - 7 + i); - } - - function handleSelect(value) { - onSelect(setYear(date, value)); - } - - function handlePrevClick() { - setCurrentDate(state => subYears(state, 15)); - } - - function handleNextClick() { - setCurrentDate(state => addYears(state, 15)); - } - - return ( -
-
- -
-
- - - {chunkArray(years, 5).map((row, i) => ( - - {row.map((n, j) => ( - - ))} - - ))} - -
maxYear, - })} - onClick={() => (n < minYear || n > maxYear ? null : handleSelect(n))} - > - {n} -
-
-
- -
-
- ); -}; diff --git a/components/common/Calendar.module.css b/components/common/Calendar.module.css deleted file mode 100644 index f1630fa7..00000000 --- a/components/common/Calendar.module.css +++ /dev/null @@ -1,110 +0,0 @@ -.calendar { - display: flex; - flex-direction: column; - flex: 1; - min-height: 306px; -} - -.calendar table { - width: 100%; - border-spacing: 5px; -} - -.calendar td { - color: var(--base800); - cursor: pointer; - text-align: center; - vertical-align: center; - height: 40px; - width: 40px; - border-radius: 5px; - border: 1px solid transparent; -} - -.calendar td:hover { - border: 1px solid var(--base300); - background: var(--base75); -} - -.calendar td.faded { - color: var(--base500); -} - -.calendar td.selected { - font-weight: 600; - border: 1px solid var(--base600); -} - -.calendar td.selected:hover { - background: transparent; -} - -.calendar td.disabled { - color: var(--base400); - background: var(--base75); -} - -.calendar td.disabled:hover { - cursor: default; - background: var(--base75); - border-color: transparent; -} - -.calendar td.faded.disabled { - background: var(--base100); -} - -.header { - display: flex; - justify-content: space-evenly; - align-items: center; - font-weight: 700; - line-height: 40px; - font-size: var(--font-size-md); -} - -.body { - display: flex; -} - -.selector { - cursor: pointer; -} - -.pager { - display: flex; - flex: 1; -} - -.pager button { - align-self: center; -} - -.middle { - flex: 1; -} - -.left, -.right { - display: flex; - justify-content: center; - align-items: center; -} - -.left svg { - transform: rotate(90deg); -} - -.right svg { - transform: rotate(-90deg); -} - -.icon { - margin-left: 10px; -} - -@media only screen and (max-width: 992px) { - .calendar table { - max-width: calc(100vw - 30px); - } -} diff --git a/components/common/CopyButton.js b/components/common/CopyButton.js deleted file mode 100644 index e1664a1e..00000000 --- a/components/common/CopyButton.js +++ /dev/null @@ -1,37 +0,0 @@ -import { useState } from 'react'; -import PropTypes from 'prop-types'; -import { Button } from 'react-basics'; -import { FormattedMessage } from 'react-intl'; - -const defaultText = ( - -); - -function CopyButton({ element, ...props }) { - const [text, setText] = useState(defaultText); - - function handleClick() { - if (element?.current) { - element.current.select(); - document.execCommand('copy'); - setText(); - window.getSelection().removeAllRanges(); - } - } - - return ( - - ); -} - -CopyButton.propTypes = { - element: PropTypes.shape({ - current: PropTypes.shape({ - select: PropTypes.func.isRequired, - }), - }), -}; - -export default CopyButton; diff --git a/components/common/DropDown.js b/components/common/DropDown.js deleted file mode 100644 index 7cd2d529..00000000 --- a/components/common/DropDown.js +++ /dev/null @@ -1,66 +0,0 @@ -import { useState, useRef } from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; -import Menu from './Menu'; -import useDocumentClick from 'hooks/useDocumentClick'; -import Chevron from 'assets/chevron-down.svg'; -import styles from './Dropdown.module.css'; -import { Icon } from 'react-basics'; - -function DropDown({ value, className, menuClassName, options = [], onChange = () => {} }) { - const [showMenu, setShowMenu] = useState(false); - const ref = useRef(); - const selectedOption = options.find(e => e.value === value); - - function handleShowMenu() { - setShowMenu(state => !state); - } - - function handleSelect(selected, e) { - e.stopPropagation(); - setShowMenu(false); - - onChange(selected); - } - - useDocumentClick(e => { - if (!ref.current?.contains(e.target)) { - setShowMenu(false); - } - }); - - return ( -
-
-
{options.find(e => e.value === value)?.label || value}
- - - -
- {showMenu && ( - - )} -
- ); -} - -DropDown.propTypes = { - value: PropTypes.any, - className: PropTypes.string, - menuClassName: PropTypes.string, - options: PropTypes.arrayOf( - PropTypes.shape({ - value: PropTypes.any.isRequired, - label: PropTypes.node, - }), - ), - onChange: PropTypes.func, -}; - -export default DropDown; diff --git a/components/common/Dropdown.module.css b/components/common/Dropdown.module.css deleted file mode 100644 index e0db7432..00000000 --- a/components/common/Dropdown.module.css +++ /dev/null @@ -1,27 +0,0 @@ -.dropdown { - position: relative; - display: flex; - justify-content: space-between; - align-items: center; - border: 1px solid var(--base500); - border-radius: 4px; - cursor: pointer; -} - -.value { - flex: 1; - display: flex; - justify-content: space-between; - flex-wrap: nowrap; - white-space: nowrap; - padding: 4px 16px; - min-width: 160px; -} - -.text { - flex: 1; -} - -.icon { - padding-left: 20px; -} diff --git a/components/common/FilterLink.js b/components/common/FilterLink.js index 33211aa1..f91d4764 100644 --- a/components/common/FilterLink.js +++ b/components/common/FilterLink.js @@ -2,8 +2,7 @@ import classNames from 'classnames'; import Link from 'next/link'; import { safeDecodeURI } from 'next-basics'; import usePageQuery from 'hooks/usePageQuery'; -import External from 'assets/arrow-up-right-from-square.svg'; -import { Icon } from 'react-basics'; +import { Icon, Icons } from 'react-basics'; import styles from './FilterLink.module.css'; export default function FilterLink({ id, value, label, externalUrl }) { @@ -26,7 +25,7 @@ export default function FilterLink({ id, value, label, externalUrl }) { {externalUrl && ( - + )} diff --git a/components/common/HamburgerButton.js b/components/common/HamburgerButton.js index 906c5291..49f3232e 100644 --- a/components/common/HamburgerButton.js +++ b/components/common/HamburgerButton.js @@ -1,10 +1,9 @@ import { Button, Icon } from 'react-basics'; -import XMark from 'assets/xmark.svg'; -import Bars from 'assets/bars.svg'; import { useState } from 'react'; -import styles from './HamburgerButton.module.css'; -import MobileMenu from './MobileMenu'; import { FormattedMessage } from 'react-intl'; +import MobileMenu from './MobileMenu'; +import Icons from 'components/icons'; +import styles from './HamburgerButton.module.css'; const menuItems = [ { @@ -37,7 +36,7 @@ export default function HamburgerButton() { return ( <> {active && } diff --git a/components/common/MobileMenu.js b/components/common/MobileMenu.js index 1a953d18..1c93f18a 100644 --- a/components/common/MobileMenu.js +++ b/components/common/MobileMenu.js @@ -1,19 +1,25 @@ import classNames from 'classnames'; -import Link from './Link'; -import { Button } from 'react-basics'; -import XMark from 'assets/xmark.svg'; +import Link from 'next/link'; +import { Button, Icon } from 'react-basics'; +import Icons from 'components/icons'; import styles from './MobileMenu.module.css'; export default function MobileMenu({ items = [], onClose }) { return ( -
+
-
{items.map(({ label, value }) => ( - - {label} + + + {label} + ))}
diff --git a/components/common/RefreshButton.js b/components/common/RefreshButton.js index 507ecd34..a23ea9c5 100644 --- a/components/common/RefreshButton.js +++ b/components/common/RefreshButton.js @@ -1,12 +1,10 @@ import { useState, useEffect, useCallback } from 'react'; -import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; import useStore from 'store/queries'; import { setDateRange } from 'store/websites'; import { Button, Icon } from 'react-basics'; -import Refresh from 'assets/redo.svg'; -import Dots from 'assets/ellipsis-h.svg'; import useDateRange from 'hooks/useDateRange'; +import Icons from 'components/icons'; function RefreshButton({ websiteId }) { const [dateRange] = useDateRange(websiteId); @@ -17,7 +15,7 @@ function RefreshButton({ websiteId }) { function handleClick() { if (!loading && dateRange) { setLoading(true); - if (/^[\d]+/.test(dateRange.value)) { + if (/^\d+/.test(dateRange.value)) { setDateRange(websiteId, dateRange.value); } else { setDateRange(websiteId, dateRange); @@ -36,13 +34,11 @@ function RefreshButton({ websiteId }) { size="small" onClick={handleClick} > - {loading ? : } + + + ); } -RefreshButton.propTypes = { - websiteId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), -}; - export default RefreshButton; diff --git a/components/icons.js b/components/icons.js index 0766dcb8..a8d6cd79 100644 --- a/components/icons.js +++ b/components/icons.js @@ -1,3 +1,4 @@ +import { Icons } from 'react-basics'; import Bolt from 'assets/bolt.svg'; import Calendar from 'assets/calendar.svg'; import Clock from 'assets/clock.svg'; @@ -12,7 +13,8 @@ import Sun from 'assets/sun.svg'; import User from 'assets/user.svg'; import Users from 'assets/users.svg'; -export { +const icons = { + ...Icons, Bolt, Calendar, Clock, @@ -27,3 +29,5 @@ export { User, Users, }; + +export default icons; diff --git a/components/layout/AppLayout.js b/components/layout/AppLayout.js index 8d9b15f4..2b5f0b92 100644 --- a/components/layout/AppLayout.js +++ b/components/layout/AppLayout.js @@ -5,7 +5,11 @@ import useRequireLogin from 'hooks/useRequireLogin'; import styles from './AppLayout.module.css'; export default function AppLayout({ title, children }) { - useRequireLogin(); + const { user } = useRequireLogin(); + + if (!user) { + return null; + } return (
diff --git a/components/layout/Header.js b/components/layout/Header.js index e300038d..a9046b2b 100644 --- a/components/layout/Header.js +++ b/components/layout/Header.js @@ -12,7 +12,7 @@ import styles from './Header.module.css'; import classNames from 'classnames'; export default function Header({ className }) { - const user = useUser(); + const { user } = useUser(); const { pathname } = useRouter(); const { updatesDisabled, adminDisabled } = useConfig(); const isSharePage = pathname.includes('/share/'); diff --git a/components/layout/NavBar.js b/components/layout/NavBar.js index bc4d3d44..633e935d 100644 --- a/components/layout/NavBar.js +++ b/components/layout/NavBar.js @@ -1,32 +1,38 @@ import { useState } from 'react'; import { useIntl } from 'react-intl'; -import { Icon, Text, Icons } from 'react-basics'; +import { Icon, Text } from 'react-basics'; import classNames from 'classnames'; -import { Dashboard, Logo, Profile, User, Users, Clock, Globe } from 'components/icons'; -import ThemeButton from '../buttons/ThemeButton'; +import Icons from 'components/icons'; +import ThemeButton from 'components/buttons/ThemeButton'; import LanguageButton from 'components/buttons/LanguageButton'; import LogoutButton from 'components/buttons/LogoutButton'; import { labels } from 'components/messages'; +import useUser from 'hooks/useUser'; import NavGroup from './NavGroup'; import styles from './NavBar.module.css'; export default function NavBar() { + const { user } = useUser(); const { formatMessage } = useIntl(); const [minimized, setMinimized] = useState(false); const tooltipPosition = minimized ? 'right' : 'top'; const analytics = [ - { label: formatMessage(labels.dashboard), url: '/dashboard', icon: }, - { label: formatMessage(labels.realtime), url: '/realtime', icon: }, + { label: formatMessage(labels.dashboard), url: '/dashboard', icon: }, + { label: formatMessage(labels.realtime), url: '/realtime', icon: }, { label: formatMessage(labels.queries), url: '/queries', icon: }, ]; const settings = [ - { label: formatMessage(labels.websites), url: '/settings/websites', icon: }, - { label: formatMessage(labels.users), url: '/settings/users', icon: }, - { label: formatMessage(labels.teams), url: '/settings/teams', icon: }, - { label: formatMessage(labels.profile), url: '/settings/profile', icon: }, - ]; + { label: formatMessage(labels.websites), url: '/settings/websites', icon: }, + user?.isAdmin && { + label: formatMessage(labels.users), + url: '/settings/users', + icon: , + }, + { label: formatMessage(labels.teams), url: '/settings/teams', icon: }, + { label: formatMessage(labels.profile), url: '/settings/profile', icon: }, + ].filter(n => n); const handleMinimize = () => setMinimized(state => !state); @@ -34,7 +40,7 @@ export default function NavBar() {
- + umami diff --git a/components/layout/PageHeader.js b/components/layout/PageHeader.js index 2de1f915..42667750 100644 --- a/components/layout/PageHeader.js +++ b/components/layout/PageHeader.js @@ -1,24 +1,11 @@ import React from 'react'; -import Link from 'next/link'; import classNames from 'classnames'; -import { Button, Icon } from 'react-basics'; import styles from './PageHeader.module.css'; -export default function PageHeader({ title, backUrl, children, className, style }) { +export default function PageHeader({ title, children, className, style }) { return (
-
- {backUrl && ( - - - - - - )} - {title} -
+
{title}
{children}
); diff --git a/components/layout/PageHeader.module.css b/components/layout/PageHeader.module.css index 6fe45e8b..c48749f7 100644 --- a/components/layout/PageHeader.module.css +++ b/components/layout/PageHeader.module.css @@ -5,8 +5,6 @@ align-content: center; align-self: stretch; margin-bottom: 40px; - font-size: 18px; - font-weight: bold; height: 50px; } @@ -21,5 +19,7 @@ .title { display: flex; align-items: center; + font-size: 18px; + font-weight: bold; gap: 20px; } diff --git a/components/messages.js b/components/messages.js index 53fbea23..d4299597 100644 --- a/components/messages.js +++ b/components/messages.js @@ -48,7 +48,7 @@ export const labels = defineMessages({ newPassword: { id: 'label.new-password', defaultMessage: 'New password' }, confirmPassword: { id: 'label.confirm-password', defaultMessage: 'Confirm password' }, timezone: { id: 'label.timezone', defaultMessage: 'Timezone' }, - dateRange: { id: 'label.default-date-range', defaultMessage: 'Default date range' }, + defaultDateRange: { id: 'label.default-date-range', defaultMessage: 'Default date range' }, language: { id: 'label.language', defaultMessage: 'Language' }, theme: { id: 'label.theme', defaultMessage: 'Theme' }, profile: { id: 'label.profile', defaultMessage: 'Profile' }, @@ -59,6 +59,8 @@ export const labels = defineMessages({ teams: { id: 'label.teams', defaultMessage: 'Teams' }, analytics: { id: 'label.analytics', defaultMessage: 'Analytics' }, logout: { id: 'label.logout', defaultMessage: 'Logout' }, + singleDay: { id: 'label.single-day', defaultMessage: 'Single day' }, + dateRange: { id: 'label.date-range', defaultMessage: 'Date range' }, }); export const messages = defineMessages({ diff --git a/components/metrics/DatePickerForm.js b/components/metrics/DatePickerForm.js index 07f620aa..d5a6533b 100644 --- a/components/metrics/DatePickerForm.js +++ b/components/metrics/DatePickerForm.js @@ -1,14 +1,15 @@ -import Calendar from 'components/common/Calendar'; -import { FormButtons } from 'components/layout/FormLayout'; -import { isAfter, isBefore, isSameDay } from 'date-fns'; -import { getDateRangeValues } from 'lib/date'; import { useState } from 'react'; -import { Button, ButtonGroup } from 'react-basics'; -import { FormattedMessage } from 'react-intl'; +import { Button, ButtonGroup, Calendar } from 'react-basics'; +import { useIntl } from 'react-intl'; +import { isAfter, isBefore, isSameDay } from 'date-fns'; +import useLocale from 'hooks/useLocale'; +import { getDateRangeValues } from 'lib/date'; +import { getDateLocale } from 'lib/lang'; +import { labels } from 'components/messages'; import styles from './DatePickerForm.module.css'; -const FILTER_DAY = 0; -const FILTER_RANGE = 1; +const FILTER_DAY = 'day'; +const FILTER_RANGE = 'range'; export default function DatePickerForm({ startDate: defaultStartDate, @@ -24,59 +25,59 @@ export default function DatePickerForm({ const [date, setDate] = useState(defaultStartDate); const [startDate, setStartDate] = useState(defaultStartDate); const [endDate, setEndDate] = useState(defaultEndDate); + const { locale } = useLocale(); + const { formatMessage } = useIntl(); const disabled = selected === FILTER_DAY ? isAfter(minDate, date) && isBefore(maxDate, date) : isAfter(startDate, endDate); - const buttons = [ - { - label: , - value: FILTER_DAY, - }, - { - label: , - value: FILTER_RANGE, - }, - ]; - - function handleSave() { + const handleSave = () => { if (selected === FILTER_DAY) { onChange({ ...getDateRangeValues(date, date), value: 'custom' }); } else { onChange({ ...getDateRangeValues(startDate, endDate), value: 'custom' }); } - } + }; return (
- + + + +
- {selected === FILTER_DAY ? ( + {selected === FILTER_DAY && ( - ) : ( + )} + {selected === FILTER_RANGE && ( <> - + )}
- - - - + +
); } diff --git a/components/metrics/DatePickerForm.module.css b/components/metrics/DatePickerForm.module.css index 92e59bb7..a3d9851d 100644 --- a/components/metrics/DatePickerForm.module.css +++ b/components/metrics/DatePickerForm.module.css @@ -26,6 +26,14 @@ margin-bottom: 20px; } +.buttons { + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + margin-top: 20px; +} + @media only screen and (max-width: 768px) { .calendars { flex-direction: column; diff --git a/components/metrics/MetricsTable.js b/components/metrics/MetricsTable.js index 25388fbe..642ce818 100644 --- a/components/metrics/MetricsTable.js +++ b/components/metrics/MetricsTable.js @@ -1,11 +1,10 @@ import { useMemo } from 'react'; -import { Loading } from 'react-basics'; +import { Loading, Icons } from 'react-basics'; import { defineMessages, useIntl } from 'react-intl'; import firstBy from 'thenby'; import classNames from 'classnames'; import Link from 'components/common/Link'; import useApi from 'hooks/useApi'; -import Arrow from 'assets/arrow-right.svg'; import { percentFilter } from 'lib/filters'; import useDateRange from 'hooks/useDateRange'; import usePageQuery from 'hooks/usePageQuery'; @@ -80,7 +79,7 @@ export default function MetricsTable({
{data && !error && limit && ( } + icon={} href={router.pathname} as={resolve({ view: type })} size="small" diff --git a/components/metrics/RealtimeHeader.js b/components/metrics/RealtimeHeader.js index f313adad..c0b6cbcc 100644 --- a/components/metrics/RealtimeHeader.js +++ b/components/metrics/RealtimeHeader.js @@ -2,25 +2,11 @@ import { useMemo } from 'react'; import { FormattedMessage } from 'react-intl'; import { differenceInMinutes } from 'date-fns'; import PageHeader from 'components/layout/PageHeader'; -import DropDown from 'components/common/DropDown'; import ActiveUsers from './ActiveUsers'; import MetricCard from './MetricCard'; import styles from './RealtimeHeader.module.css'; -export default function RealtimeHeader({ websites, data, websiteId, onSelect }) { - const options = [ - { - label: , - value: null, - }, - ].concat( - websites.map(({ name, id }, index) => ({ - label: name, - value: id, - divider: index === 0, - })), - ); - +export default function RealtimeHeader({ data, websiteId }) { const { pageviews, sessions, events, countries } = data; const count = useMemo(() => { @@ -38,7 +24,6 @@ export default function RealtimeHeader({ websites, data, websiteId, onSelect })
-
- get('/websites?include_all=true'), - ); + const { data, isLoading, error } = useQuery(['websites:test-console'], () => get('/websites')); const router = useRouter(); const { basePath, query: { id }, } = router; - const websiteId = id?.[0]; - if (isLoading) { - return ; - } - - if (!data) { - return null; - } - - const options = data.map(({ name, id }) => ({ label: name, value: id })); - const website = data.find(({ id }) => websiteId === id); - const selectedValue = options.find(({ value }) => value === website?.id)?.value; - - function handleSelect(value) { + function handleChange(value) { router.push(`/console/${value}`); } @@ -45,8 +29,15 @@ export default function TestConsole() { window.umami.trackEvent('track-event-with-data', { test: 'test-data', time: Date.now() }); } + if (!data) { + return null; + } + + const websiteId = id?.[0]; + const website = data.find(({ id }) => websiteId === id); + return ( - + {typeof window !== 'undefined' && website && (