Compare commits
22 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
0f5401f82d | ||
|
d010ec17c0 | ||
|
f70308762f | ||
|
bd3cd5bfa3 | ||
|
6614833cb1 | ||
|
8d97eb6f63 | ||
|
14864a9f7e | ||
|
f4c7148e7e | ||
|
65f19ff56d | ||
|
39fe9f0acc | ||
|
26bb228e90 | ||
|
2dfe939656 | ||
|
f3233955e8 | ||
|
1f67d90f84 | ||
|
0c9f1b1745 | ||
|
fd7f7afabd | ||
|
e6df6bd53c | ||
|
7745851d4c | ||
|
a1368abd66 | ||
|
cd9f065be2 | ||
|
2661c76d23 | ||
|
eae5a70d52 |
|
@ -10,12 +10,9 @@ import {
|
||||||
import { User } from './user'
|
import { User } from './user'
|
||||||
import { LiquidityProvision } from './liquidity-provision'
|
import { LiquidityProvision } from './liquidity-provision'
|
||||||
import { noFees } from './fees'
|
import { noFees } from './fees'
|
||||||
|
import { ENV_CONFIG } from './envs/constants'
|
||||||
|
|
||||||
export const FIXED_ANTE = 100
|
export const FIXED_ANTE = ENV_CONFIG.fixedAnte ?? 10
|
||||||
|
|
||||||
// deprecated
|
|
||||||
export const PHANTOM_ANTE = 0.001
|
|
||||||
export const MINIMUM_ANTE = 50
|
|
||||||
|
|
||||||
export const HOUSE_LIQUIDITY_PROVIDER_ID = 'IPTOzEqrpkWmEzh6hwvAyY9PqFb2' // @ManifoldMarkets' id
|
export const HOUSE_LIQUIDITY_PROVIDER_ID = 'IPTOzEqrpkWmEzh6hwvAyY9PqFb2' // @ManifoldMarkets' id
|
||||||
|
|
||||||
|
|
35
common/envs/atlas.ts
Normal file
35
common/envs/atlas.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import { EnvConfig, PROD_CONFIG } from './prod'
|
||||||
|
|
||||||
|
export const ATLAS_CONFIG: EnvConfig = {
|
||||||
|
domain: 'atlas.manifold.markets',
|
||||||
|
firebaseConfig: {
|
||||||
|
apiKey: 'AIzaSyCQvm7AjL1NjULPaEYjAiUjiVhfXmHGh_w',
|
||||||
|
authDomain: 'atlas-manifold.firebaseapp.com',
|
||||||
|
projectId: 'atlas-manifold',
|
||||||
|
storageBucket: 'atlas-manifold.appspot.com',
|
||||||
|
messagingSenderId: '802386508975',
|
||||||
|
appId: '1:802386508975:web:1b1ff75deec469945ca85a',
|
||||||
|
measurementId: 'G-FR9SJTFF2K',
|
||||||
|
region: 'us-central1',
|
||||||
|
},
|
||||||
|
functionEndpoints: {
|
||||||
|
placebet: 'https://placebet-txwwmth7kq-uc.a.run.app',
|
||||||
|
sellshares: 'https://sellshares-txwwmth7kq-uc.a.run.app',
|
||||||
|
sellbet: 'https://sellbet-txwwmth7kq-uc.a.run.app',
|
||||||
|
createmarket: 'https://createmarket-txwwmth7kq-uc.a.run.app',
|
||||||
|
},
|
||||||
|
adminEmails: [...PROD_CONFIG.adminEmails],
|
||||||
|
whitelistEmail: '',
|
||||||
|
moneyMoniker: '📎',
|
||||||
|
fixedAnte: 25,
|
||||||
|
startingBalance: 500,
|
||||||
|
visibility: 'PRIVATE',
|
||||||
|
// faviconPath: '/atlas/atlas-favicon.png',
|
||||||
|
navbarLogoPath: '/atlas/atlas-logo-white.svg',
|
||||||
|
newQuestionPlaceholders: [
|
||||||
|
'Will we have at least 5 new team members by the end of this quarter?',
|
||||||
|
'Will we meet or exceed our goals this sprint?',
|
||||||
|
'Will we sign on 3 or more new clients this month?',
|
||||||
|
'Will Paul shave his beard by the end of the month?',
|
||||||
|
],
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import { escapeRegExp } from 'lodash'
|
import { escapeRegExp } from 'lodash'
|
||||||
|
import { ATLAS_CONFIG } from './atlas'
|
||||||
import { DEV_CONFIG } from './dev'
|
import { DEV_CONFIG } from './dev'
|
||||||
import { EnvConfig, PROD_CONFIG } from './prod'
|
import { EnvConfig, PROD_CONFIG } from './prod'
|
||||||
import { THEOREMONE_CONFIG } from './theoremone'
|
import { THEOREMONE_CONFIG } from './theoremone'
|
||||||
|
@ -9,6 +10,7 @@ const CONFIGS: { [env: string]: EnvConfig } = {
|
||||||
PROD: PROD_CONFIG,
|
PROD: PROD_CONFIG,
|
||||||
DEV: DEV_CONFIG,
|
DEV: DEV_CONFIG,
|
||||||
THEOREMONE: THEOREMONE_CONFIG,
|
THEOREMONE: THEOREMONE_CONFIG,
|
||||||
|
ATLAS: ATLAS_CONFIG,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ENV_CONFIG = CONFIGS[ENV]
|
export const ENV_CONFIG = CONFIGS[ENV]
|
||||||
|
|
|
@ -19,6 +19,10 @@ export type EnvConfig = {
|
||||||
faviconPath?: string // Should be a file in /public
|
faviconPath?: string // Should be a file in /public
|
||||||
navbarLogoPath?: string
|
navbarLogoPath?: string
|
||||||
newQuestionPlaceholders: string[]
|
newQuestionPlaceholders: string[]
|
||||||
|
|
||||||
|
// Currency controls
|
||||||
|
fixedAnte?: number
|
||||||
|
startingBalance?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
type FirebaseConfig = {
|
type FirebaseConfig = {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { ENV_CONFIG } from './envs/constants'
|
||||||
|
|
||||||
export type User = {
|
export type User = {
|
||||||
id: string
|
id: string
|
||||||
createdTime: number
|
createdTime: number
|
||||||
|
@ -21,8 +23,9 @@ export type User = {
|
||||||
followedCategories?: string[]
|
followedCategories?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const STARTING_BALANCE = 1000
|
export const STARTING_BALANCE = ENV_CONFIG.startingBalance ?? 1000
|
||||||
export const SUS_STARTING_BALANCE = 10 // for sus users, i.e. multiple sign ups for same person
|
// for sus users, i.e. multiple sign ups for same person
|
||||||
|
export const SUS_STARTING_BALANCE = ENV_CONFIG.startingBalance ?? 10
|
||||||
|
|
||||||
export type PrivateUser = {
|
export type PrivateUser = {
|
||||||
id: string // same as User.id
|
id: string // same as User.id
|
||||||
|
|
|
@ -7,9 +7,13 @@ const formatter = new Intl.NumberFormat('en-US', {
|
||||||
minimumFractionDigits: 0,
|
minimumFractionDigits: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// export function formatMoney(amount: number) {
|
||||||
|
// const newAmount = Math.round(amount) === 0 ? 0 : Math.floor(amount) // handle -0 case
|
||||||
|
// return ENV_CONFIG.moneyMoniker + formatter.format(newAmount).replace('$', '')
|
||||||
|
// }
|
||||||
|
|
||||||
export function formatMoney(amount: number) {
|
export function formatMoney(amount: number) {
|
||||||
const newAmount = Math.round(amount) === 0 ? 0 : Math.floor(amount) // handle -0 case
|
return ENV_CONFIG.moneyMoniker + amount.toFixed(1)
|
||||||
return ENV_CONFIG.moneyMoniker + formatter.format(newAmount).replace('$', '')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatWithCommas(amount: number) {
|
export function formatWithCommas(amount: number) {
|
||||||
|
|
|
@ -1,5 +1,69 @@
|
||||||
{
|
{
|
||||||
"indexes": [
|
"indexes": [
|
||||||
|
{
|
||||||
|
"collectionGroup": "bets",
|
||||||
|
"queryScope": "COLLECTION_GROUP",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "isAnte",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isRedemption",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "userId",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "createdTime",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collectionGroup": "bets",
|
||||||
|
"queryScope": "COLLECTION_GROUP",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "userId",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "createdTime",
|
||||||
|
"order": "DESCENDING"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collectionGroup": "comments",
|
||||||
|
"queryScope": "COLLECTION_GROUP",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "userId",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "createdTime",
|
||||||
|
"order": "DESCENDING"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collectionGroup": "contracts",
|
||||||
|
"queryScope": "COLLECTION",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "creatorId",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "createdTime",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"collectionGroup": "contracts",
|
"collectionGroup": "contracts",
|
||||||
"queryScope": "COLLECTION",
|
"queryScope": "COLLECTION",
|
||||||
|
@ -104,6 +168,24 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"collectionGroup": "contracts",
|
||||||
|
"queryScope": "COLLECTION",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "isResolved",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "visibility",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "volume7Days",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"collectionGroup": "contracts",
|
"collectionGroup": "contracts",
|
||||||
"queryScope": "COLLECTION",
|
"queryScope": "COLLECTION",
|
||||||
|
@ -118,6 +200,84 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"collectionGroup": "contracts",
|
||||||
|
"queryScope": "COLLECTION",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "isResolved",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "volume7Days",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collectionGroup": "contracts",
|
||||||
|
"queryScope": "COLLECTION",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "isResolved",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "volume7Days",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "closeTime",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collectionGroup": "contracts",
|
||||||
|
"queryScope": "COLLECTION",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "isResolved",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "volume7Days",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "createdTime",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collectionGroup": "contracts",
|
||||||
|
"queryScope": "COLLECTION",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "isResolved",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "volume7Days",
|
||||||
|
"order": "DESCENDING"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collectionGroup": "contracts",
|
||||||
|
"queryScope": "COLLECTION",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "lowercaseTags",
|
||||||
|
"arrayConfig": "CONTAINS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "createdTime",
|
||||||
|
"order": "DESCENDING"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"collectionGroup": "contracts",
|
"collectionGroup": "contracts",
|
||||||
"queryScope": "COLLECTION",
|
"queryScope": "COLLECTION",
|
||||||
|
@ -131,6 +291,24 @@
|
||||||
"order": "DESCENDING"
|
"order": "DESCENDING"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collectionGroup": "txns",
|
||||||
|
"queryScope": "COLLECTION",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "toId",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "toType",
|
||||||
|
"order": "ASCENDING"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "createdTime",
|
||||||
|
"order": "DESCENDING"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"fieldOverrides": [
|
"fieldOverrides": [
|
||||||
|
@ -295,6 +473,28 @@
|
||||||
"queryScope": "COLLECTION_GROUP"
|
"queryScope": "COLLECTION_GROUP"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collectionGroup": "follows",
|
||||||
|
"fieldPath": "userId",
|
||||||
|
"indexes": [
|
||||||
|
{
|
||||||
|
"order": "ASCENDING",
|
||||||
|
"queryScope": "COLLECTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"order": "DESCENDING",
|
||||||
|
"queryScope": "COLLECTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"arrayConfig": "CONTAINS",
|
||||||
|
"queryScope": "COLLECTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"order": "ASCENDING",
|
||||||
|
"queryScope": "COLLECTION_GROUP"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,5 +59,5 @@ Adapted from https://firebase.google.com/docs/functions/get-started
|
||||||
|
|
||||||
Secrets are strings that shouldn't be checked into Git (eg API keys, passwords). We store these using [Google Secret Manager](https://console.cloud.google.com/security/secret-manager), which provides them as environment variables to functions that require them. Some useful workflows:
|
Secrets are strings that shouldn't be checked into Git (eg API keys, passwords). We store these using [Google Secret Manager](https://console.cloud.google.com/security/secret-manager), which provides them as environment variables to functions that require them. Some useful workflows:
|
||||||
|
|
||||||
- Set a secret: `$ firebase functions:secrets:set stripe.test_secret="THE-API-KEY"`
|
|
||||||
- Read a secret: `$ firebase functions:secrets:access STRIPE_APIKEY`
|
- Read a secret: `$ firebase functions:secrets:access STRIPE_APIKEY`
|
||||||
|
- Set a secret: `$ firebase functions:secrets:set STRIPE_APIKEY`
|
||||||
|
|
|
@ -19,13 +19,14 @@ import { ContractsGrid } from './contract/contracts-list'
|
||||||
import { Row } from './layout/row'
|
import { Row } from './layout/row'
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { Spacer } from './layout/spacer'
|
import { Spacer } from './layout/spacer'
|
||||||
import { ENV } from 'common/envs/constants'
|
import { ENV, IS_PRIVATE_MANIFOLD } from 'common/envs/constants'
|
||||||
import { useUser } from 'web/hooks/use-user'
|
import { useUser } from 'web/hooks/use-user'
|
||||||
import { useFollows } from 'web/hooks/use-follows'
|
import { useFollows } from 'web/hooks/use-follows'
|
||||||
import { EditCategoriesButton } from './feed/category-selector'
|
import { EditCategoriesButton } from './feed/category-selector'
|
||||||
import { CATEGORIES } from 'common/categories'
|
import { CATEGORIES } from 'common/categories'
|
||||||
import { Tabs } from './layout/tabs'
|
import { Tabs } from './layout/tabs'
|
||||||
import { EditFollowingButton } from './following-button'
|
import { EditFollowingButton } from './following-button'
|
||||||
|
import ContractSearchFirestore from 'web/pages/contract-search-firestore'
|
||||||
|
|
||||||
const searchClient = algoliasearch(
|
const searchClient = algoliasearch(
|
||||||
'GJQPAYENIF',
|
'GJQPAYENIF',
|
||||||
|
@ -119,6 +120,10 @@ export function ContractSearch(props: {
|
||||||
|
|
||||||
const indexName = `${indexPrefix}contracts-${sort}`
|
const indexName = `${indexPrefix}contracts-${sort}`
|
||||||
|
|
||||||
|
if (IS_PRIVATE_MANIFOLD) {
|
||||||
|
return <ContractSearchFirestore querySortOptions={querySortOptions} />
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstantSearch searchClient={searchClient} indexName={indexName}>
|
<InstantSearch searchClient={searchClient} indexName={indexName}>
|
||||||
<Row className="gap-1 sm:gap-2">
|
<Row className="gap-1 sm:gap-2">
|
||||||
|
|
|
@ -25,7 +25,7 @@ import { useSaveShares } from '../use-save-shares'
|
||||||
import { sellShares } from 'web/lib/firebase/api-call'
|
import { sellShares } from 'web/lib/firebase/api-call'
|
||||||
import { calculateCpmmSale, getCpmmProbability } from 'common/calculate-cpmm'
|
import { calculateCpmmSale, getCpmmProbability } from 'common/calculate-cpmm'
|
||||||
|
|
||||||
const BET_SIZE = 10
|
const BET_SIZE = 1
|
||||||
|
|
||||||
export function QuickBet(props: { contract: Contract; user: User }) {
|
export function QuickBet(props: { contract: Contract; user: User }) {
|
||||||
const { contract, user } = props
|
const { contract, user } = props
|
||||||
|
@ -159,7 +159,7 @@ export function QuickBet(props: { contract: Contract; user: User }) {
|
||||||
onClick={() => placeQuickBet('UP')}
|
onClick={() => placeQuickBet('UP')}
|
||||||
/>
|
/>
|
||||||
<div className="mt-2 text-center text-xs text-transparent peer-hover:text-gray-400">
|
<div className="mt-2 text-center text-xs text-transparent peer-hover:text-gray-400">
|
||||||
{formatMoney(10)}
|
{formatMoney(BET_SIZE)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{hasUpShares > 0 ? (
|
{hasUpShares > 0 ? (
|
||||||
|
@ -213,7 +213,7 @@ export function QuickBet(props: { contract: Contract; user: User }) {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="mb-2 text-center text-xs text-transparent peer-hover:text-gray-400">
|
<div className="mb-2 text-center text-xs text-transparent peer-hover:text-gray-400">
|
||||||
{formatMoney(10)}
|
{formatMoney(BET_SIZE)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -17,16 +17,23 @@ export function ManifoldLogo(props: {
|
||||||
return (
|
return (
|
||||||
<Link href={user ? '/home' : '/'}>
|
<Link href={user ? '/home' : '/'}>
|
||||||
<a className={clsx('group flex flex-shrink-0 flex-row gap-4', className)}>
|
<a className={clsx('group flex flex-shrink-0 flex-row gap-4', className)}>
|
||||||
|
{!ENV_CONFIG.navbarLogoPath && (
|
||||||
<img
|
<img
|
||||||
className="transition-all group-hover:rotate-12"
|
className="transition-all group-hover:rotate-12"
|
||||||
src={darkBackground ? '/logo-white.svg' : '/logo.svg'}
|
src={darkBackground ? '/logo-white.svg' : '/logo.svg'}
|
||||||
width={45}
|
width={45}
|
||||||
height={45}
|
height={45}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{!hideText &&
|
{!hideText &&
|
||||||
(ENV_CONFIG.navbarLogoPath ? (
|
(ENV_CONFIG.navbarLogoPath ? (
|
||||||
<img src={ENV_CONFIG.navbarLogoPath} width={245} height={45} />
|
<img
|
||||||
|
className="rounded-md bg-gradient-to-r from-cyan-500 to-sky-600 p-2"
|
||||||
|
src={ENV_CONFIG.navbarLogoPath}
|
||||||
|
width={350}
|
||||||
|
height={80}
|
||||||
|
/>
|
||||||
) : twoLine ? (
|
) : twoLine ? (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
|
|
|
@ -48,7 +48,9 @@ function getNavigation(username: string) {
|
||||||
icon: NotificationsIcon,
|
icon: NotificationsIcon,
|
||||||
},
|
},
|
||||||
|
|
||||||
{ name: 'Get M$', href: '/add-funds', icon: CashIcon },
|
...(IS_PRIVATE_MANIFOLD
|
||||||
|
? []
|
||||||
|
: [{ name: 'Get M$', href: '/add-funds', icon: CashIcon }]),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +104,9 @@ const signedOutMobileNavigation = [
|
||||||
]
|
]
|
||||||
|
|
||||||
const mobileNavigation = [
|
const mobileNavigation = [
|
||||||
{ name: 'Get M$', href: '/add-funds', icon: CashIcon },
|
...(IS_PRIVATE_MANIFOLD
|
||||||
|
? []
|
||||||
|
: [{ name: 'Get M$', href: '/add-funds', icon: CashIcon }]),
|
||||||
...signedOutMobileNavigation,
|
...signedOutMobileNavigation,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
"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\"",
|
"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:dev": "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: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:atlas": "cross-env NEXT_PUBLIC_FIREBASE_ENV=ATLAS concurrently -n NEXT,TS -c magenta,cyan \"cross-env FIREBASE_ENV=ATLAS next dev -p 3000\" \"cross-env FIREBASE_ENV=ATLAS yarn ts --watch\"",
|
||||||
"dev:emulate": "cross-env NEXT_PUBLIC_FIREBASE_EMULATE=TRUE yarn devdev",
|
"dev:emulate": "cross-env NEXT_PUBLIC_FIREBASE_EMULATE=TRUE yarn devdev",
|
||||||
"ts": "tsc --noEmit --incremental --preserveWatchOutput --pretty",
|
"ts": "tsc --noEmit --incremental --preserveWatchOutput --pretty",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
|
|
101
web/pages/contract-search-firestore.tsx
Normal file
101
web/pages/contract-search-firestore.tsx
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
import { Answer } from 'common/answer'
|
||||||
|
import { sortBy } from 'lodash'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { ContractsGrid } from 'web/components/contract/contracts-list'
|
||||||
|
import { LoadingIndicator } from 'web/components/loading-indicator'
|
||||||
|
import { useContracts } from 'web/hooks/use-contracts'
|
||||||
|
import {
|
||||||
|
Sort,
|
||||||
|
useInitialQueryAndSort,
|
||||||
|
} from 'web/hooks/use-sort-and-query-params'
|
||||||
|
|
||||||
|
export default function ContractSearchFirestore(props: {
|
||||||
|
querySortOptions?: {
|
||||||
|
defaultSort: Sort
|
||||||
|
shouldLoadFromStorage?: boolean
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
const contracts = useContracts()
|
||||||
|
const { querySortOptions } = props
|
||||||
|
|
||||||
|
const { initialSort, initialQuery } = useInitialQueryAndSort(querySortOptions)
|
||||||
|
const [sort, setSort] = useState(initialSort || 'newest')
|
||||||
|
const [query, setQuery] = useState(initialQuery)
|
||||||
|
|
||||||
|
const queryWords = query.toLowerCase().split(' ')
|
||||||
|
function check(corpus: string) {
|
||||||
|
return queryWords.every((word) => corpus.toLowerCase().includes(word))
|
||||||
|
}
|
||||||
|
|
||||||
|
let matches = (contracts ?? []).filter(
|
||||||
|
(c) =>
|
||||||
|
check(c.question) ||
|
||||||
|
check(c.description) ||
|
||||||
|
check(c.creatorName) ||
|
||||||
|
check(c.creatorUsername) ||
|
||||||
|
check(c.lowercaseTags.map((tag) => `#${tag}`).join(' ')) ||
|
||||||
|
check(
|
||||||
|
((c as any).answers ?? [])
|
||||||
|
.map((answer: Answer) => answer.text)
|
||||||
|
.join(' ')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (sort === 'newest') {
|
||||||
|
matches.sort((a, b) => b.createdTime - a.createdTime)
|
||||||
|
} else if (sort === 'resolve-date') {
|
||||||
|
matches = sortBy(matches, (contract) => -1 * (contract.resolutionTime ?? 0))
|
||||||
|
} else if (sort === 'oldest') {
|
||||||
|
matches.sort((a, b) => a.createdTime - b.createdTime)
|
||||||
|
} else if (sort === 'close-date') {
|
||||||
|
matches = sortBy(matches, ({ volume24Hours }) => -1 * volume24Hours)
|
||||||
|
matches = sortBy(
|
||||||
|
matches,
|
||||||
|
(contract) =>
|
||||||
|
(sort === 'close-date' ? -1 : 1) * (contract.closeTime ?? Infinity)
|
||||||
|
)
|
||||||
|
} else if (sort === 'most-traded') {
|
||||||
|
matches.sort((a, b) => b.volume - a.volume)
|
||||||
|
} else if (sort === '24-hour-vol') {
|
||||||
|
// Use lodash for stable sort, so previous sort breaks all ties.
|
||||||
|
matches = sortBy(matches, ({ volume7Days }) => -1 * volume7Days)
|
||||||
|
matches = sortBy(matches, ({ volume24Hours }) => -1 * volume24Hours)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{/* Show a search input next to a sort dropdown */}
|
||||||
|
<div className="mt-2 mb-8 flex justify-between gap-2">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={query}
|
||||||
|
onChange={(e) => setQuery(e.target.value)}
|
||||||
|
placeholder="Search markets"
|
||||||
|
className="input input-bordered w-full"
|
||||||
|
/>
|
||||||
|
<select
|
||||||
|
className="select select-bordered"
|
||||||
|
value={sort}
|
||||||
|
onChange={(e) => setSort(e.target.value as Sort)}
|
||||||
|
>
|
||||||
|
<option value="newest">Newest</option>
|
||||||
|
<option value="oldest">Oldest</option>
|
||||||
|
<option value="most-traded">Most traded</option>
|
||||||
|
<option value="24-hour-vol">24h volume</option>
|
||||||
|
<option value="close-date">Closing soon</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{contracts === undefined ? (
|
||||||
|
<LoadingIndicator />
|
||||||
|
) : (
|
||||||
|
<ContractsGrid
|
||||||
|
contracts={matches}
|
||||||
|
loadMore={() => {}}
|
||||||
|
hasMore={false}
|
||||||
|
showCloseTime={['close-date', 'closed'].includes(sort)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ import { Spacer } from 'web/components/layout/spacer'
|
||||||
import { useUser } from 'web/hooks/use-user'
|
import { useUser } from 'web/hooks/use-user'
|
||||||
import { Contract, contractPath } from 'web/lib/firebase/contracts'
|
import { Contract, contractPath } from 'web/lib/firebase/contracts'
|
||||||
import { createMarket } from 'web/lib/firebase/api-call'
|
import { createMarket } from 'web/lib/firebase/api-call'
|
||||||
import { FIXED_ANTE, MINIMUM_ANTE } from 'common/antes'
|
import { FIXED_ANTE } from 'common/antes'
|
||||||
import { InfoTooltip } from 'web/components/info-tooltip'
|
import { InfoTooltip } from 'web/components/info-tooltip'
|
||||||
import { Page } from 'web/components/page'
|
import { Page } from 'web/components/page'
|
||||||
import { Row } from 'web/components/layout/row'
|
import { Row } from 'web/components/layout/row'
|
||||||
|
@ -109,7 +109,6 @@ export function NewContract(props: { question: string }) {
|
||||||
question.length > 0 &&
|
question.length > 0 &&
|
||||||
ante !== undefined &&
|
ante !== undefined &&
|
||||||
ante !== null &&
|
ante !== null &&
|
||||||
ante >= MINIMUM_ANTE &&
|
|
||||||
(ante <= balance ||
|
(ante <= balance ||
|
||||||
(mustWaitForDailyFreeMarketStatus != 'loading' &&
|
(mustWaitForDailyFreeMarketStatus != 'loading' &&
|
||||||
!mustWaitForDailyFreeMarketStatus)) &&
|
!mustWaitForDailyFreeMarketStatus)) &&
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
import { Col } from 'web/components/layout/col'
|
|
||||||
import { Spacer } from 'web/components/layout/spacer'
|
|
||||||
import { fromPropz } from 'web/hooks/use-propz'
|
|
||||||
import Analytics, {
|
|
||||||
CustomAnalytics,
|
|
||||||
FirebaseAnalytics,
|
|
||||||
getStaticPropz,
|
|
||||||
} from '../stats'
|
|
||||||
|
|
||||||
export const getStaticProps = fromPropz(getStaticPropz)
|
|
||||||
|
|
||||||
export default function AnalyticsEmbed(props: Parameters<typeof Analytics>[0]) {
|
|
||||||
return (
|
|
||||||
<Col className="w-full bg-white px-2">
|
|
||||||
<CustomAnalytics {...props} />
|
|
||||||
<Spacer h={8} />
|
|
||||||
<FirebaseAnalytics />
|
|
||||||
</Col>
|
|
||||||
)
|
|
||||||
}
|
|
BIN
web/public/atlas/atlas-favicon.png
Normal file
BIN
web/public/atlas/atlas-favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
1
web/public/atlas/atlas-logo-white.svg
Normal file
1
web/public/atlas/atlas-logo-white.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 443.37"><defs><style>.d{fill:#fff;}</style></defs><g id="a"/><g id="b"><g id="c"><g><g><path class="d" d="M500.26,351.29v-78.83h50.58v5.93h-43.31v30.08h40.92v5.93h-40.92v36.9h-7.28Z"/><path class="d" d="M570.89,351.29v-78.83h51.78v5.93h-44.62v29.96h42.11v5.93h-42.11v31.08h44.62v5.93h-51.78Z"/><path class="d" d="M645.57,351.29v-78.83h7.28v72.68h43.9v6.15h-51.18Z"/><path class="d" d="M715.36,351.29v-78.83h7.28v72.68h43.9v6.15h-51.18Z"/><path class="d" d="M815.09,352.19c-7.72,0-14.38-1.64-19.98-4.92-5.61-3.28-9.94-7.94-13-13.98-3.06-6.04-4.59-13.19-4.59-21.47s1.51-15.43,4.53-21.47c3.02-6.04,7.36-10.68,13-13.92,5.65-3.24,12.33-4.86,20.04-4.86s14.49,1.62,20.1,4.86c5.61,3.24,9.94,7.87,13,13.86,3.06,6,4.59,13.14,4.59,21.41s-1.53,15.54-4.59,21.58c-3.06,6.04-7.42,10.7-13.06,13.98-5.65,3.28-12.33,4.92-20.04,4.92Zm0-6.26c9.46,0,16.82-2.98,22.07-8.94,5.25-5.96,7.87-14.35,7.87-25.16s-2.61-19.18-7.81-25.1c-5.21-5.93-12.59-8.89-22.13-8.89s-16.8,2.98-22.01,8.94c-5.21,5.96-7.81,14.31-7.81,25.05s2.6,19.1,7.81,25.1c5.21,6,12.54,9,22.01,9Z"/><path class="d" d="M897.76,351.29l-29.23-78.83h7.64l25.17,68.65,25.41-68.65h6.2l25.41,69.1,25.41-69.1h7.4l-29.23,78.83h-6.92l-25.17-68.43-25.41,68.43h-6.68Z"/><path class="d" d="M1037.11,352.19c-6.52,0-12.39-.8-17.6-2.4-5.21-1.6-9.72-3.97-13.54-7.1l2.86-5.7c4.13,3.06,8.37,5.31,12.71,6.76,4.33,1.45,9.52,2.18,15.57,2.18,7.55,0,13.22-1.38,17-4.14,3.78-2.76,5.67-6.37,5.67-10.85,0-3.73-1.37-6.63-4.12-8.72-2.74-2.09-7.26-3.73-13.54-4.92l-12.05-2.35c-7.48-1.41-13.06-3.8-16.76-7.16s-5.55-7.83-5.55-13.42c0-4.55,1.25-8.53,3.76-11.96,2.51-3.43,5.98-6.09,10.44-7.99,4.45-1.9,9.58-2.85,15.39-2.85,11.61,0,20.88,3.28,27.8,9.84l-2.86,5.59c-3.66-3.2-7.48-5.53-11.45-6.99-3.98-1.45-8.47-2.18-13.48-2.18-6.68,0-12.03,1.49-16.05,4.47-4.02,2.98-6.02,6.97-6.02,11.96,0,3.95,1.27,7.06,3.82,9.34,2.54,2.27,6.64,3.93,12.29,4.98l12.17,2.35c8.03,1.57,14,3.9,17.9,6.99,3.9,3.09,5.85,7.32,5.85,12.69,0,4.25-1.21,7.99-3.64,11.24-2.43,3.24-5.91,5.78-10.44,7.6-4.53,1.83-9.9,2.74-16.1,2.74Z"/><path class="d" d="M1089.24,351.29v-78.83h7.28v35.78h53.68v-35.78h7.28v78.83h-7.28v-36.9h-53.68v36.9h-7.28Z"/><path class="d" d="M1185.4,351.29v-78.83h7.28v78.83h-7.28Z"/><path class="d" d="M1220.59,351.29v-78.83h31.73c8.99,0,15.85,2.01,20.58,6.04,4.73,4.03,7.1,9.77,7.1,17.22s-2.37,13.1-7.1,17.16c-4.73,4.06-11.59,6.09-20.58,6.09h-24.46v32.31h-7.28Zm7.28-38.35h23.86c13.92,0,20.88-5.74,20.88-17.22s-6.96-17.33-20.88-17.33h-23.86v34.55Z"/></g><path class="d" d="M231.33,216.67L126.1,6.2c-1.9-3.8-5.79-6.2-10.03-6.2s-8.13,2.4-10.03,6.2L2.21,213.83c-.7,1.14-2.14,3.81-2.21,7.5-.07,3.48,1.11,6.08,1.74,7.26l104.29,208.57c1.9,3.8,5.79,6.2,10.03,6.2h.01c4.25,0,8.14-2.41,10.03-6.22l103.4-207.83c.73-1.26,1.81-3.47,2.19-6.43,.34-2.66-.02-4.86-.36-6.22ZM58.72,150.99h114.69l29.63,59.27H29.08l29.63-59.27ZM116.06,36.3l46.13,92.26H69.93L116.06,36.3Zm-.03,370.72l-46.08-92.15h64.99c6.49,0,11.75-5.02,11.75-11.22s-5.26-11.22-11.75-11.22H58.74l-29.87-59.74H202.77l-86.73,174.33Z"/><g><path class="d" d="M271.65,232.48l72.08-159.3h23.72l72.08,159.3h-29.37l-15.82-36.83h-77.73l-15.59,36.83h-29.37Zm83.6-127.89l-28.7,68.01h57.84l-28.7-68.01h-.45Z"/><path class="d" d="M500.32,232.48V97.36h-54.68v-24.18h138.28v24.18h-54.68V232.48h-28.92Z"/><path class="d" d="M624.81,232.48V73.18h28.92V207.85h76.37v24.63h-105.29Z"/><path class="d" d="M753.83,232.48l72.08-159.3h23.72l72.08,159.3h-29.37l-15.82-36.83h-77.73l-15.59,36.83h-29.37Zm83.6-127.89l-28.7,68.01h57.84l-28.7-68.01h-.45Z"/><path class="d" d="M1014.8,234.74c-12.5,0-24.1-1.62-34.8-4.86-10.7-3.24-19.74-7.64-27.11-13.22l8.81-22.82c7.38,5.27,15.48,9.34,24.29,12.2,8.81,2.86,18.41,4.29,28.81,4.29,11.9,0,20.56-1.99,25.98-5.99,5.42-3.99,8.13-9.15,8.13-15.48,0-5.27-1.92-9.41-5.76-12.43-3.84-3.01-10.43-5.5-19.77-7.46l-24.85-5.2c-28.32-6.02-42.48-20.56-42.48-43.61,0-9.94,2.63-18.6,7.91-25.98,5.27-7.38,12.58-13.1,21.92-17.17,9.34-4.07,20.11-6.1,32.31-6.1,10.85,0,21.01,1.62,30.5,4.86,9.49,3.24,17.4,7.8,23.72,13.67l-8.81,21.69c-12.51-10.54-27.72-15.82-45.64-15.82-10.39,0-18.53,2.19-24.4,6.55-5.87,4.37-8.81,10.09-8.81,17.17,0,5.42,1.81,9.76,5.42,12.99,3.62,3.24,9.79,5.76,18.53,7.57l24.63,5.2c14.91,3.16,26.02,8.13,33.33,14.91,7.3,6.78,10.96,15.82,10.96,27.11,0,9.49-2.56,17.85-7.68,25.08-5.12,7.23-12.39,12.84-21.8,16.83-9.42,3.99-20.53,5.99-33.33,5.99Z"/></g></g></g></g></svg>
|
After Width: | Height: | Size: 4.3 KiB |
Loading…
Reference in New Issue
Block a user