diff --git a/components/common/Calendar.js b/components/common/Calendar.js index d68465be..9fcd26dc 100644 --- a/components/common/Calendar.js +++ b/components/common/Calendar.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import classNames from 'classnames'; import { startOfWeek, diff --git a/components/common/CopyButton.js b/components/common/CopyButton.js index 610c1c1c..e1664a1e 100644 --- a/components/common/CopyButton.js +++ b/components/common/CopyButton.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import PropTypes from 'prop-types'; import { Button } from 'react-basics'; import { FormattedMessage } from 'react-intl'; diff --git a/components/common/DateFilter.js b/components/common/DateFilter.js index 1769a55c..e48a7925 100644 --- a/components/common/DateFilter.js +++ b/components/common/DateFilter.js @@ -4,7 +4,7 @@ import { endOfYear, isSameDay } from 'date-fns'; import useLocale from 'hooks/useLocale'; import { dateFormat } from 'lib/date'; import PropTypes from 'prop-types'; -import React, { useState } from 'react'; +import { useState } from 'react'; import { Icon, Modal } from 'react-basics'; import { FormattedMessage } from 'react-intl'; import DropDown from './DropDown'; diff --git a/components/common/Dot.js b/components/common/Dot.js deleted file mode 100644 index 81454c48..00000000 --- a/components/common/Dot.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; -import styles from './Dot.module.css'; - -function Dot({ color, size, className }) { - return ( -
-
-
- ); -} - -Dot.propTypes = { - color: PropTypes.string, - size: PropTypes.oneOf(['small', 'large']), - className: PropTypes.string, -}; - -export default Dot; diff --git a/components/common/Dot.module.css b/components/common/Dot.module.css deleted file mode 100644 index 284aa66d..00000000 --- a/components/common/Dot.module.css +++ /dev/null @@ -1,22 +0,0 @@ -.wrapper { - background: var(--base50); - margin-right: 10px; - border-radius: 100%; -} - -.dot { - background: var(--green400); - width: 10px; - height: 10px; - border-radius: 100%; -} - -.dot.small { - width: 8px; - height: 8px; -} - -.dot.large { - width: 16px; - height: 16px; -} diff --git a/components/common/DropDown.js b/components/common/DropDown.js index c84a9d04..7cd2d529 100644 --- a/components/common/DropDown.js +++ b/components/common/DropDown.js @@ -1,4 +1,4 @@ -import React, { useState, useRef } from 'react'; +import { useState, useRef } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import Menu from './Menu'; diff --git a/components/common/EmptyPlaceholder.js b/components/common/EmptyPlaceholder.js index 77b1ce4e..f7aa6dd7 100644 --- a/components/common/EmptyPlaceholder.js +++ b/components/common/EmptyPlaceholder.js @@ -1,4 +1,3 @@ -import React from 'react'; import PropTypes from 'prop-types'; import { Icon, Flexbox } from 'react-basics'; import Logo from 'assets/logo.svg'; diff --git a/components/common/ErrorMessage.js b/components/common/ErrorMessage.js index efc6cc31..2a411425 100644 --- a/components/common/ErrorMessage.js +++ b/components/common/ErrorMessage.js @@ -1,5 +1,4 @@ import Exclamation from 'assets/exclamation-triangle.svg'; -import React from 'react'; import { FormattedMessage } from 'react-intl'; import styles from './ErrorMessage.module.css'; import { Icon } from 'react-basics'; diff --git a/components/common/Favicon.js b/components/common/Favicon.js index d72cd3c7..ad7056af 100644 --- a/components/common/Favicon.js +++ b/components/common/Favicon.js @@ -1,4 +1,3 @@ -import React from 'react'; import PropTypes from 'prop-types'; import styles from './Favicon.module.css'; diff --git a/components/common/FilterButtons.js b/components/common/FilterButtons.js index 79962c51..b4b42291 100644 --- a/components/common/FilterButtons.js +++ b/components/common/FilterButtons.js @@ -1,4 +1,3 @@ -import React from 'react'; import PropTypes from 'prop-types'; import ButtonLayout from 'components/layout/ButtonLayout'; import { ButtonGroup } from 'react-basics'; diff --git a/components/common/FilterLink.js b/components/common/FilterLink.js index 7500ffdb..33211aa1 100644 --- a/components/common/FilterLink.js +++ b/components/common/FilterLink.js @@ -1,4 +1,3 @@ -import React from 'react'; import classNames from 'classnames'; import Link from 'next/link'; import { safeDecodeURI } from 'next-basics'; diff --git a/components/common/Icon.js b/components/common/Icon.js index e9d96eb5..362d5376 100644 --- a/components/common/Icon.js +++ b/components/common/Icon.js @@ -1,4 +1,3 @@ -import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import styles from './Icon.module.css'; diff --git a/components/common/Link.js b/components/common/Link.js index 1e05d8b2..3721a9a7 100644 --- a/components/common/Link.js +++ b/components/common/Link.js @@ -1,4 +1,3 @@ -import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import NextLink from 'next/link'; diff --git a/components/common/Loading.js b/components/common/Loading.js deleted file mode 100644 index 81c8a77e..00000000 --- a/components/common/Loading.js +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; -import styles from './Loading.module.css'; - -function Loading({ className, overlay = false }) { - return ( -
-
-
-
-
- ); -} - -Loading.propTypes = { - className: PropTypes.string, - overlay: PropTypes.bool, -}; - -export default Loading; diff --git a/components/common/Loading.module.css b/components/common/Loading.module.css deleted file mode 100644 index e2d53243..00000000 --- a/components/common/Loading.module.css +++ /dev/null @@ -1,55 +0,0 @@ -@keyframes blink { - 0% { - opacity: 0.2; - } - 20% { - opacity: 1; - } - 100% { - opacity: 0.2; - } -} - -.loading { - display: flex; - justify-content: center; - align-items: center; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - margin: 0; -} - -.loading.overlay { - height: 100%; - width: 100%; - z-index: 10; - background: var(--base400); - opacity: 0.4; -} - -.loading div { - width: 10px; - height: 10px; - border-radius: 100%; - background: var(--base400); - animation: blink 1.4s infinite; - animation-fill-mode: both; -} - -.loading.overlay div { - background: var(--base900); -} - -.loading div + div { - margin-left: 10px; -} - -.loading div:nth-child(2) { - animation-delay: 0.2s; -} - -.loading div:nth-child(3) { - animation-delay: 0.4s; -} diff --git a/components/common/Menu.js b/components/common/Menu.js index 91eeee97..771ed05d 100644 --- a/components/common/Menu.js +++ b/components/common/Menu.js @@ -1,4 +1,3 @@ -import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import styles from './Menu.module.css'; diff --git a/components/common/MenuButton.js b/components/common/MenuButton.js index 9eb4554f..69a448d0 100644 --- a/components/common/MenuButton.js +++ b/components/common/MenuButton.js @@ -1,4 +1,4 @@ -import React, { useState, useRef } from 'react'; +import { useState, useRef } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import Menu from 'components/common/Menu'; diff --git a/components/common/NavMenu.js b/components/common/NavMenu.js index 82d97fff..8994daa0 100644 --- a/components/common/NavMenu.js +++ b/components/common/NavMenu.js @@ -1,4 +1,3 @@ -import React from 'react'; import PropTypes from 'prop-types'; import { useRouter } from 'next/router'; import classNames from 'classnames'; diff --git a/components/common/NoData.js b/components/common/NoData.js index 9d523437..4ee593ae 100644 --- a/components/common/NoData.js +++ b/components/common/NoData.js @@ -1,4 +1,3 @@ -import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import { FormattedMessage } from 'react-intl'; diff --git a/components/common/OverflowText.js b/components/common/OverflowText.js index d67c4923..9be705b8 100644 --- a/components/common/OverflowText.js +++ b/components/common/OverflowText.js @@ -1,5 +1,5 @@ import PropTypes from 'prop-types'; -import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import ReactTooltip from 'react-tooltip'; import styles from './OverflowText.module.css'; diff --git a/components/common/RefreshButton.js b/components/common/RefreshButton.js index 89d8c9f2..507ecd34 100644 --- a/components/common/RefreshButton.js +++ b/components/common/RefreshButton.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useCallback } from 'react'; +import { useState, useEffect, useCallback } from 'react'; import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; import useStore from 'store/queries'; diff --git a/components/common/Tag.js b/components/common/Tag.js index 08589c36..b9005d86 100644 --- a/components/common/Tag.js +++ b/components/common/Tag.js @@ -1,4 +1,3 @@ -import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import styles from './Tag.module.css'; diff --git a/components/common/WorldMap.js b/components/common/WorldMap.js index 0f9a1d6a..55ee3109 100644 --- a/components/common/WorldMap.js +++ b/components/common/WorldMap.js @@ -1,4 +1,4 @@ -import React, { useState, useMemo } from 'react'; +import { useState, useMemo } from 'react'; import { useRouter } from 'next/router'; import PropTypes from 'prop-types'; import ReactTooltip from 'react-tooltip'; diff --git a/components/forms/DatePickerForm.js b/components/forms/DatePickerForm.js index 15f60a86..07f620aa 100644 --- a/components/forms/DatePickerForm.js +++ b/components/forms/DatePickerForm.js @@ -2,7 +2,7 @@ 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 React, { useState } from 'react'; +import { useState } from 'react'; import { Button, ButtonGroup } from 'react-basics'; import { FormattedMessage } from 'react-intl'; import styles from './DatePickerForm.module.css'; diff --git a/components/forms/ShareUrlForm.js b/components/forms/ShareUrlForm.js index aa1e1a46..ebbe2c06 100644 --- a/components/forms/ShareUrlForm.js +++ b/components/forms/ShareUrlForm.js @@ -1,6 +1,5 @@ import { useMutation } from '@tanstack/react-query'; -import { getClientAuthToken } from 'lib/client'; -import { getRandomChars, useApi } from 'next-basics'; +import { getRandomChars } from 'next-basics'; import { useEffect, useMemo, useRef, useState } from 'react'; import { Button, @@ -12,11 +11,12 @@ import { TextField, Toggle, } from 'react-basics'; +import useApi from 'hooks/useApi'; export default function ShareUrlForm({ websiteId, data, onSave }) { const { name, shareId } = data; const [id, setId] = useState(shareId); - const { post } = useApi(getClientAuthToken()); + const { post } = useApi(); const { mutate, error } = useMutation(({ shareId }) => post(`/websites/${websiteId}`, { shareId }), ); diff --git a/components/forms/TeamAddForm.js b/components/forms/TeamAddForm.js index 79543511..78c316ab 100644 --- a/components/forms/TeamAddForm.js +++ b/components/forms/TeamAddForm.js @@ -3,10 +3,9 @@ import { Form, FormInput, FormButtons, TextField, Button } from 'react-basics'; import useApi from 'hooks/useApi'; import styles from './Form.module.css'; import { useMutation } from '@tanstack/react-query'; -import { getClientAuthToken } from 'lib/client'; export default function TeamAddForm({ onSave, onClose }) { - const { post } = useApi(getClientAuthToken()); + const { post } = useApi(); const { mutate, error, isLoading } = useMutation(data => post('/teams', data)); const ref = useRef(null); diff --git a/components/forms/TeamEditForm.js b/components/forms/TeamEditForm.js index 474fa866..2ba8c661 100644 --- a/components/forms/TeamEditForm.js +++ b/components/forms/TeamEditForm.js @@ -2,10 +2,9 @@ import { SubmitButton, Form, FormInput, FormRow, FormButtons, TextField } from ' import { useMutation } from '@tanstack/react-query'; import { useRef } from 'react'; import useApi from 'hooks/useApi'; -import { getClientAuthToken } from 'lib/client'; export default function TeamEditForm({ teamId, data, onSave }) { - const { post } = useApi(getClientAuthToken()); + const { post } = useApi(); const { mutate, error } = useMutation(data => post(`/teams/${teamId}`, data)); const ref = useRef(null); diff --git a/components/forms/UserDeleteForm.js b/components/forms/UserDeleteForm.js index 0f6353a5..beefd368 100644 --- a/components/forms/UserDeleteForm.js +++ b/components/forms/UserDeleteForm.js @@ -1,5 +1,4 @@ import { useMutation } from '@tanstack/react-query'; -import { getClientAuthToken } from 'lib/client'; import useApi from 'hooks/useApi'; import { Button, Form, FormButtons, FormInput, SubmitButton, TextField } from 'react-basics'; import styles from './Form.module.css'; @@ -7,7 +6,7 @@ import styles from './Form.module.css'; const CONFIRM_VALUE = 'DELETE'; export default function UserDeleteForm({ userId, onSave, onClose }) { - const { del } = useApi(getClientAuthToken()); + const { del } = useApi(); const { mutate, error, isLoading } = useMutation(data => del(`/users/${userId}`, data)); const handleSubmit = async data => { diff --git a/components/forms/UserEditForm.js b/components/forms/UserEditForm.js index 26d805d0..28233250 100644 --- a/components/forms/UserEditForm.js +++ b/components/forms/UserEditForm.js @@ -10,7 +10,6 @@ import { import { useRef } from 'react'; import { useMutation } from '@tanstack/react-query'; import useApi from 'hooks/useApi'; -import { getClientAuthToken } from 'lib/client'; import { ROLES } from 'lib/constants'; import styles from './UserForm.module.css'; @@ -27,7 +26,7 @@ const items = [ export default function UserEditForm({ data, onSave }) { const { id } = data; - const { post } = useApi(getClientAuthToken()); + const { post } = useApi(); const { mutate, error } = useMutation(({ username }) => post(`/user/${id}`, { username })); const ref = useRef(null); diff --git a/components/forms/UserPasswordForm.js b/components/forms/UserPasswordForm.js index 748f462b..83eaaa81 100644 --- a/components/forms/UserPasswordForm.js +++ b/components/forms/UserPasswordForm.js @@ -2,18 +2,15 @@ import { useRef } from 'react'; import { Form, FormInput, FormButtons, PasswordField, Button } from 'react-basics'; import useApi from 'hooks/useApi'; import { useMutation } from '@tanstack/react-query'; -import { getClientAuthToken } from 'lib/client'; import styles from './UserPasswordForm.module.css'; import useUser from 'hooks/useUser'; export default function UserPasswordForm({ onSave, userId }) { - const { - user: { id }, - } = useUser(); + const user = useUser(); - const isCurrentUser = !userId || id === userId; - const url = isCurrentUser ? `/users/${id}/password` : `/users/${id}`; - const { post } = useApi(getClientAuthToken()); + const isCurrentUser = !userId || user?.id === userId; + const url = isCurrentUser ? `/users/${user?.id}/password` : `/users/${user?.id}`; + const { post } = useApi(); const { mutate, error, isLoading } = useMutation(data => post(url, data)); const ref = useRef(null); diff --git a/components/forms/WebsiteAddForm.js b/components/forms/WebsiteAddForm.js index c3fea4b2..45392ed7 100644 --- a/components/forms/WebsiteAddForm.js +++ b/components/forms/WebsiteAddForm.js @@ -3,11 +3,10 @@ import { Form, FormInput, FormButtons, TextField, Button, SubmitButton } from 'r import useApi from 'hooks/useApi'; import styles from './Form.module.css'; import { useMutation } from '@tanstack/react-query'; -import { getClientAuthToken } from 'lib/client'; import { DOMAIN_REGEX } from 'lib/constants'; export default function WebsiteAddForm({ onSave, onClose }) { - const { post } = useApi(getClientAuthToken()); + const { post } = useApi(); const { mutate, error, isLoading } = useMutation(data => post('/websites', data)); const ref = useRef(null); diff --git a/components/forms/WebsiteDeleteForm.js b/components/forms/WebsiteDeleteForm.js index 623a4aff..9b6ad698 100644 --- a/components/forms/WebsiteDeleteForm.js +++ b/components/forms/WebsiteDeleteForm.js @@ -1,5 +1,4 @@ import { useMutation } from '@tanstack/react-query'; -import { getClientAuthToken } from 'lib/client'; import useApi from 'hooks/useApi'; import { Button, Form, FormButtons, FormInput, SubmitButton, TextField } from 'react-basics'; import styles from './Form.module.css'; @@ -7,7 +6,7 @@ import styles from './Form.module.css'; const CONFIRM_VALUE = 'DELETE'; export default function WebsiteDeleteForm({ websiteId, onSave, onClose }) { - const { del } = useApi(getClientAuthToken()); + const { del } = useApi(); const { mutate, error, isLoading } = useMutation(data => del(`/websites/${websiteId}`, data)); const handleSubmit = async data => { diff --git a/components/forms/WebsiteResetForm.js b/components/forms/WebsiteResetForm.js index b8032a55..a40c5cbb 100644 --- a/components/forms/WebsiteResetForm.js +++ b/components/forms/WebsiteResetForm.js @@ -1,5 +1,4 @@ import { useMutation } from '@tanstack/react-query'; -import { getClientAuthToken } from 'lib/client'; import useApi from 'hooks/useApi'; import { Button, Form, FormButtons, FormInput, SubmitButton, TextField } from 'react-basics'; import styles from './Form.module.css'; @@ -7,7 +6,7 @@ import styles from './Form.module.css'; const CONFIRM_VALUE = 'RESET'; export default function WebsiteResetForm({ websiteId, onSave, onClose }) { - const { post } = useApi(getClientAuthToken()); + const { post } = useApi(); const { mutate, error, isLoading } = useMutation(data => post(`/websites/${websiteId}/reset`, data), ); diff --git a/components/helpers/CheckVisible.js b/components/helpers/CheckVisible.js index 7d503aec..a150f725 100644 --- a/components/helpers/CheckVisible.js +++ b/components/helpers/CheckVisible.js @@ -1,4 +1,4 @@ -import React, { useState, useRef, useEffect } from 'react'; +import { useState, useRef, useEffect } from 'react'; function isInViewport(element) { const rect = element.getBoundingClientRect(); diff --git a/components/helpers/StickyHeader.js b/components/helpers/StickyHeader.js index 9c42e4fd..7f97b12d 100644 --- a/components/helpers/StickyHeader.js +++ b/components/helpers/StickyHeader.js @@ -1,4 +1,4 @@ -import React, { useState, useRef, useEffect } from 'react'; +import { useState, useRef, useEffect } from 'react'; import classNames from 'classnames'; export default function StickyHeader({ diff --git a/components/layout/ButtonLayout.js b/components/layout/ButtonLayout.js index 40be399f..dd6a390d 100644 --- a/components/layout/ButtonLayout.js +++ b/components/layout/ButtonLayout.js @@ -1,4 +1,3 @@ -import React from 'react'; import classNames from 'classnames'; import styles from './ButtonLayout.module.css'; diff --git a/components/layout/FormLayout.js b/components/layout/FormLayout.js index 51303337..81830b14 100644 --- a/components/layout/FormLayout.js +++ b/components/layout/FormLayout.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useSpring, animated } from 'react-spring'; import classNames from 'classnames'; import { ErrorMessage } from 'formik'; diff --git a/components/layout/GridLayout.js b/components/layout/GridLayout.js index 1d3170d6..e83655ee 100644 --- a/components/layout/GridLayout.js +++ b/components/layout/GridLayout.js @@ -1,4 +1,3 @@ -import React from 'react'; import classNames from 'classnames'; import styles from './GridLayout.module.css'; diff --git a/components/layout/Header.js b/components/layout/Header.js index 43f2192a..53f5d6ee 100644 --- a/components/layout/Header.js +++ b/components/layout/Header.js @@ -15,7 +15,7 @@ import SettingsButton from '../settings/SettingsButton'; import styles from './Header.module.css'; export default function Header() { - const { user } = useUser(); + const user = useUser(); const { pathname } = useRouter(); const { updatesDisabled, adminDisabled } = useConfig(); const isSharePage = pathname.includes('/share/'); diff --git a/components/layout/MenuLayout.js b/components/layout/MenuLayout.js index c5d86b92..6832e06d 100644 --- a/components/layout/MenuLayout.js +++ b/components/layout/MenuLayout.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useRouter } from 'next/router'; import classNames from 'classnames'; import NavMenu from 'components/common/NavMenu'; diff --git a/components/layout/PageHeader.js b/components/layout/PageHeader.js index 2de1f915..c4d24a00 100644 --- a/components/layout/PageHeader.js +++ b/components/layout/PageHeader.js @@ -1,4 +1,3 @@ -import React from 'react'; import Link from 'next/link'; import classNames from 'classnames'; import { Button, Icon } from 'react-basics'; diff --git a/components/metrics/ActiveUsers.js b/components/metrics/ActiveUsers.js index 0ab266d3..83895b5a 100644 --- a/components/metrics/ActiveUsers.js +++ b/components/metrics/ActiveUsers.js @@ -1,15 +1,17 @@ -import React, { useMemo } from 'react'; +import { useMemo } from 'react'; +import { StatusLight } from 'react-basics'; import { FormattedMessage } from 'react-intl'; import classNames from 'classnames'; -import useFetch from 'hooks/useFetch'; -import Dot from 'components/common/Dot'; +import useApi from 'hooks/useApi'; import styles from './ActiveUsers.module.css'; -export default function ActiveUsers({ websiteId, className, value, interval = 60000 }) { +export default function ActiveUsers({ websiteId, className, value, refetchInterval = 60000 }) { const url = websiteId ? `/websites/${websiteId}/active` : null; - const { data } = useFetch(url, { - interval, + const { get, useQuery } = useApi(); + const { data } = useQuery(['websites:active', websiteId], () => get(url), { + refetchInterval, }); + const count = useMemo(() => { if (websiteId) { return data?.[0]?.x || 0; @@ -24,7 +26,7 @@ export default function ActiveUsers({ websiteId, className, value, interval = 60 return (
- +
{title}
- + {value} {label}
diff --git a/components/metrics/CountriesTable.js b/components/metrics/CountriesTable.js index 45a1b922..37b884e0 100644 --- a/components/metrics/CountriesTable.js +++ b/components/metrics/CountriesTable.js @@ -1,4 +1,3 @@ -import React from 'react'; import MetricsTable from './MetricsTable'; import { percentFilter } from 'lib/filters'; import { useIntl, defineMessages } from 'react-intl'; diff --git a/components/metrics/DataTable.js b/components/metrics/DataTable.js index c9596106..9a2de075 100644 --- a/components/metrics/DataTable.js +++ b/components/metrics/DataTable.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import { FixedSizeList } from 'react-window'; import { useSpring, animated, config } from 'react-spring'; import classNames from 'classnames'; diff --git a/components/metrics/DevicesTable.js b/components/metrics/DevicesTable.js index c704e08d..7c58699a 100644 --- a/components/metrics/DevicesTable.js +++ b/components/metrics/DevicesTable.js @@ -1,4 +1,3 @@ -import React from 'react'; import MetricsTable from './MetricsTable'; import { useIntl, FormattedMessage } from 'react-intl'; import { getDeviceMessage } from 'components/messages'; diff --git a/components/metrics/EventsChart.js b/components/metrics/EventsChart.js index 76c48a03..f8e90c8c 100644 --- a/components/metrics/EventsChart.js +++ b/components/metrics/EventsChart.js @@ -1,39 +1,37 @@ -import React, { useMemo } from 'react'; +import { useMemo } from 'react'; +import { Loading } from 'react-basics'; import { colord } from 'colord'; import BarChart from './BarChart'; import { getDateArray, getDateLength } from 'lib/date'; -import useFetch from 'hooks/useFetch'; +import useApi from 'hooks/useApi'; import useDateRange from 'hooks/useDateRange'; import useTimezone from 'hooks/useTimezone'; import usePageQuery from 'hooks/usePageQuery'; import { EVENT_COLORS } from 'lib/constants'; export default function EventsChart({ websiteId, className, token }) { + const { get, useQuery } = useApi(); const [{ startDate, endDate, unit, modified }] = useDateRange(websiteId); const [timezone] = useTimezone(); const { query: { url, eventName }, } = usePageQuery(); - const { data, loading } = useFetch( - `/websites/${websiteId}/events`, - { - params: { - startAt: +startDate, - endAt: +endDate, - unit, - tz: timezone, - url, - eventName, - token, - }, - }, - [modified, eventName], + const { data, isLoading } = useQuery(['events', { websiteId, modified, eventName }], () => + get(`/websites/${websiteId}/events`, { + startAt: +startDate, + endAt: +endDate, + unit, + timezone, + url, + eventName, + token, + }), ); const datasets = useMemo(() => { if (!data) return []; - if (loading) return data; + if (isLoading) return data; const map = data.reduce((obj, { x, t, y }) => { if (!obj[x]) { @@ -60,7 +58,7 @@ export default function EventsChart({ websiteId, className, token }) { borderWidth: 1, }; }); - }, [data, loading]); + }, [data, isLoading]); function handleUpdate(chart) { chart.data.datasets = datasets; @@ -68,6 +66,10 @@ export default function EventsChart({ websiteId, className, token }) { chart.update(); } + if (isLoading) { + return ; + } + if (!data) { return null; } @@ -81,7 +83,7 @@ export default function EventsChart({ websiteId, className, token }) { height={300} records={getDateLength(startDate, endDate, unit)} onUpdate={handleUpdate} - loading={loading} + loading={isLoading} stacked /> ); diff --git a/components/metrics/FilterTags.js b/components/metrics/FilterTags.js index 2fc04ced..1fb27271 100644 --- a/components/metrics/FilterTags.js +++ b/components/metrics/FilterTags.js @@ -1,4 +1,3 @@ -import React from 'react'; import classNames from 'classnames'; import { safeDecodeURI } from 'next-basics'; import { Button } from 'react-basics'; diff --git a/components/metrics/LanguagesTable.js b/components/metrics/LanguagesTable.js index 2b6cd868..2bc89076 100644 --- a/components/metrics/LanguagesTable.js +++ b/components/metrics/LanguagesTable.js @@ -1,4 +1,3 @@ -import React from 'react'; import MetricsTable from './MetricsTable'; import { percentFilter } from 'lib/filters'; import { FormattedMessage } from 'react-intl'; diff --git a/components/metrics/Legend.js b/components/metrics/Legend.js index 56b0ff65..f10b29bc 100644 --- a/components/metrics/Legend.js +++ b/components/metrics/Legend.js @@ -1,7 +1,6 @@ -import React from 'react'; +import { StatusLight } from 'react-basics'; import { colord } from 'colord'; import classNames from 'classnames'; -import Dot from 'components/common/Dot'; import useLocale from 'hooks/useLocale'; import useForceUpdate from 'hooks/useForceUpdate'; import styles from './Legend.module.css'; @@ -35,7 +34,7 @@ export default function Legend({ chart }) { className={classNames(styles.label, { [styles.hidden]: hidden })} onClick={() => handleClick(datasetIndex)} > - + {text}
); diff --git a/components/metrics/MetricCard.js b/components/metrics/MetricCard.js index ecb52e1e..aaf9054d 100644 --- a/components/metrics/MetricCard.js +++ b/components/metrics/MetricCard.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useSpring, animated } from 'react-spring'; import { formatNumber } from 'lib/format'; import styles from './MetricCard.module.css'; diff --git a/components/metrics/MetricsBar.js b/components/metrics/MetricsBar.js index 41bce9c3..cbf45ddd 100644 --- a/components/metrics/MetricsBar.js +++ b/components/metrics/MetricsBar.js @@ -1,9 +1,9 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; +import { Loading } from 'react-basics'; import { FormattedMessage } from 'react-intl'; import classNames from 'classnames'; -import Loading from 'components/common/Loading'; import ErrorMessage from 'components/common/ErrorMessage'; -import useFetch from 'hooks/useFetch'; +import useApi from 'hooks/useApi'; import useDateRange from 'hooks/useDateRange'; import usePageQuery from 'hooks/usePageQuery'; import { formatShortTime, formatNumber, formatLongNumber } from 'lib/format'; @@ -11,6 +11,7 @@ import MetricCard from './MetricCard'; import styles from './MetricsBar.module.css'; export default function MetricsBar({ websiteId, className }) { + const { get, useQuery } = useApi(); const [dateRange] = useDateRange(websiteId); const { startDate, endDate, modified } = dateRange; const [format, setFormat] = useState(true); @@ -18,10 +19,10 @@ export default function MetricsBar({ websiteId, className }) { query: { url, referrer, os, browser, device, country }, } = usePageQuery(); - const { data, error, loading } = useFetch( - `/websites/${websiteId}/stats`, - { - params: { + const { data, error, isLoading } = useQuery( + ['websites:stats', { websiteId, modified, url, referrer, os, browser, device, country }], + () => + get(`/websites/${websiteId}/stats`, { startAt: +startDate, endAt: +endDate, url, @@ -30,9 +31,7 @@ export default function MetricsBar({ websiteId, className }) { browser, device, country, - }, - }, - [modified, url, referrer, os, browser, device, country], + }), ); const formatFunc = format @@ -54,7 +53,7 @@ export default function MetricsBar({ websiteId, className }) { return (
- {!data && loading && } + {isLoading && } {error && } {data && !error && ( <> diff --git a/components/metrics/MetricsTable.js b/components/metrics/MetricsTable.js index 631dc68a..25388fbe 100644 --- a/components/metrics/MetricsTable.js +++ b/components/metrics/MetricsTable.js @@ -1,10 +1,10 @@ -import React, { useMemo } from 'react'; +import { useMemo } from 'react'; +import { Loading } from 'react-basics'; import { defineMessages, useIntl } from 'react-intl'; import firstBy from 'thenby'; import classNames from 'classnames'; import Link from 'components/common/Link'; -import Loading from 'components/common/Loading'; -import useFetch from 'hooks/useFetch'; +import useApi from 'hooks/useApi'; import Arrow from 'assets/arrow-right.svg'; import { percentFilter } from 'lib/filters'; import useDateRange from 'hooks/useDateRange'; @@ -36,11 +36,15 @@ export default function MetricsTable({ query: { url, referrer, os, browser, device, country }, } = usePageQuery(); const { formatMessage } = useIntl(); + const { get, useQuery } = useApi(); - const { data, loading, error } = useFetch( - `/websites/${websiteId}/metrics`, - { - params: { + const { data, isLoading, error } = useQuery( + [ + 'websites:mnetrics', + { websiteId, type, modified, url, referrer, os, browser, device, country }, + ], + () => + get(`/websites/${websiteId}/metrics`, { type, startAt: +startDate, endAt: +endDate, @@ -50,11 +54,8 @@ export default function MetricsTable({ browser, device, country, - }, - onDataLoad, - delay: delay || DEFAULT_ANIMATION_DURATION, - }, - [type, modified, url, referrer, os, browser, device, country], + }), + { onSuccess: onDataLoad, retryDelay: delay || DEFAULT_ANIMATION_DURATION }, ); const filteredData = useMemo(() => { @@ -73,7 +74,7 @@ export default function MetricsTable({ return (
- {!data && loading && } + {!data && isLoading && } {error && } {data && !error && }
diff --git a/components/metrics/OSTable.js b/components/metrics/OSTable.js index 18bc2499..4fc08a4e 100644 --- a/components/metrics/OSTable.js +++ b/components/metrics/OSTable.js @@ -1,4 +1,3 @@ -import React from 'react'; import MetricsTable from './MetricsTable'; import { FormattedMessage } from 'react-intl'; import FilterLink from 'components/common/FilterLink'; diff --git a/components/metrics/PagesTable.js b/components/metrics/PagesTable.js index e69a67ac..8b53dec0 100644 --- a/components/metrics/PagesTable.js +++ b/components/metrics/PagesTable.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import { useIntl, defineMessage } from 'react-intl'; import FilterLink from 'components/common/FilterLink'; import FilterButtons from 'components/common/FilterButtons'; diff --git a/components/metrics/PageviewsChart.js b/components/metrics/PageviewsChart.js index 6d5afd19..e7998c39 100644 --- a/components/metrics/PageviewsChart.js +++ b/components/metrics/PageviewsChart.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useIntl } from 'react-intl'; import { colord } from 'colord'; import CheckVisible from 'components/helpers/CheckVisible'; diff --git a/components/metrics/RealtimeChart.js b/components/metrics/RealtimeChart.js index 0842532b..f33126f0 100644 --- a/components/metrics/RealtimeChart.js +++ b/components/metrics/RealtimeChart.js @@ -1,4 +1,4 @@ -import React, { useMemo, useRef } from 'react'; +import { useMemo, useRef } from 'react'; import { format, parseISO, startOfMinute, subMinutes, isBefore } from 'date-fns'; import PageviewsChart from './PageviewsChart'; import { getDateArray } from 'lib/date'; diff --git a/components/metrics/RealtimeHeader.js b/components/metrics/RealtimeHeader.js index d3c43dde..f313adad 100644 --- a/components/metrics/RealtimeHeader.js +++ b/components/metrics/RealtimeHeader.js @@ -1,4 +1,4 @@ -import React, { useMemo } from 'react'; +import { useMemo } from 'react'; import { FormattedMessage } from 'react-intl'; import { differenceInMinutes } from 'date-fns'; import PageHeader from 'components/layout/PageHeader'; diff --git a/components/metrics/RealtimeLog.js b/components/metrics/RealtimeLog.js index 0a8a0ec2..c2dbd202 100644 --- a/components/metrics/RealtimeLog.js +++ b/components/metrics/RealtimeLog.js @@ -1,9 +1,9 @@ -import React, { useMemo, useState } from 'react'; +import { useMemo, useState } from 'react'; +import { StatusLight } from 'react-basics'; import { FormattedMessage, useIntl } from 'react-intl'; import { FixedSizeList } from 'react-window'; import firstBy from 'thenby'; import { Icon } from 'react-basics'; -import Dot from 'components/common/Dot'; import FilterButtons from 'components/common/FilterButtons'; import NoData from 'components/common/NoData'; import { getDeviceMessage, labels } from 'components/messages'; @@ -149,7 +149,7 @@ export default function RealtimeLog({ data, websites, websiteId }) { return (
- +
{getTime(row)}
diff --git a/components/metrics/RealtimeViews.js b/components/metrics/RealtimeViews.js index 2a8f728c..155c2f07 100644 --- a/components/metrics/RealtimeViews.js +++ b/components/metrics/RealtimeViews.js @@ -1,4 +1,4 @@ -import React, { useMemo, useState, useCallback } from 'react'; +import { useMemo, useState, useCallback } from 'react'; import { FormattedMessage } from 'react-intl'; import firstBy from 'thenby'; import { percentFilter } from 'lib/filters'; diff --git a/components/metrics/ReferrersTable.js b/components/metrics/ReferrersTable.js index f611626d..a2416abb 100644 --- a/components/metrics/ReferrersTable.js +++ b/components/metrics/ReferrersTable.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import { useIntl, defineMessages } from 'react-intl'; import MetricsTable from './MetricsTable'; import FilterButtons from 'components/common/FilterButtons'; diff --git a/components/metrics/ScreenTable.js b/components/metrics/ScreenTable.js index fcaf8824..bc3e39de 100644 --- a/components/metrics/ScreenTable.js +++ b/components/metrics/ScreenTable.js @@ -1,4 +1,3 @@ -import React from 'react'; import MetricsTable from './MetricsTable'; import { FormattedMessage } from 'react-intl'; diff --git a/components/metrics/WebsiteChart.js b/components/metrics/WebsiteChart.js index 819090d9..a1bb5289 100644 --- a/components/metrics/WebsiteChart.js +++ b/components/metrics/WebsiteChart.js @@ -1,5 +1,5 @@ import { useMemo } from 'react'; -import { Row, Column } from 'react-basics'; +import { Row, Column, Loading } from 'react-basics'; import PageviewsChart from './PageviewsChart'; import MetricsBar from './MetricsBar'; import WebsiteHeader from './WebsiteHeader'; @@ -7,12 +7,11 @@ import DateFilter from 'components/common/DateFilter'; import StickyHeader from 'components/helpers/StickyHeader'; import ErrorMessage from 'components/common/ErrorMessage'; import FilterTags from 'components/metrics/FilterTags'; -import useFetch from 'hooks/useFetch'; +import useApi from 'hooks/useApi'; import useDateRange from 'hooks/useDateRange'; import useTimezone from 'hooks/useTimezone'; import usePageQuery from 'hooks/usePageQuery'; import { getDateArray, getDateLength, getDateRangeValues } from 'lib/date'; -import useApi from 'hooks/useApi'; import styles from './WebsiteChart.module.css'; export default function WebsiteChart({ @@ -31,26 +30,24 @@ export default function WebsiteChart({ resolve, query: { url, referrer, os, browser, device, country }, } = usePageQuery(); - const { get } = useApi(); + const { get, useQuery } = useApi(); - const { data, loading, error } = useFetch( - `/websites/${websiteId}/pageviews`, - { - params: { + const { data, isLoading, error } = useQuery( + ['websites:pageviews', { websiteId, modified, url, referrer, os, browser, device, country }], + () => + get(`/websites/${websiteId}/pageviews`, { startAt: +startDate, endAt: +endDate, unit, - tz: timezone, + timezone, url, referrer, os, browser, device, country, - }, - onDataLoad, - }, - [modified, url, referrer, os, browser, device, country], + }), + { onSuccess: onDataLoad }, ); const chartData = useMemo(() => { @@ -78,10 +75,13 @@ export default function WebsiteChart({ } } + if (isLoading) { + return ; + } + return ( <> - )} diff --git a/components/nav/Nav.js b/components/nav/Nav.js index 91f9c966..722074bd 100644 --- a/components/nav/Nav.js +++ b/components/nav/Nav.js @@ -6,19 +6,21 @@ import Link from 'next/link'; import { useRouter } from 'next/router'; import { Icon, Item, Menu, Text } from 'react-basics'; import styles from './Nav.module.css'; -import useRequireLogin from 'hooks/useRequireLogin'; +import useUser from 'hooks/useUser'; export default function Nav() { - const { - user: { role }, - } = useRequireLogin(); + const user = useUser(); const { pathname } = useRouter(); + if (!user) { + return null; + } + const handleSelect = () => {}; const items = [ { icon: , label: 'Websites', url: '/websites' }, - { icon: , label: 'Users', url: '/users', hidden: role !== 'admin' }, + { icon: , label: 'Users', url: '/users', hidden: !user.isAdmin }, { icon: , label: 'Teams', url: '/teams' }, { icon: , label: 'Profile', url: '/profile' }, ]; diff --git a/components/pages/Dashboard.js b/components/pages/Dashboard.js index 343ac3f7..e1c948af 100644 --- a/components/pages/Dashboard.js +++ b/components/pages/Dashboard.js @@ -3,9 +3,9 @@ import { defineMessages, useIntl } from 'react-intl'; import Page from 'components/layout/Page'; import PageHeader from 'components/layout/PageHeader'; import WebsiteList from 'components/pages/WebsiteList'; -import { Button } from 'react-basics'; +import { Button, Loading } from 'react-basics'; import DashboardSettingsButton from 'components/settings/DashboardSettingsButton'; -import useFetch from 'hooks/useFetch'; +import useApi from 'hooks/useApi'; import useDashboard from 'store/dashboard'; import DashboardEdit from './DashboardEdit'; import styles from './WebsiteList.module.css'; @@ -19,13 +19,18 @@ export default function Dashboard({ userId }) { const dashboard = useDashboard(); const { showCharts, limit, editing } = dashboard; const [max, setMax] = useState(limit); - const { data } = useFetch('/websites', { params: { user_id: userId } }); + const { get, useQuery } = useApi(); + const { data, isLoading } = useQuery(['websites'], () => get('/websites', { userId })); const { formatMessage } = useIntl(); function handleMore() { setMax(max + limit); } + if (isLoading) { + return ; + } + if (!data) { return null; } diff --git a/components/pages/RealtimeDashboard.js b/components/pages/RealtimeDashboard.js index 8af6f9be..941d0f0c 100644 --- a/components/pages/RealtimeDashboard.js +++ b/components/pages/RealtimeDashboard.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useMemo, useCallback } from 'react'; +import { useState, useEffect, useMemo, useCallback } from 'react'; import { FormattedMessage } from 'react-intl'; import { subMinutes, startOfMinute } from 'date-fns'; import firstBy from 'thenby'; @@ -10,7 +10,7 @@ import RealtimeHeader from 'components/metrics/RealtimeHeader'; import WorldMap from 'components/common/WorldMap'; import DataTable from 'components/metrics/DataTable'; import RealtimeViews from 'components/metrics/RealtimeViews'; -import useFetch from 'hooks/useFetch'; +import useApi from 'hooks/useApi'; import useLocale from 'hooks/useLocale'; import useCountryNames from 'hooks/useCountryNames'; import { percentFilter } from 'lib/filters'; @@ -33,13 +33,17 @@ export default function RealtimeDashboard() { const countryNames = useCountryNames(locale); const [data, setData] = useState(); const [websiteId, setWebsiteId] = useState(null); - const { data: init, loading } = useFetch('/realtime/init'); - const { data: updates } = useFetch('/realtime/update', { - params: { startAt: data?.timestamp }, - disabled: !init?.websites?.length || !data, - interval: REALTIME_INTERVAL, - headers: { [SHARE_TOKEN_HEADER]: init?.token }, - }); + const { get, useQuery } = useApi(); + const { data: init, isLoading } = useQuery(['realtime:init'], () => get('/realtime/init')); + const { data: updates } = useQuery( + ['realtime:updates'], + () => + get('/realtime/update', { startAt: data?.timestamp }, { [SHARE_TOKEN_HEADER]: init?.token }), + { + disabled: !init?.websites?.length || !data, + retryInterval: REALTIME_INTERVAL, + }, + ); const renderCountryName = useCallback( ({ x }) => {countryNames[x]}, @@ -108,7 +112,7 @@ export default function RealtimeDashboard() { } }, [updates]); - if (!init || !data || loading) { + if (!init || !data || isLoading) { return null; } diff --git a/components/pages/Settings.js b/components/pages/Settings.js index 20d86e4e..120411c3 100644 --- a/components/pages/Settings.js +++ b/components/pages/Settings.js @@ -1,12 +1,12 @@ import Layout from 'components/layout/Layout'; import Menu from 'components/nav/Nav'; -import useRequireLogin from 'hooks/useRequireLogin'; +import useUser from 'hooks/useUser'; import styles from './Settings.module.css'; export default function Settings({ children }) { - const { user: loggedIn } = useRequireLogin(); + const user = useUser(); - if (!loggedIn) { + if (!user) { return null; } diff --git a/components/pages/TeamDetails.js b/components/pages/TeamDetails.js index 96b71a41..979d34ab 100644 --- a/components/pages/TeamDetails.js +++ b/components/pages/TeamDetails.js @@ -6,13 +6,12 @@ import Link from 'next/link'; import Page from 'components/layout/Page'; import TeamEditForm from 'components/forms/TeamEditForm'; import PageHeader from 'components/layout/PageHeader'; -import { getClientAuthToken } from 'lib/client'; import TeamMembersTable from '../tables/TeamMembersTable'; export default function TeamDetails({ teamId }) { const [values, setValues] = useState(null); const [tab, setTab] = useState('general'); - const { get } = useApi(getClientAuthToken()); + const { get } = useApi(); const { toast, showToast } = useToast(); const { data, isLoading } = useQuery( ['team', teamId], diff --git a/components/pages/TeamsList.js b/components/pages/TeamsList.js index 7aae1f3a..50dee246 100644 --- a/components/pages/TeamsList.js +++ b/components/pages/TeamsList.js @@ -6,13 +6,12 @@ import TeamAddForm from 'components/forms/TeamAddForm'; import PageHeader from 'components/layout/PageHeader'; import TeamsTable from 'components/tables/TeamsTable'; import Page from 'components/layout/Page'; -import { getClientAuthToken } from 'lib/client'; import { useQuery } from '@tanstack/react-query'; export default function TeamsList() { const [edit, setEdit] = useState(false); const [update, setUpdate] = useState(0); - const { get } = useApi(getClientAuthToken()); + const { get } = useApi(); const { data, isLoading, error } = useQuery(['teams', update], () => get(`/teams`)); const hasData = data && data.length !== 0; const { toast, showToast } = useToast(); diff --git a/components/pages/TestConsole.js b/components/pages/TestConsole.js index 9da67663..bbde3b97 100644 --- a/components/pages/TestConsole.js +++ b/components/pages/TestConsole.js @@ -1,17 +1,20 @@ +import { Button, Column, Loading, Row } from 'react-basics'; +import Head from 'next/head'; +import Link from 'next/link'; +import { useRouter } from 'next/router'; import DropDown from 'components/common/DropDown'; import Page from 'components/layout/Page'; import PageHeader from 'components/layout/PageHeader'; import EventsChart from 'components/metrics/EventsChart'; import WebsiteChart from 'components/metrics/WebsiteChart'; -import useFetch from 'hooks/useFetch'; -import Head from 'next/head'; -import Link from 'next/link'; -import { useRouter } from 'next/router'; -import { Button, Column, Row } from 'react-basics'; +import useApi from 'hooks/useApi'; import styles from './TestConsole.module.css'; export default function TestConsole() { - const { data } = useFetch('/websites?include_all=true'); + const { get, useQuery } = useApi(); + const { data, isLoading } = useQuery(['websites:test-console'], () => + get('/websites?include_all=true'), + ); const router = useRouter(); const { basePath, @@ -19,6 +22,10 @@ export default function TestConsole() { } = router; const websiteId = id?.[0]; + if (isLoading) { + return ; + } + if (!data) { return null; } diff --git a/components/pages/UserSettings.js b/components/pages/UserSettings.js index b74164a9..52f2d9d8 100644 --- a/components/pages/UserSettings.js +++ b/components/pages/UserSettings.js @@ -4,7 +4,6 @@ import UserEditForm from 'components/forms/UserEditForm'; import UserPasswordForm from 'components/forms/UserPasswordForm'; import Page from 'components/layout/Page'; import PageHeader from 'components/layout/PageHeader'; -import { getClientAuthToken } from 'lib/client'; import useApi from 'hooks/useApi'; import Link from 'next/link'; import { useRouter } from 'next/router'; @@ -14,7 +13,7 @@ import { Breadcrumbs, Item, Tabs, useToast } from 'react-basics'; export default function UserSettings({ userId }) { const [values, setValues] = useState(null); const [tab, setTab] = useState('general'); - const { get } = useApi(getClientAuthToken()); + const { get } = useApi(); const { toast, showToast } = useToast(); const router = useRouter(); const { data, isLoading } = useQuery( diff --git a/components/pages/UsersList.js b/components/pages/UsersList.js index e1260387..194d5e01 100644 --- a/components/pages/UsersList.js +++ b/components/pages/UsersList.js @@ -3,7 +3,6 @@ import PageHeader from 'components/layout/PageHeader'; import UsersTable from 'components/tables/UsersTable'; import { useState } from 'react'; import { Button, Icon, useToast } from 'react-basics'; -import { getClientAuthToken } from 'lib/client'; import { useMutation } from '@tanstack/react-query'; import useApi from 'hooks/useApi'; @@ -11,7 +10,7 @@ export default function UsersList() { const [loading, setLoading] = useState(false); const [error, setError] = useState(); const { toast, showToast } = useToast(); - const { post } = useApi(getClientAuthToken()); + const { post } = useApi(); const { mutate, isLoading } = useMutation(data => post('/api-key', data)); const handleSave = () => { diff --git a/components/pages/WebsiteDetails.js b/components/pages/WebsiteDetails.js index 9f53c9b6..44412a5f 100644 --- a/components/pages/WebsiteDetails.js +++ b/components/pages/WebsiteDetails.js @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { Column } from 'react-basics'; +import { Column, Loading } from 'react-basics'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import classNames from 'classnames'; import WebsiteChart from 'components/metrics/WebsiteChart'; @@ -8,7 +8,6 @@ import Page from 'components/layout/Page'; import GridRow from 'components/layout/GridRow'; import MenuLayout from 'components/layout/MenuLayout'; import Link from 'components/common/Link'; -import Loading from 'components/common/Loading'; import PagesTable from 'components/metrics/PagesTable'; import ReferrersTable from 'components/metrics/ReferrersTable'; import BrowsersTable from 'components/metrics/BrowsersTable'; @@ -18,8 +17,8 @@ import CountriesTable from 'components/metrics/CountriesTable'; import LanguagesTable from 'components/metrics/LanguagesTable'; import ScreenTable from 'components/metrics/ScreenTable'; import QueryParametersTable from 'components/metrics/QueryParametersTable'; -import useFetch from 'hooks/useFetch'; import usePageQuery from 'hooks/usePageQuery'; +import useApi from 'hooks/useApi'; import { DEFAULT_ANIMATION_DURATION } from 'lib/constants'; import Arrow from 'assets/arrow-right.svg'; import styles from './WebsiteDetails.module.css'; @@ -49,7 +48,10 @@ const views = { }; export default function WebsiteDetails({ websiteId }) { - const { data } = useFetch(`/websites/${websiteId}`); + const { get, useQuery } = useApi(); + const { data, isLoading } = useQuery(['websites', websiteId], () => + get(`/websites/${websiteId}`), + ); const [chartLoaded, setChartLoaded] = useState(false); const [countryData, setCountryData] = useState(); const { @@ -122,6 +124,10 @@ export default function WebsiteDetails({ websiteId }) { } } + if (isLoading) { + return ; + } + if (!data) { return null; } @@ -136,7 +142,7 @@ export default function WebsiteDetails({ websiteId }) { showLink={false} stickyHeader /> - {!chartLoaded && } + {!chartLoaded && } {chartLoaded && !view && ( <> diff --git a/components/pages/WebsiteSettings.js b/components/pages/WebsiteSettings.js index d9d0b139..25f00da0 100644 --- a/components/pages/WebsiteSettings.js +++ b/components/pages/WebsiteSettings.js @@ -9,13 +9,12 @@ import WebsiteReset from 'components/forms/WebsiteReset'; import PageHeader from 'components/layout/PageHeader'; import TrackingCodeForm from 'components/forms/TrackingCodeForm'; import ShareUrlForm from 'components/forms/ShareUrlForm'; -import { getClientAuthToken } from 'lib/client'; import ExternalLink from 'assets/external-link.svg'; export default function Websites({ websiteId }) { const [values, setValues] = useState(null); const [tab, setTab] = useState('general'); - const { get } = useApi(getClientAuthToken()); + const { get } = useApi(); const { toast, showToast } = useToast(); const { data, isLoading } = useQuery( ['website', websiteId], diff --git a/components/pages/WebsitesList.js b/components/pages/WebsitesList.js index ead1217f..8618db74 100644 --- a/components/pages/WebsitesList.js +++ b/components/pages/WebsitesList.js @@ -7,14 +7,13 @@ import WebsiteAddForm from 'components/forms/WebsiteAddForm'; import PageHeader from 'components/layout/PageHeader'; import WebsitesTable from 'components/tables/WebsitesTable'; import Page from 'components/layout/Page'; -import { getClientAuthToken } from 'lib/client'; import useUser from 'hooks/useUser'; export default function WebsitesList() { const [edit, setEdit] = useState(false); const [update, setUpdate] = useState(0); - const { get } = useApi(getClientAuthToken()); - const { user } = useUser(); + const { get } = useApi(); + const user = useUser(); const { data, isLoading, error } = useQuery(['websites', update], () => get(`/users/${user.id}/websites`), ); diff --git a/components/settings/DashboardSettingsButton.js b/components/settings/DashboardSettingsButton.js index 64781ef0..c7f902f8 100644 --- a/components/settings/DashboardSettingsButton.js +++ b/components/settings/DashboardSettingsButton.js @@ -1,4 +1,3 @@ -import React from 'react'; import { defineMessages, useIntl } from 'react-intl'; import MenuButton from 'components/common/MenuButton'; import Gear from 'assets/gear.svg'; diff --git a/components/settings/DateRangeSetting.js b/components/settings/DateRangeSetting.js index a6c2e4c8..c2c2c94c 100644 --- a/components/settings/DateRangeSetting.js +++ b/components/settings/DateRangeSetting.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import DateFilter, { filterOptions } from 'components/common/DateFilter'; import { Button } from 'react-basics'; diff --git a/components/settings/LanguageButton.js b/components/settings/LanguageButton.js index 42ddc63a..b83596e4 100644 --- a/components/settings/LanguageButton.js +++ b/components/settings/LanguageButton.js @@ -1,4 +1,3 @@ -import React from 'react'; import { languages } from 'lib/lang'; import useLocale from 'hooks/useLocale'; import MenuButton from 'components/common/MenuButton'; diff --git a/components/settings/LanguageSetting.js b/components/settings/LanguageSetting.js index fda5fbfd..eb3d698a 100644 --- a/components/settings/LanguageSetting.js +++ b/components/settings/LanguageSetting.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import DropDown from 'components/common/DropDown'; import { Button } from 'react-basics'; diff --git a/components/settings/ProfileDetails.js b/components/settings/ProfileDetails.js index c77b946b..bc6b5c0b 100644 --- a/components/settings/ProfileDetails.js +++ b/components/settings/ProfileDetails.js @@ -1,6 +1,6 @@ import TimezoneSetting from 'components/settings/TimezoneSetting'; import useUser from 'hooks/useUser'; -import React from 'react'; + import { FormattedMessage } from 'react-intl'; import DateRangeSetting from './DateRangeSetting'; import LanguageSetting from './LanguageSetting'; @@ -8,7 +8,7 @@ import styles from './ProfileSettings.module.css'; import ThemeSetting from './ThemeSetting'; export default function ProfileDetails() { - const { user } = useUser(); + const user = useUser(); if (!user) { return null; diff --git a/components/settings/SettingsButton.js b/components/settings/SettingsButton.js index f789dfe9..596b36b9 100644 --- a/components/settings/SettingsButton.js +++ b/components/settings/SettingsButton.js @@ -1,4 +1,4 @@ -import React, { useRef, useState } from 'react'; +import { useRef, useState } from 'react'; import { FormattedMessage } from 'react-intl'; import TimezoneSetting from './TimezoneSetting'; import DateRangeSetting from './DateRangeSetting'; diff --git a/components/settings/ThemeButton.js b/components/settings/ThemeButton.js index 18f96f01..ed517596 100644 --- a/components/settings/ThemeButton.js +++ b/components/settings/ThemeButton.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useTransition, animated } from 'react-spring'; import useTheme from 'hooks/useTheme'; import Sun from 'assets/sun.svg'; diff --git a/components/settings/TimezoneSetting.js b/components/settings/TimezoneSetting.js index bc32a3af..8cac4d0d 100644 --- a/components/settings/TimezoneSetting.js +++ b/components/settings/TimezoneSetting.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import { listTimeZones } from 'timezone-support'; import DropDown from 'components/common/DropDown'; diff --git a/components/settings/UserButton.js b/components/settings/UserButton.js index edd0f09d..542588d6 100644 --- a/components/settings/UserButton.js +++ b/components/settings/UserButton.js @@ -4,7 +4,7 @@ import useUser from 'hooks/useUser'; import { AUTH_TOKEN } from 'lib/constants'; import { removeItem } from 'next-basics'; import { useRouter } from 'next/router'; -import React, { useRef, useState } from 'react'; +import { useRef, useState } from 'react'; import { Button, Icon, Item, Menu, Popup, Text } from 'react-basics'; import { FormattedMessage } from 'react-intl'; import styles from './UserButton.module.css'; @@ -13,7 +13,7 @@ import useDocumentClick from '../../hooks/useDocumentClick'; 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/tables/UsersTable.js b/components/tables/UsersTable.js index ee5de9b3..72abd5f8 100644 --- a/components/tables/UsersTable.js +++ b/components/tables/UsersTable.js @@ -1,7 +1,6 @@ import { useQuery } from '@tanstack/react-query'; import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; import { formatDistance } from 'date-fns'; -import { getClientAuthToken } from 'lib/client'; import useApi from 'hooks/useApi'; import Link from 'next/link'; import { useEffect, useState } from 'react'; @@ -26,7 +25,7 @@ const defaultColumns = [ export default function UsersTable({ columns = defaultColumns, onLoading, onAddKeyClick }) { const [values, setValues] = useState(null); - const { get } = useApi(getClientAuthToken()); + const { get } = useApi(); const { data, isLoading, error } = useQuery(['user'], () => get(`/users`)); const hasData = data && data.length !== 0; diff --git a/hooks/useApi.js b/hooks/useApi.js index 72683df1..40a0638d 100644 --- a/hooks/useApi.js +++ b/hooks/useApi.js @@ -1,13 +1,12 @@ import { useApi as nextUseApi } from 'next-basics'; import { getClientAuthToken } from 'lib/client'; import { useRouter } from 'next/router'; +import * as reactQuery from '@tanstack/react-query'; -export function useApi() { +export default function useApi() { const { basePath } = useRouter(); const { get, post, put, del } = nextUseApi(getClientAuthToken(), basePath); - return { get, post, put, del }; + return { get, post, put, del, ...reactQuery }; } - -export default useApi; diff --git a/hooks/useFetch.js b/hooks/useFetch.js deleted file mode 100644 index bf50b917..00000000 --- a/hooks/useFetch.js +++ /dev/null @@ -1,62 +0,0 @@ -import { useState, useEffect } from 'react'; -import { saveQuery } from 'store/queries'; -import useApi from './useApi'; - -export default function useFetch(url, options = {}, update = []) { - const [response, setResponse] = useState(); - const [error, setError] = useState(); - const [loading, setLoading] = useState(false); - const [count, setCount] = useState(0); - const { get } = useApi(); - const { params = {}, headers = {}, disabled = false, delay = 0, interval, onDataLoad } = options; - - async function loadData(params) { - try { - setLoading(true); - setError(null); - const time = performance.now(); - - const { data, status, ok } = await get(url, params, headers); - - await saveQuery(url, { time: performance.now() - time, completed: Date.now() }); - - if (status >= 400) { - setError(data); - setResponse({ data: null, status, ok }); - } else { - setResponse({ data, status, ok }); - } - - onDataLoad?.(data); - } catch (e) { - // eslint-disable-next-line no-console - console.error(e); - - setError(e); - } finally { - setLoading(false); - } - } - - useEffect(() => { - if (url && !disabled) { - const id = setTimeout(() => loadData(params), delay); - - return () => { - clearTimeout(id); - }; - } - }, [url, disabled, count, ...update]); - - useEffect(() => { - if (interval && !disabled) { - const id = setInterval(() => setCount(state => state + 1), interval); - - return () => { - clearInterval(id); - }; - } - }, [interval, disabled]); - - return { ...response, error, loading }; -} diff --git a/hooks/useRequireLogin.js b/hooks/useRequireLogin.js deleted file mode 100644 index 1e73f38b..00000000 --- a/hooks/useRequireLogin.js +++ /dev/null @@ -1,36 +0,0 @@ -import { useState, useEffect } from 'react'; -import { useRouter } from 'next/router'; -import useUser from 'hooks/useUser'; -import useApi from 'hooks/useApi'; - -export default function useRequireLogin() { - const router = useRouter(); - const { get } = useApi(); - const { user, setUser } = useUser(); - const [loading, setLoading] = useState(false); - - async function loadUser() { - setLoading(true); - - const { ok, data } = await get('/auth/verify'); - - if (!ok) { - await router.push('/login'); - return null; - } - - setUser(data.user); - - setLoading(false); - } - - useEffect(() => { - if (loading || user) { - return; - } - - loadUser(); - }, [user, loading]); - - return { user, loading }; -} diff --git a/hooks/useUser.js b/hooks/useUser.js index 6b73c113..108888ea 100644 --- a/hooks/useUser.js +++ b/hooks/useUser.js @@ -1,9 +1,33 @@ +import { useEffect } from 'react'; +import { useRouter } from 'next/router'; import useStore, { setUser } from 'store/app'; +import useApi from 'hooks/useApi'; const selector = state => state.user; +let loading = false; export default function useUser() { const user = useStore(selector); + const { get } = useApi(); + const router = useRouter(); - return { user, setUser }; + useEffect(() => { + async function loadUser() { + const { user } = await get('/auth/verify'); + loading = false; + + if (!user) { + await router.push('/login'); + } else { + setUser(user); + } + } + + if (!user && !loading) { + loading = true; + loadUser(); + } + }, [user, get, router]); + + return user; } diff --git a/lib/prisma.ts b/lib/prisma.ts index 17c5d094..4f63bf7d 100644 --- a/lib/prisma.ts +++ b/lib/prisma.ts @@ -52,7 +52,7 @@ function getTimestampInterval(field: string): string { } } -function getJsonField(column, property, isNumber): string { +function getJsonField(column: string, property: string, isNumber: boolean): string { const db = getDatabaseType(process.env.DATABASE_URL); if (db === POSTGRESQL) { diff --git a/pages/404.js b/pages/404.js index 4c85b10a..0d8d8c7f 100644 --- a/pages/404.js +++ b/pages/404.js @@ -1,4 +1,3 @@ -import React from 'react'; import Layout from 'components/layout/Layout'; import { FormattedMessage } from 'react-intl'; diff --git a/pages/api/websites/[id]/active.ts b/pages/api/websites/[id]/active.ts index 1cfcd54c..5f49c352 100644 --- a/pages/api/websites/[id]/active.ts +++ b/pages/api/websites/[id]/active.ts @@ -20,7 +20,7 @@ export default async ( const { id: websiteId } = req.query; if (req.method === 'GET') { - if (await canViewWebsite(req.auth, websiteId)) { + if (!(await canViewWebsite(req.auth, websiteId))) { return unauthorized(res); } diff --git a/pages/api/websites/[id]/pageviews.ts b/pages/api/websites/[id]/pageviews.ts index 19303aa3..71cb1146 100644 --- a/pages/api/websites/[id]/pageviews.ts +++ b/pages/api/websites/[id]/pageviews.ts @@ -1,9 +1,9 @@ -import { NextApiRequestQueryBody, WebsitePageviews } from 'lib/types'; -import { canViewWebsite } from 'lib/auth'; -import { useAuth, useCors } from 'lib/middleware'; import moment from 'moment-timezone'; import { NextApiResponse } from 'next'; import { badRequest, methodNotAllowed, ok, unauthorized } from 'next-basics'; +import { NextApiRequestQueryBody, WebsitePageviews } from 'lib/types'; +import { canViewWebsite } from 'lib/auth'; +import { useAuth, useCors } from 'lib/middleware'; import { getPageviewStats } from 'queries'; const unitTypes = ['year', 'month', 'hour', 'day']; @@ -14,7 +14,7 @@ export interface WebsitePageviewRequestQuery { startAt: number; endAt: number; unit: string; - tz: string; + timezone: string; url?: string; referrer?: string; os?: string; @@ -35,7 +35,7 @@ export default async ( startAt, endAt, unit, - tz, + timezone, url, referrer, os, @@ -52,7 +52,7 @@ export default async ( const startDate = new Date(+startAt); const endDate = new Date(+endAt); - if (!moment.tz.zone(tz) || !unitTypes.includes(unit)) { + if (!moment.tz.zone(timezone) || !unitTypes.includes(unit)) { return badRequest(res); } @@ -60,7 +60,7 @@ export default async ( getPageviewStats(websiteId, { startDate, endDate, - timezone: tz, + timezone, unit, count: '*', filters: { @@ -75,7 +75,7 @@ export default async ( getPageviewStats(websiteId, { startDate, endDate, - timezone: tz, + timezone, unit, count: 'distinct pageview.', filters: { diff --git a/pages/api/websites/index.ts b/pages/api/websites/index.ts index ec151c95..b1e3204d 100644 --- a/pages/api/websites/index.ts +++ b/pages/api/websites/index.ts @@ -1,4 +1,3 @@ -import { Prisma } from '@prisma/client'; import { canCreateWebsite } from 'lib/auth'; import { uuid } from 'lib/crypto'; import { useAuth, useCors } from 'lib/middleware'; @@ -40,7 +39,7 @@ export default async ( return unauthorized(res); } - const data: Prisma.WebsiteUncheckedCreateInput = { + const data: any = { id: uuid(), name, domain, diff --git a/pages/console/[[...id]].js b/pages/console/[[...id]].js index fa73c3a9..666e0597 100644 --- a/pages/console/[[...id]].js +++ b/pages/console/[[...id]].js @@ -1,15 +1,11 @@ -import React from 'react'; import Layout from 'components/layout/Layout'; import TestConsole from 'components/pages/TestConsole'; -import useRequireLogin from 'hooks/useRequireLogin'; import useUser from 'hooks/useUser'; -import { ROLES } from 'lib/constants'; export default function ConsolePage({ pageDisabled }) { - const { loading } = useRequireLogin(); - const { user } = useUser(); + const user = useUser(); - if (pageDisabled || loading || user?.role !== ROLES.admin) { + if (pageDisabled || !user || !user.isAdmin) { return null; } diff --git a/pages/dashboard/[[...id]].js b/pages/dashboard/[[...id]].js index c9ef6231..b6fc4492 100644 --- a/pages/dashboard/[[...id]].js +++ b/pages/dashboard/[[...id]].js @@ -1,8 +1,6 @@ -import React from 'react'; import { useRouter } from 'next/router'; import Layout from 'components/layout/Layout'; import Dashboard from 'components/pages/Dashboard'; -import useRequireLogin from 'hooks/useRequireLogin'; import useUser from 'hooks/useUser'; import useConfig from 'hooks/useConfig'; @@ -12,11 +10,10 @@ export default function DashboardPage() { isReady, asPath, } = useRouter(); - const { loading } = useRequireLogin(); const user = useUser(); const { adminDisabled } = useConfig(); - if (adminDisabled || !user || !isReady || loading) { + if (adminDisabled || !user || !isReady) { return null; } diff --git a/pages/login.js b/pages/login.js index fb2fcb21..43244a80 100644 --- a/pages/login.js +++ b/pages/login.js @@ -1,4 +1,3 @@ -import React from 'react'; import Layout from 'components/layout/Layout'; import LoginForm from 'components/forms/LoginForm'; diff --git a/pages/profile/index.js b/pages/profile/index.js index 46287b0d..aa560b55 100644 --- a/pages/profile/index.js +++ b/pages/profile/index.js @@ -1,12 +1,11 @@ import Settings from 'components/pages/Settings'; import ProfileSettings from 'components/pages/ProfileSettings'; -import useRequireLogin from 'hooks/useRequireLogin'; -import React from 'react'; +import useUser from 'hooks/useUser'; export default function TeamsPage() { - const { loading } = useRequireLogin(); + const user = useUser(); - if (loading) { + if (!user) { return null; } diff --git a/pages/realtime.js b/pages/realtime.js index 9f1ebffa..472f2692 100644 --- a/pages/realtime.js +++ b/pages/realtime.js @@ -1,12 +1,11 @@ -import React from 'react'; import Layout from 'components/layout/Layout'; import RealtimeDashboard from 'components/pages/RealtimeDashboard'; -import useRequireLogin from 'hooks/useRequireLogin'; +import useUser from 'hooks/useUser'; export default function RealtimePage() { - const { loading } = useRequireLogin(); + const user = useUser(); - if (loading) { + if (!user) { return null; } diff --git a/pages/share/[...id].js b/pages/share/[...id].js index d449afa5..50955748 100644 --- a/pages/share/[...id].js +++ b/pages/share/[...id].js @@ -1,4 +1,3 @@ -import React from 'react'; import { useRouter } from 'next/router'; import Layout from 'components/layout/Layout'; import WebsiteDetails from 'components/pages/WebsiteDetails'; diff --git a/pages/sso.js b/pages/sso.js index 17ffa6b8..39f66f9a 100644 --- a/pages/sso.js +++ b/pages/sso.js @@ -1,7 +1,6 @@ import { useEffect } from 'react'; import { useRouter } from 'next/router'; -import { setItem } from 'next-basics'; -import { AUTH_TOKEN } from 'lib/constants'; +import { setClientAuthToken } from 'lib/client'; export default function SingleSignOnPage() { const router = useRouter(); @@ -9,7 +8,7 @@ export default function SingleSignOnPage() { useEffect(() => { if (url && token) { - setItem(AUTH_TOKEN, token); + setClientAuthToken(token); router.push(url); } diff --git a/pages/teams/[...id].js b/pages/teams/[...id].js index 6e44c43a..7afebd0c 100644 --- a/pages/teams/[...id].js +++ b/pages/teams/[...id].js @@ -1,15 +1,14 @@ import Settings from 'components/pages/Settings'; import TeamDetails from 'components/pages/TeamDetails'; -import useRequireLogin from 'hooks/useRequireLogin'; +import useUser from 'hooks/useUser'; import { useRouter } from 'next/router'; -import React from 'react'; export default function TeamDetailPage() { - const { loading } = useRequireLogin(); + const user = useUser(); const router = useRouter(); const { id } = router.query; - if (loading) { + if (!user) { return null; } diff --git a/pages/teams/index.js b/pages/teams/index.js index a3d18c74..c7b91576 100644 --- a/pages/teams/index.js +++ b/pages/teams/index.js @@ -1,12 +1,11 @@ import Settings from 'components/pages/Settings'; import TeamsList from 'components/pages/TeamsList'; -import useRequireLogin from 'hooks/useRequireLogin'; -import React from 'react'; +import useUser from 'hooks/useUser'; export default function TeamsPage() { - const { loading } = useRequireLogin(); + const user = useUser(); - if (loading) { + if (!user) { return null; } diff --git a/pages/users/[...id].js b/pages/users/[...id].js index a8023b06..ba18ef69 100644 --- a/pages/users/[...id].js +++ b/pages/users/[...id].js @@ -1,15 +1,14 @@ import Settings from 'components/pages/Settings'; import UserSettings from 'components/pages/UserSettings'; -import useRequireLogin from 'hooks/useRequireLogin'; +import useUser from 'hooks/useUser'; import { useRouter } from 'next/router'; -import React from 'react'; export default function TeamDetailPage() { - const { loading } = useRequireLogin(); + const user = useUser(); const router = useRouter(); const { id } = router.query; - if (loading) { + if (!user) { return null; } diff --git a/pages/users/index.js b/pages/users/index.js index cd525319..1412e1b7 100644 --- a/pages/users/index.js +++ b/pages/users/index.js @@ -1,14 +1,14 @@ import Settings from 'components/pages/Settings'; import useConfig from 'hooks/useConfig'; -import useRequireLogin from 'hooks/useRequireLogin'; -import React from 'react'; +import useUser from 'hooks/useUser'; + import UsersList from 'components/pages/UsersList'; export default function UsersPage() { - const { loading } = useRequireLogin(); + const user = useUser(); const { adminDisabled } = useConfig(); - if (adminDisabled || loading) { + if (adminDisabled || !user) { return null; } diff --git a/pages/websites/[id]/index.js b/pages/websites/[id]/index.js index 8149da83..034295a0 100644 --- a/pages/websites/[id]/index.js +++ b/pages/websites/[id]/index.js @@ -1,15 +1,14 @@ -import React from 'react'; import { useRouter } from 'next/router'; import Layout from 'components/layout/Layout'; import WebsiteDetails from 'components/pages/WebsiteDetails'; -import useRequireLogin from 'hooks/useRequireLogin'; +import useUser from 'hooks/useUser'; export default function DetailsPage() { - const { loading } = useRequireLogin(); + const user = useUser(); const router = useRouter(); const { id } = router.query; - if (!id || loading) { + if (!id || !user) { return null; } diff --git a/pages/websites/[id]/settings.js b/pages/websites/[id]/settings.js index 387f34aa..ba2d326b 100644 --- a/pages/websites/[id]/settings.js +++ b/pages/websites/[id]/settings.js @@ -1,15 +1,14 @@ -import React from 'react'; import { useRouter } from 'next/router'; import WebsiteSettings from 'components/pages/WebsiteSettings'; -import useRequireLogin from 'hooks/useRequireLogin'; +import useUser from 'hooks/useUser'; import Settings from 'components/pages/Settings'; export default function WebsiteSettingsPage() { - const { loading } = useRequireLogin(); + const user = useUser(); const router = useRouter(); const { id } = router.query; - if (!id || loading) { + if (!id || !user) { return null; } diff --git a/pages/websites/index.js b/pages/websites/index.js index 18a08483..56f9c67c 100644 --- a/pages/websites/index.js +++ b/pages/websites/index.js @@ -1,14 +1,14 @@ import Settings from 'components/pages/Settings'; import useConfig from 'hooks/useConfig'; -import useRequireLogin from 'hooks/useRequireLogin'; -import React from 'react'; +import useUser from 'hooks/useUser'; + import WebsitesList from 'components/pages/WebsitesList'; export default function WebsitesPage() { - const { loading } = useRequireLogin(); + const user = useUser(); const { adminDisabled } = useConfig(); - if (adminDisabled || loading) { + if (adminDisabled || !user) { return null; } diff --git a/queries/admin/teamUser.ts b/queries/admin/teamUser.ts index 13090031..2dc20d11 100644 --- a/queries/admin/teamUser.ts +++ b/queries/admin/teamUser.ts @@ -16,6 +16,9 @@ export async function getTeamUsers(teamId: string): Promise { where: { teamId, }, + include: { + user: true, + }, }); } diff --git a/queries/analytics/event/getEventData.ts b/queries/analytics/event/getEventData.ts index ae8b8503..9d03ae82 100644 --- a/queries/analytics/event/getEventData.ts +++ b/queries/analytics/event/getEventData.ts @@ -54,7 +54,7 @@ async function relationalQuery( ? `and ${getEventDataFilterQuery('event_data', filters)}` : '' }`, - params, + params as any, ); }