add event_data to goal.

This commit is contained in:
Brian Cao 2024-05-20 21:10:46 -07:00
parent 76cab03bb2
commit 79a93ed9fc
7 changed files with 231 additions and 48 deletions

View file

@ -6,27 +6,48 @@ import styles from './GoalsAddForm.module.css';
export function GoalsAddForm({
type: defaultType = 'url',
value: defaultValue = '',
property: defaultProperty = '',
operator: defaultAggregae = null,
goal: defaultGoal = 10,
onChange,
}: {
type?: string;
value?: string;
operator?: string;
property?: string;
goal?: number;
onChange?: (step: { type: string; value: string; goal: number }) => void;
onChange?: (step: {
type: string;
value: string;
goal: number;
operator?: string;
property?: string;
}) => void;
}) {
const [type, setType] = useState(defaultType);
const [value, setValue] = useState(defaultValue);
const [operator, setOperator] = useState(defaultAggregae);
const [property, setProperty] = useState(defaultProperty);
const [goal, setGoal] = useState(defaultGoal);
const { formatMessage, labels } = useMessages();
const items = [
{ label: formatMessage(labels.url), value: 'url' },
{ label: formatMessage(labels.event), value: 'event' },
{ label: formatMessage(labels.eventData), value: 'event-data' },
];
const operators = [
{ label: formatMessage(labels.count), value: 'count' },
{ label: formatMessage(labels.average), value: 'average' },
{ label: formatMessage(labels.sum), value: 'sum' },
];
const isDisabled = !type || !value;
const handleSave = () => {
onChange({ type, value, goal });
onChange(
type === 'event-data' ? { type, value, goal, operator, property } : { type, value, goal },
);
setValue('');
setProperty('');
setGoal(10);
};
@ -45,6 +66,10 @@ export function GoalsAddForm({
return items.find(item => item.value === value)?.label;
};
const renderoperatorValue = (value: any) => {
return operators.find(item => item.value === value)?.label;
};
return (
<Flexbox direction="column" gap={10}>
<FormRow label={formatMessage(defaultValue ? labels.update : labels.add)}>
@ -70,6 +95,31 @@ export function GoalsAddForm({
/>
</Flexbox>
</FormRow>
{type === 'event-data' && (
<FormRow label={formatMessage(labels.property)}>
<Flexbox gap={10}>
<Dropdown
className={styles.dropdown}
items={operators}
value={operator}
renderValue={renderoperatorValue}
onChange={(value: any) => setOperator(value)}
>
{({ value, label }) => {
return <Item key={value}>{label}</Item>;
}}
</Dropdown>
<TextField
className={styles.input}
value={property}
onChange={e => handleChange(e, setProperty)}
autoFocus={true}
autoComplete="off"
onKeyDown={handleKeyDown}
/>
</Flexbox>
</FormRow>
)}
<FormRow label={formatMessage(labels.goal)}>
<Flexbox gap={10}>
<TextField

View file

@ -11,19 +11,36 @@ export function GoalsChart({ className }: { className?: string; isLoading?: bool
const { data } = report || {};
const getLabel = type => {
let label = '';
switch (type) {
case 'url':
label = labels.viewedPage;
break;
case 'event':
label = labels.triggeredEvent;
break;
default:
label = labels.collectedData;
break;
}
return label;
};
return (
<div className={classNames(styles.chart, className)}>
{data?.map(({ type, value, goal, result }, index: number) => {
{data?.map(({ type, value, goal, result, property, operator }, index: number) => {
const percent = result > goal ? 100 : (result / goal) * 100;
return (
<div key={index} className={styles.goal}>
<div className={styles.card}>
<div className={styles.header}>
<span className={styles.label}>
{formatMessage(type === 'url' ? labels.viewedPage : labels.triggeredEvent)}
</span>
<span className={styles.item}>{value}</span>
<span className={styles.label}>{formatMessage(getLabel(type))}</span>
<span className={styles.item}>{`${value}${
type === 'event-data' ? `:(${operator}):${property}` : ''
}`}</span>
</div>
<div className={styles.track}>
<div

View file

@ -4,6 +4,16 @@
font-weight: 600;
}
.eventData {
color: var(--orange900);
background-color: var(--orange100);
font-size: 12px;
font-weight: 900;
padding: 2px 8px;
border-radius: 5px;
width: fit-content;
}
.goal {
color: var(--blue900);
background-color: var(--blue100);
@ -11,4 +21,5 @@
font-weight: 900;
padding: 2px 8px;
border-radius: 5px;
width: fit-content;
}

View file

@ -4,6 +4,7 @@ import { formatNumber } from 'lib/format';
import { useContext } from 'react';
import {
Button,
Flexbox,
Form,
FormButtons,
FormRow,
@ -79,33 +80,53 @@ export function GoalsParameters() {
<BaseParameters allowWebsiteSelect={!id} />
<FormRow label={formatMessage(labels.goals)} action={<AddGoalsButton />}>
<ParameterList>
{goals.map((goal: { type: string; value: string; goal: number }, index: number) => {
return (
<PopupTrigger key={index}>
<ParameterList.Item
icon={goal.type === 'url' ? <Icons.Eye /> : <Icons.Bolt />}
onRemove={() => handleRemoveGoals(index)}
>
<div className={styles.value}>{goal.value}</div>
<div className={styles.goal}>
{formatMessage(labels.goal)}: {formatNumber(goal.goal)}
</div>
</ParameterList.Item>
<Popup alignment="start">
{(close: () => void) => (
<PopupForm>
<GoalsAddForm
type={goal.type}
value={goal.value}
goal={goal.goal}
onChange={handleUpdateGoals.bind(null, close, index)}
/>
</PopupForm>
)}
</Popup>
</PopupTrigger>
);
})}
{goals.map(
(
goal: {
type: string;
value: string;
goal: number;
operator?: string;
property?: string;
},
index: number,
) => {
return (
<PopupTrigger key={index}>
<ParameterList.Item
icon={goal.type === 'url' ? <Icons.Eye /> : <Icons.Bolt />}
onRemove={() => handleRemoveGoals(index)}
>
<Flexbox direction="column" gap={5}>
<div className={styles.value}>{goal.value}</div>
{goal.type === 'event-data' && (
<div className={styles.eventData}>
{formatMessage(labels[goal.operator])}: {goal.property}
</div>
)}
<div className={styles.goal}>
{formatMessage(labels.goal)}: {formatNumber(goal.goal)}
</div>
</Flexbox>
</ParameterList.Item>
<Popup alignment="start">
{(close: () => void) => (
<PopupForm>
<GoalsAddForm
type={goal.type}
value={goal.value}
goal={goal.goal}
operator={goal.operator}
property={goal.property}
onChange={handleUpdateGoals.bind(null, close, index)}
/>
</PopupForm>
)}
</Popup>
</PopupTrigger>
);
},
)}
</ParameterList>
</FormRow>
<FormButtons>