Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
237 changes: 237 additions & 0 deletions components/HistoryView/HistoryFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
import FilterIcon from "@components/Icons/FilterIcon";
import {
Badge,
Box,
Button,
Flex,
Popover,
PopoverContent,
PopoverTrigger,
Text,
} from "@livepeer/design-system";

interface HistoryFilterProps {
selectedEventTypes: string[];
isOpen: boolean;
onOpenChange: (open: boolean) => void;
onToggleEventType: (eventType: string) => void;
onClearFilters: () => void;
allEventTypes: string[];
eventTypeLabels: Record<string, string>;
}

const HistoryFilter = ({
selectedEventTypes,
isOpen,
onOpenChange,
onToggleEventType,
onClearFilters,
allEventTypes,
eventTypeLabels,
}: HistoryFilterProps) => {
return (
<Popover open={isOpen} onOpenChange={onOpenChange}>
<PopoverTrigger asChild>
<Button
role="button"
css={{
display: "flex",
alignItems: "center",
justifyContent: "center",
backgroundColor: "$neutral4",
color: "$hiContrast",
minHeight: "44px",
width: "120px",
padding: "$2 $3",
"&:hover": {
backgroundColor: "$neutral5",
},
}}
>
<FilterIcon size={16} css={{ marginRight: "$1" }} />
<Text css={{ marginRight: "$2" }}>Filter</Text>
{selectedEventTypes.length > 0 && (
<Badge
css={{
backgroundColor: "$primary9",
color: "white",
borderRadius: "50%",
width: "20px",
height: "20px",
display: "flex",
alignItems: "center",
justifyContent: "center",
fontSize: "$1",
fontWeight: 600,
padding: 0,
}}
>
{selectedEventTypes.length}
</Badge>
)}
</Button>
</PopoverTrigger>
<PopoverContent
data-history-filter-popover
css={{
width: "280px",
backgroundColor: "$neutral4",
borderRadius: "$3",
padding: 0,
boxShadow:
"0px 5px 14px rgba(0, 0, 0, 0.22), 0px 0px 2px rgba(0, 0, 0, 0.2)",
border: "1px solid $neutral6",
zIndex: 9,
display: "flex",
flexDirection: "column",
maxHeight: "400px",
marginRight: "$3",
overflow: "hidden",
}}
onPointerEnterCapture={undefined}
onPointerLeaveCapture={undefined}
placeholder={undefined}
>
{/* Header - Sticky */}
<Flex
css={{
padding: "$3",
borderBottom: "1px solid $neutral6",
borderTopLeftRadius: "$3",
borderTopRightRadius: "$3",
alignItems: "center",
justifyContent: "space-between",
flexShrink: 0,
backgroundColor: "$neutral4",
position: "sticky",
top: 0,
zIndex: 1,
}}
>
<Button
onClick={onClearFilters}
css={{
color: "$neutral11",
fontSize: "$2",
padding: "$1",
backgroundColor: "transparent",
"&:hover": {
color: "$hiContrast",
backgroundColor: "transparent",
},
}}
>
Clear
</Button>
<Text css={{ fontWeight: 600, fontSize: "$3" }}>Filters</Text>
<Button
onClick={() => onOpenChange(false)}
css={{
color: "$primary11",
fontSize: "$2",
padding: "$1",
backgroundColor: "transparent",
"&:hover": {
backgroundColor: "transparent",
},
}}
>
Done
</Button>
</Flex>

{/* Event type section - Scrollable */}
<Flex
data-history-filter-scrollable
css={{
flexDirection: "column",
overflowY: "auto",
flex: 1,
borderBottomLeftRadius: "$3",
borderBottomRightRadius: "$3",
}}
>
<Box css={{ padding: "$3" }}>
<Text
css={{
fontWeight: 500,
fontSize: "$2",
marginBottom: "$2",
color: "$hiContrast",
}}
>
Event Type
</Text>
<Flex css={{ flexDirection: "column", gap: "$2" }}>
{allEventTypes.map((eventType) => {
const isChecked = selectedEventTypes.includes(eventType);
return (
<Flex
key={eventType}
css={{
alignItems: "center",
cursor: "pointer",
padding: "$1",
borderRadius: "$1",
"&:hover": {
backgroundColor: "$neutral5",
},
}}
onClick={() => onToggleEventType(eventType)}
>
Comment thread
ECWireless marked this conversation as resolved.
Comment thread
ECWireless marked this conversation as resolved.
<Box
css={{
width: "18px",
height: "18px",
border: "2px solid",
borderColor: isChecked ? "$primary11" : "$neutral8",
backgroundColor: isChecked
? "$primary11"
: "transparent",
borderRadius: "$1",
marginRight: "$2",
display: "flex",
alignItems: "center",
justifyContent: "center",
transition: "all 0.2s",
}}
>
{isChecked && (
<Box
as="svg"
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
>
<path
d="M2 6L4.5 8.5L10 3"
stroke="white"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</Box>
)}
</Box>
<Text
css={{
fontSize: "$2",
color: "$hiContrast",
userSelect: "none",
}}
>
{eventTypeLabels[eventType]}
</Text>
</Flex>
);
})}
</Flex>
</Box>
</Flex>
</PopoverContent>
</Popover>
);
};

export default HistoryFilter;
39 changes: 38 additions & 1 deletion components/HistoryView/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import HistoryFilter from "@components/HistoryView/HistoryFilter";
import Spinner from "@components/Spinner";
import TransactionBadge from "@components/TransactionBadge";
import { Fm, parsePollIpfs } from "@lib/api/polls";
Expand All @@ -20,6 +21,7 @@ import {
useTransactionsQuery,
VoteEvent,
} from "apollo";
import { useHistoryFilter } from "hooks";
import { CHAIN_INFO, DEFAULT_CHAIN_ID } from "lib/chains";
import { useRouter } from "next/router";
import numbro from "numbro";
Expand Down Expand Up @@ -176,6 +178,18 @@ const Index = () => {
]
);

// Filter events using history hook
const {
filteredEvents,
selectedEventTypes,
toggleEventType,
clearFilters,
isFilterOpen,
setIsFilterOpen,
allEventTypes,
eventTypeLabels,
} = useHistoryFilter(mergedEvents);

if (error) {
console.error(error);
}
Expand Down Expand Up @@ -248,8 +262,31 @@ const Index = () => {
position: "relative",
}}
>
<Flex
css={{
justifyContent: "flex-end",
marginBottom: "$3",
alignItems: "center",
}}
>
<HistoryFilter
selectedEventTypes={selectedEventTypes}
isOpen={isFilterOpen}
onOpenChange={setIsFilterOpen}
onToggleEventType={toggleEventType}
onClearFilters={clearFilters}
allEventTypes={allEventTypes}
eventTypeLabels={eventTypeLabels}
/>
</Flex>
<Box css={{ paddingBottom: "$3" }}>
{mergedEvents.map((event, i: number) => renderSwitch(event, i))}
{filteredEvents.length > 0 ? (
filteredEvents.map((event, i: number) => renderSwitch(event, i))
) : (
<Box css={{ paddingTop: "$3", color: "$neutral11" }}>
No events match the selected filters
</Box>
)}
</Box>
{loading && data.transactions.length >= 10 && (
<Flex
Expand Down
28 changes: 28 additions & 0 deletions components/Icons/FilterIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Box } from "@livepeer/design-system";
import { CSS } from "@stitches/react";

interface FilterIconProps {
size?: number;
css?: CSS;
}

const FilterIcon = ({ size = 16, css }: FilterIconProps) => (
<Box
as="svg"
width={size}
height={size}
viewBox="0 0 16 16"
fill="none"
css={css}
aria-hidden="true"
>
<path
d="M2 4h12M4 8h8M6 12h4"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
/>
</Box>
);

export default FilterIcon;
Loading
Loading