diff --git a/common/util/parse.ts b/common/util/parse.ts
index 102a9e90..56314ae5 100644
--- a/common/util/parse.ts
+++ b/common/util/parse.ts
@@ -100,6 +100,7 @@ const stringParseExts = [
'[embed]' + node.attrs.src ? `(${node.attrs.src})` : '',
}),
skippableComponent('gridCardsComponent'),
+ skippableComponent('staticReactEmbedComponent'),
TiptapTweet.extend({ renderText: () => '[tweet]' }),
TiptapSpoiler.extend({ renderHTML: () => ['span', '[spoiler]', 0] }),
]
diff --git a/web/components/editor.tsx b/web/components/editor.tsx
index 0c3b4eec..146075a2 100644
--- a/web/components/editor.tsx
+++ b/web/components/editor.tsx
@@ -22,6 +22,7 @@ import { linkClass } from './site-link'
import { DisplayMention } from './editor/mention'
import { DisplayContractMention } from './editor/contract-mention'
import GridComponent from './editor/tiptap-grid-cards'
+import StaticReactEmbedComponent from './editor/tiptap-static-react-embed'
import Iframe from 'common/util/tiptap-iframe'
import TiptapTweet from './editor/tiptap-tweet'
@@ -81,6 +82,7 @@ export const editorExtensions = (simple = false): Extensions => [
DisplayMention,
DisplayContractMention,
GridComponent,
+ StaticReactEmbedComponent,
Iframe,
TiptapTweet,
TiptapSpoiler.configure({
@@ -363,6 +365,7 @@ export function RichContent(props: {
DisplayMention,
DisplayContractMention,
GridComponent,
+ StaticReactEmbedComponent,
Iframe,
TiptapTweet,
TiptapSpoiler.configure({
diff --git a/web/components/editor/tiptap-static-react-embed.tsx b/web/components/editor/tiptap-static-react-embed.tsx
new file mode 100644
index 00000000..0dd819aa
--- /dev/null
+++ b/web/components/editor/tiptap-static-react-embed.tsx
@@ -0,0 +1,44 @@
+import { mergeAttributes, Node } from '@tiptap/core'
+import React from 'react'
+import { NodeViewWrapper, ReactNodeViewRenderer } from '@tiptap/react'
+import { StaticReactEmbed } from '../static-react-embed'
+
+export default Node.create({
+ name: 'staticReactEmbedComponent',
+
+ group: 'block',
+
+ atom: true,
+
+ addAttributes() {
+ return {
+ embedName: '',
+ }
+ },
+
+ parseHTML() {
+ return [
+ {
+ tag: 'static-react-embed-component',
+ },
+ ]
+ },
+
+ renderHTML({ HTMLAttributes }) {
+ return ['static-react-embed-component', mergeAttributes(HTMLAttributes)]
+ },
+
+ addNodeView() {
+ return ReactNodeViewRenderer(StaticReactEmbedComponent)
+ },
+})
+
+export function StaticReactEmbedComponent(props: any) {
+ const embedName = props.node.attrs.embedName
+
+ return (
+
+
+
+ )
+}
diff --git a/web/components/midterms-maps.tsx b/web/components/midterms-maps.tsx
new file mode 100644
index 00000000..69b3a201
--- /dev/null
+++ b/web/components/midterms-maps.tsx
@@ -0,0 +1,212 @@
+import { useEffect } from 'react'
+import { getContractFromSlug } from 'web/lib/firebase/contracts'
+import {
+ StateElectionMap,
+ StateElectionMarket,
+} from './usa-map/state-election-map'
+import { useState } from 'react'
+import { LoadingIndicator } from './loading-indicator'
+import { CPMMBinaryContract } from 'common/contract'
+
+export function MidtermsMaps(props: { mapType: string }) {
+ const { mapType } = props
+ const [contracts, setContracts] = useState(null)
+
+ useEffect(() => {
+ const getContracts = async () => {
+ if (props.mapType === 'senate') {
+ const senateContracts = await Promise.all(
+ senateMidterms.map((m) =>
+ getContractFromSlug(m.slug).then((c) => c ?? null)
+ )
+ )
+ setContracts(senateContracts as CPMMBinaryContract[])
+ } else if (props.mapType === 'governor') {
+ const governorContracts = await Promise.all(
+ governorMidterms.map((m) =>
+ getContractFromSlug(m.slug).then((c) => c ?? null)
+ )
+ )
+ setContracts(governorContracts as CPMMBinaryContract[])
+ }
+ }
+ getContracts()
+ }, [props.mapType, setContracts])
+
+ return contracts ? (
+
+ ) : (
+
+ )
+}
+
+const senateMidterms: StateElectionMarket[] = [
+ {
+ state: 'AZ',
+ creatorUsername: 'BTE',
+ slug: 'will-blake-masters-win-the-arizona',
+ isWinRepublican: true,
+ },
+ {
+ state: 'OH',
+ creatorUsername: 'BTE',
+ slug: 'will-jd-vance-win-the-ohio-senate-s',
+ isWinRepublican: true,
+ },
+ {
+ state: 'WI',
+ creatorUsername: 'BTE',
+ slug: 'will-ron-johnson-be-reelected-in-th',
+ isWinRepublican: true,
+ },
+ {
+ state: 'FL',
+ creatorUsername: 'BTE',
+ slug: 'will-marco-rubio-be-reelected-to-th',
+ isWinRepublican: true,
+ },
+ {
+ state: 'PA',
+ creatorUsername: 'MattP',
+ slug: 'will-dr-oz-be-elected-to-the-us-sen',
+ isWinRepublican: true,
+ },
+ {
+ state: 'GA',
+ creatorUsername: 'NcyRocks',
+ slug: 'will-a-democrat-win-the-2022-us-sen-3d2432ba6d79',
+ isWinRepublican: false,
+ },
+ {
+ state: 'NV',
+ creatorUsername: 'NcyRocks',
+ slug: 'will-a-democrat-win-the-2022-us-sen',
+ isWinRepublican: false,
+ },
+ {
+ state: 'NC',
+ creatorUsername: 'NcyRocks',
+ slug: 'will-a-democrat-win-the-2022-us-sen-6f1a901e1fcf',
+ isWinRepublican: false,
+ },
+ {
+ state: 'NH',
+ creatorUsername: 'NcyRocks',
+ slug: 'will-a-democrat-win-the-2022-us-sen-23194a72f1b7',
+ isWinRepublican: false,
+ },
+ {
+ state: 'UT',
+ creatorUsername: 'SG',
+ slug: 'will-mike-lee-win-the-2022-utah-sen',
+ isWinRepublican: true,
+ },
+ {
+ state: 'CO',
+ creatorUsername: 'SG',
+ slug: 'will-michael-bennet-win-the-2022-co',
+ isWinRepublican: false,
+ },
+]
+
+const governorMidterms: StateElectionMarket[] = [
+ {
+ state: 'TX',
+ creatorUsername: 'LarsDoucet',
+ slug: 'republicans-will-win-the-2022-texas',
+ isWinRepublican: true,
+ },
+ {
+ state: 'GA',
+ creatorUsername: 'MattP',
+ slug: 'will-stacey-abrams-win-the-2022-geo',
+ isWinRepublican: false,
+ },
+ {
+ state: 'FL',
+ creatorUsername: 'Tetraspace',
+ slug: 'if-charlie-crist-is-the-democratic',
+ isWinRepublican: false,
+ },
+ {
+ state: 'PA',
+ creatorUsername: 'JonathanMast',
+ slug: 'will-josh-shapiro-win-the-2022-penn',
+ isWinRepublican: false,
+ },
+ {
+ state: 'PA',
+ creatorUsername: 'JonathanMast',
+ slug: 'will-josh-shapiro-win-the-2022-penn',
+ isWinRepublican: false,
+ },
+ {
+ state: 'CO',
+ creatorUsername: 'ScottLawrence',
+ slug: 'will-jared-polis-be-reelected-as-co',
+ isWinRepublican: false,
+ },
+ {
+ state: 'OR',
+ creatorUsername: 'Tetraspace',
+ slug: 'if-tina-kotek-is-the-2022-democrati',
+ isWinRepublican: false,
+ },
+ {
+ state: 'MD',
+ creatorUsername: 'Tetraspace',
+ slug: 'if-wes-moore-is-the-2022-democratic',
+ isWinRepublican: false,
+ },
+ {
+ state: 'AK',
+ creatorUsername: 'SG',
+ slug: 'will-a-republican-win-the-2022-alas',
+ isWinRepublican: true,
+ },
+ {
+ state: 'AZ',
+ creatorUsername: 'SG',
+ slug: 'will-a-republican-win-the-2022-ariz',
+ isWinRepublican: true,
+ },
+ {
+ state: 'AZ',
+ creatorUsername: 'SG',
+ slug: 'will-a-republican-win-the-2022-ariz',
+ isWinRepublican: true,
+ },
+ {
+ state: 'WI',
+ creatorUsername: 'SG',
+ slug: 'will-a-democrat-win-the-2022-wiscon',
+ isWinRepublican: false,
+ },
+ {
+ state: 'NV',
+ creatorUsername: 'SG',
+ slug: 'will-a-democrat-win-the-2022-nevada',
+ isWinRepublican: false,
+ },
+ {
+ state: 'KS',
+ creatorUsername: 'SG',
+ slug: 'will-a-democrat-win-the-2022-kansas',
+ isWinRepublican: false,
+ },
+ {
+ state: 'NV',
+ creatorUsername: 'SG',
+ slug: 'will-a-democrat-win-the-2022-new-me',
+ isWinRepublican: false,
+ },
+ {
+ state: 'ME',
+ creatorUsername: 'SG',
+ slug: 'will-a-democrat-win-the-2022-maine',
+ isWinRepublican: false,
+ },
+]
diff --git a/web/components/static-react-embed.tsx b/web/components/static-react-embed.tsx
new file mode 100644
index 00000000..afc18e79
--- /dev/null
+++ b/web/components/static-react-embed.tsx
@@ -0,0 +1,20 @@
+import { useState, useEffect } from 'react'
+import { MidtermsMaps } from './midterms-maps'
+
+export function StaticReactEmbed(props: { embedName: string }) {
+ const { embedName } = props
+ const [embed, setEmbed] = useState(null)
+
+ useEffect(() => {
+ const governorMidtermsMap =
+ const senateMidtermsMap =
+
+ if (embedName === 'governor-midterms-map') {
+ setEmbed(governorMidtermsMap)
+ } else if (embedName === 'senate-midterms-map') {
+ setEmbed(senateMidtermsMap)
+ }
+ }, [embedName, setEmbed])
+
+ return {embed}
+}