diff --git a/web/components/editor.tsx b/web/components/editor.tsx index 018d94a6..8f49c498 100644 --- a/web/components/editor.tsx +++ b/web/components/editor.tsx @@ -21,6 +21,8 @@ import { useMutation } from 'react-query' import { linkClass } from './site-link' import { DisplayMention } from './editor/mention' import { DisplayContractMention } from './editor/contract-mention' +import GridComponent from './editor/tiptap-grid-cards' + import Iframe from 'common/util/tiptap-iframe' import TiptapTweet from './editor/tiptap-tweet' import { EmbedModal } from './editor/embed-modal' @@ -78,6 +80,7 @@ export const editorExtensions = (simple = false): Extensions => [ DisplayLink, DisplayMention, DisplayContractMention, + GridComponent, Iframe, TiptapTweet, TiptapSpoiler.configure({ @@ -358,6 +361,7 @@ export function RichContent(props: { DisplayLink.configure({ openOnClick: false }), // stop link opening twice (browser still opens) DisplayMention, DisplayContractMention, + GridComponent, Iframe, TiptapTweet, TiptapSpoiler.configure({ diff --git a/web/components/editor/market-modal.tsx b/web/components/editor/market-modal.tsx index 1e2c1482..ae0f50e1 100644 --- a/web/components/editor/market-modal.tsx +++ b/web/components/editor/market-modal.tsx @@ -1,7 +1,7 @@ import { Editor } from '@tiptap/react' import { Contract } from 'common/contract' import { SelectMarketsModal } from '../contract-select-modal' -import { embedContractCode, embedContractGridCode } from '../share-embed-button' +import { embedContractCode } from '../share-embed-button' import { insertContent } from './utils' export function MarketModal(props: { @@ -15,7 +15,10 @@ export function MarketModal(props: { if (contracts.length == 1) { insertContent(editor, embedContractCode(contracts[0])) } else if (contracts.length > 1) { - insertContent(editor, embedContractGridCode(contracts)) + insertContent( + editor, + `` + ) } } diff --git a/web/components/editor/tiptap-grid-cards.tsx b/web/components/editor/tiptap-grid-cards.tsx new file mode 100644 index 00000000..48242ea2 --- /dev/null +++ b/web/components/editor/tiptap-grid-cards.tsx @@ -0,0 +1,55 @@ +import { mergeAttributes, Node } from '@tiptap/core' +import React from 'react' +import { NodeViewWrapper, ReactNodeViewRenderer } from '@tiptap/react' +import { ContractsGrid } from '../contract/contracts-grid' + +import { useContractsFromIds } from 'web/hooks/use-contract' +import { LoadingIndicator } from '../loading-indicator' + +export default Node.create({ + name: 'gridCardsComponent', + + group: 'block', + + atom: true, + + addAttributes() { + return { + contractIds: [], + } + }, + + parseHTML() { + return [ + { + tag: 'grid-cards-component', + }, + ] + }, + + renderHTML({ HTMLAttributes }) { + return ['grid-cards-component', mergeAttributes(HTMLAttributes)] + }, + + addNodeView() { + return ReactNodeViewRenderer(GridComponent) + }, +}) + +export function GridComponent(props: any) { + const contractIds = props.node.attrs.contractIds + const contracts = useContractsFromIds(contractIds.split(',')) + + return ( + + {contracts ? ( + + ) : ( + + )} + + ) +} diff --git a/web/hooks/use-contract.ts b/web/hooks/use-contract.ts index acaf7730..2e7c4f84 100644 --- a/web/hooks/use-contract.ts +++ b/web/hooks/use-contract.ts @@ -3,10 +3,12 @@ import { useFirestoreDocumentData } from '@react-query-firebase/firestore' import { Contract, contracts, + getContractFromId, listenForContract, } from 'web/lib/firebase/contracts' import { useStateCheckEquality } from './use-state-check-equality' import { doc, DocumentData } from 'firebase/firestore' +import { useQuery } from 'react-query' export const useContract = (contractId: string) => { const result = useFirestoreDocumentData( @@ -18,6 +20,17 @@ export const useContract = (contractId: string) => { return result.isLoading ? undefined : result.data } +export const useContractsFromIds = (contractIds: string[]) => { + const contractResult = useQuery(['contracts', contractIds], () => + Promise.all(contractIds.map(getContractFromId)) + ) + const contracts = contractResult.data?.filter( + (contract): contract is Contract => !!contract + ) + + return contractResult.isLoading ? undefined : contracts +} + export const useContractWithPreload = ( initial: Contract | null | undefined ) => {