import clsx from "clsx"; import * as React from "react"; import { ListBoxItem, type SelectProps } from "react-aria-components"; import { useFetcher } from "react-router"; import type { SearchLoaderData } from "~/features/search/routes/search"; import { SearchSelect } from "./SearchSelect"; import searchSelectStyles from "./SearchSelect.module.css"; import selectStyles from "./Select.module.css"; import { useEntitySearch } from "./useEntitySearch"; export type OrganizationSearchResult = Extract< NonNullable["results"][number], { type: "organization" } >; interface OrganizationSearchProps extends Omit, "children" | "onChange"> { name?: string; label?: string; bottomText?: string; errorText?: string; initialOrganizationId?: number; onChange?: (organization: OrganizationSearchResult | null) => void; } export const OrganizationSearch = React.forwardRef(function OrganizationSearch< T extends object, >( { name, label, bottomText, errorText, initialOrganizationId, onChange, ...rest }: OrganizationSearchProps, ref?: React.Ref, ) { const initialOrganization = useInitialOrganization(initialOrganizationId); const search = useEntitySearch({ buildUrl: (query) => `/search?q=${query}&type=organizations&limit=6`, parseResults: (data, query) => parseOrganizationResults(data, query, initialOrganization), initialItem: initialOrganization, initialSelectedId: initialOrganizationId, onChange, }); return ( } /> ); }); function parseOrganizationResults( data: unknown, query: string, initialOrganization?: OrganizationSearchResult, ): OrganizationSearchResult[] | null { const searchData = data as SearchLoaderData; if (!searchData || searchData.query !== query) return null; return searchData.results .filter( (result): result is OrganizationSearchResult => result.type === "organization", ) .filter((org) => org.id !== initialOrganization?.id); } function useInitialOrganization(initialOrganizationId?: number) { const fetcher = useFetcher(); React.useEffect(() => { if (!initialOrganizationId || fetcher.state !== "idle" || fetcher.data) { return; } fetcher.load( `/search?q=${initialOrganizationId}&type=organizations&limit=1`, ); }, [initialOrganizationId, fetcher]); return fetcher.data?.results.find( (result): result is OrganizationSearchResult => result.type === "organization", ); } function OrganizationItem({ item }: { item: OrganizationSearchResult }) { return ( clsx(searchSelectStyles.item, { [selectStyles.itemFocused]: isFocused, [selectStyles.itemSelected]: isSelected, }) } data-testid="organization-search-item" >
{item.name}
/{item.slug}
); }