From 719ec5cc54aa2612c926200a515d721b45e192aa Mon Sep 17 00:00:00 2001 From: James Grugett Date: Fri, 11 Mar 2022 11:13:16 -0600 Subject: [PATCH 1/5] Linkify answer text on activity feed --- web/components/contract-feed.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/components/contract-feed.tsx b/web/components/contract-feed.tsx index b578b51b..d9fb2bcc 100644 --- a/web/components/contract-feed.tsx +++ b/web/components/contract-feed.tsx @@ -139,7 +139,7 @@ function FeedBet(props: { activityItem: any; feedType: FeedType }) {
{answer && (
- {answer.text} +
)}
From 8773bf762456e8195cc9e8520089cd24949ab041 Mon Sep 17 00:00:00 2001 From: James Grugett Date: Sun, 13 Mar 2022 12:13:26 -0500 Subject: [PATCH 2/5] Default feed excluded tags are case insensitive --- web/hooks/use-find-active-contracts.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/web/hooks/use-find-active-contracts.ts b/web/hooks/use-find-active-contracts.ts index e6f849f6..bb7f9bd7 100644 --- a/web/hooks/use-find-active-contracts.ts +++ b/web/hooks/use-find-active-contracts.ts @@ -25,7 +25,7 @@ export const getAllContractInfo = async () => { return { contracts, recentComments, folds } } -const defaultSkippedTags = [ +const defaultExcludedTags = [ 'meta', 'test', 'trolling', @@ -34,10 +34,11 @@ const defaultSkippedTags = [ 'personal', ] const includedWithDefaultFeed = (contract: Contract) => { - const { tags } = contract + const { lowercaseTags } = contract - if (tags.length === 0) return false - if (tags.some((tag) => defaultSkippedTags.includes(tag))) return false + if (lowercaseTags.length === 0) return false + if (lowercaseTags.some((tag) => defaultExcludedTags.includes(tag))) + return false return true } From 14e2071b1d3075e6634c660aaa6a9c5479563e39 Mon Sep 17 00:00:00 2001 From: Austin Chen Date: Sun, 13 Mar 2022 11:55:05 -0700 Subject: [PATCH 3/5] Show followed folds first --- web/hooks/use-fold.ts | 1 + web/pages/folds.tsx | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/web/hooks/use-fold.ts b/web/hooks/use-fold.ts index 683b364a..e7eb737f 100644 --- a/web/hooks/use-fold.ts +++ b/web/hooks/use-fold.ts @@ -49,6 +49,7 @@ export const useFollowingFold = (fold: Fold, user: User | null | undefined) => { return following } +// Note: We cache FollowedFolds in localstorage to speed up the initial load export const useFollowedFolds = (user: User | null | undefined) => { const [followedFoldIds, setFollowedFoldIds] = useState( undefined diff --git a/web/pages/folds.tsx b/web/pages/folds.tsx index 9be5a56b..a47e0d6e 100644 --- a/web/pages/folds.tsx +++ b/web/pages/folds.tsx @@ -11,7 +11,7 @@ import { SiteLink } from '../components/site-link' import { TagsList } from '../components/tags-list' import { Title } from '../components/title' import { UserLink } from '../components/user-page' -import { useFolds } from '../hooks/use-fold' +import { useFolds, useFollowedFolds } from '../hooks/use-fold' import { useUser } from '../hooks/use-user' import { foldPath, listAllFolds } from '../lib/firebase/folds' import { getUser, User } from '../lib/firebase/users' @@ -43,8 +43,11 @@ export default function Folds(props: { const [curatorsDict, setCuratorsDict] = useState(props.curatorsDict) let folds = useFolds() ?? props.folds - folds = _.sortBy(folds, (fold) => -1 * fold.followCount) const user = useUser() + const followedFoldIds = useFollowedFolds(user) || [] + // First sort by follower count, then list followed folds first + folds = _.sortBy(folds, (fold) => -1 * fold.followCount) + folds = _.sortBy(folds, (fold) => !followedFoldIds.includes(fold.id)) useEffect(() => { // Load User object for curator of new Folds. From e5d02dde062314c89d742b40f520c55110b9af9b Mon Sep 17 00:00:00 2001 From: Austin Chen Date: Sun, 13 Mar 2022 13:55:42 -0700 Subject: [PATCH 4/5] Allow filtering your trades --- web/components/bets-list.tsx | 77 +++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/web/components/bets-list.tsx b/web/components/bets-list.tsx index 8136042f..6c8dac64 100644 --- a/web/components/bets-list.tsx +++ b/web/components/bets-list.tsx @@ -38,6 +38,7 @@ import { LoadingIndicator } from './loading-indicator' import { SiteLink } from './site-link' type BetSort = 'newest' | 'profit' | 'settled' | 'value' +type BetFilter = 'open' | 'closed' | 'resolved' | 'all' export function BetsList(props: { user: User }) { const { user } = props @@ -46,6 +47,7 @@ export function BetsList(props: { user: User }) { const [contracts, setContracts] = useState() const [sort, setSort] = useState('value') + const [filter, setFilter] = useState('open') useEffect(() => { if (bets) { @@ -69,11 +71,10 @@ export function BetsList(props: { user: User }) { } if (bets.length === 0) return - // Decending creation time. bets.sort((bet1, bet2) => bet2.createdTime - bet1.createdTime) - const contractBets = _.groupBy(bets, 'contractId') + const contractsById = _.fromPairs(contracts.map((c) => [c.id, c])) const contractsCurrentValue = _.mapValues( contractBets, @@ -81,7 +82,7 @@ export function BetsList(props: { user: User }) { return _.sumBy(bets, (bet) => { if (bet.isSold || bet.sale) return 0 - const contract = contracts.find((c) => c.id === contractId) + const contract = contractsById[contractId] const payout = contract ? calculatePayout(contract, bet, 'MKT') : 0 return payout - (bet.loanAmount ?? 0) }) @@ -94,29 +95,30 @@ export function BetsList(props: { user: User }) { }) }) - let sortedContracts = contracts - if (sort === 'profit') { - sortedContracts = _.sortBy( - contracts, - (c) => -1 * (contractsCurrentValue[c.id] - contractsInvestment[c.id]) - ) - } else if (sort === 'value') { - sortedContracts = _.sortBy(contracts, (c) => -contractsCurrentValue[c.id]) - } else if (sort === 'newest') - sortedContracts = _.sortBy( - contracts, - (c) => -1 * Math.max(...contractBets[c.id].map((bet) => bet.createdTime)) - ) - else if (sort === 'settled') - sortedContracts = _.sortBy(contracts, (c) => -1 * (c.resolutionTime ?? 0)) + const FILTERS: Record boolean> = { + resolved: (c) => !!c.resolutionTime, + closed: (c) => + !FILTERS.resolved(c) && (c.closeTime ?? Infinity) < Date.now(), + open: (c) => !(FILTERS.closed(c) || FILTERS.resolved(c)), + all: () => true, + // Pepe notes: most users want "settled", to see when their bets or sold; or "realized profit" + } + const SORTS: Record number> = { + profit: (c) => contractsCurrentValue[c.id] - contractsInvestment[c.id], + value: (c) => contractsCurrentValue[c.id], + newest: (c) => + Math.max(...contractBets[c.id].map((bet) => bet.createdTime)), + settled: (c) => c.resolutionTime ?? 0, + } + const displayedContracts = _.sortBy(contracts, SORTS[sort]) + .reverse() + .filter(FILTERS[filter]) const [settled, unsettled] = _.partition( - sortedContracts, + contracts, (c) => c.isResolved || contractsInvestment[c.id] === 0 ) - const displayedContracts = sort === 'settled' ? settled : unsettled - const currentInvestment = _.sumBy(unsettled, (c) => contractsInvestment[c.id]) const currentBetsValue = _.sumBy( @@ -151,16 +153,29 @@ export function BetsList(props: { user: User }) { - + + + + + {displayedContracts.length === 0 ? ( From d053fb6cb74ddf826e6e2bab67857346c6566ee2 Mon Sep 17 00:00:00 2001 From: Austin Chen Date: Sun, 13 Mar 2022 14:46:09 -0700 Subject: [PATCH 5/5] Store users's last sort in localstorage --- web/components/contracts-list.tsx | 1 + web/hooks/use-sort-and-query-params.tsx | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/web/components/contracts-list.tsx b/web/components/contracts-list.tsx index d64df8d8..214c5e7b 100644 --- a/web/components/contracts-list.tsx +++ b/web/components/contracts-list.tsx @@ -305,6 +305,7 @@ export function CreatorContractsList(props: { creator: User }) { const { query, setQuery, sort, setSort } = useQueryAndSortParams({ defaultSort: 'all', + shouldLoadFromStorage: false, }) useEffect(() => { diff --git a/web/hooks/use-sort-and-query-params.tsx b/web/hooks/use-sort-and-query-params.tsx index 3eca5f3c..3b669718 100644 --- a/web/hooks/use-sort-and-query-params.tsx +++ b/web/hooks/use-sort-and-query-params.tsx @@ -2,6 +2,8 @@ import _ from 'lodash' import { useRouter } from 'next/router' import { useEffect, useMemo, useState } from 'react' +const MARKETS_SORT = 'markets_sort' + export type Sort = | 'creator' | 'tag' @@ -14,7 +16,13 @@ export type Sort = | 'resolved' | 'all' -export function useQueryAndSortParams(options?: { defaultSort: Sort }) { +export function useQueryAndSortParams(options?: { + defaultSort: Sort + shouldLoadFromStorage?: boolean +}) { + const { defaultSort, shouldLoadFromStorage } = _.defaults(options, { + shouldLoadFromStorage: true, + }) const router = useRouter() const { s: sort, q: query } = router.query as { @@ -25,6 +33,9 @@ export function useQueryAndSortParams(options?: { defaultSort: Sort }) { const setSort = (sort: Sort | undefined) => { router.query.s = sort router.push(router, undefined, { shallow: true }) + if (shouldLoadFromStorage) { + localStorage.setItem(MARKETS_SORT, sort || '') + } } const [queryState, setQueryState] = useState(query) @@ -52,8 +63,18 @@ export function useQueryAndSortParams(options?: { defaultSort: Sort }) { pushQuery(query) } + useEffect(() => { + // If there's no sort option, then set the one from localstorage + if (!sort && shouldLoadFromStorage) { + const localSort = localStorage.getItem(MARKETS_SORT) as Sort + if (localSort) { + setSort(localSort) + } + } + }) + return { - sort: sort ?? options?.defaultSort ?? '24-hour-vol', + sort: sort ?? defaultSort ?? '24-hour-vol', query: queryState ?? '', setSort, setQuery,