import { ClockIcon, DatabaseIcon, PencilIcon, TrendingUpIcon, UserGroupIcon, } from '@heroicons/react/outline' import clsx from 'clsx' import { Editor } from '@tiptap/react' import dayjs from 'dayjs' import Link from 'next/link' import { Row } from '../layout/row' import { formatMoney } from 'common/util/format' import { Contract, updateContract } from 'web/lib/firebase/contracts' import { DateTimeTooltip } from '../datetime-tooltip' import { fromNow } from 'web/lib/util/time' import { Avatar } from '../avatar' import { useState } from 'react' import { ContractInfoDialog } from './contract-info-dialog' 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 { exhibitExts } from 'common/util/parse' import { Button } from 'web/components/button' import { Modal } from 'web/components/layout/modal' import { Col } from 'web/components/layout/col' import { ContractGroupsList } from 'web/components/groups/contract-groups-list' import { linkClass } from 'web/components/site-link' import { getGroupLinkToDisplay, groupPath } from 'web/lib/firebase/groups' import { insertContent } from '../editor/utils' import { contractMetrics } from 'common/contract-details' import { UserLink } from 'web/components/user-link' import { FeaturedContractBadge } from 'web/components/contract/featured-contract-badge' import { Tooltip } from 'web/components/tooltip' import { useWindowSize } from 'web/hooks/use-window-size' export type ShowTime = 'resolve-date' | 'close-date' export function MiscDetails(props: { contract: Contract showHotVolume?: boolean showTime?: ShowTime hideGroupLink?: boolean }) { const { contract, showHotVolume, showTime, hideGroupLink } = props const { volume, volume24Hours, closeTime, isResolved, createdTime, resolutionTime, } = contract const isNew = createdTime > Date.now() - DAY_MS && !isResolved const groupToDisplay = getGroupLinkToDisplay(contract) return ( {showHotVolume ? ( {formatMoney(volume24Hours)} ) : showTime === 'close-date' ? ( {(closeTime || 0) < Date.now() ? 'Closed' : 'Closes'}{' '} {fromNow(closeTime || 0)} ) : showTime === 'resolve-date' && resolutionTime !== undefined ? ( {'Resolved '} {fromNow(resolutionTime || 0)} ) : (contract?.featuredOnHomeRank ?? 0) > 0 ? ( ) : volume > 0 || !isNew ? ( {formatMoney(volume)} bet ) : ( )} {!hideGroupLink && groupToDisplay && ( {groupToDisplay.name} )} ) } export function AvatarDetails(props: { contract: Contract className?: string short?: boolean }) { const { contract, short, className } = props const { creatorName, creatorUsername, creatorAvatarUrl } = contract return ( ) } export function ContractDetails(props: { contract: Contract disabled?: boolean }) { const { contract, disabled } = props const { closeTime, creatorName, creatorUsername, creatorId, creatorAvatarUrl, resolutionTime, } = contract const { volumeLabel, resolvedDate } = contractMetrics(contract) const user = useUser() const isCreator = user?.id === creatorId const [open, setOpen] = useState(false) const { width } = useWindowSize() const isMobile = (width ?? 0) < 600 const groupToDisplay = getGroupLinkToDisplay(contract) const groupInfo = groupToDisplay ? ( {groupToDisplay.name} ) : ( ) return ( {disabled ? ( creatorName ) : ( )} {!disabled && } {disabled ? ( groupInfo ) : !groupToDisplay && !user ? (
) : ( {groupInfo} {user && groupToDisplay && ( )} )} {(!!closeTime || !!resolvedDate) && ( {resolvedDate && resolutionTime ? ( <> {resolvedDate} ) : null} {!resolvedDate && closeTime && user && ( <> )} )} {user && ( <>
{volumeLabel}
{!disabled && ( )} )} ) } export function ExtraMobileContractDetails(props: { contract: Contract forceShowVolume?: boolean }) { const { contract, forceShowVolume } = props const { volume, resolutionTime, closeTime, creatorId, uniqueBettorCount } = contract const user = useUser() const uniqueBettors = uniqueBettorCount ?? 0 const { resolvedDate } = contractMetrics(contract) const volumeTranslation = volume > 800 || uniqueBettors >= 20 ? 'High' : volume > 300 || uniqueBettors >= 10 ? 'Medium' : 'Low' return ( {resolvedDate && resolutionTime ? ( {resolvedDate} Ended ) : ( !resolvedDate && closeTime && ( Ends ) )} {(user || forceShowVolume) && ( {volumeTranslation} Activity )} ) } function EditableCloseDate(props: { closeTime: number contract: Contract isCreator: boolean }) { const { closeTime, contract, isCreator } = props const dayJsCloseTime = dayjs(closeTime) const dayJsNow = dayjs() const [isEditingCloseTime, setIsEditingCloseTime] = useState(false) const [closeDate, setCloseDate] = useState( closeTime && dayJsCloseTime.format('YYYY-MM-DD') ) const [closeHoursMinutes, setCloseHoursMinutes] = useState( closeTime && dayJsCloseTime.format('HH:mm') ) const newCloseTime = closeDate ? dayjs(`${closeDate}T${closeHoursMinutes}`).valueOf() : undefined const isSameYear = dayJsCloseTime.isSame(dayJsNow, 'year') const isSameDay = dayJsCloseTime.isSame(dayJsNow, 'day') const onSave = () => { if (!newCloseTime) return if (newCloseTime === closeTime) setIsEditingCloseTime(false) else if (newCloseTime > Date.now()) { const content = contract.description const formattedCloseDate = dayjs(newCloseTime).format('YYYY-MM-DD h:mm a') const editor = new Editor({ content, extensions: exhibitExts }) editor.commands.focus('end') insertContent( editor, `

Close date updated to ${formattedCloseDate}

` ) updateContract(contract.id, { closeTime: newCloseTime, description: editor.getJSON(), }) setIsEditingCloseTime(false) } } return ( <> {isEditingCloseTime ? ( e.stopPropagation()} onChange={(e) => setCloseDate(e.target.value)} min={Date.now()} value={closeDate} /> e.stopPropagation()} onChange={(e) => setCloseHoursMinutes(e.target.value)} min="00:00" value={closeHoursMinutes} /> ) : ( Date.now() ? 'Trading ends:' : 'Trading ended:'} time={closeTime} > isCreator && setIsEditingCloseTime(true)} > {isSameDay ? ( {fromNow(closeTime)} ) : isSameYear ? ( dayJsCloseTime.format('MMM D') ) : ( dayJsCloseTime.format('MMM D, YYYY') )} )} ) }