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,
);
}