diff --git a/common/package.json b/common/package.json index 955e9662..52195398 100644 --- a/common/package.json +++ b/common/package.json @@ -8,11 +8,11 @@ }, "sideEffects": false, "dependencies": { - "@tiptap/core": "2.0.0-beta.181", + "@tiptap/core": "2.0.0-beta.182", "@tiptap/extension-image": "2.0.0-beta.30", "@tiptap/extension-link": "2.0.0-beta.43", "@tiptap/extension-mention": "2.0.0-beta.102", - "@tiptap/starter-kit": "2.0.0-beta.190", + "@tiptap/starter-kit": "2.0.0-beta.191", "lodash": "4.17.21" }, "devDependencies": { diff --git a/functions/package.json b/functions/package.json index c8f295fc..d5a578de 100644 --- a/functions/package.json +++ b/functions/package.json @@ -26,11 +26,11 @@ "dependencies": { "@amplitude/node": "1.10.0", "@google-cloud/functions-framework": "3.1.2", - "@tiptap/core": "2.0.0-beta.181", + "@tiptap/core": "2.0.0-beta.182", "@tiptap/extension-image": "2.0.0-beta.30", "@tiptap/extension-link": "2.0.0-beta.43", "@tiptap/extension-mention": "2.0.0-beta.102", - "@tiptap/starter-kit": "2.0.0-beta.190", + "@tiptap/starter-kit": "2.0.0-beta.191", "cors": "2.8.5", "dayjs": "1.11.4", "express": "4.18.1", diff --git a/web/components/answers/answers-graph.tsx b/web/components/answers/answers-graph.tsx index 27152db9..d35132be 100644 --- a/web/components/answers/answers-graph.tsx +++ b/web/components/answers/answers-graph.tsx @@ -71,10 +71,11 @@ export const AnswersGraph = memo(function AnswersGraph(props: { const yTickValues = [0, 25, 50, 75, 100] const numXTickValues = isLargeWidth ? 5 : 2 - const hoursAgo = latestTime.subtract(5, 'hours') - const startDate = dayjs(contract.createdTime).isBefore(hoursAgo) - ? new Date(contract.createdTime) - : hoursAgo.toDate() + const startDate = new Date(contract.createdTime) + const endDate = dayjs(startDate).add(1, 'hour').isAfter(latestTime) + ? latestTime.add(1, 'hours').toDate() + : latestTime.toDate() + const includeMinute = dayjs(endDate).diff(startDate, 'hours') < 2 const multiYear = !dayjs(startDate).isSame(latestTime, 'year') const lessThanAWeek = dayjs(startDate).add(1, 'week').isAfter(latestTime) @@ -96,16 +97,24 @@ export const AnswersGraph = memo(function AnswersGraph(props: { xScale={{ type: 'time', min: startDate, - max: latestTime.toDate(), + max: endDate, }} xFormat={(d) => formatTime(+d.valueOf(), multiYear, lessThanAWeek, lessThanAWeek) } axisBottom={{ tickValues: numXTickValues, - format: (time) => formatTime(+time, multiYear, lessThanAWeek, false), + format: (time) => + formatTime(+time, multiYear, lessThanAWeek, includeMinute), }} - colors={{ scheme: 'pastel1' }} + colors={[ + '#fca5a5', // red-300 + '#93c5fd', // blue-300 + '#86efac', // green-300 + '#f9a8d4', // pink-300 + '#a5b4fc', // indigo-300 + '#fcd34d', // amber-300 + ]} pointSize={0} curve="stepAfter" enableSlices="x" @@ -156,7 +165,11 @@ function formatTime( ) { const d = dayjs(time) - if (d.add(1, 'minute').isAfter(Date.now())) return 'Now' + if ( + d.add(1, 'minute').isAfter(Date.now()) && + d.subtract(1, 'minute').isBefore(Date.now()) + ) + return 'Now' let format: string if (d.isSame(Date.now(), 'day')) { diff --git a/web/components/contract/FeaturedContractBadge.tsx b/web/components/contract/FeaturedContractBadge.tsx deleted file mode 100644 index 5ef34f4a..00000000 --- a/web/components/contract/FeaturedContractBadge.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { SparklesIcon } from '@heroicons/react/solid' - -export function FeaturedContractBadge() { - return ( - - Featured - - ) -} diff --git a/web/components/contract/contract-details.tsx b/web/components/contract/contract-details.tsx index 56407c4d..1e9d96d3 100644 --- a/web/components/contract/contract-details.tsx +++ b/web/components/contract/contract-details.tsx @@ -5,12 +5,15 @@ import { TrendingUpIcon, UserGroupIcon, } from '@heroicons/react/outline' +import Router from 'next/router' +import clsx from 'clsx' +import { Editor } from '@tiptap/react' +import dayjs from 'dayjs' import { Row } from '../layout/row' import { formatMoney } from 'common/util/format' import { UserLink } from '../user-page' import { Contract, updateContract } from 'web/lib/firebase/contracts' -import dayjs from 'dayjs' import { DateTimeTooltip } from '../datetime-tooltip' import { fromNow } from 'web/lib/util/time' import { Avatar } from '../avatar' @@ -21,7 +24,6 @@ import NewContractBadge from '../new-contract-badge' import { UserFollowButton } from '../follow-button' import { DAY_MS } from 'common/util/time' import { useUser } from 'web/hooks/use-user' -import { Editor } from '@tiptap/react' import { exhibitExts } from 'common/util/parse' import { Button } from 'web/components/button' import { Modal } from 'web/components/layout/modal' @@ -30,10 +32,9 @@ import { ContractGroupsList } from 'web/components/groups/contract-groups-list' import { SiteLink } from 'web/components/site-link' import { groupPath } from 'web/lib/firebase/groups' import { insertContent } from '../editor/utils' -import clsx from 'clsx' import { contractMetrics } from 'common/contract-details' import { User } from 'common/user' -import { FeaturedContractBadge } from 'web/components/contract/FeaturedContractBadge' +import { FeaturedContractBadge } from 'web/components/contract/featured-contract-badge' export type ShowTime = 'resolve-date' | 'close-date' @@ -191,7 +192,11 @@ export function ContractDetails(props: { size={'xs'} className={'max-w-[200px]'} color={'gray-white'} - onClick={() => setOpen(!open)} + onClick={() => + groupToDisplay + ? Router.push(groupPath(groupToDisplay.slug)) + : setOpen(!open) + } > {groupInfo} diff --git a/web/components/contract/contract-info-dialog.tsx b/web/components/contract/contract-info-dialog.tsx index 7c35a071..5c66aa4c 100644 --- a/web/components/contract/contract-info-dialog.tsx +++ b/web/components/contract/contract-info-dialog.tsx @@ -17,6 +17,7 @@ import { useAdmin, useDev } from 'web/hooks/use-admin' import { SiteLink } from '../site-link' import { firestoreConsolePath } from 'common/envs/constants' import { deleteField } from 'firebase/firestore' +import ShortToggle from '../widgets/short-toggle' export const contractDetailsButtonClassName = 'group flex items-center rounded-md px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-100 text-gray-400 hover:text-gray-500' @@ -50,6 +51,21 @@ export function ContractInfoDialog(props: { contract: Contract; bets: Bet[] }) { ? 'Multiple choice' : 'Numeric' + const onFeaturedToggle = async (enabled: boolean) => { + if ( + enabled && + (contract.featuredOnHomeRank === 0 || !contract?.featuredOnHomeRank) + ) { + await updateContract(id, { featuredOnHomeRank: 1 }) + setFeatured(true) + } else if (!enabled && (contract?.featuredOnHomeRank ?? 0) > 0) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + await updateContract(id, { featuredOnHomeRank: deleteField() }) + setFeatured(false) + } + } + return ( <> - Set featured + [ADMIN] Featured - { - const newVal = e.target.value === 'true' - if ( - newVal && - (contract.featuredOnHomeRank === 0 || - !contract?.featuredOnHomeRank) - ) - updateContract(id, { - featuredOnHomeRank: 1, - }) - .then(() => { - setFeatured(true) - }) - .catch(console.error) - else if ( - !newVal && - (contract?.featuredOnHomeRank ?? 0) > 0 - ) - updateContract(id, { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - featuredOnHomeRank: deleteField(), - }) - .then(() => { - setFeatured(false) - }) - .catch(console.error) - }} - > - false - true - + )} diff --git a/web/components/contract/contract-prob-graph.tsx b/web/components/contract/contract-prob-graph.tsx index 693befbb..ab2393f0 100644 --- a/web/components/contract/contract-prob-graph.tsx +++ b/web/components/contract/contract-prob-graph.tsx @@ -58,10 +58,11 @@ export const ContractProbGraph = memo(function ContractProbGraph(props: { const { width } = useWindowSize() const numXTickValues = !width || width < 800 ? 2 : 5 - const hoursAgo = latestTime.subtract(1, 'hours') - const startDate = dayjs(times[0]).isBefore(hoursAgo) - ? times[0] - : hoursAgo.toDate() + const startDate = times[0] + const endDate = dayjs(startDate).add(1, 'hour').isAfter(latestTime) + ? latestTime.add(1, 'hours').toDate() + : latestTime.toDate() + const includeMinute = dayjs(endDate).diff(startDate, 'hours') < 2 // Minimum number of points for the graph to have. For smooth tooltip movement // On first load, width is undefined, skip adding extra points to let page load faster @@ -133,14 +134,15 @@ export const ContractProbGraph = memo(function ContractProbGraph(props: { xScale={{ type: 'time', min: startDate, - max: latestTime.toDate(), + max: endDate, }} xFormat={(d) => formatTime(+d.valueOf(), multiYear, lessThanAWeek, lessThanAWeek) } axisBottom={{ tickValues: numXTickValues, - format: (time) => formatTime(+time, multiYear, lessThanAWeek, false), + format: (time) => + formatTime(+time, multiYear, lessThanAWeek, includeMinute), }} colors={{ datum: 'color' }} curve="stepAfter" @@ -183,7 +185,11 @@ function formatTime( ) { const d = dayjs(time) - if (d.add(1, 'minute').isAfter(Date.now())) return 'Now' + if ( + d.add(1, 'minute').isAfter(Date.now()) && + d.subtract(1, 'minute').isBefore(Date.now()) + ) + return 'Now' let format: string if (d.isSame(Date.now(), 'day')) { diff --git a/web/components/contract/featured-contract-badge.tsx b/web/components/contract/featured-contract-badge.tsx new file mode 100644 index 00000000..fe31ecb9 --- /dev/null +++ b/web/components/contract/featured-contract-badge.tsx @@ -0,0 +1,9 @@ +import { BadgeCheckIcon } from '@heroicons/react/solid' + +export function FeaturedContractBadge() { + return ( + + Featured + + ) +} diff --git a/web/components/widgets/short-toggle.tsx b/web/components/widgets/short-toggle.tsx index 3c307fda..339de361 100644 --- a/web/components/widgets/short-toggle.tsx +++ b/web/components/widgets/short-toggle.tsx @@ -5,13 +5,19 @@ import clsx from 'clsx' export default function ShortToggle(props: { enabled: boolean setEnabled: (enabled: boolean) => void + onChange?: (enabled: boolean) => void }) { const { enabled, setEnabled } = props return ( { + setEnabled(e) + if (props.onChange) { + props.onChange(e) + } + }} className="group relative inline-flex h-5 w-10 flex-shrink-0 cursor-pointer items-center justify-center rounded-full focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2" > Use setting diff --git a/web/package.json b/web/package.json index db3fdf45..847c7ef5 100644 --- a/web/package.json +++ b/web/package.json @@ -27,14 +27,14 @@ "@nivo/line": "0.74.0", "@nivo/tooltip": "0.74.0", "@react-query-firebase/firestore": "0.4.2", - "@tiptap/core": "2.0.0-beta.181", + "@tiptap/core": "2.0.0-beta.182", "@tiptap/extension-character-count": "2.0.0-beta.31", "@tiptap/extension-image": "2.0.0-beta.30", "@tiptap/extension-link": "2.0.0-beta.43", "@tiptap/extension-mention": "2.0.0-beta.102", "@tiptap/extension-placeholder": "2.0.0-beta.53", "@tiptap/react": "2.0.0-beta.114", - "@tiptap/starter-kit": "2.0.0-beta.190", + "@tiptap/starter-kit": "2.0.0-beta.191", "algoliasearch": "4.13.0", "browser-image-compression": "2.0.0", "clsx": "1.1.1", diff --git a/web/pages/embed/[username]/[contractSlug].tsx b/web/pages/embed/[username]/[contractSlug].tsx index 7ec8daeb..afec84bb 100644 --- a/web/pages/embed/[username]/[contractSlug].tsx +++ b/web/pages/embed/[username]/[contractSlug].tsx @@ -166,7 +166,8 @@ export function ContractEmbed(props: { contract: Contract; bets: Bet[] }) { /> )} - {outcomeType === 'FREE_RESPONSE' && ( + {(outcomeType === 'FREE_RESPONSE' || + outcomeType === 'MULTIPLE_CHOICE') && ( )} diff --git a/web/pages/notifications.tsx b/web/pages/notifications.tsx index 0fe3b179..bfd18f7f 100644 --- a/web/pages/notifications.tsx +++ b/web/pages/notifications.tsx @@ -200,7 +200,9 @@ function IncomeNotificationGroupItem(props: { const { notificationGroup, className } = props const { notifications } = notificationGroup const numSummaryLines = 3 - const [expanded, setExpanded] = useState(false) + const [expanded, setExpanded] = useState( + notifications.length <= numSummaryLines + ) const [highlighted, setHighlighted] = useState( notifications.some((n) => !n.isSeen) ) @@ -398,7 +400,8 @@ function IncomeNotificationItem(props: { } else if (sourceType === 'tip') { reasonText = !simple ? `tipped you on` : `in tips on` } else if (sourceType === 'betting_streak_bonus') { - reasonText = 'for your' + if (sourceText && +sourceText === 50) reasonText = '(max) for your' + else reasonText = 'for your' } else if (sourceType === 'loan' && sourceText) { reasonText = `of your invested bets returned as a` } @@ -524,7 +527,7 @@ function IncomeNotificationItem(props: { - + ) @@ -541,7 +544,9 @@ function NotificationGroupItem(props: { const isMobile = (width && width < 768) || false const numSummaryLines = 3 - const [expanded, setExpanded] = useState(false) + const [expanded, setExpanded] = useState( + notifications.length <= numSummaryLines + ) const [highlighted, setHighlighted] = useState( notifications.some((n) => !n.isSeen) ) diff --git a/yarn.lock b/yarn.lock index bbc13091..f49b1ccf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2919,10 +2919,10 @@ lodash.isplainobject "^4.0.6" lodash.merge "^4.6.2" -"@tiptap/core@2.0.0-beta.181", "@tiptap/core@^2.0.0-beta.181": - version "2.0.0-beta.181" - resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.0.0-beta.181.tgz#07aeea26336814ab82eb7f4199b17538187c6fbb" - integrity sha512-tbwRqjTVvY9v31TNAH6W0Njhr/OVwI28zWXmH55/USrwyU2CB1iCVfXktZKOhB+8WyvOaBv1JA5YplMIhstYTw== +"@tiptap/core@2.0.0-beta.182", "@tiptap/core@^2.0.0-beta.182": + version "2.0.0-beta.182" + resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.0.0-beta.182.tgz#d2001e9b765adda95e15d171479860a3349e2d04" + integrity sha512-MZGkMGnVnWhBzjvpBNwQ9zBz38ndi3Irbf90uCTSArR0kaCVkW4vmyuPuOXd+0SO8Yv/l5oyDdOCpaG3rnQYfw== dependencies: prosemirror-commands "1.3.0" prosemirror-keymap "1.2.0" @@ -3099,12 +3099,12 @@ "@tiptap/extension-floating-menu" "^2.0.0-beta.56" prosemirror-view "1.26.2" -"@tiptap/starter-kit@2.0.0-beta.190": - version "2.0.0-beta.190" - resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.0.0-beta.190.tgz#fe0021e29d070fc5707722513a398c8884e15f71" - integrity sha512-jaFMkE6mjCHmCJsXUyLiXGYRVDcHF+PbH/5hEu1riUIAT0Hmm7uak5TYsPeuoCVN7P/tmDEBbBRASZ5CzEQpvw== +"@tiptap/starter-kit@2.0.0-beta.191": + version "2.0.0-beta.191" + resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.0.0-beta.191.tgz#3f549367f6dbb8cf83f63aa0941722d91d0fd8e7" + integrity sha512-YRrBCi9W4jiH/xLTJJOCdD7pL4Wb98Ip8qCJ94RElShDj0O1i5tT9wWlgVWoGIU+CRAds5XENRwZ97sJ+YfYyg== dependencies: - "@tiptap/core" "^2.0.0-beta.181" + "@tiptap/core" "^2.0.0-beta.182" "@tiptap/extension-blockquote" "^2.0.0-beta.29" "@tiptap/extension-bold" "^2.0.0-beta.28" "@tiptap/extension-bullet-list" "^2.0.0-beta.29"