mirror of
https://github.com/kremalicious/umami.git
synced 2025-02-01 12:29:35 +01:00
Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
56ee52e349
@ -13,6 +13,7 @@ export function DateFilter({
|
|||||||
endDate,
|
endDate,
|
||||||
className,
|
className,
|
||||||
onChange,
|
onChange,
|
||||||
|
selectedUnit,
|
||||||
showAllTime = false,
|
showAllTime = false,
|
||||||
alignment = 'end',
|
alignment = 'end',
|
||||||
}) {
|
}) {
|
||||||
@ -66,7 +67,12 @@ export function DateFilter({
|
|||||||
|
|
||||||
const renderValue = value => {
|
const renderValue = value => {
|
||||||
return value.startsWith('range') ? (
|
return value.startsWith('range') ? (
|
||||||
<CustomRange startDate={startDate} endDate={endDate} onClick={() => handleChange('custom')} />
|
<CustomRange
|
||||||
|
startDate={startDate}
|
||||||
|
endDate={endDate}
|
||||||
|
selectedUnit={selectedUnit}
|
||||||
|
onClick={() => handleChange('custom')}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
options.find(e => e.value === value).label
|
options.find(e => e.value === value).label
|
||||||
);
|
);
|
||||||
@ -120,9 +126,11 @@ export function DateFilter({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const CustomRange = ({ startDate, endDate, onClick }) => {
|
const CustomRange = ({ startDate, endDate, selectedUnit, onClick }) => {
|
||||||
const { locale } = useLocale();
|
const { locale } = useLocale();
|
||||||
|
|
||||||
|
const monthFormat = +selectedUnit?.num === 1 && selectedUnit?.unit === 'month';
|
||||||
|
|
||||||
function handleClick(e) {
|
function handleClick(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
@ -135,8 +143,14 @@ const CustomRange = ({ startDate, endDate, onClick }) => {
|
|||||||
<Icons.Calendar />
|
<Icons.Calendar />
|
||||||
</Icon>
|
</Icon>
|
||||||
<Text>
|
<Text>
|
||||||
{formatDate(startDate, 'd LLL y', locale)}
|
{monthFormat ? (
|
||||||
{!isSameDay(startDate, endDate) && ` — ${formatDate(endDate, 'd LLL y', locale)}`}
|
<>{formatDate(startDate, 'MMMM yyyy', locale)}</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{formatDate(startDate, 'd LLL y', locale)}
|
||||||
|
{!isSameDay(startDate, endDate) && ` — ${formatDate(endDate, 'd LLL y', locale)}`}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
</Flexbox>
|
</Flexbox>
|
||||||
);
|
);
|
||||||
|
@ -1,24 +1,51 @@
|
|||||||
import useDateRange from 'components/hooks/useDateRange';
|
import useDateRange from 'components/hooks/useDateRange';
|
||||||
|
import { isAfter } from 'date-fns';
|
||||||
|
import { incrementDateRange } from 'lib/date';
|
||||||
|
import { Button, Flexbox, Icon, Icons } from 'react-basics';
|
||||||
import DateFilter from './DateFilter';
|
import DateFilter from './DateFilter';
|
||||||
import styles from './WebsiteDateFilter.module.css';
|
import styles from './WebsiteDateFilter.module.css';
|
||||||
|
|
||||||
export function WebsiteDateFilter({ websiteId }) {
|
export function WebsiteDateFilter({ websiteId }) {
|
||||||
const [dateRange, setDateRange] = useDateRange(websiteId);
|
const [dateRange, setDateRange] = useDateRange(websiteId);
|
||||||
const { value, startDate, endDate } = dateRange;
|
const { value, startDate, endDate, selectedUnit } = dateRange;
|
||||||
|
|
||||||
|
const isFutureDate = isAfter(incrementDateRange(dateRange, -1).startDate, new Date());
|
||||||
|
|
||||||
const handleChange = async value => {
|
const handleChange = async value => {
|
||||||
setDateRange(value);
|
setDateRange(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleIncrement = async value => {
|
||||||
|
const newValue = incrementDateRange(dateRange, value);
|
||||||
|
|
||||||
|
setDateRange(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DateFilter
|
<>
|
||||||
className={styles.dropdown}
|
<DateFilter
|
||||||
value={value}
|
className={styles.dropdown}
|
||||||
startDate={startDate}
|
value={value}
|
||||||
endDate={endDate}
|
startDate={startDate}
|
||||||
onChange={handleChange}
|
endDate={endDate}
|
||||||
showAllTime={true}
|
selectedUnit={selectedUnit}
|
||||||
/>
|
onChange={handleChange}
|
||||||
|
showAllTime={true}
|
||||||
|
/>
|
||||||
|
<Flexbox justifyContent="center" gap={10} className={styles.container}>
|
||||||
|
<Button onClick={() => handleIncrement(1)}>
|
||||||
|
<Icon rotate={90}>
|
||||||
|
<Icons.ChevronDown />
|
||||||
|
</Icon>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button onClick={() => handleIncrement(-1)} disabled={isFutureDate}>
|
||||||
|
<Icon rotate={270}>
|
||||||
|
<Icons.ChevronDown />
|
||||||
|
</Icon>
|
||||||
|
</Button>
|
||||||
|
</Flexbox>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,8 +110,8 @@ export function WebsiteMetricsBar({ websiteId, sticky }) {
|
|||||||
</Column>
|
</Column>
|
||||||
<Column defaultSize={12} xl={4}>
|
<Column defaultSize={12} xl={4}>
|
||||||
<div className={styles.actions}>
|
<div className={styles.actions}>
|
||||||
<RefreshButton websiteId={websiteId} />
|
|
||||||
<WebsiteDateFilter websiteId={websiteId} />
|
<WebsiteDateFilter websiteId={websiteId} />
|
||||||
|
<RefreshButton websiteId={websiteId} />
|
||||||
</div>
|
</div>
|
||||||
</Column>
|
</Column>
|
||||||
</Row>
|
</Row>
|
||||||
|
@ -29,9 +29,19 @@ import {
|
|||||||
max,
|
max,
|
||||||
min,
|
min,
|
||||||
isDate,
|
isDate,
|
||||||
|
subWeeks,
|
||||||
} from 'date-fns';
|
} from 'date-fns';
|
||||||
import { getDateLocale } from 'lib/lang';
|
import { getDateLocale } from 'lib/lang';
|
||||||
|
|
||||||
|
export const TIME_UNIT = {
|
||||||
|
minute: 'minute',
|
||||||
|
hour: 'hour',
|
||||||
|
day: 'day',
|
||||||
|
week: 'week',
|
||||||
|
month: 'month',
|
||||||
|
year: 'year',
|
||||||
|
};
|
||||||
|
|
||||||
const dateFuncs = {
|
const dateFuncs = {
|
||||||
minute: [differenceInMinutes, addMinutes, startOfMinute],
|
minute: [differenceInMinutes, addMinutes, startOfMinute],
|
||||||
hour: [differenceInHours, addHours, startOfHour],
|
hour: [differenceInHours, addHours, startOfHour],
|
||||||
@ -81,6 +91,7 @@ export function parseDateRange(value, locale = 'en-US') {
|
|||||||
if (!match) return null;
|
if (!match) return null;
|
||||||
|
|
||||||
const { num, unit } = match.groups;
|
const { num, unit } = match.groups;
|
||||||
|
const selectedUnit = { num, unit };
|
||||||
|
|
||||||
if (+num === 1) {
|
if (+num === 1) {
|
||||||
switch (unit) {
|
switch (unit) {
|
||||||
@ -90,6 +101,7 @@ export function parseDateRange(value, locale = 'en-US') {
|
|||||||
endDate: endOfDay(now),
|
endDate: endOfDay(now),
|
||||||
unit: 'hour',
|
unit: 'hour',
|
||||||
value,
|
value,
|
||||||
|
selectedUnit,
|
||||||
};
|
};
|
||||||
case 'week':
|
case 'week':
|
||||||
return {
|
return {
|
||||||
@ -97,6 +109,7 @@ export function parseDateRange(value, locale = 'en-US') {
|
|||||||
endDate: endOfWeek(now, { locale: dateLocale }),
|
endDate: endOfWeek(now, { locale: dateLocale }),
|
||||||
unit: 'day',
|
unit: 'day',
|
||||||
value,
|
value,
|
||||||
|
selectedUnit,
|
||||||
};
|
};
|
||||||
case 'month':
|
case 'month':
|
||||||
return {
|
return {
|
||||||
@ -104,6 +117,7 @@ export function parseDateRange(value, locale = 'en-US') {
|
|||||||
endDate: endOfMonth(now),
|
endDate: endOfMonth(now),
|
||||||
unit: 'day',
|
unit: 'day',
|
||||||
value,
|
value,
|
||||||
|
selectedUnit,
|
||||||
};
|
};
|
||||||
case 'year':
|
case 'year':
|
||||||
return {
|
return {
|
||||||
@ -111,6 +125,7 @@ export function parseDateRange(value, locale = 'en-US') {
|
|||||||
endDate: endOfYear(now),
|
endDate: endOfYear(now),
|
||||||
unit: 'month',
|
unit: 'month',
|
||||||
value,
|
value,
|
||||||
|
selectedUnit,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,6 +138,7 @@ export function parseDateRange(value, locale = 'en-US') {
|
|||||||
endDate: subDays(endOfDay(now), 1),
|
endDate: subDays(endOfDay(now), 1),
|
||||||
unit: 'hour',
|
unit: 'hour',
|
||||||
value,
|
value,
|
||||||
|
selectedUnit,
|
||||||
};
|
};
|
||||||
case 'week':
|
case 'week':
|
||||||
return {
|
return {
|
||||||
@ -130,6 +146,7 @@ export function parseDateRange(value, locale = 'en-US') {
|
|||||||
endDate: subDays(endOfWeek(now, { locale: dateLocale }), 1),
|
endDate: subDays(endOfWeek(now, { locale: dateLocale }), 1),
|
||||||
unit: 'day',
|
unit: 'day',
|
||||||
value,
|
value,
|
||||||
|
selectedUnit,
|
||||||
};
|
};
|
||||||
case 'month':
|
case 'month':
|
||||||
return {
|
return {
|
||||||
@ -137,6 +154,7 @@ export function parseDateRange(value, locale = 'en-US') {
|
|||||||
endDate: subMonths(endOfMonth(now), 1),
|
endDate: subMonths(endOfMonth(now), 1),
|
||||||
unit: 'day',
|
unit: 'day',
|
||||||
value,
|
value,
|
||||||
|
selectedUnit,
|
||||||
};
|
};
|
||||||
case 'year':
|
case 'year':
|
||||||
return {
|
return {
|
||||||
@ -144,6 +162,7 @@ export function parseDateRange(value, locale = 'en-US') {
|
|||||||
endDate: subYears(endOfYear(now), 1),
|
endDate: subYears(endOfYear(now), 1),
|
||||||
unit: 'month',
|
unit: 'month',
|
||||||
value,
|
value,
|
||||||
|
selectedUnit,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -155,6 +174,7 @@ export function parseDateRange(value, locale = 'en-US') {
|
|||||||
endDate: endOfDay(now),
|
endDate: endOfDay(now),
|
||||||
unit,
|
unit,
|
||||||
value,
|
value,
|
||||||
|
selectedUnit,
|
||||||
};
|
};
|
||||||
case 'hour':
|
case 'hour':
|
||||||
return {
|
return {
|
||||||
@ -162,6 +182,46 @@ export function parseDateRange(value, locale = 'en-US') {
|
|||||||
endDate: endOfHour(now),
|
endDate: endOfHour(now),
|
||||||
unit,
|
unit,
|
||||||
value,
|
value,
|
||||||
|
selectedUnit,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function incrementDateRange(value, increment) {
|
||||||
|
const { startDate, endDate, selectedUnit } = value;
|
||||||
|
|
||||||
|
const { num, unit } = selectedUnit;
|
||||||
|
|
||||||
|
const sub = num * increment;
|
||||||
|
|
||||||
|
switch (unit) {
|
||||||
|
case 'day':
|
||||||
|
return {
|
||||||
|
...value,
|
||||||
|
startDate: subDays(startDate, sub),
|
||||||
|
endDate: subDays(endDate, sub),
|
||||||
|
value: 'range',
|
||||||
|
};
|
||||||
|
case 'week':
|
||||||
|
return {
|
||||||
|
...value,
|
||||||
|
startDate: subWeeks(startDate, sub),
|
||||||
|
endDate: subWeeks(endDate, sub),
|
||||||
|
value: 'range',
|
||||||
|
};
|
||||||
|
case 'month':
|
||||||
|
return {
|
||||||
|
...value,
|
||||||
|
startDate: subMonths(startDate, sub),
|
||||||
|
endDate: subMonths(endDate, sub),
|
||||||
|
value: 'range',
|
||||||
|
};
|
||||||
|
case 'year':
|
||||||
|
return {
|
||||||
|
...value,
|
||||||
|
startDate: subYears(startDate, sub),
|
||||||
|
endDate: subYears(endDate, sub),
|
||||||
|
value: 'range',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,7 +297,7 @@ export function getDateLength(startDate, endDate, unit) {
|
|||||||
return diff(endDate, startDate) + 1;
|
return diff(endDate, startDate) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const customFormats = {
|
export const CUSTOM_FORMATS = {
|
||||||
'en-US': {
|
'en-US': {
|
||||||
p: 'ha',
|
p: 'ha',
|
||||||
pp: 'h:mm:ss',
|
pp: 'h:mm:ss',
|
||||||
@ -252,7 +312,7 @@ export const customFormats = {
|
|||||||
export function formatDate(date, str, locale = 'en-US') {
|
export function formatDate(date, str, locale = 'en-US') {
|
||||||
return format(
|
return format(
|
||||||
typeof date === 'string' ? new Date(date) : date,
|
typeof date === 'string' ? new Date(date) : date,
|
||||||
customFormats?.[locale]?.[str] || str,
|
CUSTOM_FORMATS?.[locale]?.[str] || str,
|
||||||
{
|
{
|
||||||
locale: getDateLocale(locale),
|
locale: getDateLocale(locale),
|
||||||
},
|
},
|
||||||
|
@ -12,9 +12,12 @@ import {
|
|||||||
WEBSITE_FILTER_TYPES,
|
WEBSITE_FILTER_TYPES,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
import * as yup from 'yup';
|
import * as yup from 'yup';
|
||||||
|
import { TIME_UNIT } from './date';
|
||||||
|
|
||||||
type ObjectValues<T> = T[keyof T];
|
type ObjectValues<T> = T[keyof T];
|
||||||
|
|
||||||
|
export type TimeUnit = ObjectValues<typeof TIME_UNIT>;
|
||||||
|
|
||||||
export type CollectionType = ObjectValues<typeof COLLECTION_TYPE>;
|
export type CollectionType = ObjectValues<typeof COLLECTION_TYPE>;
|
||||||
export type Role = ObjectValues<typeof ROLES>;
|
export type Role = ObjectValues<typeof ROLES>;
|
||||||
export type EventType = ObjectValues<typeof EVENT_TYPE>;
|
export type EventType = ObjectValues<typeof EVENT_TYPE>;
|
||||||
@ -181,6 +184,8 @@ export interface DateRange {
|
|||||||
startDate: Date;
|
startDate: Date;
|
||||||
endDate: Date;
|
endDate: Date;
|
||||||
value: string;
|
value: string;
|
||||||
|
unit?: TimeUnit;
|
||||||
|
selectedUnit?: TimeUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface QueryFilters {
|
export interface QueryFilters {
|
||||||
|
@ -20,7 +20,8 @@
|
|||||||
"baseUrl": "./src",
|
"baseUrl": "./src",
|
||||||
"strictNullChecks": false,
|
"strictNullChecks": false,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "preserve"
|
"jsx": "preserve",
|
||||||
|
"incremental": true
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
|
Loading…
Reference in New Issue
Block a user