Merge branch 'main' into notifications
This commit is contained in:
commit
63bdc2c2f5
|
@ -116,7 +116,7 @@ export function getFreeAnswerAnte(
|
|||
}
|
||||
|
||||
export function getNumericAnte(
|
||||
creator: User,
|
||||
anteBettorId: string,
|
||||
contract: FullContract<DPM, Numeric>,
|
||||
ante: number,
|
||||
newBetId: string
|
||||
|
@ -136,7 +136,7 @@ export function getNumericAnte(
|
|||
|
||||
const anteBet: NumericBet = {
|
||||
id: newBetId,
|
||||
userId: creator.id,
|
||||
userId: anteBettorId,
|
||||
contractId: contract.id,
|
||||
amount: ante,
|
||||
allBetAmounts,
|
||||
|
|
|
@ -131,9 +131,13 @@ export function getContractBetMetrics(contract: Contract, yourBets: Bet[]) {
|
|||
let loan = 0
|
||||
let saleValue = 0
|
||||
let redeemed = 0
|
||||
const totalShares: { [outcome: string]: number } = {}
|
||||
|
||||
for (const bet of yourBets) {
|
||||
const { isSold, sale, amount, loanAmount, isRedemption } = bet
|
||||
const { isSold, sale, amount, loanAmount, isRedemption, shares, outcome } =
|
||||
bet
|
||||
totalShares[outcome] = (totalShares[outcome] ?? 0) + shares
|
||||
|
||||
if (isSold) {
|
||||
totalInvested += amount
|
||||
} else if (sale) {
|
||||
|
@ -165,6 +169,7 @@ export function getContractBetMetrics(contract: Contract, yourBets: Bet[]) {
|
|||
netPayout,
|
||||
profit,
|
||||
profitPercent,
|
||||
totalShares,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,6 +180,7 @@ export function getContractBetNullMetrics() {
|
|||
netPayout: 0,
|
||||
profit: 0,
|
||||
profitPercent: 0,
|
||||
totalShares: {} as { [outcome: string]: number },
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -170,7 +170,7 @@ export const createContract = newEndpoint(['POST'], async (req, [user, _]) => {
|
|||
.doc()
|
||||
|
||||
const anteBet = getNumericAnte(
|
||||
user,
|
||||
providerId,
|
||||
contract as FullContract<DPM, Numeric>,
|
||||
ante,
|
||||
anteBetDoc.id
|
||||
|
|
|
@ -125,13 +125,13 @@ export function BetsList(props: { user: User }) {
|
|||
.filter((c) => {
|
||||
if (filter === 'all') return true
|
||||
|
||||
const metrics = contractsMetrics[c.id]
|
||||
const { totalShares } = contractsMetrics[c.id]
|
||||
const hasSoldAll = Object.values(totalShares).every(
|
||||
(shares) => shares === 0
|
||||
)
|
||||
|
||||
// Filter for contracts you sold out of.
|
||||
if (filter === 'sold') return metrics.payout === 0
|
||||
|
||||
// Filter for contracts where you currently have shares.
|
||||
return metrics.payout > 0
|
||||
if (filter === 'sold') return hasSoldAll
|
||||
return !hasSoldAll
|
||||
})
|
||||
|
||||
const [settled, unsettled] = partition(
|
||||
|
|
|
@ -28,6 +28,7 @@ import { AvatarDetails, MiscDetails } from './contract-details'
|
|||
import { getExpectedValue, getValueFromBucket } from 'common/calculate-dpm'
|
||||
import { QuickBet, ProbBar, getColor } from './quick-bet'
|
||||
import { useContractWithPreload } from 'web/hooks/use-contract'
|
||||
import { useUser } from 'web/hooks/use-user'
|
||||
|
||||
export function ContractCard(props: {
|
||||
contract: Contract
|
||||
|
@ -40,10 +41,16 @@ export function ContractCard(props: {
|
|||
const { question, outcomeType } = contract
|
||||
const { resolution } = contract
|
||||
|
||||
const marketClosed = (contract.closeTime || Infinity) < Date.now()
|
||||
const user = useUser()
|
||||
|
||||
const marketClosed =
|
||||
(contract.closeTime || Infinity) < Date.now() || !!resolution
|
||||
|
||||
const showQuickBet = !(
|
||||
!user ||
|
||||
marketClosed ||
|
||||
(outcomeType === 'FREE_RESPONSE' && getTopAnswer(contract) === undefined)
|
||||
(outcomeType === 'FREE_RESPONSE' && getTopAnswer(contract) === undefined) ||
|
||||
outcomeType === 'NUMERIC'
|
||||
)
|
||||
|
||||
return (
|
||||
|
@ -96,7 +103,7 @@ export function ContractCard(props: {
|
|||
/>
|
||||
</Col>
|
||||
{showQuickBet ? (
|
||||
<QuickBet contract={contract} />
|
||||
<QuickBet contract={contract} user={user} />
|
||||
) : (
|
||||
<Col className="m-auto pl-2">
|
||||
{outcomeType === 'BINARY' && (
|
||||
|
|
|
@ -19,7 +19,7 @@ export function ContractsGrid(props: {
|
|||
const isBottomVisible = useIsVisible(elem)
|
||||
|
||||
useEffect(() => {
|
||||
if (isBottomVisible) {
|
||||
if (isBottomVisible && hasMore) {
|
||||
loadMore()
|
||||
}
|
||||
}, [isBottomVisible, hasMore, loadMore])
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
NumericContract,
|
||||
FreeResponseContract,
|
||||
} from 'common/contract'
|
||||
import { User } from 'common/user'
|
||||
import {
|
||||
formatLargeNumber,
|
||||
formatMoney,
|
||||
|
@ -21,7 +22,6 @@ import {
|
|||
} from 'common/util/format'
|
||||
import { useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
import { useUser } from 'web/hooks/use-user'
|
||||
import { useUserContractBets } from 'web/hooks/use-user-bets'
|
||||
import { placeBet } from 'web/lib/firebase/api-call'
|
||||
import { getBinaryProb, getBinaryProbPercent } from 'web/lib/firebase/contracts'
|
||||
|
@ -33,11 +33,10 @@ import { useSaveShares } from '../use-save-shares'
|
|||
|
||||
const BET_SIZE = 10
|
||||
|
||||
export function QuickBet(props: { contract: Contract }) {
|
||||
const { contract } = props
|
||||
export function QuickBet(props: { contract: Contract; user: User }) {
|
||||
const { contract, user } = props
|
||||
|
||||
const user = useUser()
|
||||
const userBets = useUserContractBets(user?.id, contract.id)
|
||||
const userBets = useUserContractBets(user.id, contract.id)
|
||||
const topAnswer =
|
||||
contract.outcomeType === 'FREE_RESPONSE'
|
||||
? getTopAnswer(contract as FreeResponseContract)
|
||||
|
|
|
@ -479,9 +479,7 @@ export function getRecentContractActivityItems(
|
|||
}
|
||||
) {
|
||||
const { contractPath } = options
|
||||
bets = bets
|
||||
.filter((bet) => !bet.isRedemption)
|
||||
.sort((b1, b2) => b1.createdTime - b2.createdTime)
|
||||
bets = bets.sort((b1, b2) => b1.createdTime - b2.createdTime)
|
||||
comments = comments.sort((c1, c2) => c1.createdTime - c2.createdTime)
|
||||
|
||||
const questionItem: QuestionItem = {
|
||||
|
|
|
@ -39,7 +39,7 @@ export function ContractActivity(props: {
|
|||
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
const updatedBets = mode === 'only-recent' ? undefined : useBets(contract.id)
|
||||
const bets = updatedBets ?? props.bets
|
||||
const bets = (updatedBets ?? props.bets).filter((bet) => !bet.isRedemption)
|
||||
|
||||
const items =
|
||||
mode === 'only-recent'
|
||||
|
|
|
@ -16,6 +16,7 @@ import { Avatar } from '../avatar'
|
|||
import clsx from 'clsx'
|
||||
import { useRouter } from 'next/router'
|
||||
import NotificationsIcon from 'web/components/notifications-icon'
|
||||
import { useIsIframe } from 'web/hooks/use-is-iframe'
|
||||
|
||||
function getNavigation(username: string) {
|
||||
return [
|
||||
|
@ -47,6 +48,11 @@ export function BottomNavBar() {
|
|||
|
||||
const user = useUser()
|
||||
|
||||
const isIframe = useIsIframe()
|
||||
if (isIframe) {
|
||||
return null
|
||||
}
|
||||
|
||||
const navigationOptions =
|
||||
user === null
|
||||
? signedOutNavigation
|
||||
|
|
|
@ -4,29 +4,6 @@ import { formatMoney } from 'common/util/format'
|
|||
import { Avatar } from '../avatar'
|
||||
import { IS_PRIVATE_MANIFOLD } from 'common/envs/constants'
|
||||
|
||||
export function getNavigationOptions(user?: User | null) {
|
||||
if (IS_PRIVATE_MANIFOLD) {
|
||||
return [{ name: 'Leaderboards', href: '/leaderboards' }]
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
return [
|
||||
{ name: 'Leaderboards', href: '/leaderboards' },
|
||||
{ name: 'Discord', href: 'https://discord.gg/eHQBNBqXuh' },
|
||||
{ name: 'Twitter', href: 'https://twitter.com/ManifoldMarkets' },
|
||||
]
|
||||
}
|
||||
|
||||
return [
|
||||
{ name: 'Add funds', href: '/add-funds' },
|
||||
{ name: 'Leaderboards', href: '/leaderboards' },
|
||||
{ name: 'Discord', href: 'https://discord.gg/eHQBNBqXuh' },
|
||||
{ name: 'Twitter', href: 'https://twitter.com/ManifoldMarkets' },
|
||||
{ name: 'About', href: 'https://docs.manifold.markets' },
|
||||
{ name: 'Sign out', href: '#', onClick: () => firebaseLogout() },
|
||||
]
|
||||
}
|
||||
|
||||
export function ProfileSummary(props: { user: User }) {
|
||||
const { user } = props
|
||||
return (
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
PresentationChartLineIcon,
|
||||
ChatAltIcon,
|
||||
SparklesIcon,
|
||||
NewspaperIcon,
|
||||
} from '@heroicons/react/outline'
|
||||
import clsx from 'clsx'
|
||||
import { sortBy } from 'lodash'
|
||||
|
@ -16,17 +17,18 @@ import Link from 'next/link'
|
|||
import { useRouter } from 'next/router'
|
||||
import { useFollowedFolds } from 'web/hooks/use-fold'
|
||||
import { useUser } from 'web/hooks/use-user'
|
||||
import { firebaseLogin, firebaseLogout } from 'web/lib/firebase/users'
|
||||
import { firebaseLogin, firebaseLogout, User } from 'web/lib/firebase/users'
|
||||
import { ManifoldLogo } from './manifold-logo'
|
||||
import { MenuButton } from './menu'
|
||||
import { getNavigationOptions, ProfileSummary } from './profile-menu'
|
||||
import { ProfileSummary } from './profile-menu'
|
||||
import {
|
||||
getUtcFreeMarketResetTime,
|
||||
useHasCreatedContractToday,
|
||||
} from 'web/hooks/use-has-created-contract-today'
|
||||
import { Row } from '../layout/row'
|
||||
import { useEffect, useState } from 'react'
|
||||
import NotificationsIcon from 'web/components/notifications-icon'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { IS_PRIVATE_MANIFOLD } from 'common/envs/constants'
|
||||
|
||||
// Create an icon from the url of an image
|
||||
function IconFromUrl(url: string): React.ComponentType<{ className?: string }> {
|
||||
|
@ -53,6 +55,30 @@ function getNavigation(username: string) {
|
|||
]
|
||||
}
|
||||
|
||||
function getMoreNavigation(user?: User | null) {
|
||||
if (IS_PRIVATE_MANIFOLD) {
|
||||
return [{ name: 'Leaderboards', href: '/leaderboards' }]
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
return [
|
||||
{ name: 'Leaderboards', href: '/leaderboards' },
|
||||
{ name: 'Discord', href: 'https://discord.gg/eHQBNBqXuh' },
|
||||
{ name: 'Twitter', href: 'https://twitter.com/ManifoldMarkets' },
|
||||
]
|
||||
}
|
||||
|
||||
return [
|
||||
{ name: 'Add funds', href: '/add-funds' },
|
||||
{ name: 'Leaderboards', href: '/leaderboards' },
|
||||
{ name: 'Blog', href: 'https://news.manifold.markets' },
|
||||
{ name: 'Discord', href: 'https://discord.gg/eHQBNBqXuh' },
|
||||
{ name: 'Twitter', href: 'https://twitter.com/ManifoldMarkets' },
|
||||
{ name: 'About', href: 'https://docs.manifold.markets' },
|
||||
{ name: 'Sign out', href: '#', onClick: () => firebaseLogout() },
|
||||
]
|
||||
}
|
||||
|
||||
const signedOutNavigation = [
|
||||
{ name: 'Home', href: '/home', icon: HomeIcon },
|
||||
{ name: 'Explore', href: '/markets', icon: SearchIcon },
|
||||
|
@ -63,6 +89,7 @@ const signedOutNavigation = [
|
|||
const signedOutMobileNavigation = [
|
||||
{ name: 'Charity', href: '/charity', icon: HeartIcon },
|
||||
{ name: 'Leaderboards', href: '/leaderboards', icon: CakeIcon },
|
||||
{ name: 'Blog', href: 'https://news.manifold.markets', icon: NewspaperIcon },
|
||||
{
|
||||
name: 'Discord',
|
||||
href: 'https://discord.gg/eHQBNBqXuh',
|
||||
|
@ -199,7 +226,7 @@ export default function Sidebar(props: { className?: string }) {
|
|||
))}
|
||||
|
||||
<MenuButton
|
||||
menuItems={getNavigationOptions(user)}
|
||||
menuItems={getMoreNavigation(user)}
|
||||
buttonContent={<MoreButton />}
|
||||
/>
|
||||
</div>
|
||||
|
@ -208,7 +235,7 @@ export default function Sidebar(props: { className?: string }) {
|
|||
{user ? (
|
||||
<Link href={'/create'} passHref>
|
||||
<button className={clsx(gradient, buttonStyle)}>
|
||||
Ask a question
|
||||
Create a question
|
||||
</button>
|
||||
</Link>
|
||||
) : (
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "concurrently -n NEXT,TS -c magenta,cyan \"next dev -p 3000\" \"yarn ts --watch\"",
|
||||
"devdev": "NEXT_PUBLIC_FIREBASE_ENV=DEV concurrently -n NEXT,TS -c magenta,cyan \"FIREBASE_ENV=DEV next dev -p 3000\" \"FIREBASE_ENV=DEV yarn ts --watch\" # see https://github.com/vercel/next.js/discussions/33634",
|
||||
"devdev": "cross-env NEXT_PUBLIC_FIREBASE_ENV=DEV concurrently -n NEXT,TS -c magenta,cyan \"cross-env FIREBASE_ENV=DEV next dev -p 3000\" \"cross-env FIREBASE_ENV=DEV yarn ts --watch\"",
|
||||
"dev:dev": "yarn devdev",
|
||||
"dev:the": "NEXT_PUBLIC_FIREBASE_ENV=THEOREMONE concurrently -n NEXT,TS -c magenta,cyan \"FIREBASE_ENV=THEOREMONE next dev -p 3000\" \"FIREBASE_ENV=THEOREMONE yarn ts --watch\"",
|
||||
"dev:emulate": "NEXT_PUBLIC_FIREBASE_EMULATE=TRUE yarn devdev",
|
||||
"dev:the": "cross-env NEXT_PUBLIC_FIREBASE_ENV=THEOREMONE concurrently -n NEXT,TS -c magenta,cyan \"cross-env FIREBASE_ENV=THEOREMONE next dev -p 3000\" \"cross-env FIREBASE_ENV=THEOREMONE yarn ts --watch\"",
|
||||
"dev:emulate": "cross-env NEXT_PUBLIC_FIREBASE_EMULATE=TRUE yarn devdev",
|
||||
"ts": "tsc --noEmit --incremental --preserveWatchOutput --pretty",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
|
@ -48,6 +48,7 @@
|
|||
"autoprefixer": "10.2.6",
|
||||
"concurrently": "6.5.1",
|
||||
"critters": "0.0.16",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint-config-next": "12.1.6",
|
||||
"next-sitemap": "^2.5.14",
|
||||
"postcss": "8.3.5",
|
||||
|
|
|
@ -1828,7 +1828,14 @@ critters@0.0.16:
|
|||
postcss "^8.3.7"
|
||||
pretty-bytes "^5.3.0"
|
||||
|
||||
cross-spawn@^7.0.2:
|
||||
cross-env@^7.0.3:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
|
||||
integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
|
||||
dependencies:
|
||||
cross-spawn "^7.0.1"
|
||||
|
||||
cross-spawn@^7.0.1, cross-spawn@^7.0.2:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
||||
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
|
||||
|
|
Loading…
Reference in New Issue
Block a user