Renamed query hooks. Fixed conversion bugs.

This commit is contained in:
Mike Cao 2025-03-22 03:48:18 -07:00
parent adca3c36d0
commit 7886c3f393
110 changed files with 423 additions and 489 deletions

View file

@ -6,10 +6,10 @@ import { UpdateNotice } from './UpdateNotice';
import { Nav } from '@/app/(main)/Nav'; import { Nav } from '@/app/(main)/Nav';
import { MenuBar } from '@/app/(main)/MenuBar'; import { MenuBar } from '@/app/(main)/MenuBar';
import { Page } from '@/components/layout/Page'; import { Page } from '@/components/layout/Page';
import { useLogin, useConfig } from '@/components/hooks'; import { useLoginQuery, useConfig } from '@/components/hooks';
export function App({ children }) { export function App({ children }) {
const { user, isLoading, error } = useLogin(); const { user, isLoading, error } = useLoginQuery();
const config = useConfig(); const config = useConfig();
const pathname = usePathname(); const pathname = usePathname();

View file

@ -17,6 +17,7 @@ export function MenuBar(props: RowProps) {
paddingY="3" paddingY="3"
paddingX="3" paddingX="3"
paddingRight="5" paddingRight="5"
backgroundColor="1"
> >
<Row> <Row>
<Button onPress={() => setCollapsed(!isCollapsed)} variant="quiet"> <Button onPress={() => setCollapsed(!isCollapsed)} variant="quiet">

View file

@ -1,12 +1,12 @@
import Link from 'next/link'; import Link from 'next/link';
import { SideNav, SideNavHeader, SideNavSection, SideNavItem } from '@umami/react-zen'; import { SideNav, SideNavHeader, SideNavSection, SideNavItem } from '@umami/react-zen';
import { Lucide, Icons } from '@/components/icons'; import { Lucide, Icons } from '@/components/icons';
import { useMessages, useTeamUrl } from '@/components/hooks'; import { useMessages, useNavigation } from '@/components/hooks';
import useGlobalState from '@/components/hooks/useGlobalState'; import useGlobalState from '@/components/hooks/useGlobalState';
export function Nav(props: any) { export function Nav(props: any) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { renderTeamUrl, pathname } = useTeamUrl(); const { renderTeamUrl, pathname } = useNavigation();
const [isCollapsed] = useGlobalState('sidenav-collapsed'); const [isCollapsed] = useGlobalState('sidenav-collapsed');
const links = [ const links = [

View file

@ -6,13 +6,13 @@ import { WebsiteChartList } from '../websites/[websiteId]/WebsiteChartList';
import { DashboardSettingsButton } from '@/app/(main)/dashboard/DashboardSettingsButton'; import { DashboardSettingsButton } from '@/app/(main)/dashboard/DashboardSettingsButton';
import { DashboardEdit } from '@/app/(main)/dashboard/DashboardEdit'; import { DashboardEdit } from '@/app/(main)/dashboard/DashboardEdit';
import { EmptyPlaceholder } from '@/components/common/EmptyPlaceholder'; import { EmptyPlaceholder } from '@/components/common/EmptyPlaceholder';
import { useMessages, useTeamUrl, useWebsites } from '@/components/hooks'; import { useMessages, useNavigation, useWebsites } from '@/components/hooks';
import { useDashboard } from '@/store/dashboard'; import { useDashboard } from '@/store/dashboard';
import { LinkButton } from '@/components/common/LinkButton'; import { LinkButton } from '@/components/common/LinkButton';
export function DashboardPage() { export function DashboardPage() {
const { formatMessage, labels, messages } = useMessages(); const { formatMessage, labels, messages } = useMessages();
const { teamId, renderTeamUrl } = useTeamUrl(); const { teamId, renderTeamUrl } = useNavigation();
const { showCharts, editing, isEdited } = useDashboard(); const { showCharts, editing, isEdited } = useDashboard();
const pageSize = isEdited ? 200 : 10; const pageSize = isEdited ? 200 : 10;

View file

@ -1,14 +1,14 @@
import { Form, FormField, Column, Label } from '@umami/react-zen'; import { Column, Label } from '@umami/react-zen';
import { TimezoneSetting } from '@/app/(main)/profile/TimezoneSetting'; import { TimezoneSetting } from '@/app/(main)/profile/TimezoneSetting';
import { DateRangeSetting } from '@/app/(main)/profile/DateRangeSetting'; import { DateRangeSetting } from '@/app/(main)/profile/DateRangeSetting';
import { LanguageSetting } from '@/app/(main)/profile/LanguageSetting'; import { LanguageSetting } from '@/app/(main)/profile/LanguageSetting';
import { ThemeSetting } from '@/app/(main)/profile/ThemeSetting'; import { ThemeSetting } from '@/app/(main)/profile/ThemeSetting';
import { PasswordChangeButton } from './PasswordChangeButton'; import { PasswordChangeButton } from './PasswordChangeButton';
import { useLogin, useMessages } from '@/components/hooks'; import { useLoginQuery, useMessages } from '@/components/hooks';
import { ROLES } from '@/lib/constants'; import { ROLES } from '@/lib/constants';
export function ProfileSettings() { export function ProfileSettings() {
const { user } = useLogin(); const { user } = useLoginQuery();
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const cloudMode = !!process.env.cloudMode; const cloudMode = !!process.env.cloudMode;

View file

@ -1,5 +1,5 @@
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { useReports } from '@/components/hooks'; import { useReportsQuery } from '@/components/hooks';
import { DataGrid } from '@/components/common/DataGrid'; import { DataGrid } from '@/components/common/DataGrid';
import { ReportsTable } from './ReportsTable'; import { ReportsTable } from './ReportsTable';
@ -12,7 +12,7 @@ export function ReportsDataTable({
teamId?: string; teamId?: string;
children?: ReactNode; children?: ReactNode;
}) { }) {
const queryResult = useReports({ websiteId, teamId }); const queryResult = useReportsQuery({ websiteId, teamId });
return ( return (
<DataGrid queryResult={queryResult} renderEmpty={() => children}> <DataGrid queryResult={queryResult} renderEmpty={() => children}>

View file

@ -1,13 +1,13 @@
import { PageHeader } from '@/components/layout/PageHeader'; import { PageHeader } from '@/components/layout/PageHeader';
import { Icon, Icons, Text } from '@umami/react-zen'; import { Icon, Icons, Text } from '@umami/react-zen';
import { useLogin, useMessages, useTeamUrl } from '@/components/hooks'; import { useLoginQuery, useMessages, useNavigation } from '@/components/hooks';
import { LinkButton } from '@/components/common/LinkButton'; import { LinkButton } from '@/components/common/LinkButton';
import { ROLES } from '@/lib/constants'; import { ROLES } from '@/lib/constants';
export function ReportsHeader() { export function ReportsHeader() {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { renderTeamUrl } = useTeamUrl(); const { renderTeamUrl } = useNavigation();
const { user } = useLogin(); const { user } = useLoginQuery();
const canEdit = user.role !== ROLES.viewOnly; const canEdit = user.role !== ROLES.viewOnly;
return ( return (

View file

@ -2,10 +2,10 @@
import { Metadata } from 'next'; import { Metadata } from 'next';
import { ReportsHeader } from './ReportsHeader'; import { ReportsHeader } from './ReportsHeader';
import { ReportsDataTable } from './ReportsDataTable'; import { ReportsDataTable } from './ReportsDataTable';
import { useTeamUrl } from '@/components/hooks'; import { useNavigation } from '@/components/hooks';
export function ReportsPage() { export function ReportsPage() {
const { teamId } = useTeamUrl(); const { teamId } = useNavigation();
return ( return (
<> <>

View file

@ -1,13 +1,13 @@
import { Icon, Icons, Text, DataTable, DataColumn, Row } from '@umami/react-zen'; import { Icon, Icons, Text, DataTable, DataColumn, Row } from '@umami/react-zen';
import { LinkButton } from '@/components/common/LinkButton'; import { LinkButton } from '@/components/common/LinkButton';
import { useMessages, useLogin, useTeamUrl } from '@/components/hooks'; import { useMessages, useLoginQuery, useNavigation } from '@/components/hooks';
import { REPORT_TYPES } from '@/lib/constants'; import { REPORT_TYPES } from '@/lib/constants';
import { ReportDeleteButton } from './ReportDeleteButton'; import { ReportDeleteButton } from './ReportDeleteButton';
export function ReportsTable({ data = [], showDomain }: { data: any[]; showDomain?: boolean }) { export function ReportsTable({ data = [], showDomain }: { data: any[]; showDomain?: boolean }) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { user } = useLogin(); const { user } = useLoginQuery();
const { renderTeamUrl } = useTeamUrl(); const { renderTeamUrl } = useNavigation();
return ( return (
<DataTable data={data}> <DataTable data={data}>

View file

@ -3,7 +3,7 @@ import { Column, Label } from '@umami/react-zen';
import { parseDateRange } from '@/lib/date'; import { parseDateRange } from '@/lib/date';
import { DateFilter } from '@/components/input/DateFilter'; import { DateFilter } from '@/components/input/DateFilter';
import { WebsiteSelect } from '@/components/input/WebsiteSelect'; import { WebsiteSelect } from '@/components/input/WebsiteSelect';
import { useMessages, useTeamUrl, useWebsite } from '@/components/hooks'; import { useMessages, useNavigation, useWebsiteQuery } from '@/components/hooks';
import { ReportContext } from './Report'; import { ReportContext } from './Report';
import styles from './BaseParameters.module.css'; import styles from './BaseParameters.module.css';
@ -22,11 +22,11 @@ export function BaseParameters({
}: BaseParametersProps) { }: BaseParametersProps) {
const { report, updateReport } = useContext(ReportContext); const { report, updateReport } = useContext(ReportContext);
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { teamId } = useTeamUrl(); const { teamId } = useNavigation();
const { parameters } = report || {}; const { parameters } = report || {};
const { websiteId, dateRange } = parameters || {}; const { websiteId, dateRange } = parameters || {};
const { value, startDate, endDate } = dateRange || {}; const { value, startDate, endDate } = dateRange || {};
const { data: website } = useWebsite(websiteId); const { data: website } = useWebsiteQuery(websiteId);
const { name } = website || {}; const { name } = website || {};
const handleWebsiteSelect = (websiteId: string) => { const handleWebsiteSelect = (websiteId: string) => {

View file

@ -1,5 +1,5 @@
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';
import { useFilters, useFormat, useMessages, useWebsiteValues } from '@/components/hooks'; import { useFilters, useFormat, useMessages, useWebsiteValuesQuery } from '@/components/hooks';
import { OPERATORS } from '@/lib/constants'; import { OPERATORS } from '@/lib/constants';
import { isEqualsOperator } from '@/lib/params'; import { isEqualsOperator } from '@/lib/params';
import { import {
@ -62,7 +62,7 @@ export function FieldFilterEditForm({
data: values = [], data: values = [],
isLoading, isLoading,
refetch, refetch,
} = useWebsiteValues({ } = useWebsiteValuesQuery({
websiteId, websiteId,
type: name, type: name,
startDate, startDate,

View file

@ -1,7 +1,7 @@
import { createContext, ReactNode } from 'react'; import { createContext, ReactNode } from 'react';
import { Loading } from '@umami/react-zen'; import { Loading } from '@umami/react-zen';
import classNames from 'classnames'; import classNames from 'classnames';
import { useReport } from '@/components/hooks'; import { useReportQuery } from '@/components/hooks';
import styles from './Report.module.css'; import styles from './Report.module.css';
export const ReportContext = createContext(null); export const ReportContext = createContext(null);
@ -17,7 +17,7 @@ export function Report({
children: ReactNode; children: ReactNode;
className?: string; className?: string;
}) { }) {
const report = useReport(reportId, defaultParameters); const report = useReportQuery(reportId, defaultParameters);
if (!report) { if (!report) {
return reportId ? <Loading position="page" /> : null; return reportId ? <Loading position="page" /> : null;

View file

@ -1,6 +1,6 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { Icon, LoadingButton, InlineEditField, useToast } from '@umami/react-zen'; import { Icon, LoadingButton, InlineEditField, useToast } from '@umami/react-zen';
import { useMessages, useApi, useNavigation, useTeamUrl } from '@/components/hooks'; import { useMessages, useApi, useNavigation } from '@/components/hooks';
import { ReportContext } from './Report'; import { ReportContext } from './Report';
import styles from './ReportHeader.module.css'; import styles from './ReportHeader.module.css';
import { REPORT_TYPES } from '@/lib/constants'; import { REPORT_TYPES } from '@/lib/constants';
@ -10,8 +10,7 @@ export function ReportHeader({ icon }) {
const { report, updateReport } = useContext(ReportContext); const { report, updateReport } = useContext(ReportContext);
const { formatMessage, labels, messages } = useMessages(); const { formatMessage, labels, messages } = useMessages();
const { toast } = useToast(); const { toast } = useToast();
const { router } = useNavigation(); const { router, renderTeamUrl } = useNavigation();
const { renderTeamUrl } = useTeamUrl();
const { post, useMutation } = useApi(); const { post, useMutation } = useApi();
const { mutate: create, isPending: isCreating } = useMutation({ const { mutate: create, isPending: isCreating } = useMutation({

View file

@ -1,5 +1,5 @@
'use client'; 'use client';
import { useReport } from '@/components/hooks'; import { useReportQuery } from '@/components/hooks';
import { EventDataReport } from '../event-data/EventDataReport'; import { EventDataReport } from '../event-data/EventDataReport';
import { FunnelReport } from '../funnel/FunnelReport'; import { FunnelReport } from '../funnel/FunnelReport';
import { GoalsReport } from '../goals/GoalsReport'; import { GoalsReport } from '../goals/GoalsReport';
@ -21,7 +21,7 @@ const reports = {
}; };
export function ReportPage({ reportId }: { reportId: string }) { export function ReportPage({ reportId }: { reportId: string }) {
const { report } = useReport(reportId); const { report } = useReportQuery(reportId);
if (!report) { if (!report) {
return null; return null;

View file

@ -1,12 +1,12 @@
import { Icon, Text, Row, Column, Grid } from '@umami/react-zen'; import { Icon, Text, Row, Column, Grid } from '@umami/react-zen';
import { useMessages, useTeamUrl } from '@/components/hooks'; import { useMessages, useNavigation } from '@/components/hooks';
import { Icons } from '@/components/icons'; import { Icons } from '@/components/icons';
import { PageHeader } from '@/components/layout/PageHeader'; import { PageHeader } from '@/components/layout/PageHeader';
import { LinkButton } from '@/components/common/LinkButton'; import { LinkButton } from '@/components/common/LinkButton';
export function ReportTemplates({ showHeader = true }: { showHeader?: boolean }) { export function ReportTemplates({ showHeader = true }: { showHeader?: boolean }) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { renderTeamUrl } = useTeamUrl(); const { renderTeamUrl } = useNavigation();
const reports = [ const reports = [
{ {

View file

@ -1,5 +1,5 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { GridTable, GridColumn } from '@umami/react-zen'; import { DataTable, DataColumn } from '@umami/react-zen';
import { useMessages } from '@/components/hooks'; import { useMessages } from '@/components/hooks';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
@ -8,10 +8,10 @@ export function EventDataTable() {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
return ( return (
<GridTable data={report?.data || []}> <DataTable data={report?.data || []}>
<GridColumn name="field" label={formatMessage(labels.field)} /> <DataColumn id="field" label={formatMessage(labels.field)} />
<GridColumn name="value" label={formatMessage(labels.value)} /> <DataColumn id="value" label={formatMessage(labels.value)} />
<GridColumn name="total" label={formatMessage(labels.total)} /> <DataColumn id="total" label={formatMessage(labels.total)} />
</GridTable> </DataTable>
); );
} }

View file

@ -1,5 +1,5 @@
import { useContext, useMemo, useState } from 'react'; import { useContext, useMemo, useState } from 'react';
import { TextOverflow, TooltipPopup } from '@umami/react-zen'; import { TooltipTrigger, Tooltip, Focusable } from '@umami/react-zen';
import { firstBy } from 'thenby'; import { firstBy } from 'thenby';
import classNames from 'classnames'; import classNames from 'classnames';
import { useEscapeKey, useMessages } from '@/components/hooks'; import { useEscapeKey, useMessages } from '@/components/hooks';
@ -192,13 +192,18 @@ export function JourneyView() {
onClick={() => handleClick(name, columnIndex, paths)} onClick={() => handleClick(name, columnIndex, paths)}
> >
<div className={styles.name} title={name}> <div className={styles.name} title={name}>
<TextOverflow> {name}</TextOverflow> {name}
</div> </div>
<TooltipPopup label={dropOffPercent} isDisabled={!selected}> <TooltipTrigger isDisabled={!selected}>
<div className={styles.count} title={nodeCount}> <Focusable>
{formatLongNumber(nodeCount)} <div>{dropOffPercent}</div>
</div> </Focusable>
</TooltipPopup> <Tooltip>
<div className={styles.count} title={nodeCount}>
{formatLongNumber(nodeCount)}
</div>
</Tooltip>
</TooltipTrigger>
{columnIndex < columns.length && {columnIndex < columns.length &&
lines.map(([fromIndex, nodeIndex], i) => { lines.map(([fromIndex, nodeIndex], i) => {
const height = const height =

View file

@ -1,5 +1,5 @@
import { useMessages } from '@/components/hooks'; import { useMessages } from '@/components/hooks';
import { useRevenueValues } from '@/components/hooks/queries/useRevenueValues'; import { useRevenueValuesQuery } from '@/components/hooks/queries/useRevenueValuesQuery';
import { useContext } from 'react'; import { useContext } from 'react';
import { Select, Form, FormButtons, FormField, ListItem, FormSubmitButton } from '@umami/react-zen'; import { Select, Form, FormButtons, FormField, ListItem, FormSubmitButton } from '@umami/react-zen';
import { BaseParameters } from '../[reportId]/BaseParameters'; import { BaseParameters } from '../[reportId]/BaseParameters';
@ -11,7 +11,7 @@ export function RevenueParameters() {
const { id, parameters } = report || {}; const { id, parameters } = report || {};
const { websiteId, dateRange } = parameters || {}; const { websiteId, dateRange } = parameters || {};
const queryEnabled = websiteId && dateRange; const queryEnabled = websiteId && dateRange;
const { data: values = [] } = useRevenueValues( const { data: values = [] } = useRevenueValuesQuery(
websiteId, websiteId,
dateRange?.startDate, dateRange?.startDate,
dateRange?.endDate, dateRange?.endDate,
@ -34,7 +34,7 @@ export function RevenueParameters() {
rules={{ required: formatMessage(labels.required) }} rules={{ required: formatMessage(labels.required) }}
> >
<Select items={values.map(item => item.currency)}> <Select items={values.map(item => item.currency)}>
{item => <ListItem key={item}>{item}</ListItem>} {(item: any) => <ListItem key={item}>{item}</ListItem>}
</Select> </Select>
</FormField> </FormField>
<FormButtons> <FormButtons>

View file

@ -1,7 +1,7 @@
import { EmptyPlaceholder } from '@/components/common/EmptyPlaceholder'; import { EmptyPlaceholder } from '@/components/common/EmptyPlaceholder';
import { useMessages } from '@/components/hooks'; import { useMessages } from '@/components/hooks';
import { useContext } from 'react'; import { useContext } from 'react';
import { GridColumn, GridTable } from '@umami/react-zen'; import { DataColumn, DataTable } from '@umami/react-zen';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
import { formatLongCurrency } from '@/lib/format'; import { formatLongCurrency } from '@/lib/format';
@ -15,22 +15,22 @@ export function RevenueTable() {
} }
return ( return (
<GridTable data={data.table || []}> <DataTable data={data.table || []}>
<GridColumn name="currency" label={formatMessage(labels.currency)} alignment="end"> <DataColumn id="currency" label={formatMessage(labels.currency)} align="end">
{row => row.currency} {(row: any) => row.currency}
</GridColumn> </DataColumn>
<GridColumn name="currency" label={formatMessage(labels.total)} width="300px" alignment="end"> <DataColumn id="currency" label={formatMessage(labels.total)} align="end">
{row => formatLongCurrency(row.sum, row.currency)} {(row: any) => formatLongCurrency(row.sum, row.currency)}
</GridColumn> </DataColumn>
<GridColumn name="currency" label={formatMessage(labels.average)} alignment="end"> <DataColumn id="currency" label={formatMessage(labels.average)} align="end">
{row => formatLongCurrency(row.count ? row.sum / row.count : 0, row.currency)} {(row: any) => formatLongCurrency(row.count ? row.sum / row.count : 0, row.currency)}
</GridColumn> </DataColumn>
<GridColumn name="currency" label={formatMessage(labels.transactions)} alignment="end"> <DataColumn id="currency" label={formatMessage(labels.transactions)} align="end">
{row => row.count} {(row: any) => row.count}
</GridColumn> </DataColumn>
<GridColumn name="currency" label={formatMessage(labels.uniqueCustomers)} alignment="end"> <DataColumn id="currency" label={formatMessage(labels.uniqueCustomers)} align="end">
{row => row.unique_count} {(row: any) => row.unique_count}
</GridColumn> </DataColumn>
</GridTable> </DataTable>
); );
} }

View file

@ -1,10 +1,10 @@
'use client'; 'use client';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { useLogin, useMessages } from '@/components/hooks'; import { useLoginQuery, useMessages } from '@/components/hooks';
import { MenuLayout } from '@/components/layout/MenuLayout'; import { MenuLayout } from '@/components/layout/MenuLayout';
export function SettingsLayout({ children }: { children: ReactNode }) { export function SettingsLayout({ children }: { children: ReactNode }) {
const { user } = useLogin(); const { user } = useLoginQuery();
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const items = [ const items = [

View file

@ -1,4 +1,4 @@
import { useLogin, useMessages, useModified } from '@/components/hooks'; import { useLoginQuery, useMessages, useModified } from '@/components/hooks';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { Button, Icon, Icons, Modal, DialogTrigger, Dialog, Text } from '@umami/react-zen'; import { Button, Icon, Icons, Modal, DialogTrigger, Dialog, Text } from '@umami/react-zen';
import { TeamLeaveForm } from './TeamLeaveForm'; import { TeamLeaveForm } from './TeamLeaveForm';
@ -6,7 +6,7 @@ import { TeamLeaveForm } from './TeamLeaveForm';
export function TeamLeaveButton({ teamId, teamName }: { teamId: string; teamName: string }) { export function TeamLeaveButton({ teamId, teamName }: { teamId: string; teamName: string }) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const router = useRouter(); const router = useRouter();
const { user } = useLogin(); const { user } = useLoginQuery();
const { touch } = useModified(); const { touch } = useModified();
const handleLeave = async () => { const handleLeave = async () => {

View file

@ -1,6 +1,6 @@
import { DataGrid } from '@/components/common/DataGrid'; import { DataGrid } from '@/components/common/DataGrid';
import { TeamsTable } from '@/app/(main)/settings/teams/TeamsTable'; import { TeamsTable } from '@/app/(main)/settings/teams/TeamsTable';
import { useLogin, useTeams } from '@/components/hooks'; import { useLoginQuery, useTeamsQuery } from '@/components/hooks';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
export function TeamsDataTable({ export function TeamsDataTable({
@ -12,8 +12,8 @@ export function TeamsDataTable({
showActions?: boolean; showActions?: boolean;
children?: ReactNode; children?: ReactNode;
}) { }) {
const { user } = useLogin(); const { user } = useLoginQuery();
const queryResult = useTeams(user.id); const queryResult = useTeamsQuery(user.id);
return ( return (
<DataGrid queryResult={queryResult} renderEmpty={() => children}> <DataGrid queryResult={queryResult} renderEmpty={() => children}>

View file

@ -1,13 +1,13 @@
import { Row } from '@umami/react-zen'; import { Row } from '@umami/react-zen';
import { PageHeader } from '@/components/layout/PageHeader'; import { PageHeader } from '@/components/layout/PageHeader';
import { ROLES } from '@/lib/constants'; import { ROLES } from '@/lib/constants';
import { useLogin, useMessages } from '@/components/hooks'; import { useLoginQuery, useMessages } from '@/components/hooks';
import { TeamsJoinButton } from './TeamsJoinButton'; import { TeamsJoinButton } from './TeamsJoinButton';
import { TeamsAddButton } from './TeamsAddButton'; import { TeamsAddButton } from './TeamsAddButton';
export function TeamsHeader({ allowCreate = true }: { allowCreate?: boolean }) { export function TeamsHeader({ allowCreate = true }: { allowCreate?: boolean }) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { user } = useLogin(); const { user } = useLoginQuery();
const cloudMode = !!process.env.cloudMode; const cloudMode = !!process.env.cloudMode;
return ( return (

View file

@ -1,5 +1,5 @@
import { Button, Icon, Icons, Modal, DialogTrigger, Dialog, Text } from '@umami/react-zen'; import { Button, Icon, Icons, Modal, DialogTrigger, Dialog, Text } from '@umami/react-zen';
import { useMessages, useLogin } from '@/components/hooks'; import { useMessages, useLoginQuery } from '@/components/hooks';
import { UserDeleteForm } from './UserDeleteForm'; import { UserDeleteForm } from './UserDeleteForm';
export function UserDeleteButton({ export function UserDeleteButton({
@ -12,7 +12,7 @@ export function UserDeleteButton({
onDelete?: () => void; onDelete?: () => void;
}) { }) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { user } = useLogin(); const { user } = useLoginQuery();
return ( return (
<DialogTrigger> <DialogTrigger>

View file

@ -1,5 +1,5 @@
import { DataGrid } from '@/components/common/DataGrid'; import { DataGrid } from '@/components/common/DataGrid';
import { useUsers } from '@/components/hooks'; import { useUsersQuery } from '@/components/hooks';
import { UsersTable } from './UsersTable'; import { UsersTable } from './UsersTable';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
@ -10,7 +10,7 @@ export function UsersDataTable({
showActions?: boolean; showActions?: boolean;
children?: ReactNode; children?: ReactNode;
}) { }) {
const queryResult = useUsers(); const queryResult = useUsersQuery();
return ( return (
<DataGrid queryResult={queryResult} renderEmpty={() => children}> <DataGrid queryResult={queryResult} renderEmpty={() => children}>

View file

@ -9,7 +9,7 @@ import {
PasswordField, PasswordField,
useToast, useToast,
} from '@umami/react-zen'; } from '@umami/react-zen';
import { useApi, useLogin, useMessages, useModified } from '@/components/hooks'; import { useApi, useLoginQuery, useMessages, useModified } from '@/components/hooks';
import { ROLES } from '@/lib/constants'; import { ROLES } from '@/lib/constants';
import { useContext } from 'react'; import { useContext } from 'react';
import { UserContext } from './UserProvider'; import { UserContext } from './UserProvider';
@ -18,7 +18,7 @@ export function UserEditForm({ userId, onSave }: { userId: string; onSave?: () =
const { formatMessage, labels, messages, getMessage } = useMessages(); const { formatMessage, labels, messages, getMessage } = useMessages();
const { post, useMutation } = useApi(); const { post, useMutation } = useApi();
const user = useContext(UserContext); const user = useContext(UserContext);
const { user: login } = useLogin(); const { user: login } = useLoginQuery();
const { toast } = useToast(); const { toast } = useToast();
const { touch } = useModified(); const { touch } = useModified();

View file

@ -1,12 +1,12 @@
import { createContext, ReactNode, useEffect } from 'react'; import { createContext, ReactNode, useEffect } from 'react';
import { Loading } from '@umami/react-zen'; import { Loading } from '@umami/react-zen';
import { useModified, useUser } from '@/components/hooks'; import { useModified, useUserQuery } from '@/components/hooks';
export const UserContext = createContext(null); export const UserContext = createContext(null);
export function UserProvider({ userId, children }: { userId: string; children: ReactNode }) { export function UserProvider({ userId, children }: { userId: string; children: ReactNode }) {
const { modified } = useModified(`user:${userId}`); const { modified } = useModified(`user:${userId}`);
const { data: user, isFetching, isLoading, refetch } = useUser(userId); const { data: user, isFetching, isLoading, refetch } = useUserQuery(userId);
useEffect(() => { useEffect(() => {
if (modified) { if (modified) {

View file

@ -1,4 +1,4 @@
import { useMessages, useTeamUrl } from '@/components/hooks'; import { useMessages, useNavigation } from '@/components/hooks';
import { PageHeader } from '@/components/layout/PageHeader'; import { PageHeader } from '@/components/layout/PageHeader';
import { WebsiteAddButton } from './WebsiteAddButton'; import { WebsiteAddButton } from './WebsiteAddButton';
@ -8,7 +8,7 @@ export interface WebsitesHeaderProps {
export function WebsitesHeader({ allowCreate = true }: WebsitesHeaderProps) { export function WebsitesHeader({ allowCreate = true }: WebsitesHeaderProps) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { teamId } = useTeamUrl(); const { teamId } = useNavigation();
return ( return (
<PageHeader title={formatMessage(labels.websites)}> <PageHeader title={formatMessage(labels.websites)}>

View file

@ -1,11 +1,11 @@
'use client'; 'use client';
import { useLogin } from '@/components/hooks'; import { useLoginQuery } from '@/components/hooks';
import { WebsitesDataTable } from './WebsitesDataTable'; import { WebsitesDataTable } from './WebsitesDataTable';
import { WebsitesHeader } from './WebsitesHeader'; import { WebsitesHeader } from './WebsitesHeader';
import { ROLES } from '@/lib/constants'; import { ROLES } from '@/lib/constants';
export function WebsitesSettingsPage({ teamId }: { teamId: string }) { export function WebsitesSettingsPage({ teamId }: { teamId: string }) {
const { user } = useLogin(); const { user } = useLoginQuery();
const canCreate = user.role !== ROLES.viewOnly; const canCreate = user.role !== ROLES.viewOnly;
return ( return (

View file

@ -1,7 +1,7 @@
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { Row, Text, Icon, Icons, DataTable, DataColumn, Button } from '@umami/react-zen'; import { Row, Text, Icon, Icons, DataTable, DataColumn, Button } from '@umami/react-zen';
import Link from 'next/link'; import Link from 'next/link';
import { useMessages, useTeamUrl } from '@/components/hooks'; import { useMessages, useNavigation } from '@/components/hooks';
export interface WebsitesTableProps { export interface WebsitesTableProps {
data: any[]; data: any[];
@ -20,7 +20,7 @@ export function WebsitesTable({
children, children,
}: WebsitesTableProps) { }: WebsitesTableProps) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { renderTeamUrl } = useTeamUrl(); const { renderTeamUrl } = useNavigation();
if (!data?.length) { if (!data?.length) {
return children; return children;

View file

@ -1,6 +1,12 @@
import { Button, Modal, DialogTrigger, Dialog, Column } from '@umami/react-zen'; import { Button, Modal, DialogTrigger, Dialog, Column } from '@umami/react-zen';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { useLogin, useMessages, useModified, useTeams, useTeamUrl } from '@/components/hooks'; import {
useLoginQuery,
useMessages,
useModified,
useTeamsQuery,
useNavigation,
} from '@/components/hooks';
import { WebsiteDeleteForm } from './WebsiteDeleteForm'; import { WebsiteDeleteForm } from './WebsiteDeleteForm';
import { WebsiteResetForm } from './WebsiteResetForm'; import { WebsiteResetForm } from './WebsiteResetForm';
import { WebsiteTransferForm } from './WebsiteTransferForm'; import { WebsiteTransferForm } from './WebsiteTransferForm';
@ -9,11 +15,11 @@ import { ROLES } from '@/lib/constants';
export function WebsiteData({ websiteId, onSave }: { websiteId: string; onSave?: () => void }) { export function WebsiteData({ websiteId, onSave }: { websiteId: string; onSave?: () => void }) {
const { formatMessage, labels, messages } = useMessages(); const { formatMessage, labels, messages } = useMessages();
const { user } = useLogin(); const { user } = useLoginQuery();
const { touch } = useModified(); const { touch } = useModified();
const { teamId, renderTeamUrl } = useTeamUrl(); const { teamId, renderTeamUrl } = useNavigation();
const router = useRouter(); const router = useRouter();
const { result } = useTeams(user.id); const { result } = useTeamsQuery(user.id);
const canTransferWebsite = const canTransferWebsite =
( (
!teamId && !teamId &&

View file

@ -10,7 +10,7 @@ import {
ListItem, ListItem,
Text, Text,
} from '@umami/react-zen'; } from '@umami/react-zen';
import { useApi, useLogin, useMessages, useTeams } from '@/components/hooks'; import { useApi, useLoginQuery, useMessages, useTeamsQuery } from '@/components/hooks';
import { WebsiteContext } from '@/app/(main)/websites/[websiteId]/WebsiteProvider'; import { WebsiteContext } from '@/app/(main)/websites/[websiteId]/WebsiteProvider';
import { ROLES } from '@/lib/constants'; import { ROLES } from '@/lib/constants';
@ -23,7 +23,7 @@ export function WebsiteTransferForm({
onSave?: () => void; onSave?: () => void;
onClose?: () => void; onClose?: () => void;
}) { }) {
const { user } = useLogin(); const { user } = useLoginQuery();
const website = useContext(WebsiteContext); const website = useContext(WebsiteContext);
const [teamId, setTeamId] = useState<string>(null); const [teamId, setTeamId] = useState<string>(null);
const { formatMessage, labels, messages } = useMessages(); const { formatMessage, labels, messages } = useMessages();
@ -31,7 +31,7 @@ export function WebsiteTransferForm({
const { mutate, error } = useMutation({ const { mutate, error } = useMutation({
mutationFn: (data: any) => post(`/websites/${websiteId}/transfer`, data), mutationFn: (data: any) => post(`/websites/${websiteId}/transfer`, data),
}); });
const { result, query } = useTeams(user.id); const { result, query } = useTeamsQuery(user.id);
const isTeamWebsite = !!website?.teamId; const isTeamWebsite = !!website?.teamId;
const items = result.data.filter(({ teamUser }) => const items = result.data.filter(({ teamUser }) =>

View file

@ -1,13 +1,13 @@
'use client'; 'use client';
import { createContext, ReactNode, useEffect } from 'react'; import { createContext, ReactNode, useEffect } from 'react';
import { useTeam, useModified } from '@/components/hooks'; import { useTeamQuery, useModified } from '@/components/hooks';
import { Loading } from '@umami/react-zen'; import { Loading } from '@umami/react-zen';
export const TeamContext = createContext(null); export const TeamContext = createContext(null);
export function TeamProvider({ teamId, children }: { teamId?: string; children: ReactNode }) { export function TeamProvider({ teamId, children }: { teamId?: string; children: ReactNode }) {
const { modified } = useModified(`teams`); const { modified } = useModified(`teams`);
const { data: team, isLoading, isFetching, refetch } = useTeam(teamId); const { data: team, isLoading, isFetching, refetch } = useTeamQuery(teamId);
useEffect(() => { useEffect(() => {
if (teamId && modified) { if (teamId && modified) {

View file

@ -1,11 +1,11 @@
'use client'; 'use client';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { useMessages, useTeamUrl } from '@/components/hooks'; import { useMessages, useNavigation } from '@/components/hooks';
import { MenuLayout } from '@/components/layout/MenuLayout'; import { MenuLayout } from '@/components/layout/MenuLayout';
export function TeamSettingsLayout({ children }: { children: ReactNode }) { export function TeamSettingsLayout({ children }: { children: ReactNode }) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { teamId } = useTeamUrl(); const { teamId } = useNavigation();
const items = [ const items = [
{ {

View file

@ -1,6 +1,6 @@
import { DataGrid } from '@/components/common/DataGrid'; import { DataGrid } from '@/components/common/DataGrid';
import { TeamMembersTable } from './TeamMembersTable'; import { TeamMembersTable } from './TeamMembersTable';
import { useTeamMembers } from '@/components/hooks'; import { useTeamMembersQuery } from '@/components/hooks';
export function TeamMembersDataTable({ export function TeamMembersDataTable({
teamId, teamId,
@ -9,7 +9,7 @@ export function TeamMembersDataTable({
teamId: string; teamId: string;
allowEdit?: boolean; allowEdit?: boolean;
}) { }) {
const queryResult = useTeamMembers(teamId); const queryResult = useTeamMembersQuery(teamId);
return ( return (
<DataGrid queryResult={queryResult}> <DataGrid queryResult={queryResult}>

View file

@ -2,13 +2,13 @@
import { TeamContext } from '@/app/(main)/teams/[teamId]/TeamProvider'; import { TeamContext } from '@/app/(main)/teams/[teamId]/TeamProvider';
import { TeamMembersDataTable } from './TeamMembersDataTable'; import { TeamMembersDataTable } from './TeamMembersDataTable';
import { PageHeader } from '@/components/layout/PageHeader'; import { PageHeader } from '@/components/layout/PageHeader';
import { useLogin, useMessages } from '@/components/hooks'; import { useLoginQuery, useMessages } from '@/components/hooks';
import { ROLES } from '@/lib/constants'; import { ROLES } from '@/lib/constants';
import { useContext } from 'react'; import { useContext } from 'react';
export function TeamMembersPage({ teamId }: { teamId: string }) { export function TeamMembersPage({ teamId }: { teamId: string }) {
const team = useContext(TeamContext); const team = useContext(TeamContext);
const { user } = useLogin(); const { user } = useLoginQuery();
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const canEdit = const canEdit =

View file

@ -1,5 +1,5 @@
import { DataColumn, DataTable } from '@umami/react-zen'; import { DataColumn, DataTable } from '@umami/react-zen';
import { useMessages, useLogin } from '@/components/hooks'; import { useMessages, useLoginQuery } from '@/components/hooks';
import { ROLES } from '@/lib/constants'; import { ROLES } from '@/lib/constants';
import { TeamMemberRemoveButton } from './TeamMemberRemoveButton'; import { TeamMemberRemoveButton } from './TeamMemberRemoveButton';
import { TeamMemberEditButton } from './TeamMemberEditButton'; import { TeamMemberEditButton } from './TeamMemberEditButton';
@ -14,7 +14,7 @@ export function TeamMembersTable({
allowEdit: boolean; allowEdit: boolean;
}) { }) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { user } = useLogin(); const { user } = useLoginQuery();
const roles = { const roles = {
[ROLES.teamOwner]: formatMessage(labels.teamOwner), [ROLES.teamOwner]: formatMessage(labels.teamOwner),

View file

@ -1,5 +1,5 @@
import { TeamContext } from '@/app/(main)/teams/[teamId]/TeamProvider'; import { TeamContext } from '@/app/(main)/teams/[teamId]/TeamProvider';
import { useLogin, useMessages } from '@/components/hooks'; import { useLoginQuery, useMessages } from '@/components/hooks';
import { Icons } from '@/components/icons'; import { Icons } from '@/components/icons';
import { PageHeader } from '@/components/layout/PageHeader'; import { PageHeader } from '@/components/layout/PageHeader';
import { ROLES } from '@/lib/constants'; import { ROLES } from '@/lib/constants';
@ -13,7 +13,7 @@ import { Panel } from '@/components/layout/Panel';
export function TeamDetails({ teamId }: { teamId: string }) { export function TeamDetails({ teamId }: { teamId: string }) {
const team = useContext(TeamContext); const team = useContext(TeamContext);
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { user } = useLogin(); const { user } = useLoginQuery();
const [tab, setTab] = useState('details'); const [tab, setTab] = useState('details');
const isTeamOwner = const isTeamOwner =

View file

@ -1,5 +1,5 @@
import { DataGrid } from '@/components/common/DataGrid'; import { DataGrid } from '@/components/common/DataGrid';
import { useTeamWebsites } from '@/components/hooks'; import { useTeamWebsitesQuery } from '@/components/hooks';
import { TeamWebsitesTable } from './TeamWebsitesTable'; import { TeamWebsitesTable } from './TeamWebsitesTable';
export function TeamWebsitesDataTable({ export function TeamWebsitesDataTable({
@ -9,7 +9,7 @@ export function TeamWebsitesDataTable({
teamId: string; teamId: string;
allowEdit?: boolean; allowEdit?: boolean;
}) { }) {
const queryResult = useTeamWebsites(teamId); const queryResult = useTeamWebsitesQuery(teamId);
return ( return (
<DataGrid queryResult={queryResult}> <DataGrid queryResult={queryResult}>

View file

@ -1,7 +1,7 @@
'use client'; 'use client';
import { TeamContext } from '@/app/(main)/teams/[teamId]/TeamProvider'; import { TeamContext } from '@/app/(main)/teams/[teamId]/TeamProvider';
import { WebsiteAddButton } from '@/app/(main)/settings/websites/WebsiteAddButton'; import { WebsiteAddButton } from '@/app/(main)/settings/websites/WebsiteAddButton';
import { useLogin, useMessages } from '@/components/hooks'; import { useLoginQuery, useMessages } from '@/components/hooks';
import { PageHeader } from '@/components/layout/PageHeader'; import { PageHeader } from '@/components/layout/PageHeader';
import { TeamWebsitesDataTable } from './TeamWebsitesDataTable'; import { TeamWebsitesDataTable } from './TeamWebsitesDataTable';
import { ROLES } from '@/lib/constants'; import { ROLES } from '@/lib/constants';
@ -10,7 +10,7 @@ import { useContext } from 'react';
export function TeamWebsitesPage({ teamId }: { teamId: string }) { export function TeamWebsitesPage({ teamId }: { teamId: string }) {
const team = useContext(TeamContext); const team = useContext(TeamContext);
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { user } = useLogin(); const { user } = useLoginQuery();
const canEdit = const canEdit =
!!team?.teamUser?.find( !!team?.teamUser?.find(

View file

@ -1,5 +1,5 @@
import { DataColumn, DataTable, Icon, Text } from '@umami/react-zen'; import { DataColumn, DataTable, Icon, Text } from '@umami/react-zen';
import { useLogin, useMessages } from '@/components/hooks'; import { useLoginQuery, useMessages } from '@/components/hooks';
import { Icons } from '@/components/icons'; import { Icons } from '@/components/icons';
import { LinkButton } from '@/components/common/LinkButton'; import { LinkButton } from '@/components/common/LinkButton';
@ -12,7 +12,7 @@ export function TeamWebsitesTable({
data: any[]; data: any[];
allowEdit?: boolean; allowEdit?: boolean;
}) { }) {
const { user } = useLogin(); const { user } = useLoginQuery();
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
return ( return (

View file

@ -1,10 +1,10 @@
'use client'; 'use client';
import { WebsitesHeader } from '@/app/(main)/settings/websites/WebsitesHeader'; import { WebsitesHeader } from '@/app/(main)/settings/websites/WebsitesHeader';
import { WebsitesDataTable } from '@/app/(main)/settings/websites/WebsitesDataTable'; import { WebsitesDataTable } from '@/app/(main)/settings/websites/WebsitesDataTable';
import { useTeamUrl } from '@/components/hooks'; import { useNavigation } from '@/components/hooks';
export function WebsitesPage() { export function WebsitesPage() {
const { teamId } = useTeamUrl(); const { teamId } = useNavigation();
return ( return (
<> <>

View file

@ -1,6 +1,6 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { PageviewsChart } from '@/components/metrics/PageviewsChart'; import { PageviewsChart } from '@/components/metrics/PageviewsChart';
import { useWebsitePageviews } from '@/components/hooks/queries/useWebsitePageviews'; import { useWebsitePageviewsQuery } from '@/components/hooks/queries/useWebsitePageviewsQuery';
import { useDateRange } from '@/components/hooks'; import { useDateRange } from '@/components/hooks';
export function WebsiteChart({ export function WebsiteChart({
@ -12,7 +12,10 @@ export function WebsiteChart({
}) { }) {
const { dateRange, dateCompare } = useDateRange(websiteId); const { dateRange, dateCompare } = useDateRange(websiteId);
const { startDate, endDate, unit, value } = dateRange; const { startDate, endDate, unit, value } = dateRange;
const { data, isLoading } = useWebsitePageviews(websiteId, compareMode ? dateCompare : undefined); const { data, isLoading } = useWebsitePageviewsQuery(
websiteId,
compareMode ? dateCompare : undefined,
);
const { pageviews, sessions, compare } = (data || {}) as any; const { pageviews, sessions, compare } = (data || {}) as any;
const chartData = useMemo(() => { const chartData = useMemo(() => {

View file

@ -5,7 +5,7 @@ import { WebsiteChart } from './WebsiteChart';
import { useDashboard } from '@/store/dashboard'; import { useDashboard } from '@/store/dashboard';
import { WebsiteHeader } from './WebsiteHeader'; import { WebsiteHeader } from './WebsiteHeader';
import { WebsiteMetricsBar } from './WebsiteMetricsBar'; import { WebsiteMetricsBar } from './WebsiteMetricsBar';
import { useMessages, useTeamUrl } from '@/components/hooks'; import { useMessages, useNavigation } from '@/components/hooks';
import { LinkButton } from '@/components/common/LinkButton'; import { LinkButton } from '@/components/common/LinkButton';
export function WebsiteChartList({ export function WebsiteChartList({
@ -19,7 +19,7 @@ export function WebsiteChartList({
}) { }) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { websiteOrder, websiteActive } = useDashboard(); const { websiteOrder, websiteActive } = useDashboard();
const { renderTeamUrl } = useTeamUrl(); const { renderTeamUrl } = useNavigation();
const ordered = useMemo(() => { const ordered = useMemo(() => {
return websites return websites

View file

@ -1,62 +0,0 @@
.header {
display: flex;
gap: 10px;
align-items: center;
flex-wrap: wrap;
padding: 20px 0px;
}
.title {
display: flex;
flex-direction: row;
align-items: center;
gap: 10px;
font-size: 24px;
font-weight: 700;
overflow: hidden;
height: 60px;
}
.actions {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
gap: 30px;
min-height: 0;
margin-left: auto;
}
.selected {
font-weight: bold;
}
.links {
display: flex;
flex-direction: row;
align-items: center;
}
@media only screen and (max-width: 768px) {
.header {
grid-template-columns: 1fr;
}
.links {
justify-content: space-evenly;
flex: 1;
border-bottom: 1px solid var(--base300);
padding-bottom: 10px;
margin-bottom: 10px;
}
.label {
display: none;
}
.icon,
.icon svg {
width: 20px;
height: 20px;
}
}

View file

@ -1,99 +1,31 @@
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { Button, Icon, Text } from '@umami/react-zen'; import { Row, Heading } from '@umami/react-zen';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import classNames from 'classnames';
import { Favicon } from '@/components/common/Favicon'; import { Favicon } from '@/components/common/Favicon';
import { useMessages, useTeamUrl, useWebsite } from '@/components/hooks'; import { useWebsiteQuery } from '@/components/hooks';
import { Icons } from '@/components/icons';
import { ActiveUsers } from '@/components/metrics/ActiveUsers'; import { ActiveUsers } from '@/components/metrics/ActiveUsers';
import styles from './WebsiteHeader.module.css'; import { WebsiteTabs } from '@/app/(main)/websites/[websiteId]/WebsiteTabs';
export function WebsiteHeader({ export function WebsiteHeader({
websiteId, websiteId,
showLinks = true,
children, children,
}: { }: {
websiteId: string; websiteId: string;
showLinks?: boolean;
children?: ReactNode; children?: ReactNode;
}) { }) {
const { formatMessage, labels } = useMessages(); const { data: website } = useWebsiteQuery(websiteId);
const { renderTeamUrl } = useTeamUrl();
const pathname = usePathname();
const { data: website } = useWebsite(websiteId);
const { name, domain } = website || {}; const { name, domain } = website || {};
const links = [
{
label: formatMessage(labels.overview),
icon: <Icons.Overview />,
path: '',
},
{
label: formatMessage(labels.events),
icon: <Icons.Lightning />,
path: '/events',
},
{
label: formatMessage(labels.sessions),
icon: <Icons.User />,
path: '/sessions',
},
{
label: formatMessage(labels.realtime),
icon: <Icons.Clock />,
path: '/realtime',
},
{
label: formatMessage(labels.compare),
icon: <Icons.Compare />,
path: '/compare',
},
{
label: formatMessage(labels.reports),
icon: <Icons.Reports />,
path: '/reports',
},
];
return ( return (
<div className={styles.header}> <>
<div className={styles.title}> <Row alignItems="center" gap="3" marginY="6">
<Favicon domain={domain} /> <Favicon domain={domain} />
<Text>{name}</Text> <Heading>
<ActiveUsers websiteId={websiteId} /> {name}
</div> <ActiveUsers websiteId={websiteId} />
<div className={styles.actions}> </Heading>
{showLinks && (
<div className={styles.links}>
{links.map(({ label, icon, path }) => {
const selected = path
? pathname.includes(path)
: pathname.match(/^\/websites\/[\w-]+$/);
return (
<Link
key={label}
href={renderTeamUrl(`/websites/${websiteId}${path}`)}
shallow={true}
>
<Button
variant="quiet"
className={classNames({
[styles.selected]: selected,
})}
>
<Icon className={styles.icon}>{icon}</Icon>
<Text className={styles.label}>{label}</Text>
</Button>
</Link>
);
})}
</div>
)}
{children} {children}
</div> </Row>
</div> <WebsiteTabs websiteId={websiteId} />
</>
); );
} }

View file

@ -5,7 +5,7 @@ import { WebsiteDateFilter } from '@/components/input/WebsiteDateFilter';
import { MetricCard } from '@/components/metrics/MetricCard'; import { MetricCard } from '@/components/metrics/MetricCard';
import { MetricsBar } from '@/components/metrics/MetricsBar'; import { MetricsBar } from '@/components/metrics/MetricsBar';
import { formatShortTime, formatLongNumber } from '@/lib/format'; import { formatShortTime, formatLongNumber } from '@/lib/format';
import { useWebsiteStats } from '@/components/hooks/queries/useWebsiteStats'; import { useWebsiteStatsQuery } from '@/components/hooks/queries/useWebsiteStatsQuery';
import { useWebsites, setWebsiteDateCompare } from '@/store/websites'; import { useWebsites, setWebsiteDateCompare } from '@/store/websites';
import { WebsiteFilterButton } from './WebsiteFilterButton'; import { WebsiteFilterButton } from './WebsiteFilterButton';
import styles from './WebsiteMetricsBar.module.css'; import styles from './WebsiteMetricsBar.module.css';
@ -26,8 +26,8 @@ export function WebsiteMetricsBar({
const { dateRange } = useDateRange(websiteId); const { dateRange } = useDateRange(websiteId);
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const dateCompare = useWebsites(state => state[websiteId]?.dateCompare); const dateCompare = useWebsites(state => state[websiteId]?.dateCompare);
const { ref, isSticky } = useSticky({ enabled: sticky }); const { ref } = useSticky({ enabled: sticky });
const { data, isLoading, isFetched, error } = useWebsiteStats( const { data, isLoading, isFetched, error } = useWebsiteStatsQuery(
websiteId, websiteId,
compareMode && dateCompare, compareMode && dateCompare,
); );
@ -82,13 +82,7 @@ export function WebsiteMetricsBar({
]; ];
return ( return (
<div <div ref={ref} className={classNames(styles.container)}>
ref={ref}
className={classNames(styles.container, {
[styles.sticky]: sticky,
[styles.isSticky]: sticky && isSticky,
})}
>
<div> <div>
<MetricsBar isLoading={isLoading} isFetched={isFetched} error={error}> <MetricsBar isLoading={isLoading} isFetched={isFetched} error={error}>
{metrics.map(({ label, value, prev, change, formatValue, reverseColors }) => { {metrics.map(({ label, value, prev, change, formatValue, reverseColors }) => {

View file

@ -1,6 +1,6 @@
'use client'; 'use client';
import { createContext, ReactNode, useEffect } from 'react'; import { createContext, ReactNode, useEffect } from 'react';
import { useModified, useWebsite } from '@/components/hooks'; import { useModified, useWebsiteQuery } from '@/components/hooks';
import { Loading } from '@umami/react-zen'; import { Loading } from '@umami/react-zen';
export const WebsiteContext = createContext(null); export const WebsiteContext = createContext(null);
@ -13,7 +13,7 @@ export function WebsiteProvider({
children: ReactNode; children: ReactNode;
}) { }) {
const { modified } = useModified(`website:${websiteId}`); const { modified } = useModified(`website:${websiteId}`);
const { data: website, isFetching, isLoading, refetch } = useWebsite(websiteId); const { data: website, isFetching, isLoading, refetch } = useWebsiteQuery(websiteId);
useEffect(() => { useEffect(() => {
if (modified) { if (modified) {

View file

@ -0,0 +1,58 @@
import { Tabs, TabList, Tab, Icon, Text, Row } from '@umami/react-zen';
import { Icons } from '@/components/icons';
import { useMessages, useNavigation } from '@/components/hooks';
export function WebsiteTabs({ websiteId }: { websiteId: string }) {
const { formatMessage, labels } = useMessages();
const { renderTeamUrl } = useNavigation();
const links = [
{
label: formatMessage(labels.overview),
icon: <Icons.Overview />,
path: '',
},
{
label: formatMessage(labels.events),
icon: <Icons.Lightning />,
path: '/events',
},
{
label: formatMessage(labels.sessions),
icon: <Icons.User />,
path: '/sessions',
},
{
label: formatMessage(labels.realtime),
icon: <Icons.Clock />,
path: '/realtime',
},
{
label: formatMessage(labels.compare),
icon: <Icons.Compare />,
path: '/compare',
},
{
label: formatMessage(labels.reports),
icon: <Icons.Reports />,
path: '/reports',
},
].map((link, index) => ({ ...link, id: index }));
return (
<Tabs>
<TabList items={links}>
{({ label, icon, path }) => {
return (
<Tab key={path} href={renderTeamUrl(`/websites/${websiteId}/${path}`)}>
<Row gap="3" alignItems="center">
<Icon fillColor="currentColor">{icon}</Icon>
<Text>{label}</Text>
</Row>
</Tab>
);
}}
</TabList>
</Tabs>
);
}

View file

@ -1,5 +1,9 @@
import { GridColumn, GridTable } from '@umami/react-zen'; import { DataColumn, DataTable } from '@umami/react-zen';
import { useEventDataProperties, useEventDataValues, useMessages } from '@/components/hooks'; import {
useEventDataPropertiesQuery,
useEventDataValuesQuery,
useMessages,
} from '@/components/hooks';
import { LoadingPanel } from '@/components/common/LoadingPanel'; import { LoadingPanel } from '@/components/common/LoadingPanel';
import { PieChart } from '@/components/charts/PieChart'; import { PieChart } from '@/components/charts/PieChart';
import { useState } from 'react'; import { useState } from 'react';
@ -10,8 +14,8 @@ export function EventProperties({ websiteId }: { websiteId: string }) {
const [propertyName, setPropertyName] = useState(''); const [propertyName, setPropertyName] = useState('');
const [eventName, setEventName] = useState(''); const [eventName, setEventName] = useState('');
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { data, isLoading, isFetched, error } = useEventDataProperties(websiteId); const { data, isLoading, isFetched, error } = useEventDataPropertiesQuery(websiteId);
const { data: values } = useEventDataValues(websiteId, eventName, propertyName); const { data: values } = useEventDataValuesQuery(websiteId, eventName, propertyName);
const chartData = const chartData =
propertyName && values propertyName && values
? { ? {
@ -34,23 +38,23 @@ export function EventProperties({ websiteId }: { websiteId: string }) {
return ( return (
<LoadingPanel isLoading={isLoading} isFetched={isFetched} data={data} error={error}> <LoadingPanel isLoading={isLoading} isFetched={isFetched} data={data} error={error}>
<div className={styles.container}> <div className={styles.container}>
<GridTable data={data} cardMode={false} className={styles.table}> <DataTable data={data} cardMode={false} className={styles.table}>
<GridColumn name="eventName" label={formatMessage(labels.name)}> <DataColumn name="eventName" label={formatMessage(labels.name)}>
{row => ( {row => (
<div className={styles.link} onClick={() => handleRowClick(row)}> <div className={styles.link} onClick={() => handleRowClick(row)}>
{row.eventName} {row.eventName}
</div> </div>
)} )}
</GridColumn> </DataColumn>
<GridColumn name="propertyName" label={formatMessage(labels.property)}> <DataColumn name="propertyName" label={formatMessage(labels.property)}>
{row => ( {row => (
<div className={styles.link} onClick={() => handleRowClick(row)}> <div className={styles.link} onClick={() => handleRowClick(row)}>
{row.propertyName} {row.propertyName}
</div> </div>
)} )}
</GridColumn> </DataColumn>
<GridColumn name="total" label={formatMessage(labels.count)} alignment="end" /> <DataColumn name="total" label={formatMessage(labels.count)} alignment="end" />
</GridTable> </DataTable>
{propertyName && ( {propertyName && (
<div className={styles.chart}> <div className={styles.chart}>
<div className={styles.title}>{propertyName}</div> <div className={styles.title}>{propertyName}</div>

View file

@ -1,4 +1,4 @@
import { useWebsiteEvents } from '@/components/hooks'; import { useWebsiteEventsQuery } from '@/components/hooks';
import { EventsTable } from './EventsTable'; import { EventsTable } from './EventsTable';
import { DataGrid } from '@/components/common/DataGrid'; import { DataGrid } from '@/components/common/DataGrid';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
@ -10,7 +10,7 @@ export function EventsDataTable({
teamId?: string; teamId?: string;
children?: ReactNode; children?: ReactNode;
}) { }) {
const queryResult = useWebsiteEvents(websiteId); const queryResult = useWebsiteEventsQuery(websiteId);
return ( return (
<DataGrid queryResult={queryResult} allowSearch={true} autoFocus={false}> <DataGrid queryResult={queryResult} allowSearch={true} autoFocus={false}>

View file

@ -1,5 +1,5 @@
import { useMessages } from '@/components/hooks'; import { useMessages } from '@/components/hooks';
import { useWebsiteSessionStats } from '@/components/hooks/queries/useWebsiteSessionStats'; import { useWebsiteSessionStatsQuery } from '@/components/hooks/queries/useWebsiteSessionStatsQuery';
import { WebsiteDateFilter } from '@/components/input/WebsiteDateFilter'; import { WebsiteDateFilter } from '@/components/input/WebsiteDateFilter';
import { MetricCard } from '@/components/metrics/MetricCard'; import { MetricCard } from '@/components/metrics/MetricCard';
import { MetricsBar } from '@/components/metrics/MetricsBar'; import { MetricsBar } from '@/components/metrics/MetricsBar';
@ -8,7 +8,7 @@ import { Flexbox } from '@umami/react-zen';
export function EventsMetricsBar({ websiteId }: { websiteId: string }) { export function EventsMetricsBar({ websiteId }: { websiteId: string }) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { data, isLoading, isFetched, error } = useWebsiteSessionStats(websiteId); const { data, isLoading, isFetched, error } = useWebsiteSessionStatsQuery(websiteId);
return ( return (
<Flexbox direction="row" justifyContent="space-between" style={{ minHeight: 120 }}> <Flexbox direction="row" justifyContent="space-between" style={{ minHeight: 120 }}>

View file

@ -6,7 +6,7 @@ import { EventsChart } from '@/components/metrics/EventsChart';
import { GridRow } from '@/components/layout/Grid'; import { GridRow } from '@/components/layout/Grid';
import { MetricsTable } from '@/components/metrics/MetricsTable'; import { MetricsTable } from '@/components/metrics/MetricsTable';
import { useMessages } from '@/components/hooks'; import { useMessages } from '@/components/hooks';
import { Item, Tabs } from '@umami/react-zen'; import { TabList, Tab, Tabs } from '@umami/react-zen';
import { useState } from 'react'; import { useState } from 'react';
import { EventProperties } from './EventProperties'; import { EventProperties } from './EventProperties';
@ -30,11 +30,13 @@ export function EventsPage({ websiteId }) {
<div> <div>
<Tabs <Tabs
selectedKey={tab} selectedKey={tab}
onSelect={(value: any) => setTab(value)} onSelectionChange={(value: any) => setTab(value)}
style={{ marginBottom: 30 }} style={{ marginBottom: 30 }}
> >
<Item key="activity">{formatMessage(labels.activity)}</Item> <TabList>
<Item key="properties">{formatMessage(labels.properties)}</Item> <Tab key="activity">{formatMessage(labels.activity)}</Tab>
<Tab key="properties">{formatMessage(labels.properties)}</Tab>
</TabList>
</Tabs> </Tabs>
{tab === 'activity' && <EventsDataTable websiteId={websiteId} />} {tab === 'activity' && <EventsDataTable websiteId={websiteId} />}
{tab === 'properties' && <EventProperties websiteId={websiteId} />} {tab === 'properties' && <EventProperties websiteId={websiteId} />}

View file

@ -1,5 +1,5 @@
import { GridTable, GridColumn, Icon } from '@umami/react-zen'; import { DataTable, DataColumn, Icon } from '@umami/react-zen';
import { useMessages, useTeamUrl, useTimezone } from '@/components/hooks'; import { useMessages, useNavigation, useTimezone } from '@/components/hooks';
import { Empty } from '@/components/common/Empty'; import { Empty } from '@/components/common/Empty';
import { Avatar } from '@/components/common/Avatar'; import { Avatar } from '@/components/common/Avatar';
import Link from 'next/link'; import Link from 'next/link';
@ -8,23 +8,23 @@ import { Icons } from '@/components/icons';
export function EventsTable({ data = [] }) { export function EventsTable({ data = [] }) {
const { formatTimezoneDate } = useTimezone(); const { formatTimezoneDate } = useTimezone();
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { renderTeamUrl } = useTeamUrl(); const { renderTeamUrl } = useNavigation();
if (data.length === 0) { if (data.length === 0) {
return <Empty />; return <Empty />;
} }
return ( return (
<GridTable data={data}> <DataTable data={data}>
<GridColumn name="session" label={formatMessage(labels.session)} width={'100px'}> <DataColumn id="session" label={formatMessage(labels.session)}>
{row => ( {(row: any) => (
<Link href={renderTeamUrl(`/websites/${row.websiteId}/sessions/${row.sessionId}`)}> <Link href={renderTeamUrl(`/websites/${row.websiteId}/sessions/${row.sessionId}`)}>
<Avatar seed={row.sessionId} size={64} /> <Avatar seed={row.sessionId} size={64} />
</Link> </Link>
)} )}
</GridColumn> </DataColumn>
<GridColumn name="event" label={formatMessage(labels.event)}> <DataColumn id="event" label={formatMessage(labels.event)}>
{row => { {(row: any) => {
return ( return (
<> <>
<Icon>{row.eventName ? <Icons.Bolt /> : <Icons.Eye />}</Icon> <Icon>{row.eventName ? <Icons.Bolt /> : <Icons.Eye />}</Icon>
@ -33,10 +33,10 @@ export function EventsTable({ data = [] }) {
</> </>
); );
}} }}
</GridColumn> </DataColumn>
<GridColumn name="created" label={formatMessage(labels.created)} width={'300px'}> <DataColumn id="created" label={formatMessage(labels.created)}>
{row => formatTimezoneDate(row.createdAt, 'PPPpp')} {(row: any) => formatTimezoneDate(row.createdAt, 'PPPpp')}
</GridColumn> </DataColumn>
</GridTable> </DataTable>
); );
} }

View file

@ -1,5 +1,4 @@
import { Key, useContext, useState } from 'react'; import { Key, useContext, useState } from 'react';
import { ButtonGroup, Button, Flexbox } from '@umami/react-zen';
import thenby from 'thenby'; import thenby from 'thenby';
import { percentFilter } from '@/lib/filters'; import { percentFilter } from '@/lib/filters';
import { ListTable } from '@/components/metrics/ListTable'; import { ListTable } from '@/components/metrics/ListTable';
@ -7,6 +6,7 @@ import { FILTER_PAGES, FILTER_REFERRERS } from '@/lib/constants';
import { useMessages } from '@/components/hooks'; import { useMessages } from '@/components/hooks';
import { RealtimeData } from '@/lib/types'; import { RealtimeData } from '@/lib/types';
import { WebsiteContext } from '../WebsiteProvider'; import { WebsiteContext } from '../WebsiteProvider';
import { FilterButtons } from '@/components/common/FilterButtons';
export function RealtimeUrls({ data }: { data: RealtimeData }) { export function RealtimeUrls({ data }: { data: RealtimeData }) {
const website = useContext(WebsiteContext); const website = useContext(WebsiteContext);
@ -17,10 +17,12 @@ export function RealtimeUrls({ data }: { data: RealtimeData }) {
const buttons = [ const buttons = [
{ {
id: 1,
label: formatMessage(labels.referrers), label: formatMessage(labels.referrers),
key: FILTER_REFERRERS, key: FILTER_REFERRERS,
}, },
{ {
id: 2,
label: formatMessage(labels.pages), label: formatMessage(labels.pages),
key: FILTER_PAGES, key: FILTER_PAGES,
}, },
@ -61,11 +63,7 @@ export function RealtimeUrls({ data }: { data: RealtimeData }) {
return ( return (
<> <>
<Flexbox justifyContent="center"> <FilterButtons items={buttons} onSelect={setFilter} />
<ButtonGroup items={buttons} selectedKey={filter} onSelect={setFilter}>
{({ key, label }) => <Button key={key}>{label}</Button>}
</ButtonGroup>
</Flexbox>
{filter === FILTER_REFERRERS && ( {filter === FILTER_REFERRERS && (
<ListTable <ListTable
title={formatMessage(labels.referrers)} title={formatMessage(labels.referrers)}

View file

@ -4,7 +4,7 @@ import { Grid, GridRow } from '@/components/layout/Grid';
import { Page } from '@/components/layout/Page'; import { Page } from '@/components/layout/Page';
import { RealtimeChart } from '@/components/metrics/RealtimeChart'; import { RealtimeChart } from '@/components/metrics/RealtimeChart';
import { WorldMap } from '@/components/metrics/WorldMap'; import { WorldMap } from '@/components/metrics/WorldMap';
import { useRealtime } from '@/components/hooks'; import { useRealtimeQuery } from '@/components/hooks';
import { RealtimeLog } from './RealtimeLog'; import { RealtimeLog } from './RealtimeLog';
import { RealtimeHeader } from './RealtimeHeader'; import { RealtimeHeader } from './RealtimeHeader';
import { RealtimeUrls } from './RealtimeUrls'; import { RealtimeUrls } from './RealtimeUrls';
@ -13,7 +13,7 @@ import { WebsiteHeader } from '../WebsiteHeader';
import { percentFilter } from '@/lib/filters'; import { percentFilter } from '@/lib/filters';
export function WebsiteRealtimePage({ websiteId }) { export function WebsiteRealtimePage({ websiteId }) {
const { data, isLoading, error } = useRealtime(websiteId); const { data, isLoading, error } = useRealtimeQuery(websiteId);
if (isLoading || error) { if (isLoading || error) {
return <Page isLoading={isLoading} error={error} />; return <Page isLoading={isLoading} error={error} />;

View file

@ -1,13 +1,13 @@
'use client'; 'use client';
import Link from 'next/link'; import Link from 'next/link';
import { Button, Flexbox, Icon, Icons, Text } from '@umami/react-zen'; import { Button, Flexbox, Icon, Icons, Text } from '@umami/react-zen';
import { useMessages, useTeamUrl } from '@/components/hooks'; import { useMessages, useNavigation } from '@/components/hooks';
import { WebsiteHeader } from '../WebsiteHeader'; import { WebsiteHeader } from '../WebsiteHeader';
import { ReportsDataTable } from '@/app/(main)/reports/ReportsDataTable'; import { ReportsDataTable } from '@/app/(main)/reports/ReportsDataTable';
export function WebsiteReportsPage({ websiteId }) { export function WebsiteReportsPage({ websiteId }) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { renderTeamUrl } = useTeamUrl(); const { renderTeamUrl } = useNavigation();
return ( return (
<> <>

View file

@ -1,5 +1,9 @@
import { GridColumn, GridTable } from '@umami/react-zen'; import { DataColumn, DataTable } from '@umami/react-zen';
import { useSessionDataProperties, useSessionDataValues, useMessages } from '@/components/hooks'; import {
useSessionDataPropertiesQuery,
useSessionDataValuesQuery,
useMessages,
} from '@/components/hooks';
import { LoadingPanel } from '@/components/common/LoadingPanel'; import { LoadingPanel } from '@/components/common/LoadingPanel';
import { PieChart } from '@/components/charts/PieChart'; import { PieChart } from '@/components/charts/PieChart';
import { useState } from 'react'; import { useState } from 'react';
@ -9,8 +13,8 @@ import styles from './SessionProperties.module.css';
export function SessionProperties({ websiteId }: { websiteId: string }) { export function SessionProperties({ websiteId }: { websiteId: string }) {
const [propertyName, setPropertyName] = useState(''); const [propertyName, setPropertyName] = useState('');
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { data, isLoading, isFetched, error } = useSessionDataProperties(websiteId); const { data, isLoading, isFetched, error } = useSessionDataPropertiesQuery(websiteId);
const { data: values } = useSessionDataValues(websiteId, propertyName); const { data: values } = useSessionDataValuesQuery(websiteId, propertyName);
const chartData = const chartData =
propertyName && values propertyName && values
? { ? {
@ -28,16 +32,16 @@ export function SessionProperties({ websiteId }: { websiteId: string }) {
return ( return (
<LoadingPanel isLoading={isLoading} isFetched={isFetched} data={data} error={error}> <LoadingPanel isLoading={isLoading} isFetched={isFetched} data={data} error={error}>
<div className={styles.container}> <div className={styles.container}>
<GridTable data={data} cardMode={false} className={styles.table}> <DataTable data={data} className={styles.table}>
<GridColumn name="propertyName" label={formatMessage(labels.property)}> <DataColumn id="propertyName" label={formatMessage(labels.property)}>
{row => ( {(row: any) => (
<div className={styles.link} onClick={() => setPropertyName(row.propertyName)}> <div className={styles.link} onClick={() => setPropertyName(row.propertyName)}>
{row.propertyName} {row.propertyName}
</div> </div>
)} )}
</GridColumn> </DataColumn>
<GridColumn name="total" label={formatMessage(labels.count)} alignment="end" /> <DataColumn id="total" label={formatMessage(labels.count)} align="end" />
</GridTable> </DataTable>
{propertyName && ( {propertyName && (
<div className={styles.chart}> <div className={styles.chart}>
<div className={styles.title}>{propertyName}</div> <div className={styles.title}>{propertyName}</div>

View file

@ -1,4 +1,4 @@
import { useWebsiteSessions } from '@/components/hooks'; import { useWebsiteSessionsQuery } from '@/components/hooks';
import { SessionsTable } from './SessionsTable'; import { SessionsTable } from './SessionsTable';
import { DataGrid } from '@/components/common/DataGrid'; import { DataGrid } from '@/components/common/DataGrid';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
@ -11,7 +11,7 @@ export function SessionsDataTable({
teamId?: string; teamId?: string;
children?: ReactNode; children?: ReactNode;
}) { }) {
const queryResult = useWebsiteSessions(websiteId); const queryResult = useWebsiteSessionsQuery(websiteId);
return ( return (
<DataGrid queryResult={queryResult} allowSearch={false} renderEmpty={() => children}> <DataGrid queryResult={queryResult} allowSearch={false} renderEmpty={() => children}>

View file

@ -1,5 +1,5 @@
import { useMessages } from '@/components/hooks'; import { useMessages } from '@/components/hooks';
import { useWebsiteSessionStats } from '@/components/hooks/queries/useWebsiteSessionStats'; import { useWebsiteSessionStatsQuery } from '@/components/hooks/queries/useWebsiteSessionStatsQuery';
import { WebsiteDateFilter } from '@/components/input/WebsiteDateFilter'; import { WebsiteDateFilter } from '@/components/input/WebsiteDateFilter';
import { MetricCard } from '@/components/metrics/MetricCard'; import { MetricCard } from '@/components/metrics/MetricCard';
import { MetricsBar } from '@/components/metrics/MetricsBar'; import { MetricsBar } from '@/components/metrics/MetricsBar';
@ -8,7 +8,7 @@ import { Flexbox } from '@umami/react-zen';
export function SessionsMetricsBar({ websiteId }: { websiteId: string }) { export function SessionsMetricsBar({ websiteId }: { websiteId: string }) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { data, isLoading, isFetched, error } = useWebsiteSessionStats(websiteId); const { data, isLoading, isFetched, error } = useWebsiteSessionStatsQuery(websiteId);
return ( return (
<Flexbox direction="row" justifyContent="space-between" style={{ minHeight: 120 }}> <Flexbox direction="row" justifyContent="space-between" style={{ minHeight: 120 }}>

View file

@ -5,7 +5,7 @@ import { SessionsMetricsBar } from './SessionsMetricsBar';
import { SessionProperties } from './SessionProperties'; import { SessionProperties } from './SessionProperties';
import { WorldMap } from '@/components/metrics/WorldMap'; import { WorldMap } from '@/components/metrics/WorldMap';
import { GridRow } from '@/components/layout/Grid'; import { GridRow } from '@/components/layout/Grid';
import { Item, Tabs } from '@umami/react-zen'; import { TabList, Tab, Tabs } from '@umami/react-zen';
import { useState } from 'react'; import { useState } from 'react';
import { useMessages } from '@/components/hooks'; import { useMessages } from '@/components/hooks';
import { SessionsWeekly } from './SessionsWeekly'; import { SessionsWeekly } from './SessionsWeekly';
@ -22,9 +22,15 @@ export function SessionsPage({ websiteId }) {
<WorldMap websiteId={websiteId} /> <WorldMap websiteId={websiteId} />
<SessionsWeekly websiteId={websiteId} /> <SessionsWeekly websiteId={websiteId} />
</GridRow> </GridRow>
<Tabs selectedKey={tab} onSelect={(value: any) => setTab(value)} style={{ marginBottom: 30 }}> <Tabs
<Item key="activity">{formatMessage(labels.activity)}</Item> selectedKey={tab}
<Item key="properties">{formatMessage(labels.properties)}</Item> onSelectionChange={(value: any) => setTab(value)}
style={{ marginBottom: 30 }}
>
<TabList>
<Tab key="activity">{formatMessage(labels.activity)}</Tab>
<Tab key="properties">{formatMessage(labels.properties)}</Tab>
</TabList>
</Tabs> </Tabs>
{tab === 'activity' && <SessionsDataTable websiteId={websiteId} />} {tab === 'activity' && <SessionsDataTable websiteId={websiteId} />}
{tab === 'properties' && <SessionProperties websiteId={websiteId} />} {tab === 'properties' && <SessionProperties websiteId={websiteId} />}

View file

@ -1,5 +1,5 @@
import Link from 'next/link'; import Link from 'next/link';
import { GridColumn, GridTable } from '@umami/react-zen'; import { DataColumn, DataTable } from '@umami/react-zen';
import { useFormat, useMessages, useTimezone } from '@/components/hooks'; import { useFormat, useMessages, useTimezone } from '@/components/hooks';
import { Avatar } from '@/components/common/Avatar'; import { Avatar } from '@/components/common/Avatar';
import styles from './SessionsTable.module.css'; import styles from './SessionsTable.module.css';
@ -11,48 +11,48 @@ export function SessionsTable({ data = [] }: { data: any[]; showDomain?: boolean
const { formatValue } = useFormat(); const { formatValue } = useFormat();
return ( return (
<GridTable data={data}> <DataTable data={data}>
<GridColumn name="id" label={formatMessage(labels.session)} width="100px"> <DataColumn id="id" label={formatMessage(labels.session)}>
{row => ( {(row: any) => (
<Link href={`sessions/${row.id}`} className={styles.link}> <Link href={`sessions/${row.id}`} className={styles.link}>
<Avatar key={row.id} seed={row.id} size={64} /> <Avatar key={row.id} seed={row.id} size={64} />
</Link> </Link>
)} )}
</GridColumn> </DataColumn>
<GridColumn name="visits" label={formatMessage(labels.visits)} width="100px" /> <DataColumn id="visits" label={formatMessage(labels.visits)} />
<GridColumn name="views" label={formatMessage(labels.views)} width="100px" /> <DataColumn id="views" label={formatMessage(labels.views)} />
<GridColumn name="country" label={formatMessage(labels.country)}> <DataColumn id="country" label={formatMessage(labels.country)}>
{row => ( {(row: any) => (
<TypeIcon type="country" value={row.country}> <TypeIcon type="country" value={row.country}>
{formatValue(row.country, 'country')} {formatValue(row.country, 'country')}
</TypeIcon> </TypeIcon>
)} )}
</GridColumn> </DataColumn>
<GridColumn name="city" label={formatMessage(labels.city)} /> <DataColumn id="city" label={formatMessage(labels.city)} />
<GridColumn name="browser" label={formatMessage(labels.browser)}> <DataColumn id="browser" label={formatMessage(labels.browser)}>
{row => ( {(row: any) => (
<TypeIcon type="browser" value={row.browser}> <TypeIcon type="browser" value={row.browser}>
{formatValue(row.browser, 'browser')} {formatValue(row.browser, 'browser')}
</TypeIcon> </TypeIcon>
)} )}
</GridColumn> </DataColumn>
<GridColumn name="os" label={formatMessage(labels.os)}> <DataColumn id="os" label={formatMessage(labels.os)}>
{row => ( {(row: any) => (
<TypeIcon type="os" value={row.os}> <TypeIcon type="os" value={row.os}>
{formatValue(row.os, 'os')} {formatValue(row.os, 'os')}
</TypeIcon> </TypeIcon>
)} )}
</GridColumn> </DataColumn>
<GridColumn name="device" label={formatMessage(labels.device)}> <DataColumn id="device" label={formatMessage(labels.device)}>
{row => ( {(row: any) => (
<TypeIcon type="device" value={row.device}> <TypeIcon type="device" value={row.device}>
{formatValue(row.device, 'device')} {formatValue(row.device, 'device')}
</TypeIcon> </TypeIcon>
)} )}
</GridColumn> </DataColumn>
<GridColumn name="lastAt" label={formatMessage(labels.lastSeen)}> <DataColumn id="lastAt" label={formatMessage(labels.lastSeen)}>
{row => formatTimezoneDate(row.createdAt, 'PPPpp')} {(row: any) => formatTimezoneDate(row.createdAt, 'PPPpp')}
</GridColumn> </DataColumn>
</GridTable> </DataTable>
); );
} }

View file

@ -1,13 +1,13 @@
import { format, startOfDay, addHours } from 'date-fns'; import { format, startOfDay, addHours } from 'date-fns';
import { useLocale, useMessages, useWebsiteSessionsWeekly } from '@/components/hooks'; import { useLocale, useMessages, useWebsiteSessionsWeeklyQuery } from '@/components/hooks';
import { LoadingPanel } from '@/components/common/LoadingPanel'; import { LoadingPanel } from '@/components/common/LoadingPanel';
import { getDayOfWeekAsDate } from '@/lib/date'; import { getDayOfWeekAsDate } from '@/lib/date';
import styles from './SessionsWeekly.module.css'; import styles from './SessionsWeekly.module.css';
import classNames from 'classnames'; import classNames from 'classnames';
import { TooltipPopup } from '@umami/react-zen'; import { Tooltip, TooltipTrigger } from '@umami/react-zen';
export function SessionsWeekly({ websiteId }: { websiteId: string }) { export function SessionsWeekly({ websiteId }: { websiteId: string }) {
const { data, ...props } = useWebsiteSessionsWeekly(websiteId); const { data, ...props } = useWebsiteSessionsWeeklyQuery(websiteId);
const { dateLocale } = useLocale(); const { dateLocale } = useLocale();
const { labels, formatMessage } = useMessages(); const { labels, formatMessage } = useMessages();
const { weekStartsOn } = dateLocale.options; const { weekStartsOn } = dateLocale.options;
@ -67,15 +67,13 @@ export function SessionsWeekly({ websiteId }: { websiteId: string }) {
return ( return (
<div key={j} className={classNames(styles.cell)}> <div key={j} className={classNames(styles.cell)}>
{hour > 0 && ( {hour > 0 && (
<TooltipPopup <TooltipTrigger>
label={`${formatMessage(labels.visitors)}: ${hour}`}
position="right"
>
<div <div
className={styles.block} className={styles.block}
style={{ opacity: pct, transform: `scale(${pct})` }} style={{ opacity: pct, transform: `scale(${pct})` }}
/> />
</TooltipPopup> <Tooltip>{`${formatMessage(labels.visitors)}: ${hour}`}</Tooltip>
</TooltipTrigger>
)} )}
</div> </div>
); );

View file

@ -1,7 +1,7 @@
import { isSameDay } from 'date-fns'; import { isSameDay } from 'date-fns';
import { Loading, Icon, StatusLight } from '@umami/react-zen'; import { Loading, Icon, StatusLight } from '@umami/react-zen';
import { Icons } from '@/components/icons'; import { Icons } from '@/components/icons';
import { useSessionActivity, useTimezone } from '@/components/hooks'; import { useSessionActivityQuery, useTimezone } from '@/components/hooks';
import styles from './SessionActivity.module.css'; import styles from './SessionActivity.module.css';
import { Fragment } from 'react'; import { Fragment } from 'react';
@ -17,7 +17,7 @@ export function SessionActivity({
endDate: Date; endDate: Date;
}) { }) {
const { formatTimezoneDate } = useTimezone(); const { formatTimezoneDate } = useTimezone();
const { data, isLoading } = useSessionActivity(websiteId, sessionId, startDate, endDate); const { data, isLoading } = useSessionActivityQuery(websiteId, sessionId, startDate, endDate);
if (isLoading) { if (isLoading) {
return <Loading position="page" />; return <Loading position="page" />;

View file

@ -1,5 +1,5 @@
import { TextOverflow } from '@umami/react-zen'; import { TextOverflow } from '@umami/react-zen';
import { useMessages, useSessionData } from '@/components/hooks'; import { useMessages, useSessionDataQuery } from '@/components/hooks';
import { Empty } from '@/components/common/Empty'; import { Empty } from '@/components/common/Empty';
import { DATA_TYPES } from '@/lib/constants'; import { DATA_TYPES } from '@/lib/constants';
import styles from './SessionData.module.css'; import styles from './SessionData.module.css';
@ -7,7 +7,7 @@ import { LoadingPanel } from '@/components/common/LoadingPanel';
export function SessionData({ websiteId, sessionId }: { websiteId: string; sessionId: string }) { export function SessionData({ websiteId, sessionId }: { websiteId: string; sessionId: string }) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { data, ...query } = useSessionData(websiteId, sessionId); const { data, ...query } = useSessionDataQuery(websiteId, sessionId);
return ( return (
<> <>

View file

@ -1,7 +1,7 @@
'use client'; 'use client';
import { Avatar } from '@/components/common/Avatar'; import { Avatar } from '@/components/common/Avatar';
import { LoadingPanel } from '@/components/common/LoadingPanel'; import { LoadingPanel } from '@/components/common/LoadingPanel';
import { useWebsiteSession } from '@/components/hooks'; import { useWebsiteSessionQuery } from '@/components/hooks';
import { WebsiteHeader } from '../../WebsiteHeader'; import { WebsiteHeader } from '../../WebsiteHeader';
import { SessionActivity } from './SessionActivity'; import { SessionActivity } from './SessionActivity';
import { SessionData } from './SessionData'; import { SessionData } from './SessionData';
@ -16,7 +16,7 @@ export function SessionDetailsPage({
websiteId: string; websiteId: string;
sessionId: string; sessionId: string;
}) { }) {
const { data, ...query } = useWebsiteSession(websiteId, sessionId); const { data, ...query } = useWebsiteSessionQuery(websiteId, sessionId);
return ( return (
<LoadingPanel {...query} loadingIcon="spinner" data={data}> <LoadingPanel {...query} loadingIcon="spinner" data={data}>

View file

@ -1,6 +1,6 @@
'use client'; 'use client';
import { WebsiteDetailsPage } from '../../(main)/websites/[websiteId]/WebsiteDetailsPage'; import { WebsiteDetailsPage } from '../../(main)/websites/[websiteId]/WebsiteDetailsPage';
import { useShareToken } from '@/components/hooks'; import { useShareTokenQuery } from '@/components/hooks';
import { Page } from '@/components/layout/Page'; import { Page } from '@/components/layout/Page';
import { Header } from './Header'; import { Header } from './Header';
import { Footer } from './Footer'; import { Footer } from './Footer';
@ -8,7 +8,7 @@ import styles from './SharePage.module.css';
import { WebsiteProvider } from '@/app/(main)/websites/[websiteId]/WebsiteProvider'; import { WebsiteProvider } from '@/app/(main)/websites/[websiteId]/WebsiteProvider';
export function SharePage({ shareId }) { export function SharePage({ shareId }) {
const { shareToken, isLoading } = useShareToken(shareId); const { shareToken, isLoading } = useShareTokenQuery(shareId);
if (isLoading || !shareToken) { if (isLoading || !shareToken) {
return null; return null;

View file

@ -1,32 +1,32 @@
export * from './queries/useConfig'; export * from './queries/useEventDataEventsQuery';
export * from './queries/useEventDataEvents'; export * from './queries/useEventDataPropertiesQuery';
export * from './queries/useEventDataProperties'; export * from './queries/useEventDataValuesQuery';
export * from './queries/useEventDataValues'; export * from './queries/useLoginQuery';
export * from './queries/useLogin'; export * from './queries/useRealtimeQuery';
export * from './queries/useRealtime'; export * from './queries/useReportQuery';
export * from './queries/useReport'; export * from './queries/useReportsQuery';
export * from './queries/useReports'; export * from './queries/useSessionActivityQuery';
export * from './queries/useSessionActivity'; export * from './queries/useSessionDataQuery';
export * from './queries/useSessionData'; export * from './queries/useSessionDataPropertiesQuery';
export * from './queries/useSessionDataProperties'; export * from './queries/useSessionDataValuesQuery';
export * from './queries/useSessionDataValues'; export * from './queries/useWebsiteSessionQuery';
export * from './queries/useWebsiteSession'; export * from './queries/useWebsiteSessionsQuery';
export * from './queries/useWebsiteSessions'; export * from './queries/useWebsiteSessionsWeeklyQuery';
export * from './queries/useWebsiteSessionsWeekly'; export * from './queries/useShareTokenQuery';
export * from './queries/useShareToken'; export * from './queries/useTeamQuery';
export * from './queries/useTeam'; export * from './queries/useTeamsQuery';
export * from './queries/useTeams'; export * from './queries/useTeamWebsitesQuery';
export * from './queries/useTeamWebsites'; export * from './queries/useTeamMembersQuery';
export * from './queries/useTeamMembers'; export * from './queries/useUserQuery';
export * from './queries/useUser'; export * from './queries/useUsersQuery';
export * from './queries/useUsers'; export * from './queries/useWebsiteQuery';
export * from './queries/useWebsite';
export * from './queries/useWebsites'; export * from './queries/useWebsites';
export * from './queries/useWebsiteEvents'; export * from './queries/useWebsiteEventsQuery';
export * from './queries/useWebsiteEventsSeries'; export * from './queries/useWebsiteEventsSeriesQuery';
export * from './queries/useWebsiteMetrics'; export * from './queries/useWebsiteMetricsQuery';
export * from './queries/useWebsiteValues'; export * from './queries/useWebsiteValuesQuery';
export * from './useApi'; export * from './useApi';
export * from './useConfig';
export * from './useCountryNames'; export * from './useCountryNames';
export * from './useDateRange'; export * from './useDateRange';
export * from './useDocumentClick'; export * from './useDocumentClick';
@ -39,10 +39,9 @@ export * from './useLanguageNames';
export * from './useLocale'; export * from './useLocale';
export * from './useMessages'; export * from './useMessages';
export * from './useModified'; export * from './useModified';
export * from './useNavigation';
export * from './usePagedQuery'; export * from './usePagedQuery';
export * from './useRegionNames'; export * from './useRegionNames';
export * from './useSticky'; export * from './useSticky';
export * from './useTeamUrl'; export * from './useNavigation';
export * from './useTheme'; export * from './useTheme';
export * from './useTimezone'; export * from './useTimezone';

View file

@ -2,7 +2,7 @@ import { useApi } from '../useApi';
import { UseQueryOptions } from '@tanstack/react-query'; import { UseQueryOptions } from '@tanstack/react-query';
import { useFilterParams } from '../useFilterParams'; import { useFilterParams } from '../useFilterParams';
export function useEventDataEvents( export function useEventDataEventsQuery(
websiteId: string, websiteId: string,
options?: Omit<UseQueryOptions, 'queryKey' | 'queryFn'>, options?: Omit<UseQueryOptions, 'queryKey' | 'queryFn'>,
) { ) {

View file

@ -2,7 +2,7 @@ import { UseQueryOptions } from '@tanstack/react-query';
import { useApi } from '../useApi'; import { useApi } from '../useApi';
import { useFilterParams } from '../useFilterParams'; import { useFilterParams } from '../useFilterParams';
export function useEventDataProperties( export function useEventDataPropertiesQuery(
websiteId: string, websiteId: string,
options?: Omit<UseQueryOptions, 'queryKey' | 'queryFn'>, options?: Omit<UseQueryOptions, 'queryKey' | 'queryFn'>,
) { ) {

View file

@ -2,7 +2,7 @@ import { UseQueryOptions } from '@tanstack/react-query';
import { useApi } from '../useApi'; import { useApi } from '../useApi';
import { useFilterParams } from '../useFilterParams'; import { useFilterParams } from '../useFilterParams';
export function useEventDataValues( export function useEventDataValuesQuery(
websiteId: string, websiteId: string,
eventName: string, eventName: string,
propertyName: string, propertyName: string,

View file

@ -4,7 +4,7 @@ import { useApi } from '../useApi';
const selector = (state: { user: any }) => state.user; const selector = (state: { user: any }) => state.user;
export function useLogin(): { export function useLoginQuery(): {
user: any; user: any;
setUser: (data: any) => void; setUser: (data: any) => void;
} & UseQueryResult { } & UseQueryResult {

View file

@ -3,7 +3,7 @@ import { REALTIME_INTERVAL } from '@/lib/constants';
import { RealtimeData } from '@/lib/types'; import { RealtimeData } from '@/lib/types';
import { useApi } from '../useApi'; import { useApi } from '../useApi';
export function useRealtime(websiteId: string) { export function useRealtimeQuery(websiteId: string) {
const { get, useQuery } = useApi(); const { get, useQuery } = useApi();
const { timezone } = useTimezone(); const { timezone } = useTimezone();
const { data, isLoading, error } = useQuery<RealtimeData>({ const { data, isLoading, error } = useQuery<RealtimeData>({

View file

@ -5,7 +5,7 @@ import { useTimezone } from '../useTimezone';
import { useMessages } from '../useMessages'; import { useMessages } from '../useMessages';
import { parseDateRange } from '@/lib/date'; import { parseDateRange } from '@/lib/date';
export function useReport( export function useReportQuery(
reportId: string, reportId: string,
defaultParameters?: { type: string; parameters: { [key: string]: any } }, defaultParameters?: { type: string; parameters: { [key: string]: any } },
) { ) {

View file

@ -2,7 +2,7 @@ import { useApi } from '../useApi';
import { usePagedQuery } from '../usePagedQuery'; import { usePagedQuery } from '../usePagedQuery';
import { useModified } from '../useModified'; import { useModified } from '../useModified';
export function useReports({ websiteId, teamId }: { websiteId?: string; teamId?: string }) { export function useReportsQuery({ websiteId, teamId }: { websiteId?: string; teamId?: string }) {
const { modified } = useModified(`reports`); const { modified } = useModified(`reports`);
const { get, del, useMutation } = useApi(); const { get, del, useMutation } = useApi();
const queryResult = usePagedQuery({ const queryResult = usePagedQuery({

View file

@ -1,6 +1,6 @@
import { useApi } from '../useApi'; import { useApi } from '../useApi';
export function useRevenueValues(websiteId: string, startDate: Date, endDate: Date) { export function useRevenueValuesQuery(websiteId: string, startDate: Date, endDate: Date) {
const { get, useQuery } = useApi(); const { get, useQuery } = useApi();
return useQuery({ return useQuery({

View file

@ -1,6 +1,6 @@
import { useApi } from '../useApi'; import { useApi } from '../useApi';
export function useSessionActivity( export function useSessionActivityQuery(
websiteId: string, websiteId: string,
sessionId: string, sessionId: string,
startDate: Date, startDate: Date,

View file

@ -2,7 +2,7 @@ import { useApi } from '../useApi';
import { UseQueryOptions } from '@tanstack/react-query'; import { UseQueryOptions } from '@tanstack/react-query';
import { useFilterParams } from '../useFilterParams'; import { useFilterParams } from '../useFilterParams';
export function useSessionDataProperties( export function useSessionDataPropertiesQuery(
websiteId: string, websiteId: string,
options?: Omit<UseQueryOptions, 'queryKey' | 'queryFn'>, options?: Omit<UseQueryOptions, 'queryKey' | 'queryFn'>,
) { ) {

View file

@ -1,6 +1,6 @@
import { useApi } from '../useApi'; import { useApi } from '../useApi';
export function useSessionData(websiteId: string, sessionId: string) { export function useSessionDataQuery(websiteId: string, sessionId: string) {
const { get, useQuery } = useApi(); const { get, useQuery } = useApi();
return useQuery({ return useQuery({

View file

@ -2,7 +2,7 @@ import { useApi } from '../useApi';
import { UseQueryOptions } from '@tanstack/react-query'; import { UseQueryOptions } from '@tanstack/react-query';
import { useFilterParams } from '../useFilterParams'; import { useFilterParams } from '../useFilterParams';
export function useSessionDataValues( export function useSessionDataValuesQuery(
websiteId: string, websiteId: string,
propertyName: string, propertyName: string,
options?: Omit<UseQueryOptions, 'queryKey' | 'queryFn'>, options?: Omit<UseQueryOptions, 'queryKey' | 'queryFn'>,

View file

@ -3,7 +3,7 @@ import { useApi } from '../useApi';
const selector = (state: { shareToken: string }) => state.shareToken; const selector = (state: { shareToken: string }) => state.shareToken;
export function useShareToken(shareId: string): { export function useShareTokenQuery(shareId: string): {
shareToken: any; shareToken: any;
isLoading?: boolean; isLoading?: boolean;
error?: Error; error?: Error;

View file

@ -2,7 +2,7 @@ import { useApi } from '../useApi';
import { usePagedQuery } from '../usePagedQuery'; import { usePagedQuery } from '../usePagedQuery';
import { useModified } from '../useModified'; import { useModified } from '../useModified';
export function useTeamMembers(teamId: string) { export function useTeamMembersQuery(teamId: string) {
const { get } = useApi(); const { get } = useApi();
const { modified } = useModified(`teams:members`); const { modified } = useModified(`teams:members`);

View file

@ -1,6 +1,6 @@
import { useApi } from '../useApi'; import { useApi } from '../useApi';
export function useTeam(teamId: string) { export function useTeamQuery(teamId: string) {
const { get, useQuery } = useApi(); const { get, useQuery } = useApi();
return useQuery({ return useQuery({
queryKey: ['teams', teamId], queryKey: ['teams', teamId],

View file

@ -2,7 +2,7 @@ import { useApi } from '../useApi';
import { usePagedQuery } from '../usePagedQuery'; import { usePagedQuery } from '../usePagedQuery';
import { useModified } from '../useModified'; import { useModified } from '../useModified';
export function useTeamWebsites(teamId: string) { export function useTeamWebsitesQuery(teamId: string) {
const { get } = useApi(); const { get } = useApi();
const { modified } = useModified(`websites`); const { modified } = useModified(`websites`);

View file

@ -2,7 +2,7 @@ import { useApi } from '../useApi';
import { usePagedQuery } from '../usePagedQuery'; import { usePagedQuery } from '../usePagedQuery';
import { useModified } from '../useModified'; import { useModified } from '../useModified';
export function useTeams(userId: string) { export function useTeamsQuery(userId: string) {
const { get } = useApi(); const { get } = useApi();
const { modified } = useModified(`teams`); const { modified } = useModified(`teams`);

View file

@ -1,6 +1,6 @@
import { useApi } from '../useApi'; import { useApi } from '../useApi';
export function useUser(userId: string, options?: { [key: string]: any }) { export function useUserQuery(userId: string, options?: { [key: string]: any }) {
const { get, useQuery } = useApi(); const { get, useQuery } = useApi();
return useQuery({ return useQuery({
queryKey: ['users', userId], queryKey: ['users', userId],

View file

@ -2,7 +2,7 @@ import { useApi } from '../useApi';
import { usePagedQuery } from '../usePagedQuery'; import { usePagedQuery } from '../usePagedQuery';
import { useModified } from '../useModified'; import { useModified } from '../useModified';
export function useUsers() { export function useUsersQuery() {
const { get } = useApi(); const { get } = useApi();
const { modified } = useModified(`users`); const { modified } = useModified(`users`);

View file

@ -3,7 +3,7 @@ import { UseQueryOptions } from '@tanstack/react-query';
import { useFilterParams } from '../useFilterParams'; import { useFilterParams } from '../useFilterParams';
import { usePagedQuery } from '../usePagedQuery'; import { usePagedQuery } from '../usePagedQuery';
export function useWebsiteEvents( export function useWebsiteEventsQuery(
websiteId: string, websiteId: string,
options?: Omit<UseQueryOptions, 'queryKey' | 'queryFn'>, options?: Omit<UseQueryOptions, 'queryKey' | 'queryFn'>,
) { ) {

View file

@ -2,7 +2,7 @@ import { useApi } from '../useApi';
import { UseQueryOptions } from '@tanstack/react-query'; import { UseQueryOptions } from '@tanstack/react-query';
import { useFilterParams } from '../useFilterParams'; import { useFilterParams } from '../useFilterParams';
export function useWebsiteEventsSeries( export function useWebsiteEventsSeriesQuery(
websiteId: string, websiteId: string,
options?: Omit<UseQueryOptions, 'queryKey' | 'queryFn'>, options?: Omit<UseQueryOptions, 'queryKey' | 'queryFn'>,
) { ) {

View file

@ -3,7 +3,7 @@ import { useApi } from '../useApi';
import { useFilterParams } from '../useFilterParams'; import { useFilterParams } from '../useFilterParams';
import { useSearchParams } from 'next/navigation'; import { useSearchParams } from 'next/navigation';
export function useWebsiteMetrics( export function useWebsiteMetricsQuery(
websiteId: string, websiteId: string,
queryParams: { type: string; limit?: number; search?: string; startAt?: number; endAt?: number }, queryParams: { type: string; limit?: number; search?: string; startAt?: number; endAt?: number },
options?: Omit<UseQueryOptions & { onDataLoad?: (data: any) => void }, 'queryKey' | 'queryFn'>, options?: Omit<UseQueryOptions & { onDataLoad?: (data: any) => void }, 'queryKey' | 'queryFn'>,

View file

@ -2,7 +2,7 @@ import { UseQueryOptions } from '@tanstack/react-query';
import { useApi } from '../useApi'; import { useApi } from '../useApi';
import { useFilterParams } from '../useFilterParams'; import { useFilterParams } from '../useFilterParams';
export function useWebsitePageviews( export function useWebsitePageviewsQuery(
websiteId: string, websiteId: string,
compare?: string, compare?: string,
options?: Omit<UseQueryOptions, 'queryKey' | 'queryFn'>, options?: Omit<UseQueryOptions, 'queryKey' | 'queryFn'>,

View file

@ -1,6 +1,6 @@
import { useApi } from '../useApi'; import { useApi } from '../useApi';
export function useWebsite(websiteId: string, options?: { [key: string]: any }) { export function useWebsiteQuery(websiteId: string, options?: { [key: string]: any }) {
const { get, useQuery } = useApi(); const { get, useQuery } = useApi();
return useQuery({ return useQuery({

View file

@ -1,6 +1,6 @@
import { useApi } from '../useApi'; import { useApi } from '../useApi';
export function useWebsiteSession(websiteId: string, sessionId: string) { export function useWebsiteSessionQuery(websiteId: string, sessionId: string) {
const { get, useQuery } = useApi(); const { get, useQuery } = useApi();
return useQuery({ return useQuery({

View file

@ -1,7 +1,10 @@
import { useApi } from '../useApi'; import { useApi } from '../useApi';
import { useFilterParams } from '../useFilterParams'; import { useFilterParams } from '../useFilterParams';
export function useWebsiteSessionStats(websiteId: string, options?: { [key: string]: string }) { export function useWebsiteSessionStatsQuery(
websiteId: string,
options?: { [key: string]: string },
) {
const { get, useQuery } = useApi(); const { get, useQuery } = useApi();
const params = useFilterParams(websiteId); const params = useFilterParams(websiteId);

View file

@ -3,7 +3,10 @@ import { usePagedQuery } from '../usePagedQuery';
import { useModified } from '../useModified'; import { useModified } from '../useModified';
import { useFilterParams } from '@/components/hooks/useFilterParams'; import { useFilterParams } from '@/components/hooks/useFilterParams';
export function useWebsiteSessions(websiteId: string, params?: { [key: string]: string | number }) { export function useWebsiteSessionsQuery(
websiteId: string,
params?: { [key: string]: string | number },
) {
const { get } = useApi(); const { get } = useApi();
const { modified } = useModified(`sessions`); const { modified } = useModified(`sessions`);
const filters = useFilterParams(websiteId); const filters = useFilterParams(websiteId);

View file

@ -2,7 +2,7 @@ import { useApi } from '../useApi';
import { useModified } from '../useModified'; import { useModified } from '../useModified';
import { useFilterParams } from '@/components/hooks/useFilterParams'; import { useFilterParams } from '@/components/hooks/useFilterParams';
export function useWebsiteSessionsWeekly( export function useWebsiteSessionsWeeklyQuery(
websiteId: string, websiteId: string,
params?: { [key: string]: string | number }, params?: { [key: string]: string | number },
) { ) {

View file

@ -1,7 +1,7 @@
import { useApi } from '../useApi'; import { useApi } from '../useApi';
import { useFilterParams } from '../useFilterParams'; import { useFilterParams } from '../useFilterParams';
export function useWebsiteStats( export function useWebsiteStatsQuery(
websiteId: string, websiteId: string,
compare?: string, compare?: string,
options?: { [key: string]: string }, options?: { [key: string]: string },

View file

@ -3,7 +3,7 @@ import { useCountryNames } from '@/components/hooks/useCountryNames';
import { useRegionNames } from '@/components/hooks/useRegionNames'; import { useRegionNames } from '@/components/hooks/useRegionNames';
import { useLocale } from '../useLocale'; import { useLocale } from '../useLocale';
export function useWebsiteValues({ export function useWebsiteValuesQuery({
websiteId, websiteId,
type, type,
startDate, startDate,

View file

@ -1,6 +1,6 @@
import { useApi } from '../useApi'; import { useApi } from '../useApi';
import { usePagedQuery } from '../usePagedQuery'; import { usePagedQuery } from '../usePagedQuery';
import { useLogin } from './useLogin'; import { useLoginQuery } from './useLoginQuery';
import { useModified } from '../useModified'; import { useModified } from '../useModified';
export function useWebsites( export function useWebsites(
@ -8,7 +8,7 @@ export function useWebsites(
params?: { [key: string]: string | number }, params?: { [key: string]: string | number },
) { ) {
const { get } = useApi(); const { get } = useApi();
const { user } = useLogin(); const { user } = useLoginQuery();
const { modified } = useModified(`websites`); const { modified } = useModified(`websites`);
return usePagedQuery({ return usePagedQuery({

Some files were not shown because too many files have changed in this diff Show more