Skip to content

Commit

Permalink
Add filters to transactions page (#13534)
Browse files Browse the repository at this point in the history
GitOrigin-RevId: b38c948a5b1d252ca03943a2067caf9626e96cc3
  • Loading branch information
carsonp6 authored and Lightspark Eng committed Nov 26, 2024
1 parent e44b6a2 commit 0d965a4
Show file tree
Hide file tree
Showing 3 changed files with 202 additions and 9 deletions.
162 changes: 162 additions & 0 deletions packages/ui/src/components/DataManagerTable/CurrencyFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import styled from "@emotion/styled";
import { type CurrencyAmountInputObj, CurrencyUnit } from "@lightsparkdev/core";
import { useState } from "react";
import { ButtonRow } from "../ButtonRow.js";
import NumberInput from "../NumberInput.js";
import { Filter, type FilterState } from "./Filter.js";
import { FilterType } from "./filters.js";

enum FilterRangeType {
LessThan = "Less than",
Between = "Between",
MoreThan = "More than",
}

export interface CurrencyFilterState extends FilterState {
type: FilterType.CURRENCY;
min_amount: CurrencyAmountInputObj | null;
max_amount: CurrencyAmountInputObj | null;
}

export const isCurrencyFilterState = (
state: FilterState,
): state is CurrencyFilterState => state.type === FilterType.CURRENCY;

export const getDefaultCurrencyFilterState = () => ({
type: FilterType.CURRENCY,
min_amount: null,
max_amount: null,
isApplied: false,
});

export const CurrencyFilter = ({
updateFilterState,
state,
label,
}: {
updateFilterState: (state: CurrencyFilterState) => void;
state: CurrencyFilterState;
label: string;
}) => {
const [filterRangeType, setFilterRangeType] = useState<FilterRangeType>(
FilterRangeType.LessThan,
);

const isMinDisplayed = filterRangeType !== FilterRangeType.LessThan;
const isMaxDisplayed = filterRangeType !== FilterRangeType.MoreThan;

const handleMinChange = (value: string) => {
updateFilterState({
...state,
min_amount: value
? { value: parseInt(value), unit: CurrencyUnit.SATOSHI }
: null,
isApplied: state.max_amount !== null || !!value,
});
};

const handleMaxChange = (value: string) => {
updateFilterState({
...state,
max_amount: value
? { value: parseInt(value), unit: CurrencyUnit.SATOSHI }
: null,
isApplied: state.min_amount !== null || !!value,
});
};

const handleClick = (type: FilterRangeType) => {
setFilterRangeType(type);

updateFilterState({
...state,
min_amount: null,
max_amount: null,
isApplied: false,
});
};

return (
<div>
<Filter label={label}>
<NumberButtonRowContainer
smSticky={false}
bottomBorder={false}
buttons={[
{
text: "Less than",
kind:
filterRangeType === FilterRangeType.LessThan
? "primary"
: undefined,
onClick: () => handleClick(FilterRangeType.LessThan),
size: "ExtraSmall",
},
{
text: "Between",
kind:
filterRangeType === FilterRangeType.Between
? "primary"
: undefined,
onClick: () => handleClick(FilterRangeType.Between),
size: "ExtraSmall",
},
{
text: "More than",
kind:
filterRangeType === FilterRangeType.MoreThan
? "primary"
: undefined,
onClick: () => handleClick(FilterRangeType.MoreThan),
size: "ExtraSmall",
},
]}
/>
<InputContainer>
{isMinDisplayed && (
<NumberInput
placeholder="0"
onChange={handleMinChange}
value={state.min_amount?.value?.toString() || ""}
icon={{ name: "Satoshi", side: "left", width: 8 }}
typography={{ color: "black" }}
allowNegativeValue
/>
)}

{isMinDisplayed && isMaxDisplayed && <Divider />}
{isMaxDisplayed && (
<NumberInput
placeholder="0"
onChange={handleMaxChange}
value={state.max_amount?.value?.toString() || ""}
icon={{ name: "Satoshi", side: "left", width: 8 }}
typography={{ color: "black" }}
allowNegativeValue
/>
)}
</InputContainer>
</Filter>
</div>
);
};

const NumberButtonRowContainer = styled(ButtonRow)`
padding: 0px !important;
`;

const InputContainer = styled.div`
display: flex;
flex-direction: row;
margin-top: 24px;
gap: 10px;
align-items: center;
`;

const Divider = styled.div`
height: 4px;
width: 12px;
flex-shrink: 0;
border-radius: 999px;
background-color: ${({ theme }) => theme.c1Neutral};
`;
40 changes: 32 additions & 8 deletions packages/ui/src/components/DataManagerTable/DataManagerTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import styled from "@emotion/styled";
import { useEffect, useState } from "react";

import { type useClipboard } from "../../hooks/useClipboard.js";
import { Breakpoints, bp, useBreakpoints } from "../../styles/breakpoints.js";
import { bp, useBreakpoints } from "../../styles/breakpoints.js";
import { standardContentInset } from "../../styles/common.js";
import { Spacing } from "../../styles/tokens/spacing.js";
import { Button, StyledButton } from "../Button.js";
Expand All @@ -17,6 +17,11 @@ import {
getDefaultBooleanFilterState,
type BooleanFilterState,
} from "./BooleanFilter.js";
import {
CurrencyFilter,
getDefaultCurrencyFilterState,
type CurrencyFilterState,
} from "./CurrencyFilter.js";
import {
DateFilter,
getDefaultDateFilterState,
Expand All @@ -29,6 +34,11 @@ import {
type EnumFilterState,
} from "./EnumFilter.js";
import { type FilterState } from "./Filter.js";
import {
FilterType,
type Filter,
type StringFilter as StringFilterType,
} from "./filters.js";
import {
IdFilter,
getDefaultIdFilterState,
Expand All @@ -42,11 +52,6 @@ import {
isStringFilterState,
type StringFilterState,
} from "./StringFilter.js";
import {
FilterType,
type Filter,
type StringFilter as StringFilterType,
} from "./filters.js";

interface FilterOptions<
T extends Record<string, unknown>,
Expand Down Expand Up @@ -112,6 +117,8 @@ function getDefaultFilterState<T extends Record<string, unknown>>(
return getDefaultIdFilterState(filter.allowedEntities);
case FilterType.BOOLEAN:
return getDefaultBooleanFilterState();
case FilterType.CURRENCY:
return getDefaultCurrencyFilterState();
default:
throw new Error("Invalid filter type");
}
Expand Down Expand Up @@ -165,7 +172,7 @@ export function DataManagerTable<
props.filterOptions?.initialQueryVariables || ({} as QueryVariablesType),
);

const isSm = breakPoint.current(Breakpoints.sm);
const isSm = breakPoint.isSm();

useEffect(() => {
setIsLoading(Boolean(props.loading));
Expand Down Expand Up @@ -333,7 +340,7 @@ export function DataManagerTable<
updateFilterState(filter)(newFilterState);
} else if (filterState.appliedValues?.length === 0) {
// If there are no more applied values, remove the filter
updateFilterState(filter)(getDefaultStringFilterState());
updateFilterState(filter)(getDefaultEnumFilterState());
filterState.isApplied = false;
}
}
Expand Down Expand Up @@ -554,6 +561,23 @@ export function DataManagerTable<
/>
</div>
);
case FilterType.CURRENCY:
return (
<div key={filter.label}>
<CurrencyFilter
updateFilterState={(state) => {
setFilterStates((prevState) => ({
...prevState,
[filter.accessorKey]: state,
}));
}}
label={filter.label}
state={
filterStates[filter.accessorKey] as CurrencyFilterState
}
/>
</div>
);
default:
return null;
}
Expand Down
9 changes: 8 additions & 1 deletion packages/ui/src/components/DataManagerTable/filters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,25 @@ export interface BooleanFilter<T extends Record<string, unknown>>
queryVariable: string;
}

export interface CurrencyFilter<T extends Record<string, unknown>>
extends FilterBase<T> {
type: FilterType.CURRENCY;
}

export type Filter<T extends Record<string, unknown>> =
| DateFilter<T>
| EnumFilter<T>
| StringFilter<T>
| IdFilter<T>
| BooleanFilter<T>;
| BooleanFilter<T>
| CurrencyFilter<T>;

export enum FilterType {
DATE = "date",
ENUM = "enum",
STRING = "string",
ID = "id",
NUMBER = "number",
CURRENCY = "currency",
BOOLEAN = "boolean",
}

0 comments on commit 0d965a4

Please sign in to comment.