43 lines
1.7 KiB
TypeScript
43 lines
1.7 KiB
TypeScript
"use client"
|
|
|
|
// The workspace page's projects, with a count of those ticked. The count exists only in the browser, so the
|
|
// loader cannot translate it: the page hands over the message with its placeholder left in, and this island
|
|
// fills it with `formatMessage`, which brings the language's plural rules and no catalogue (F10, decision 2).
|
|
|
|
import { formatMessage } from "@conusai-kit/i18n/format"
|
|
import { ResourceList } from "@conusai-kit/ui/patterns"
|
|
import { useUiLabel } from "@conusai-kit/ui/primitives"
|
|
import { type ReactElement, useState } from "react"
|
|
|
|
export interface ProjectPickerProps {
|
|
readonly label: string
|
|
readonly column: string
|
|
readonly empty: string
|
|
readonly projects: readonly { readonly slug: string; readonly name: string; readonly href: string }[]
|
|
/** `{count, plural, ...}`, in the person's language, not yet filled in. */
|
|
readonly selected: string
|
|
readonly locale: string
|
|
}
|
|
|
|
export function ProjectPicker({ projects, selected, locale, label, column, empty }: ProjectPickerProps): ReactElement {
|
|
const [picked, setPicked] = useState<ReadonlySet<string>>(new Set())
|
|
const selectAll = useUiLabel("selectAll")
|
|
return (
|
|
<ResourceList
|
|
label={label}
|
|
columns={[{ id: "name", header: column, wrap: true }]}
|
|
data={projects}
|
|
rowId={(project) => project.slug}
|
|
rowHref={(project) => project.href}
|
|
rowLabel={(project) => project.name}
|
|
selectionMode="multiple"
|
|
selectionLabel={selectAll}
|
|
rowSelectionLabel={(project) => project.name}
|
|
selectedKeys={picked}
|
|
onSelectionChange={setPicked}
|
|
count={formatMessage(selected, { count: picked.size }, locale)}
|
|
empty={{ title: empty }}
|
|
/>
|
|
)
|
|
}
|