Updated reports.

This commit is contained in:
Mike Cao 2025-06-08 22:21:28 -07:00
parent 28e872f219
commit 01bd21c5b4
75 changed files with 1373 additions and 980 deletions

View file

@ -1,12 +0,0 @@
.container {
color: var(--base500);
font-size: var(--font-size-md);
position: relative;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
width: 100%;
height: 100%;
min-height: 70px;
}

View file

@ -1,18 +1,16 @@
import classNames from 'classnames';
import { Row } from '@umami/react-zen';
import { useMessages } from '@/components/hooks';
import styles from './Empty.module.css';
export interface EmptyProps {
message?: string;
className?: string;
}
export function Empty({ message, className }: EmptyProps) {
export function Empty({ message }: EmptyProps) {
const { formatMessage, messages } = useMessages();
return (
<div className={classNames(styles.container, className)}>
<Row color="muted" alignItems="center" justifyContent="center" width="100%" height="100%">
{message || formatMessage(messages.noDataAvailable)}
</div>
</Row>
);
}

View file

@ -1,19 +1,28 @@
import { ReactNode } from 'react';
import { Icon, Text, Column } from '@umami/react-zen';
import { Logo } from '@/components/icons';
export interface EmptyPlaceholderProps {
message?: string;
title?: string;
description?: string;
icon?: ReactNode;
children?: ReactNode;
}
export function EmptyPlaceholder({ message, icon, children }: EmptyPlaceholderProps) {
export function EmptyPlaceholder({ title, description, icon, children }: EmptyPlaceholderProps) {
return (
<Column alignItems="center" justifyContent="center" gap="5" height="100%" width="100%">
<Icon size="xl">{icon || <Logo />}</Icon>
<Text>{message}</Text>
<div>{children}</div>
{icon && (
<Icon color="10" size="xl">
{icon}
</Icon>
)}
{title && (
<Text weight="bold" size="4">
{title}
</Text>
)}
{description && <Text color="muted">{description}</Text>}
{children}
</Column>
);
}

View file

@ -1,7 +1,8 @@
import { useState, Key } from 'react';
import { Grid, Row, Column, Label, List, ListItem, Button, Heading, Text } from '@umami/react-zen';
import { Grid, Row, Column, Label, List, ListItem, Button, Heading } from '@umami/react-zen';
import { useFilters, useMessages } from '@/components/hooks';
import { FilterRecord } from '@/components/common/FilterRecord';
import { Empty } from '@/components/common/Empty';
export interface FilterEditFormProps {
websiteId?: string;
@ -11,7 +12,7 @@ export interface FilterEditFormProps {
}
export function FilterEditForm({ data = [], onChange, onClose }: FilterEditFormProps) {
const { formatMessage, labels } = useMessages();
const { formatMessage, labels, messages } = useMessages();
const [filters, setFilters] = useState(data);
const { fields } = useFilters();
@ -72,7 +73,7 @@ export function FilterEditForm({ data = [], onChange, onClose }: FilterEditFormP
/>
);
})}
{!filters.length && <Text align="center">{formatMessage(labels.none)}</Text>}
{!filters.length && <Empty message={formatMessage(messages.nothingSelected)} />}
</Column>
<Row alignItems="center" justifyContent="flex-end" gridColumn="span 2" gap>
<Button onPress={onClose}>{formatMessage(labels.cancel)}</Button>

View file

@ -1,16 +0,0 @@
.panel {
display: flex;
flex-direction: column;
position: relative;
flex: 1;
height: 100%;
}
.loading {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}

View file

@ -1,9 +1,7 @@
import { ReactNode } from 'react';
import classNames from 'classnames';
import { Spinner, Dots } from '@umami/react-zen';
import { Spinner, Dots, Column, type ColumnProps } from '@umami/react-zen';
import { ErrorMessage } from '@/components/common/ErrorMessage';
import { Empty } from '@/components/common/Empty';
import styles from './LoadingPanel.module.css';
export function LoadingPanel({
error,
@ -12,25 +10,23 @@ export function LoadingPanel({
isLoading,
loadingIcon = 'dots',
renderEmpty = () => <Empty />,
className,
children,
...props
}: {
data?: any;
error?: Error;
isEmpty?: boolean;
isFetched?: boolean;
isLoading?: boolean;
loadingIcon?: 'dots' | 'spinner';
renderEmpty?: () => ReactNode;
className?: string;
children: ReactNode;
}) {
} & ColumnProps) {
return (
<div className={classNames(styles.panel, className)}>
<Column {...props}>
{isLoading && !isFetched && (loadingIcon === 'dots' ? <Dots /> : <Spinner />)}
{error && <ErrorMessage />}
{!error && !isLoading && isEmpty && renderEmpty()}
{!error && !isLoading && !isEmpty && children}
</div>
</Column>
);
}

View file

@ -4,7 +4,7 @@ import { AlertBanner, Loading, Column } from '@umami/react-zen';
import { useMessages } from '@/components/hooks';
export function PageBody({
maxWidth = '1600px',
maxWidth = '1320px',
error,
isLoading,
children,

View file

@ -5,11 +5,13 @@ export function PageHeader({
title,
description,
icon,
showBorder = true,
children,
}: {
title: string;
description?: string;
icon?: ReactNode;
showBorder?: boolean;
allowEdit?: boolean;
className?: string;
children?: ReactNode;
@ -19,7 +21,7 @@ export function PageHeader({
justifyContent="space-between"
alignItems="center"
paddingY="6"
border="bottom"
border={showBorder ? 'bottom' : undefined}
width="100%"
>
<Row alignItems="center" gap="3">