More conversions.

This commit is contained in:
Mike Cao 2025-03-07 12:21:20 -08:00
parent 5999bf6256
commit b4be6cb221
14 changed files with 240 additions and 262 deletions

View file

@ -1,5 +1,5 @@
import { useState } from 'react'; import { useState } from 'react';
import { Button, Dropdown, Item, Flexbox } from '@umami/react-zen'; import { Button, Select, ListItem, Flexbox } from '@umami/react-zen';
import { useLocale, useMessages } from '@/components/hooks'; import { useLocale, useMessages } from '@/components/hooks';
import { DEFAULT_LOCALE } from '@/lib/constants'; import { DEFAULT_LOCALE } from '@/lib/constants';
import { languages } from '@/lib/lang'; import { languages } from '@/lib/lang';
@ -20,22 +20,19 @@ export function LanguageSetting() {
const handleReset = () => saveLocale(DEFAULT_LOCALE); const handleReset = () => saveLocale(DEFAULT_LOCALE);
const renderValue = (value: string | number) => languages?.[value]?.label;
return ( return (
<Flexbox gap={10}> <Flexbox gap={10}>
<Dropdown <Select
items={options} items={options}
value={locale} value={locale}
renderValue={renderValue}
onChange={val => saveLocale(val as string)} onChange={val => saveLocale(val as string)}
allowSearch={true} allowSearch={true}
onSearch={setSearch} onSearch={setSearch}
menuProps={{ className: styles.menu }} menuProps={{ className: styles.menu }}
> >
{item => <Item key={item}>{languages[item].label}</Item>} {item => <ListItem key={item}>{languages[item].label}</ListItem>}
</Dropdown> </Select>
<Button onClick={handleReset}>{formatMessage(labels.reset)}</Button> <Button onPress={handleReset}>{formatMessage(labels.reset)}</Button>
</Flexbox> </Flexbox>
); );
} }

View file

@ -1,5 +1,5 @@
import { useState } from 'react'; import { useState } from 'react';
import { Dropdown, Item, Button, Flexbox } from '@umami/react-zen'; import { Row, Select, ListItem, Button } from '@umami/react-zen';
import { useTimezone, useMessages } from '@/components/hooks'; import { useTimezone, useMessages } from '@/components/hooks';
import { getTimezone } from '@/lib/date'; import { getTimezone } from '@/lib/date';
import styles from './TimezoneSetting.module.css'; import styles from './TimezoneSetting.module.css';
@ -17,19 +17,22 @@ export function TimezoneSetting() {
const handleReset = () => saveTimezone(getTimezone()); const handleReset = () => saveTimezone(getTimezone());
return ( return (
<Flexbox gap={10}> <Row gap="3">
<Dropdown <Select
className={styles.dropdown} className={styles.dropdown}
items={options} items={options}
value={timezone} value={timezone}
onChange={(value: any) => saveTimezone(value)} onChange={(value: any) => saveTimezone(value)}
menuProps={{ className: styles.menu }}
allowSearch={true} allowSearch={true}
onSearch={setSearch} onSearch={setSearch}
> >
{item => <Item key={item}>{item}</Item>} {item => (
</Dropdown> <ListItem key={item} id={item}>
<Button onClick={handleReset}>{formatMessage(labels.reset)}</Button> {item}
</Flexbox> </ListItem>
)}
</Select>
<Button onPress={handleReset}>{formatMessage(labels.reset)}</Button>
</Row>
); );
} }

View file

@ -1,7 +1,7 @@
import { useFields, useMessages } from '@/components/hooks'; import { useFields, useMessages } from '@/components/hooks';
import { Icons } from '@/components/icons'; import { Icons } from '@/components/icons';
import { useContext } from 'react'; import { useContext } from 'react';
import { Button, FormRow, Icon, Popup, PopupTrigger } from '@umami/react-zen'; import { Button, Row, Label, Icon, Popover, MenuTrigger } from '@umami/react-zen';
import { FieldSelectForm } from '../[reportId]/FieldSelectForm'; import { FieldSelectForm } from '../[reportId]/FieldSelectForm';
import { ParameterList } from '../[reportId]/ParameterList'; import { ParameterList } from '../[reportId]/ParameterList';
import { PopupForm } from '../[reportId]/PopupForm'; import { PopupForm } from '../[reportId]/PopupForm';
@ -26,27 +26,26 @@ export function FieldParameters() {
const AddButton = () => { const AddButton = () => {
return ( return (
<PopupTrigger> <MenuTrigger>
<Button size="sm"> <Button size="sm">
<Icon> <Icon>
<Icons.Plus /> <Icons.Plus />
</Icon> </Icon>
</Button> </Button>
<Popup position="bottom" alignment="start"> <Popover placement="start">
<PopupForm> <FieldSelectForm
<FieldSelectForm fields={fieldOptions.filter(({ name }) => !fields.find(f => f.name === name))}
fields={fieldOptions.filter(({ name }) => !fields.find(f => f.name === name))} onSelect={handleAdd}
onSelect={handleAdd} showType={false}
showType={false} />
/> </Popover>
</PopupForm> </MenuTrigger>
</Popup>
</PopupTrigger>
); );
}; };
return ( return (
<FormRow label={formatMessage(labels.fields)} action={<AddButton />}> <Row>
<Label>{formatMessage(labels.fields)}</Label>
<ParameterList> <ParameterList>
{fields.map(({ name }) => { {fields.map(({ name }) => {
return ( return (
@ -56,6 +55,7 @@ export function FieldParameters() {
); );
})} })}
</ParameterList> </ParameterList>
</FormRow> <AddButton />
</Row>
); );
} }

View file

@ -1,7 +1,7 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { useMessages, useFormat, useFilters, useFields } from '@/components/hooks'; import { useMessages, useFormat, useFilters, useFields } from '@/components/hooks';
import { Icons } from '@/components/icons'; import { Icons } from '@/components/icons';
import { Button, FormRow, Icon, Popup, PopupTrigger } from '@umami/react-zen'; import { Button, Text, Row, Label, Icon, Popover, MenuTrigger } from '@umami/react-zen';
import { FilterSelectForm } from '../[reportId]/FilterSelectForm'; import { FilterSelectForm } from '../[reportId]/FilterSelectForm';
import { ParameterList } from '../[reportId]/ParameterList'; import { ParameterList } from '../[reportId]/ParameterList';
import { PopupForm } from '../[reportId]/PopupForm'; import { PopupForm } from '../[reportId]/PopupForm';
@ -44,13 +44,13 @@ export function FilterParameters() {
const AddButton = () => { const AddButton = () => {
return ( return (
<PopupTrigger> <MenuTrigger>
<Button size="sm"> <Button size="sm">
<Icon> <Icon>
<Icons.Plus /> <Icons.Plus />
</Icon> </Icon>
</Button> </Button>
<Popup position="bottom" alignment="start"> <Popover placement="bottom start">
<PopupForm> <PopupForm>
<FilterSelectForm <FilterSelectForm
websiteId={websiteId} websiteId={websiteId}
@ -60,13 +60,17 @@ export function FilterParameters() {
onChange={handleAdd} onChange={handleAdd}
/> />
</PopupForm> </PopupForm>
</Popup> </Popover>
</PopupTrigger> </MenuTrigger>
); );
}; };
return ( return (
<FormRow label={formatMessage(labels.filters)} action={<AddButton />}> <>
<Row justifyContent="space-between">
<Label>{formatMessage(labels.filters)}</Label>
<AddButton />
</Row>
<ParameterList> <ParameterList>
{filters.map( {filters.map(
({ name, operator, value }: { name: string; operator: string; value: string }) => { ({ name, operator, value }: { name: string; operator: string; value: string }) => {
@ -90,7 +94,7 @@ export function FilterParameters() {
}, },
)} )}
</ParameterList> </ParameterList>
</FormRow> </>
); );
} }
@ -108,29 +112,27 @@ const FilterParameter = ({
const { operatorLabels } = useFilters(); const { operatorLabels } = useFilters();
return ( return (
<PopupTrigger> <MenuTrigger>
<div className={styles.item}> <div className={styles.item}>
<div className={styles.label}>{label}</div> <div className={styles.label}>{label}</div>
<div className={styles.op}>{operatorLabels[operator]}</div> <div className={styles.op}>{operatorLabels[operator]}</div>
<div className={styles.value}>{value}</div> <div className={styles.value}>{value}</div>
</div> </div>
<Popup className={styles.edit} alignment="start"> <Popover className={styles.edit} placement="right top">
{(close: any) => ( {(close: any) => (
<PopupForm> <FieldFilterEditForm
<FieldFilterEditForm websiteId={websiteId}
websiteId={websiteId} name={name}
name={name} label={label}
label={label} type={type}
type={type} startDate={startDate}
startDate={startDate} endDate={endDate}
endDate={endDate} operator={operator}
operator={operator} defaultValue={value}
defaultValue={value} onChange={onChange.bind(null, close)}
onChange={onChange.bind(null, close)} />
/>
</PopupForm>
)} )}
</Popup> </Popover>
</PopupTrigger> </MenuTrigger>
); );
}; };

View file

@ -1,8 +1,8 @@
import { useContext, useState } from 'react'; import { useContext, useState } from 'react';
import { ReportContext } from './Report';
import styles from './ReportMenu.module.css';
import { Icon, Icons } from '@umami/react-zen'; import { Icon, Icons } from '@umami/react-zen';
import classNames from 'classnames'; import classNames from 'classnames';
import { ReportContext } from './Report';
import styles from './ReportMenu.module.css';
export function ReportMenu({ children }) { export function ReportMenu({ children }) {
const [collapsed, setCollapsed] = useState(false); const [collapsed, setCollapsed] = useState(false);
@ -16,7 +16,7 @@ export function ReportMenu({ children }) {
<div className={classNames(styles.menu, collapsed && styles.collapsed)}> <div className={classNames(styles.menu, collapsed && styles.collapsed)}>
<div className={styles.button} onClick={() => setCollapsed(!collapsed)}> <div className={styles.button} onClick={() => setCollapsed(!collapsed)}>
<Icon rotate={collapsed ? -90 : 90}> <Icon rotate={collapsed ? -90 : 90}>
<Icons.ChevronDown /> <Icons.Chevron />
</Icon> </Icon>
</div> </div>
{!collapsed && children} {!collapsed && children}

View file

@ -1,6 +1,15 @@
import { useState } from 'react'; import { useState } from 'react';
import { useMessages } from '@/components/hooks'; import { useMessages } from '@/components/hooks';
import { Button, FormRow, TextField, Flexbox, Dropdown, Item } from '@umami/react-zen'; import {
Button,
Column,
Row,
TextField,
Label,
Select,
ListItem,
FormButtons,
} from '@umami/react-zen';
import styles from './FunnelStepAddForm.module.css'; import styles from './FunnelStepAddForm.module.css';
export interface FunnelStepAddFormProps { export interface FunnelStepAddFormProps {
@ -39,40 +48,34 @@ export function FunnelStepAddForm({
} }
}; };
const renderTypeValue = (value: any) => {
return items.find(item => item.value === value)?.label;
};
return ( return (
<Flexbox direction="column" gap={10}> <Column gap="3">
<FormRow label={formatMessage(defaultValue ? labels.update : labels.add)}> <Label>{formatMessage(defaultValue ? labels.update : labels.add)}</Label>
<Flexbox gap={10}> <Row gap="3">
<Dropdown <Select
className={styles.dropdown} className={styles.dropdown}
items={items} items={items}
value={type} value={type}
renderValue={renderTypeValue} onChange={(value: any) => setType(value)}
onChange={(value: any) => setType(value)} >
> {({ value, label }: any) => {
{({ value, label }) => { return <ListItem key={value}>{label}</ListItem>;
return <Item key={value}>{label}</Item>; }}
}} </Select>
</Dropdown> <TextField
<TextField className={styles.input}
className={styles.input} value={value}
value={value} onChange={handleChange}
onChange={handleChange} autoFocus={true}
autoFocus={true} autoComplete="off"
autoComplete="off" onKeyDown={handleKeyDown}
onKeyDown={handleKeyDown} />
/> </Row>
</Flexbox> <FormButtons>
</FormRow> <Button variant="primary" onPress={handleSave} isDisabled={isDisabled}>
<FormRow>
<Button variant="primary" onClick={handleSave} disabled={isDisabled}>
{formatMessage(defaultValue ? labels.update : labels.add)} {formatMessage(defaultValue ? labels.update : labels.add)}
</Button> </Button>
</FormRow> </FormButtons>
</Flexbox> </Column>
); );
} }

View file

@ -1,6 +1,15 @@
import { useMessages } from '@/components/hooks'; import { useMessages } from '@/components/hooks';
import { useState } from 'react'; import { useState } from 'react';
import { Button, Dropdown, Flexbox, FormRow, Item, TextField } from '@umami/react-zen'; import {
Button,
Row,
Column,
Select,
Label,
ListItem,
TextField,
FormButtons,
} from '@umami/react-zen';
import styles from './GoalsAddForm.module.css'; import styles from './GoalsAddForm.module.css';
export function GoalsAddForm({ export function GoalsAddForm({
@ -71,44 +80,43 @@ export function GoalsAddForm({
}; };
return ( return (
<Flexbox direction="column" gap={10}> <Column gap="3">
<FormRow label={formatMessage(defaultValue ? labels.update : labels.add)}> <Label>{formatMessage(defaultValue ? labels.update : labels.add)}</Label>
<Flexbox gap={10}> <Row gap="3">
<Dropdown <Select
className={styles.dropdown} className={styles.dropdown}
items={items} items={items}
value={type} value={type}
renderValue={renderTypeValue} renderValue={renderTypeValue}
onChange={(value: any) => setType(value)} onChange={(value: any) => setType(value)}
> >
{({ value, label }) => { {({ value, label }: any) => {
return <Item key={value}>{label}</Item>; return <ListItem key={value}>{label}</ListItem>;
}} }}
</Dropdown> </Select>
<TextField <TextField
className={styles.input} className={styles.input}
value={value} value={value}
onChange={e => handleChange(e, setValue)} onChange={e => handleChange(e, setValue)}
autoFocus={true} autoFocus={true}
autoComplete="off" autoComplete="off"
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
/> />
</Flexbox> </Row>
</FormRow>
{type === 'event-data' && ( {type === 'event-data' && (
<FormRow label={formatMessage(labels.property)}> <Column>
<Flexbox gap={10}> <Label>label={formatMessage(labels.property)}</Label>
<Dropdown <Row gap="3">
<Select
className={styles.dropdown} className={styles.dropdown}
items={operators} items={operators}
value={operator} value={operator}
renderValue={renderoperatorValue}
onChange={(value: any) => setOperator(value)} onChange={(value: any) => setOperator(value)}
> >
{({ value, label }) => { {({ value, label }: any) => {
return <Item key={value}>{label}</Item>; return <ListItem key={value}>{label}</ListItem>;
}} }}
</Dropdown> </Select>
<TextField <TextField
className={styles.input} className={styles.input}
value={property} value={property}
@ -117,11 +125,12 @@ export function GoalsAddForm({
autoComplete="off" autoComplete="off"
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
/> />
</Flexbox> </Row>
</FormRow> </Column>
)} )}
<FormRow label={formatMessage(labels.goal)}> <Column>
<Flexbox gap={10}> <Label>{formatMessage(labels.goal)}</Label>
<Row gap="3">
<TextField <TextField
className={styles.input} className={styles.input}
value={goal?.toString()} value={goal?.toString()}
@ -129,13 +138,13 @@ export function GoalsAddForm({
autoComplete="off" autoComplete="off"
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
/> />
</Flexbox> </Row>
</FormRow> </Column>
<FormRow> <FormButtons>
<Button variant="primary" onClick={handleSave} disabled={isDisabled}> <Button variant="primary" onPress={handleSave} isDisabled={isDisabled}>
{formatMessage(defaultValue ? labels.update : labels.add)} {formatMessage(defaultValue ? labels.update : labels.add)}
</Button> </Button>
</FormRow> </FormButtons>
</Flexbox> </Column>
); );
} }

View file

@ -4,18 +4,17 @@ import { formatNumber } from '@/lib/format';
import { useContext } from 'react'; import { useContext } from 'react';
import { import {
Button, Button,
Flexbox,
Form, Form,
FormButtons, FormButtons,
FormRow, FormField,
Icon, Icon,
Popup, Popover,
PopupTrigger, MenuTrigger,
SubmitButton, FormSubmitButton,
Column,
} from '@umami/react-zen'; } from '@umami/react-zen';
import { BaseParameters } from '../[reportId]/BaseParameters'; import { BaseParameters } from '../[reportId]/BaseParameters';
import { ParameterList } from '../[reportId]/ParameterList'; import { ParameterList } from '../[reportId]/ParameterList';
import { PopupForm } from '../[reportId]/PopupForm';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
import { GoalsAddForm } from './GoalsAddForm'; import { GoalsAddForm } from './GoalsAddForm';
import styles from './GoalsParameters.module.css'; import styles from './GoalsParameters.module.css';
@ -60,25 +59,24 @@ export function GoalsParameters() {
const AddGoalsButton = () => { const AddGoalsButton = () => {
return ( return (
<PopupTrigger> <MenuTrigger>
<Button> <Button>
<Icon> <Icon>
<Icons.Plus /> <Icons.Plus />
</Icon> </Icon>
</Button> </Button>
<Popup alignment="start"> <Popover placement="start">
<PopupForm> <GoalsAddForm onChange={handleAddGoals} />
<GoalsAddForm onChange={handleAddGoals} /> </Popover>
</PopupForm> </MenuTrigger>
</Popup>
</PopupTrigger>
); );
}; };
return ( return (
<Form values={parameters} onSubmit={handleSubmit} preventSubmit={true}> <Form values={parameters} onSubmit={handleSubmit} preventSubmit={true}>
<BaseParameters allowWebsiteSelect={!id} /> <BaseParameters allowWebsiteSelect={!id} />
<FormRow label={formatMessage(labels.goals)} action={<AddGoalsButton />}> <AddGoalsButton />
<FormField label={formatMessage(labels.goals)}>
<ParameterList> <ParameterList>
{goals.map( {goals.map(
( (
@ -92,12 +90,12 @@ export function GoalsParameters() {
index: number, index: number,
) => { ) => {
return ( return (
<PopupTrigger key={index}> <MenuTrigger key={index}>
<ParameterList.Item <ParameterList.Item
icon={goal.type === 'url' ? <Icons.Eye /> : <Icons.Bolt />} icon={goal.type === 'url' ? <Icons.Eye /> : <Icons.Bolt />}
onRemove={() => handleRemoveGoals(index)} onRemove={() => handleRemoveGoals(index)}
> >
<Flexbox direction="column" gap={5}> <Column>
<div className={styles.value}>{goal.value}</div> <div className={styles.value}>{goal.value}</div>
{goal.type === 'event-data' && ( {goal.type === 'event-data' && (
<div className={styles.eventData}> <div className={styles.eventData}>
@ -107,32 +105,28 @@ export function GoalsParameters() {
<div className={styles.goal}> <div className={styles.goal}>
{formatMessage(labels.goal)}: {formatNumber(goal.goal)} {formatMessage(labels.goal)}: {formatNumber(goal.goal)}
</div> </div>
</Flexbox> </Column>
</ParameterList.Item> </ParameterList.Item>
<Popup alignment="start"> <Popover placement="start">
{(close: () => void) => ( <GoalsAddForm
<PopupForm> type={goal.type}
<GoalsAddForm value={goal.value}
type={goal.type} goal={goal.goal}
value={goal.value} operator={goal.operator}
goal={goal.goal} property={goal.property}
operator={goal.operator} onChange={handleUpdateGoals.bind(null, () => {}, index)}
property={goal.property} />
onChange={handleUpdateGoals.bind(null, close, index)} </Popover>
/> </MenuTrigger>
</PopupForm>
)}
</Popup>
</PopupTrigger>
); );
}, },
)} )}
</ParameterList> </ParameterList>
</FormRow> </FormField>
<FormButtons> <FormButtons>
<SubmitButton variant="primary" disabled={queryDisabled} isLoading={isRunning}> <FormSubmitButton variant="primary" isDisabled={queryDisabled} isLoading={isRunning}>
{formatMessage(labels.runQuery)} {formatMessage(labels.runQuery)}
</SubmitButton> </FormSubmitButton>
</FormButtons> </FormButtons>
</Form> </Form>
); );

View file

@ -1,6 +1,6 @@
import { useMessages } from '@/components/hooks'; import { useMessages } from '@/components/hooks';
import { useContext } from 'react'; import { useContext } from 'react';
import { Form, FormButtons, SubmitButton } from '@umami/react-zen'; import { Form, FormButtons, FormSubmitButton } from '@umami/react-zen';
import { BaseParameters } from '../[reportId]/BaseParameters'; import { BaseParameters } from '../[reportId]/BaseParameters';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
import { FieldParameters } from '../[reportId]/FieldParameters'; import { FieldParameters } from '../[reportId]/FieldParameters';
@ -25,9 +25,9 @@ export function InsightsParameters() {
{parametersSelected && <FieldParameters />} {parametersSelected && <FieldParameters />}
{parametersSelected && <FilterParameters />} {parametersSelected && <FilterParameters />}
<FormButtons> <FormButtons>
<SubmitButton variant="primary" disabled={!queryEnabled} isLoading={isRunning}> <FormSubmitButton variant="primary" isDisabled={!queryEnabled} isLoading={isRunning}>
{formatMessage(labels.runQuery)} {formatMessage(labels.runQuery)}
</SubmitButton> </FormSubmitButton>
</FormButtons> </FormButtons>
</Form> </Form>
); );

View file

@ -1,5 +1,5 @@
import { useContext, useEffect, useState } from 'react'; import { useContext, useEffect, useState } from 'react';
import { GridTable, GridColumn } from '@umami/react-zen'; import { DataTable, DataColumn } from '@umami/react-zen';
import { useFormat, useMessages } from '@/components/hooks'; import { useFormat, useMessages } from '@/components/hooks';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
import { EmptyPlaceholder } from '@/components/common/EmptyPlaceholder'; import { EmptyPlaceholder } from '@/components/common/EmptyPlaceholder';
@ -24,50 +24,35 @@ export function InsightsTable() {
} }
return ( return (
<GridTable data={report?.data || []}> <DataTable data={report?.data || []}>
{fields.map(({ name, label }) => { {fields.map(({ name, label }) => {
return ( return (
<GridColumn key={name} name={name} label={label}> <DataColumn key={name} id={name} label={label}>
{row => formatValue(row[name], name)} {row => formatValue(row[name], name)}
</GridColumn> </DataColumn>
); );
})} })}
<GridColumn name="views" label={formatMessage(labels.views)} width="100px" alignment="end"> <DataColumn id="views" label={formatMessage(labels.views)} align="end">
{row => row?.views?.toLocaleString()} {(row: any) => row?.views?.toLocaleString()}
</GridColumn> </DataColumn>
<GridColumn name="visits" label={formatMessage(labels.visits)} width="100px" alignment="end"> <DataColumn id="visits" label={formatMessage(labels.visits)} align="end">
{row => row?.visits?.toLocaleString()} {(row: any) => row?.visits?.toLocaleString()}
</GridColumn> </DataColumn>
<GridColumn <DataColumn id="visitors" label={formatMessage(labels.visitors)} align="end">
name="visitors" {(row: any) => row?.visitors?.toLocaleString()}
label={formatMessage(labels.visitors)} </DataColumn>
width="100px" <DataColumn id="bounceRate" label={formatMessage(labels.bounceRate)} align="end">
alignment="end" {(row: any) => {
>
{row => row?.visitors?.toLocaleString()}
</GridColumn>
<GridColumn
name="bounceRate"
label={formatMessage(labels.bounceRate)}
width="100px"
alignment="end"
>
{row => {
const n = (Math.min(row?.visits, row?.bounces) / row?.visits) * 100; const n = (Math.min(row?.visits, row?.bounces) / row?.visits) * 100;
return Math.round(+n) + '%'; return Math.round(+n) + '%';
}} }}
</GridColumn> </DataColumn>
<GridColumn <DataColumn id="visitDuration" label={formatMessage(labels.visitDuration)} align="end">
name="visitDuration" {(row: any) => {
label={formatMessage(labels.visitDuration)}
width="100px"
alignment="end"
>
{row => {
const n = row?.totaltime / row?.visits; const n = row?.totaltime / row?.visits;
return `${+n < 0 ? '-' : ''}${formatShortTime(Math.abs(~~n), ['m', 's'], ' ')}`; return `${+n < 0 ? '-' : ''}${formatShortTime(Math.abs(~~n), ['m', 's'], ' ')}`;
}} }}
</GridColumn> </DataColumn>
</GridTable> </DataTable>
); );
} }

View file

@ -1,13 +1,12 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { useMessages } from '@/components/hooks'; import { useMessages } from '@/components/hooks';
import { import {
Dropdown, Select,
Form, Form,
FormButtons, FormButtons,
FormInput, FormField,
FormRow, ListItem,
Item, FormSubmitButton,
SubmitButton,
TextField, TextField,
} from '@umami/react-zen'; } from '@umami/react-zen';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
@ -33,28 +32,29 @@ export function JourneyParameters() {
return ( return (
<Form values={parameters} onSubmit={handleSubmit} preventSubmit={true}> <Form values={parameters} onSubmit={handleSubmit} preventSubmit={true}>
<BaseParameters showDateSelect={true} allowWebsiteSelect={!id} /> <BaseParameters showDateSelect={true} allowWebsiteSelect={!id} />
<FormRow label={formatMessage(labels.steps)}> <FormField
<FormInput label={formatMessage(labels.steps)}
name="steps" name="steps"
rules={{ required: formatMessage(labels.required), pattern: /[0-9]+/, min: 3, max: 7 }} rules={{ required: formatMessage(labels.required), pattern: /[0-9]+/, min: 3, max: 7 }}
> >
<Dropdown items={[3, 4, 5, 6, 7]}>{item => <Item key={item}>{item}</Item>}</Dropdown> <Select items={[3, 4, 5, 6, 7]}>
</FormInput> {(item: any) => (
</FormRow> <ListItem key={item.toString()} id={item.toString()}>
<FormRow label={formatMessage(labels.startStep)}> {item}
<FormInput name="startStep"> </ListItem>
<TextField autoComplete="off" /> )}
</FormInput> </Select>
</FormRow> </FormField>
<FormRow label={formatMessage(labels.endStep)}> <FormField label={formatMessage(labels.startStep)} name="startStep">
<FormInput name="endStep"> <TextField autoComplete="off" />
<TextField autoComplete="off" /> </FormField>
</FormInput> <FormField label={formatMessage(labels.endStep)} name="endStep">
</FormRow> <TextField autoComplete="off" />
</FormField>
<FormButtons> <FormButtons>
<SubmitButton variant="primary" disabled={queryDisabled} isLoading={isRunning}> <FormSubmitButton variant="primary" isDisabled={queryDisabled} isLoading={isRunning}>
{formatMessage(labels.runQuery)} {formatMessage(labels.runQuery)}
</SubmitButton> </FormSubmitButton>
</FormButtons> </FormButtons>
</Form> </Form>
); );

View file

@ -11,7 +11,6 @@ export function RetentionParameters() {
const { id, parameters } = report || {}; const { id, parameters } = report || {};
const { websiteId, dateRange } = parameters || {}; const { websiteId, dateRange } = parameters || {};
const { startDate } = dateRange || {};
const queryDisabled = !websiteId || !dateRange; const queryDisabled = !websiteId || !dateRange;
const handleSubmit = (data: any, e: any) => { const handleSubmit = (data: any, e: any) => {

View file

@ -1,15 +1,7 @@
import { useMessages } from '@/components/hooks'; import { useMessages } from '@/components/hooks';
import { useRevenueValues } from '@/components/hooks/queries/useRevenueValues'; import { useRevenueValues } from '@/components/hooks/queries/useRevenueValues';
import { useContext } from 'react'; import { useContext } from 'react';
import { import { Select, Form, FormButtons, FormField, ListItem, FormSubmitButton } from '@umami/react-zen';
Dropdown,
Form,
FormButtons,
FormInput,
FormRow,
Item,
SubmitButton,
} from '@umami/react-zen';
import { BaseParameters } from '../[reportId]/BaseParameters'; import { BaseParameters } from '../[reportId]/BaseParameters';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
@ -35,17 +27,20 @@ export function RevenueParameters() {
return ( return (
<Form values={parameters} onSubmit={handleSubmit} preventSubmit={true}> <Form values={parameters} onSubmit={handleSubmit} preventSubmit={true}>
<BaseParameters showDateSelect={true} allowWebsiteSelect={!id} /> <BaseParameters showDateSelect={true} allowWebsiteSelect={!id} />
<FormRow label={formatMessage(labels.currency)}>
<FormInput name="currency" rules={{ required: formatMessage(labels.required) }}> <FormField
<Dropdown items={values.map(item => item.currency)}> label={formatMessage(labels.currency)}
{item => <Item key={item}>{item}</Item>} name="currency"
</Dropdown> rules={{ required: formatMessage(labels.required) }}
</FormInput> >
</FormRow> <Select items={values.map(item => item.currency)}>
{item => <ListItem key={item}>{item}</ListItem>}
</Select>
</FormField>
<FormButtons> <FormButtons>
<SubmitButton variant="primary" disabled={!queryEnabled} isLoading={isRunning}> <FormSubmitButton variant="primary" isDisabled={!queryEnabled} isLoading={isRunning}>
{formatMessage(labels.runQuery)} {formatMessage(labels.runQuery)}
</SubmitButton> </FormSubmitButton>
</FormButtons> </FormButtons>
</Form> </Form>
); );

View file

@ -1,8 +1,7 @@
import { useState, Key } from 'react'; import { useState, Key } from 'react';
import { Dropdown, Item } from '@umami/react-zen'; import { Select, ListItem } from '@umami/react-zen';
import { useWebsite, useWebsites, useMessages } from '@/components/hooks'; import { useWebsite, useWebsites, useMessages } from '@/components/hooks';
import { Empty } from '@/components/common/Empty'; import { Empty } from '@/components/common/Empty';
import styles from './WebsiteSelect.module.css';
export function WebsiteSelect({ export function WebsiteSelect({
websiteId, websiteId,
@ -21,10 +20,6 @@ export function WebsiteSelect({
const queryResult = useWebsites({ teamId }, { search, pageSize: 5 }); const queryResult = useWebsites({ teamId }, { search, pageSize: 5 });
const renderValue = () => {
return website?.name;
};
const renderEmpty = () => { const renderEmpty = () => {
return <Empty message={formatMessage(messages.noResultsFound)} />; return <Empty message={formatMessage(messages.noResultsFound)} />;
}; };
@ -39,20 +34,16 @@ export function WebsiteSelect({
}; };
return ( return (
<Dropdown <Select
menuProps={{ className: styles.dropdown }}
items={queryResult?.result?.data as any[]} items={queryResult?.result?.data as any[]}
value={selectedId as string} value={selectedId as string}
renderValue={renderValue}
renderEmpty={renderEmpty}
onChange={handleSelect} onChange={handleSelect}
alignment="end"
placeholder={formatMessage(labels.selectWebsite)} placeholder={formatMessage(labels.selectWebsite)}
allowSearch={true} allowSearch={true}
onSearch={handleSearch} onSearch={handleSearch}
isLoading={queryResult.query.isLoading} isLoading={queryResult.query.isLoading}
> >
{({ id, name }) => <Item key={id}>{name}</Item>} {({ id, name }: any) => <ListItem key={id}>{name}</ListItem>}
</Dropdown> </Select>
); );
} }