mirror of
https://github.com/umami-software/umami.git
synced 2026-02-06 21:57:16 +01:00
Website header updates.
This commit is contained in:
parent
2b99274895
commit
96c2c32d14
26 changed files with 137 additions and 247 deletions
|
|
@ -1,3 +1,4 @@
|
|||
export * from './queries/useActiveUsersQuery';
|
||||
export * from './queries/useEventDataEventsQuery';
|
||||
export * from './queries/useEventDataPropertiesQuery';
|
||||
export * from './queries/useEventDataValuesQuery';
|
||||
|
|
|
|||
15
src/components/hooks/queries/useActiveUsersQuery.ts
Normal file
15
src/components/hooks/queries/useActiveUsersQuery.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { useApi } from '../useApi';
|
||||
import { UseQueryOptions } from '@tanstack/react-query';
|
||||
|
||||
export function useActyiveUsersQuery(
|
||||
websiteId: string,
|
||||
options?: Omit<UseQueryOptions, 'queryKey' | 'queryFn'>,
|
||||
) {
|
||||
const { get, useQuery } = useApi();
|
||||
return useQuery<any>({
|
||||
queryKey: ['websites:active', websiteId],
|
||||
queryFn: () => get(`/websites/${websiteId}/active`),
|
||||
enabled: !!websiteId,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
|
@ -7,12 +7,7 @@ import { DateRange } from '@/lib/types';
|
|||
import { useLocale } from './useLocale';
|
||||
import { useApi } from './useApi';
|
||||
|
||||
export function useDateRange(websiteId?: string): {
|
||||
dateRange: DateRange;
|
||||
saveDateRange: (value: string | DateRange) => void;
|
||||
dateCompare: string;
|
||||
saveDateCompare: (value: string) => void;
|
||||
} {
|
||||
export function useDateRange(websiteId?: string) {
|
||||
const { get } = useApi();
|
||||
const { locale } = useLocale();
|
||||
const websiteConfig = useWebsites(state => state[websiteId]?.dateRange);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,5 @@ import { WebsiteContext } from '@/app/(main)/websites/[websiteId]/WebsiteProvide
|
|||
import { useContext } from 'react';
|
||||
|
||||
export function useWebsite() {
|
||||
const website = useContext(WebsiteContext);
|
||||
|
||||
return website;
|
||||
return useContext(WebsiteContext);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
.dropdown span {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
|
@ -95,7 +95,7 @@ export function DateFilter({
|
|||
return (
|
||||
<>
|
||||
<Select
|
||||
value={value}
|
||||
selectedKey={value}
|
||||
placeholder={formatMessage(labels.selectDate)}
|
||||
onSelectionChange={handleChange}
|
||||
>
|
||||
|
|
@ -103,9 +103,7 @@ export function DateFilter({
|
|||
return (
|
||||
<Fragment key={label}>
|
||||
{divider && <ListSeparator />}
|
||||
<ListItem key={label} id={value}>
|
||||
{label}
|
||||
</ListItem>
|
||||
<ListItem id={value}>{label}</ListItem>
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid var(--base400);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.popup {
|
||||
border: 1px solid var(--base400);
|
||||
background: var(--base50);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 20px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
|
@ -1,17 +1,15 @@
|
|||
import { useRef } from 'react';
|
||||
import { Row, Text, Icon, Button, MenuTrigger, Popover, Menu, MenuItem } from '@umami/react-zen';
|
||||
import { startOfMonth, endOfMonth, startOfYear, addMonths, subYears } from 'date-fns';
|
||||
import { Icons } from '@/components/icons';
|
||||
import { useLocale } from '@/components/hooks';
|
||||
import { formatDate } from '@/lib/date';
|
||||
import styles from './MonthSelect.module.css';
|
||||
|
||||
export function MonthSelect({ date = new Date(), onChange }) {
|
||||
const { locale, dateLocale } = useLocale();
|
||||
const { locale } = useLocale();
|
||||
const month = formatDate(date, 'MMMM', locale);
|
||||
const year = date.getFullYear();
|
||||
const ref = useRef();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const handleChange = (close: () => void, date: Date) => {
|
||||
onChange(`range:${startOfMonth(date).getTime()}:${endOfMonth(date).getTime()}`);
|
||||
close();
|
||||
|
|
@ -30,32 +28,36 @@ export function MonthSelect({ date = new Date(), onChange }) {
|
|||
return (
|
||||
<Row>
|
||||
<MenuTrigger>
|
||||
<Button className={styles.input} variant="quiet">
|
||||
<Button variant="quiet">
|
||||
<Text>{month}</Text>
|
||||
<Icon size="sm">
|
||||
<Icons.Chevron />
|
||||
</Icon>
|
||||
</Button>
|
||||
<Popover>
|
||||
<Menu items={months}>
|
||||
{month => {
|
||||
return <MenuItem id={month}>{month.getDay()}</MenuItem>;
|
||||
}}
|
||||
<Menu>
|
||||
{months.map(month => {
|
||||
return (
|
||||
<MenuItem key={month.toString()} id={month.toString()}>
|
||||
{month.getDay()}
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
</Popover>
|
||||
</MenuTrigger>
|
||||
<MenuTrigger>
|
||||
<Button className={styles.input} variant="quiet">
|
||||
<Button variant="quiet">
|
||||
<Text>{year}</Text>
|
||||
<Icon size="sm">
|
||||
<Icons.Chevron />
|
||||
</Icon>
|
||||
</Button>
|
||||
<Popover>
|
||||
<Menu items={years}>
|
||||
{year => {
|
||||
<Menu>
|
||||
{years.map(year => {
|
||||
return <MenuItem id={year}>{year}</MenuItem>;
|
||||
}}
|
||||
})}
|
||||
</Menu>
|
||||
</Popover>
|
||||
</MenuTrigger>
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
.menu {
|
||||
width: 200px;
|
||||
z-index: var(--z-index-popup);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--border-radius);
|
||||
overflow: hidden;
|
||||
background: var(--base50);
|
||||
}
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
background: var(--base50);
|
||||
}
|
||||
|
||||
.version {
|
||||
font-family: monospace;
|
||||
font-size: 11px;
|
||||
color: var(--base600);
|
||||
text-align: right;
|
||||
margin-inline-end: 10px;
|
||||
}
|
||||
|
||||
.name {
|
||||
color: var(--font-color200);
|
||||
background: var(--base75);
|
||||
padding: var(--size300) var(--size600);
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
.popup {
|
||||
background: var(--base50);
|
||||
border: 1px solid var(--base500);
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
|
|
@ -1,30 +1,27 @@
|
|||
import { Button, Icon, PopupTrigger, Popup, Form, FormRow } from '@umami/react-zen';
|
||||
import { Button, Icon, DialogTrigger, Popover, Column, Label } from '@umami/react-zen';
|
||||
import { TimezoneSetting } from '@/app/(main)/profile/TimezoneSetting';
|
||||
import { DateRangeSetting } from '@/app/(main)/profile/DateRangeSetting';
|
||||
import { Icons } from '@/components/icons';
|
||||
import { useMessages } from '@/components/hooks';
|
||||
import styles from './SettingsButton.module.css';
|
||||
|
||||
export function SettingsButton() {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
||||
return (
|
||||
<PopupTrigger>
|
||||
<DialogTrigger>
|
||||
<Button variant="quiet">
|
||||
<Icon>
|
||||
<Icons.Gear />
|
||||
</Icon>
|
||||
</Button>
|
||||
<Popup className={styles.popup} position="bottom" alignment="end">
|
||||
<Form>
|
||||
<FormRow label={formatMessage(labels.timezone)}>
|
||||
<TimezoneSetting />
|
||||
</FormRow>
|
||||
<FormRow label={formatMessage(labels.defaultDateRange)}>
|
||||
<DateRangeSetting />
|
||||
</FormRow>
|
||||
</Form>
|
||||
</Popup>
|
||||
</PopupTrigger>
|
||||
<Popover placement="bottom end">
|
||||
<Column gap="3">
|
||||
<Label>{formatMessage(labels.timezone)}</Label>
|
||||
<TimezoneSetting />
|
||||
<Label>{formatMessage(labels.defaultDateRange)}</Label>
|
||||
<DateRangeSetting />
|
||||
</Column>
|
||||
</Popover>
|
||||
</DialogTrigger>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
.button {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.menu {
|
||||
background: var(--base50);
|
||||
min-width: 260px;
|
||||
}
|
||||
|
||||
.heading {
|
||||
color: var(--base600);
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
padding: 8px 16px;
|
||||
text-transform: uppercase;
|
||||
border-bottom: 1px solid var(--base300);
|
||||
}
|
||||
|
||||
.selected {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.buttons button:first-child {
|
||||
border-start-end-radius: 0;
|
||||
border-end-end-radius: 0;
|
||||
border-inline-end: 1px solid var(--base400);
|
||||
}
|
||||
|
||||
.buttons button:last-child {
|
||||
border-start-start-radius: 0;
|
||||
border-end-start-radius: 0;
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@ export function WebsiteDateFilter({
|
|||
value === 'all' || isAfter(getOffsetDateRange(dateRange, 1).startDate, new Date());
|
||||
|
||||
const handleChange = (value: string | DateRange) => {
|
||||
console.log('WebsiteDateFilter', value);
|
||||
saveDateRange(value);
|
||||
};
|
||||
|
||||
|
|
@ -25,6 +26,8 @@ export function WebsiteDateFilter({
|
|||
saveDateRange(getOffsetDateRange(dateRange, increment));
|
||||
};
|
||||
|
||||
console.log({ dateRange, disableForward });
|
||||
|
||||
return (
|
||||
<Row gap="3">
|
||||
{value !== 'all' && !value.startsWith('range') && (
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
.dropdown {
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
|
@ -51,6 +51,7 @@ export const labels = defineMessages({
|
|||
data: { id: 'label.data', defaultMessage: 'Data' },
|
||||
trackingCode: { id: 'label.tracking-code', defaultMessage: 'Tracking code' },
|
||||
shareUrl: { id: 'label.share-url', defaultMessage: 'Share URL' },
|
||||
share: { id: 'label.share', defaultMessage: 'Share' },
|
||||
actions: { id: 'label.actions', defaultMessage: 'Actions' },
|
||||
domain: { id: 'label.domain', defaultMessage: 'Domain' },
|
||||
websiteId: { id: 'label.website-id', defaultMessage: 'Website ID' },
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-inline-start: 20px;
|
||||
}
|
||||
|
||||
.text {
|
||||
display: flex;
|
||||
white-space: nowrap;
|
||||
font-size: var(--font-size-md);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
import { useMemo } from 'react';
|
||||
import { StatusLight } from '@umami/react-zen';
|
||||
import { useApi } from '@/components/hooks';
|
||||
import { useMessages } from '@/components/hooks';
|
||||
import styles from './ActiveUsers.module.css';
|
||||
import { Text, StatusLight } from '@umami/react-zen';
|
||||
import { useMessages, useActyiveUsersQuery } from '@/components/hooks';
|
||||
|
||||
export function ActiveUsers({
|
||||
websiteId,
|
||||
|
|
@ -14,13 +12,7 @@ export function ActiveUsers({
|
|||
refetchInterval?: number;
|
||||
}) {
|
||||
const { formatMessage, messages } = useMessages();
|
||||
const { get, useQuery } = useApi();
|
||||
const { data } = useQuery({
|
||||
queryKey: ['websites:active', websiteId],
|
||||
queryFn: () => get(`/websites/${websiteId}/active`),
|
||||
enabled: !!websiteId,
|
||||
refetchInterval,
|
||||
});
|
||||
const { data } = useActyiveUsersQuery(websiteId, { refetchInterval });
|
||||
|
||||
const count = useMemo(() => {
|
||||
if (websiteId) {
|
||||
|
|
@ -35,8 +27,8 @@ export function ActiveUsers({
|
|||
}
|
||||
|
||||
return (
|
||||
<StatusLight className={styles.container} variant="success">
|
||||
<div className={styles.text}>{formatMessage(messages.activeUsers, { x: count })}</div>
|
||||
<StatusLight variant="success">
|
||||
<Text size="2">{formatMessage(messages.activeUsers, { x: count })}</Text>
|
||||
</StatusLight>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue