Update insights report parameters. Added contains logic.

This commit is contained in:
Mike Cao 2024-03-22 23:33:45 -07:00
parent d59477deb5
commit 5daad2726e
15 changed files with 280 additions and 190 deletions

View file

@ -1,7 +1,7 @@
.popup {
display: flex;
max-width: 300px;
max-height: 400px;
max-height: 210px;
overflow-x: hidden;
}
@ -19,6 +19,6 @@
min-width: 180px;
}
.menu {
min-width: 200px;
.text {
min-width: 180px;
}

View file

@ -1,6 +1,19 @@
import { useState, useMemo } from 'react';
import { Form, FormRow, Item, Flexbox, Dropdown, Button } from 'react-basics';
import {
Form,
FormRow,
Item,
Flexbox,
Dropdown,
Button,
TextField,
Menu,
Popup,
PopupTrigger,
} from 'react-basics';
import { useMessages, useFilters, useFormat, useLocale } from 'components/hooks';
import { safeDecodeURIComponent } from 'next-basics';
import { OPERATORS } from 'lib/constants';
import styles from './FieldFilterForm.module.css';
export interface FieldFilterFormProps {
@ -22,12 +35,11 @@ export default function FieldFilterForm({
}: FieldFilterFormProps) {
const { formatMessage, labels } = useMessages();
const [filter, setFilter] = useState('eq');
const [value, setValue] = useState();
const [value, setValue] = useState('');
const { getFilters } = useFilters();
const { formatValue } = useFormat();
const { locale } = useLocale();
const filters = getFilters(type);
const [search, setSearch] = useState('');
const formattedValues = useMemo(() => {
const formatted = {};
@ -45,21 +57,25 @@ export default function FieldFilterForm({
}, [formatValue, locale, name, values]);
const filteredValues = useMemo(() => {
return search ? values.filter(n => n.includes(search)) : values;
}, [search, formattedValues]);
return value ? values.filter(n => n.includes(value)) : values;
}, [value, formattedValues]);
const renderFilterValue = value => {
return filters.find(f => f.value === value)?.label;
};
const renderValue = value => {
return formattedValues[value];
};
const handleAdd = () => {
onSelect({ name, type, filter, value });
};
const handleMenuSelect = value => {
setValue(value);
};
const showMenu =
[OPERATORS.equals, OPERATORS.notEquals].includes(filter as any) &&
!(filteredValues.length === 1 && filteredValues[0] === value);
return (
<Form>
<FormRow label={label} className={styles.filter}>
@ -77,21 +93,24 @@ export default function FieldFilterForm({
}}
</Dropdown>
)}
<Dropdown
className={styles.dropdown}
popupProps={{ className: styles.popup }}
menuProps={{ className: styles.menu }}
items={filteredValues}
value={value}
renderValue={renderValue}
onChange={(key: any) => setValue(key)}
allowSearch={true}
onSearch={setSearch}
>
{(value: string) => {
return <Item key={value}>{formattedValues[value]}</Item>;
}}
</Dropdown>
<PopupTrigger>
<TextField
className={styles.text}
value={decodeURIComponent(value)}
onChange={e => setValue(e.target.value)}
/>
{showMenu && (
<Popup className={styles.popup} alignment="end">
{filteredValues.length > 0 && (
<Menu variant="popup" onSelect={handleMenuSelect}>
{filteredValues.map(value => {
return <Item key={value}>{safeDecodeURIComponent(value)}</Item>;
})}
</Menu>
)}
</Popup>
)}
</PopupTrigger>
</Flexbox>
<Button variant="primary" onClick={handleAdd} disabled={!filter || !value}>
{formatMessage(labels.add)}

View file

@ -24,14 +24,14 @@ function useValues(websiteId: string, type: string) {
export interface FilterSelectFormProps {
websiteId: string;
items: any[];
fields: any[];
onSelect?: (key: any) => void;
allowFilterSelect?: boolean;
}
export default function FilterSelectForm({
websiteId,
items,
fields,
onSelect,
allowFilterSelect,
}: FilterSelectFormProps) {
@ -39,7 +39,7 @@ export default function FilterSelectForm({
const { data, isLoading } = useValues(websiteId, field?.name);
if (!field) {
return <FieldSelectForm fields={items} onSelect={setField} showType={false} />;
return <FieldSelectForm fields={fields} onSelect={setField} showType={false} />;
}
if (isLoading) {

View file

@ -13,9 +13,4 @@
border: 1px solid var(--base400);
border-radius: var(--border-radius);
box-shadow: 1px 1px 1px var(--base400);
gap: 10px;
}
.icon {
align-self: center;
}

View file

@ -1,40 +1,36 @@
import { ReactNode } from 'react';
import { Icon, TooltipPopup } from 'react-basics';
import { Icon } from 'react-basics';
import Icons from 'components/icons';
import Empty from 'components/common/Empty';
import { useMessages } from 'components/hooks';
import styles from './ParameterList.module.css';
export interface ParameterListProps {
items: any[];
children?: ReactNode | ((item: any) => ReactNode);
onRemove: (index: number, e: any) => void;
children?: ReactNode;
}
export function ParameterList({ items = [], children, onRemove }: ParameterListProps) {
export function ParameterList({ children }: ParameterListProps) {
const { formatMessage, labels } = useMessages();
return (
<div className={styles.list}>
{!items.length && <Empty message={formatMessage(labels.none)} />}
{items.map((item, index) => {
return (
<div key={index} className={styles.item}>
{typeof children === 'function' ? children(item) : item}
<TooltipPopup
className={styles.icon}
label={formatMessage(labels.remove)}
position="right"
>
<Icon onClick={onRemove.bind(null, index)}>
<Icons.Close />
</Icon>
</TooltipPopup>
</div>
);
})}
{!children && <Empty message={formatMessage(labels.none)} />}
{children}
</div>
);
}
const Item = ({ children, onRemove }: { children?: ReactNode; onRemove?: () => void }) => {
return (
<div className={styles.item}>
{children}
<Icon onClick={onRemove}>
<Icons.Close />
</Icon>
</div>
);
};
ParameterList.Item = Item;
export default ParameterList;

View file

@ -2,4 +2,5 @@
display: grid;
grid-template-rows: max-content 1fr;
grid-template-columns: max-content 1fr;
margin-bottom: 60px;
}