Fix some hydration issues (#1033)
* Extract `useIsClient` hook * Fix a bunch of hydration bugs relevant to the contract page
This commit is contained in:
parent
aa717a767d
commit
c44f223064
|
@ -34,6 +34,7 @@ import { ExtraContractActionsRow } from './extra-contract-actions-row'
|
|||
import { GroupLink } from 'common/group'
|
||||
import { Subtitle } from '../subtitle'
|
||||
import { useIsMobile } from 'web/hooks/use-is-mobile'
|
||||
import { useIsClient } from 'web/hooks/use-is-client'
|
||||
import {
|
||||
BountiedContractBadge,
|
||||
BountiedContractSmallBadge,
|
||||
|
@ -52,22 +53,23 @@ export function MiscDetails(props: {
|
|||
const { volume, closeTime, isResolved, createdTime, resolutionTime } =
|
||||
contract
|
||||
|
||||
const isClient = useIsClient()
|
||||
const isNew = createdTime > Date.now() - DAY_MS && !isResolved
|
||||
const groupToDisplay = getGroupLinkToDisplay(contract)
|
||||
|
||||
return (
|
||||
<Row className="items-center gap-3 truncate text-sm text-gray-400">
|
||||
{showTime === 'close-date' ? (
|
||||
{isClient && showTime === 'close-date' ? (
|
||||
<Row className="gap-0.5 whitespace-nowrap">
|
||||
<ClockIcon className="h-5 w-5" />
|
||||
{(closeTime || 0) < Date.now() ? 'Closed' : 'Closes'}{' '}
|
||||
{fromNow(closeTime || 0)}
|
||||
</Row>
|
||||
) : showTime === 'resolve-date' && resolutionTime !== undefined ? (
|
||||
) : isClient && showTime === 'resolve-date' && resolutionTime ? (
|
||||
<Row className="gap-0.5">
|
||||
<ClockIcon className="h-5 w-5" />
|
||||
{'Resolved '}
|
||||
{fromNow(resolutionTime || 0)}
|
||||
{fromNow(resolutionTime)}
|
||||
</Row>
|
||||
) : (contract?.featuredOnHomeRank ?? 0) > 0 ? (
|
||||
<FeaturedContractBadge />
|
||||
|
@ -390,6 +392,7 @@ function EditableCloseDate(props: {
|
|||
}) {
|
||||
const { closeTime, contract, isCreator, disabled } = props
|
||||
|
||||
const isClient = useIsClient()
|
||||
const dayJsCloseTime = dayjs(closeTime)
|
||||
const dayJsNow = dayjs()
|
||||
|
||||
|
@ -452,7 +455,7 @@ function EditableCloseDate(props: {
|
|||
className="w-full shrink-0 sm:w-fit"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onChange={(e) => setCloseDate(e.target.value)}
|
||||
min={Date.now()}
|
||||
min={isClient ? Date.now() : undefined}
|
||||
value={closeDate}
|
||||
/>
|
||||
<Input
|
||||
|
@ -479,14 +482,18 @@ function EditableCloseDate(props: {
|
|||
</Col>
|
||||
</Modal>
|
||||
<DateTimeTooltip
|
||||
text={closeTime > Date.now() ? 'Trading ends:' : 'Trading ended:'}
|
||||
text={
|
||||
isClient && closeTime <= Date.now()
|
||||
? 'Trading ended:'
|
||||
: 'Trading ends:'
|
||||
}
|
||||
time={closeTime}
|
||||
>
|
||||
<Row
|
||||
className={clsx(!disabled && isCreator ? 'cursor-pointer' : '')}
|
||||
onClick={() => !disabled && isCreator && setIsEditingCloseTime(true)}
|
||||
>
|
||||
{isSameDay ? (
|
||||
{isSameDay && isClient ? (
|
||||
<span className={'capitalize'}> {fromNow(closeTime)}</span>
|
||||
) : isSameYear ? (
|
||||
dayJsCloseTime.format('MMM D')
|
||||
|
|
|
@ -6,17 +6,19 @@ import { contractPath, getBinaryProbPercent } from 'web/lib/firebase/contracts'
|
|||
import { fromNow } from 'web/lib/util/time'
|
||||
import { BinaryContractOutcomeLabel } from '../outcome-label'
|
||||
import { getColor } from './quick-bet'
|
||||
import { useIsClient } from 'web/hooks/use-is-client'
|
||||
|
||||
export function ContractMention(props: { contract: Contract }) {
|
||||
const { contract } = props
|
||||
const { outcomeType, resolution } = contract
|
||||
const probTextColor = `text-${getColor(contract)}`
|
||||
const isClient = useIsClient()
|
||||
|
||||
return (
|
||||
<Link href={contractPath(contract)}>
|
||||
<a
|
||||
className="group inline whitespace-nowrap rounded-sm hover:bg-indigo-50 focus:bg-indigo-50"
|
||||
title={tooltipLabel(contract)}
|
||||
title={isClient ? tooltipLabel(contract) : undefined}
|
||||
>
|
||||
<span className="break-anywhere mr-0.5 whitespace-normal font-normal text-indigo-700">
|
||||
{contract.question}
|
||||
|
|
|
@ -5,6 +5,7 @@ import Link from 'next/link'
|
|||
import { fromNow } from 'web/lib/util/time'
|
||||
import { ToastClipboard } from 'web/components/toast-clipboard'
|
||||
import { LinkIcon } from '@heroicons/react/outline'
|
||||
import { useIsClient } from 'web/hooks/use-is-client'
|
||||
|
||||
export function CopyLinkDateTimeComponent(props: {
|
||||
prefix: string
|
||||
|
@ -14,6 +15,7 @@ export function CopyLinkDateTimeComponent(props: {
|
|||
className?: string
|
||||
}) {
|
||||
const { prefix, slug, elementId, createdTime, className } = props
|
||||
const isClient = useIsClient()
|
||||
const [showToast, setShowToast] = useState(false)
|
||||
|
||||
function copyLinkToComment(
|
||||
|
@ -36,7 +38,7 @@ export function CopyLinkDateTimeComponent(props: {
|
|||
'text-greyscale-4 hover:bg-greyscale-1.5 mx-1 whitespace-nowrap rounded-sm px-1 text-xs transition-colors'
|
||||
}
|
||||
>
|
||||
{fromNow(createdTime)}
|
||||
{isClient && fromNow(createdTime)}
|
||||
{showToast && <ToastClipboard />}
|
||||
<LinkIcon className="ml-1 mb-0.5 inline" height={13} />
|
||||
</a>
|
||||
|
|
|
@ -1,22 +1,16 @@
|
|||
import { DateTimeTooltip } from './datetime-tooltip'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { fromNow } from 'web/lib/util/time'
|
||||
import { useIsClient } from 'web/hooks/use-is-client'
|
||||
|
||||
export function RelativeTimestamp(props: { time: number }) {
|
||||
const { time } = props
|
||||
const [isClient, setIsClient] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
// Only render on client to prevent difference from server.
|
||||
setIsClient(true)
|
||||
}, [])
|
||||
|
||||
const isClient = useIsClient()
|
||||
return (
|
||||
<DateTimeTooltip
|
||||
className="ml-1 whitespace-nowrap text-gray-400"
|
||||
time={time}
|
||||
>
|
||||
{isClient ? fromNow(time) : ''}
|
||||
{isClient && fromNow(time)}
|
||||
</DateTimeTooltip>
|
||||
)
|
||||
}
|
||||
|
|
7
web/hooks/use-is-client.ts
Normal file
7
web/hooks/use-is-client.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
|
||||
export const useIsClient = () => {
|
||||
const [isClient, setIsClient] = useState(false)
|
||||
useEffect(() => setIsClient(true), [])
|
||||
return isClient
|
||||
}
|
Loading…
Reference in New Issue
Block a user