From 84296bfdde82cb63923d101f61845c8007f9fdc8 Mon Sep 17 00:00:00 2001 From: mantikoros Date: Fri, 10 Dec 2021 00:43:19 -0600 Subject: [PATCH 1/4] update landing page with new idea --- web/components/header.tsx | 2 +- web/components/hero.tsx | 3 +-- web/package-lock.json | 8 ++++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/web/components/header.tsx b/web/components/header.tsx index 8b1a5ded..f36b3a39 100644 --- a/web/components/header.tsx +++ b/web/components/header.tsx @@ -6,7 +6,7 @@ import { firebaseLogin } from '../lib/firebase/users' const navigation = [ { name: 'About', - href: 'https://mantic.notion.site/About-Mantic-Markets-09bdde9044614e62a27477b4b1bf77ea', + href: 'https://mantic.notion.site/About-Mantic-Markets-46a1a0fb6e294011a8b6b582e276359f', }, { name: 'Simulator', href: '/simulator' }, ] diff --git a/web/components/hero.tsx b/web/components/hero.tsx index e218d696..27e4f7f2 100644 --- a/web/components/hero.tsx +++ b/web/components/hero.tsx @@ -18,8 +18,7 @@ export const Hero = () => {

- Create and resolve your own prediction markets to earn a - percent of the bet volume. Powered by Solana. + Forecast the future with play-money prediction markets for you and your community

diff --git a/web/package-lock.json b/web/package-lock.json index 43009849..db44421e 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -8,12 +8,12 @@ "dependencies": { "@headlessui/react": "1.4.2", "@heroicons/react": "1.0.5", - "chart.js": "^3.6.1", - "daisyui": "^1.16.2", - "firebase": "^9.6.0", + "chart.js": "3.6.1", + "daisyui": "1.16.2", + "firebase": "9.6.0", "next": "12.0.4", "react": "17.0.2", - "react-chartjs-2": "^4.0.0", + "react-chartjs-2": "4.0.0", "react-dom": "17.0.2" }, "devDependencies": { From 48a249eaa9eae81d930e70b0cf2e87ff94c0ca1d Mon Sep 17 00:00:00 2001 From: James Grugett Date: Fri, 10 Dec 2021 08:56:17 -0600 Subject: [PATCH 2/4] Contract page (#5) * Add Firestore package and config * Upload basic Firebase Auth code * Basic ability to sign in and view profile * Move html head content to Next's _document * Apply dark theme to all DaisyUI components * Add contract page * Smaller width bet input * Add some buttons * Add Row, Col, and Spacer components * Implement skeleton ContractPage * Apply dark theme to all DaisyUI components * Fix hooks lints (#3) * Add background to bet panel * Changes based on review comments Co-authored-by: Austin Chen --- web/components/bet-panel.tsx | 52 ++++++++++++++++++++++ web/components/contract-overview.tsx | 64 +++++++++++++++++++++++++++ web/components/layout/col.tsx | 5 +++ web/components/layout/row.tsx | 5 +++ web/components/layout/spacer.tsx | 8 ++++ web/components/yes-no-selector.tsx | 66 ++++++++++++++++++++++++++++ web/lib/firebase/contracts.ts | 3 ++ web/pages/contract/[contractId].tsx | 25 +++++++---- web/pages/simulator/index.tsx | 1 + 9 files changed, 221 insertions(+), 8 deletions(-) create mode 100644 web/components/bet-panel.tsx create mode 100644 web/components/contract-overview.tsx create mode 100644 web/components/layout/col.tsx create mode 100644 web/components/layout/row.tsx create mode 100644 web/components/layout/spacer.tsx create mode 100644 web/components/yes-no-selector.tsx diff --git a/web/components/bet-panel.tsx b/web/components/bet-panel.tsx new file mode 100644 index 00000000..565a5219 --- /dev/null +++ b/web/components/bet-panel.tsx @@ -0,0 +1,52 @@ +import React, { useState } from 'react' +import { Contract } from '../lib/firebase/contracts' +import { Col } from './layout/col' +import { Spacer } from './layout/spacer' +import { YesNoSelector } from './yes-no-selector' + +export function BetPanel(props: { contract: Contract; className?: string }) { + const { contract, className } = props + + const [betChoice, setBetChoice] = useState<'YES' | 'NO'>('YES') + const [shares, setShares] = useState(0) + + return ( + +
Pick outcome
+ + + + +
Shares
+
+ setShares(parseInt(e.target.value) || 0)} + onFocus={(e) => e.target.select()} + /> +
+ + + +
Price
+
+ {shares * (betChoice === 'YES' ? 57 : 43)} points +
+ + + + {shares !== 0 && ( + + )} + + ) +} diff --git a/web/components/contract-overview.tsx b/web/components/contract-overview.tsx new file mode 100644 index 00000000..543aa98a --- /dev/null +++ b/web/components/contract-overview.tsx @@ -0,0 +1,64 @@ +import React from 'react' +import { Line } from 'react-chartjs-2' +import { + CategoryScale, + Chart, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + Legend, +} from 'chart.js' +import { Contract } from '../lib/firebase/contracts' +import { Col } from './layout/col' +import { Row } from './layout/row' +import { Spacer } from './layout/spacer' + +// Auto import doesn't work for some reason... +// So we manually register ChartJS components instead: +Chart.register( + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + Legend +) +const chartData = { + labels: Array.from({ length: 0 }, (_, i) => i + 1), + datasets: [ + { + label: 'Implied probability', + data: [], + borderColor: 'rgb(75, 192, 192)', + }, + ], +} + +export const ContractOverview = (props: { contract: Contract }) => { + const { contract } = props + + return ( + +
{contract.question}
+ + +
By {contract.creatorName}
+
+
Dec 9
+
+
200,000 volume
+
+ + + + + + + +
{contract.description}
+ + ) +} diff --git a/web/components/layout/col.tsx b/web/components/layout/col.tsx new file mode 100644 index 00000000..da71f130 --- /dev/null +++ b/web/components/layout/col.tsx @@ -0,0 +1,5 @@ +export function Col(props: { children?: any; className?: string }) { + const { children, className } = props + + return
{children}
+} diff --git a/web/components/layout/row.tsx b/web/components/layout/row.tsx new file mode 100644 index 00000000..4faaeb6c --- /dev/null +++ b/web/components/layout/row.tsx @@ -0,0 +1,5 @@ +export function Row(props: { children?: any; className?: string }) { + const { children, className } = props + + return
{children}
+} diff --git a/web/components/layout/spacer.tsx b/web/components/layout/spacer.tsx new file mode 100644 index 00000000..04a9b0d7 --- /dev/null +++ b/web/components/layout/spacer.tsx @@ -0,0 +1,8 @@ +export function Spacer(props: { w?: number; h?: number }) { + const { w, h } = props + + const width = w === undefined ? undefined : w * 0.25 + 'rem' + const height = h === undefined ? undefined : h * 0.25 + 'rem' + + return
+} diff --git a/web/components/yes-no-selector.tsx b/web/components/yes-no-selector.tsx new file mode 100644 index 00000000..632e5b54 --- /dev/null +++ b/web/components/yes-no-selector.tsx @@ -0,0 +1,66 @@ +import React from 'react' +import { Row } from './layout/row' + +export function YesNoSelector(props: { + selected: 'YES' | 'NO' + onSelect: (selected: 'YES' | 'NO') => void + yesLabel?: string + noLabel?: string + className?: string +}) { + const { selected, onSelect, yesLabel, noLabel, className } = props + + return ( + + + + + + ) +} + +function Button(props: { + className?: string + onClick?: () => void + color: 'green' | 'red' | 'deemphasized' + hideFocusRing?: boolean + children?: any +}) { + const { className, onClick, children, color, hideFocusRing } = props + + return ( + + ) +} + +function classNames(...classes: any[]) { + return classes.filter(Boolean).join(' ') +} diff --git a/web/lib/firebase/contracts.ts b/web/lib/firebase/contracts.ts index 42166817..87d49c04 100644 --- a/web/lib/firebase/contracts.ts +++ b/web/lib/firebase/contracts.ts @@ -3,7 +3,10 @@ import { db } from './init' export type Contract = { id: string + creatorId: string + creatorName: string question: string + description: string } const contractCollection = collection(db, 'contracts') diff --git a/web/pages/contract/[contractId].tsx b/web/pages/contract/[contractId].tsx index 4b34715a..610b9959 100644 --- a/web/pages/contract/[contractId].tsx +++ b/web/pages/contract/[contractId].tsx @@ -1,27 +1,36 @@ +import React from 'react' import { useRouter } from 'next/router' import { useContract } from '../../hooks/use-contract' -import { useUser } from '../../hooks/use-user' +import { Header } from '../../components/header' +import { Row } from '../../components/layout/row' +import { ContractOverview } from '../../components/contract-overview' +import { BetPanel } from '../../components/bet-panel' export default function ContractPage() { - const user = useUser() - const router = useRouter() const { contractId } = router.query as { contractId: string } const contract = useContract(contractId) if (contract === 'loading') { - return
Loading...
+ return
} - if (contract === null) { + if (!contract) { return
Contract not found...
} return ( -
-
{contract.id}
-
{contract.question}
+
+
+ +
+ + + + + +
) } diff --git a/web/pages/simulator/index.tsx b/web/pages/simulator/index.tsx index 6e562bbc..5f57f49d 100644 --- a/web/pages/simulator/index.tsx +++ b/web/pages/simulator/index.tsx @@ -199,6 +199,7 @@ function NewBidTable(props: { type="number" placeholder="0" className="input input-bordered" + style={{ maxWidth: 100 }} value={newBid} onChange={(e) => setNewBid(parseInt(e.target.value) || 0)} onKeyUp={(e) => { From ae8f7b76f5d227ffe482448cb0ec19e5cf5e3425 Mon Sep 17 00:00:00 2001 From: jahooma Date: Fri, 10 Dec 2021 09:51:48 -0600 Subject: [PATCH 3/4] Change from inputing shares to a points amount. Show average price and estimated winnings. --- web/components/bet-panel.tsx | 40 +++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/web/components/bet-panel.tsx b/web/components/bet-panel.tsx index 565a5219..36c1f83d 100644 --- a/web/components/bet-panel.tsx +++ b/web/components/bet-panel.tsx @@ -1,6 +1,7 @@ import React, { useState } from 'react' import { Contract } from '../lib/firebase/contracts' import { Col } from './layout/col' +import { Row } from './layout/row' import { Spacer } from './layout/spacer' import { YesNoSelector } from './yes-no-selector' @@ -8,7 +9,7 @@ export function BetPanel(props: { contract: Contract; className?: string }) { const { contract, className } = props const [betChoice, setBetChoice] = useState<'YES' | 'NO'>('YES') - const [shares, setShares] = useState(0) + const [betAmount, setBetAmount] = useState(undefined) return ( @@ -23,29 +24,40 @@ export function BetPanel(props: { contract: Contract; className?: string }) { -
Shares
-
+
Bet amount
+ setShares(parseInt(e.target.value) || 0)} + placeholder="0" + value={betAmount} + onChange={(e) => setBetAmount(parseInt(e.target.value) || 0)} onFocus={(e) => e.target.select()} /> -
+
points
+ - + {!!betAmount && ( + <> + -
Price
-
- {shares * (betChoice === 'YES' ? 57 : 43)} points -
+
Average price
+
+ {betChoice === 'YES' ? 0.57 : 0.43} points +
- + - {shares !== 0 && ( - +
Estimated winnings
+
+ {Math.floor(betAmount / (betChoice === 'YES' ? 0.57 : 0.43))} points +
+ + + + + )} ) From f602561323092cd750b5cf141b34cb8a7c140c32 Mon Sep 17 00:00:00 2001 From: jahooma Date: Fri, 10 Dec 2021 10:04:59 -0600 Subject: [PATCH 4/4] Tweak bet input to let you clear 0. --- web/components/bet-panel.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/web/components/bet-panel.tsx b/web/components/bet-panel.tsx index 36c1f83d..7b1bd550 100644 --- a/web/components/bet-panel.tsx +++ b/web/components/bet-panel.tsx @@ -11,6 +11,11 @@ export function BetPanel(props: { contract: Contract; className?: string }) { const [betChoice, setBetChoice] = useState<'YES' | 'NO'>('YES') const [betAmount, setBetAmount] = useState(undefined) + function onBetChange(str: string) { + const amount = parseInt(str) + setBetAmount(isNaN(amount) ? undefined : amount) + } + return (
Pick outcome
@@ -31,9 +36,8 @@ export function BetPanel(props: { contract: Contract; className?: string }) { style={{ maxWidth: 80 }} type="text" placeholder="0" - value={betAmount} - onChange={(e) => setBetAmount(parseInt(e.target.value) || 0)} - onFocus={(e) => e.target.select()} + value={betAmount ?? ''} + onChange={(e) => onBetChange(e.target.value)} />
points