CI / changes (push) Successful in 9s
CI / commitlint (push) Has been skipped
CI / openapi (push) Has been skipped
CI / web (push) Successful in 52s
CI / go (push) Has been skipped
CI / bird2 (push) Has been skipped
CI / release (push) Successful in 4m16s
Updated multiple components to replace DataGridShell with DataGridSection, integrating search functionality and improved data handling. This change enhances user experience by providing a consistent interface across various grids, including AccessApiKeysGrid, DashboardRecentJobsGrid, and others. Additionally, introduced global filtering capabilities to streamline data retrieval and presentation, ensuring a more efficient user interaction with the data grids.
107 lines
3.2 KiB
TypeScript
107 lines
3.2 KiB
TypeScript
"use client"
|
|
|
|
import { useState } from "react"
|
|
|
|
import { Checkbox } from "@evobgp/ui/components/checkbox"
|
|
import { Field } from "@evobgp/ui/components/field"
|
|
import {
|
|
InputGroup,
|
|
InputGroupAddon,
|
|
InputGroupButton,
|
|
InputGroupInput,
|
|
} from "@evobgp/ui/components/input-group"
|
|
import { Label } from "@evobgp/ui/components/label"
|
|
import {
|
|
Popover,
|
|
PopoverContent,
|
|
PopoverTrigger,
|
|
} from "@evobgp/ui/components/popover"
|
|
import { SearchIcon, XIcon, ListFilterIcon } from "lucide-react"
|
|
|
|
const statuses = ["Pending", "Shipped", "Cancelled"] as const
|
|
|
|
type Status = (typeof statuses)[number]
|
|
|
|
function toggleStatus(values: Status[], value: Status) {
|
|
return values.includes(value)
|
|
? values.filter((item) => item !== value)
|
|
: [...values, value]
|
|
}
|
|
|
|
export function Pattern() {
|
|
const [searchQuery, setSearchQuery] = useState("")
|
|
const [selectedStatuses, setSelectedStatuses] = useState<Status[]>([])
|
|
|
|
return (
|
|
<Field className="max-w-sm">
|
|
<InputGroup>
|
|
<InputGroupAddon align="inline-start">
|
|
<SearchIcon aria-hidden="true" />
|
|
</InputGroupAddon>
|
|
|
|
<InputGroupInput
|
|
placeholder="Search orders..."
|
|
value={searchQuery}
|
|
onChange={(event) => setSearchQuery(event.target.value)}
|
|
/>
|
|
|
|
<InputGroupAddon align="inline-end" className="gap-1">
|
|
{searchQuery.length > 0 ? (
|
|
<InputGroupButton
|
|
aria-label="Clear search"
|
|
size="icon-xs"
|
|
variant="ghost"
|
|
onClick={() => setSearchQuery("")}
|
|
>
|
|
<XIcon aria-hidden="true" />
|
|
</InputGroupButton>
|
|
) : null}
|
|
|
|
<Popover>
|
|
<PopoverTrigger
|
|
render={
|
|
<InputGroupButton
|
|
variant="ghost"
|
|
size="xs"
|
|
className="gap-1.5"
|
|
aria-label="Filter order status"
|
|
/>
|
|
}
|
|
>
|
|
<ListFilterIcon className="size-3.5" aria-hidden="true" />
|
|
Status
|
|
{selectedStatuses.length > 0 ? (
|
|
<span className="text-muted-foreground tabular-nums">
|
|
{selectedStatuses.length}
|
|
</span>
|
|
) : null}
|
|
</PopoverTrigger>
|
|
<PopoverContent align="end" className="w-40 p-3">
|
|
<div className="flex flex-col gap-2">
|
|
{statuses.map((status) => (
|
|
<div key={status} className="flex items-center gap-2.5">
|
|
<Checkbox
|
|
id={`order-status-${status}`}
|
|
checked={selectedStatuses.includes(status)}
|
|
onCheckedChange={() =>
|
|
setSelectedStatuses((previous) =>
|
|
toggleStatus(previous, status)
|
|
)
|
|
}
|
|
/>
|
|
<Label
|
|
htmlFor={`order-status-${status}`}
|
|
className="text-sm font-normal"
|
|
>
|
|
{status}
|
|
</Label>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</PopoverContent>
|
|
</Popover>
|
|
</InputGroupAddon>
|
|
</InputGroup>
|
|
</Field>
|
|
)
|
|
} |