import { Button, Dialog, DialogContent, DialogFooter, DocumentTypeBadge, IconMagnifyingGlass, IconPlusLarge, IconTrashCan, InfiniteScrollTrigger, Input, Spinner, } from "@probo/ui"; import { useTranslate } from "@probo/i18n"; import { Suspense, useMemo, useState, type ReactNode } from "react"; import { graphql } from "relay-runtime"; import { useLazyLoadQuery, usePaginationFragment } from "react-relay"; import type { LinkedDocumentsDialogQuery } from "/__generated__/core/LinkedDocumentsDialogQuery.graphql"; import { useOrganizationId } from "/hooks/useOrganizationId"; import type { NodeOf } from "/types"; import type { LinkedDocumentsDialogFragment$data, LinkedDocumentsDialogFragment$key, } from "/__generated__/core/LinkedDocumentsDialogFragment.graphql"; const documentsQuery = graphql` query LinkedDocumentsDialogQuery($organizationId: ID!) { organization: node(id: $organizationId) { id ... on Organization { ...LinkedDocumentsDialogFragment } } } `; const documentsFragment = graphql` fragment LinkedDocumentsDialogFragment on Organization @refetchable(queryName: "LinkedDocumentsDialogQuery_fragment") @argumentDefinitions( first: { type: "Int", defaultValue: 20 } order: { type: "DocumentOrder", defaultValue: null } after: { type: "CursorKey", defaultValue: null } before: { type: "CursorKey", defaultValue: null } last: { type: "Int", defaultValue: null } ) { documents( first: $first after: $after last: $last before: $before orderBy: $order ) @connection(key: "LinkedDocumentsDialogQuery_documents") { edges { node { id title documentType } } } } `; type Props = { children: ReactNode; connectionId: string; disabled?: boolean; linkedDocuments?: { id: string }[]; onLink: (documentId: string) => void; onUnlink: (documentId: string) => void; }; export function LinkedDocumentDialog({ children, ...props }: Props) { const { __ } = useTranslate(); return ( }> ); } function LinkedDocumentsDialogContent(props: Omit) { const organizationId = useOrganizationId(); const query = useLazyLoadQuery( documentsQuery, { organizationId, }, { fetchPolicy: "network-only" }, ); const { data, loadNext, hasNext, isLoadingNext } = usePaginationFragment( documentsFragment, query.organization as LinkedDocumentsDialogFragment$key, ); const { __ } = useTranslate(); const [search, setSearch] = useState(""); const documents = useMemo( () => data.documents?.edges?.map(edge => edge.node) ?? [], [data.documents], ); const linkedIds = useMemo(() => { return new Set(props.linkedDocuments?.map(m => m.id) ?? []); }, [props.linkedDocuments]); const filteredDocuments = useMemo(() => { return documents.filter(document => document.title.toLowerCase().includes(search.toLowerCase()), ); }, [documents, search]); return ( <>
{filteredDocuments.map(document => ( ))} {hasNext && ( loadNext(20)} /> )}
); } type Document = NodeOf; type RowProps = { document: Document; linkedDocuments: Set; disabled?: boolean; onLink: (documentId: string) => void; onUnlink: (documentId: string) => void; }; function DocumentRow(props: RowProps) { const { __ } = useTranslate(); const isLinked = props.linkedDocuments.has(props.document.id); const onClick = isLinked ? props.onUnlink : props.onLink; const IconComponent = isLinked ? IconTrashCan : IconPlusLarge; return ( ); }