From d0347ff5c2226d7d0fbaa6a064d03a71b1069259 Mon Sep 17 00:00:00 2001 From: Ian Philips Date: Mon, 23 May 2022 08:43:11 -0600 Subject: [PATCH] Add countdown timer for daily free market (#276) * Add countdown timer for daily free market * Reset example numbers * Remove daily * Free market reset => 4pm UTC --- functions/src/create-contract.ts | 10 ++-- web/components/nav/sidebar.tsx | 48 ++++++++++++++++--- web/hooks/use-has-created-contract-today.ts | 20 +++++--- web/pages/create.tsx | 52 ++++++++++++--------- 4 files changed, 91 insertions(+), 39 deletions(-) diff --git a/functions/src/create-contract.ts b/functions/src/create-contract.ts index 5feb32c0..485e3bb1 100644 --- a/functions/src/create-contract.ts +++ b/functions/src/create-contract.ts @@ -87,13 +87,17 @@ export const createContract = newEndpoint(['POST'], async (req, _res) => { ) throw new APIError(400, 'Invalid initial probability') - // uses utc time on server: - const today = new Date().setHours(0, 0, 0, 0) + // Uses utc time on server: + const yesterday = new Date() + yesterday.setUTCDate(yesterday.getUTCDate() - 1) + const freeMarketResetTime = yesterday.setUTCHours(16, 0, 0, 0) + const userContractsCreatedTodaySnapshot = await firestore .collection(`contracts`) .where('creatorId', '==', creator.id) - .where('createdTime', '>=', today) + .where('createdTime', '>=', freeMarketResetTime) .get() + console.log('free market reset time: ', freeMarketResetTime) const isFree = userContractsCreatedTodaySnapshot.size === 0 const ante = FIXED_ANTE diff --git a/web/components/nav/sidebar.tsx b/web/components/nav/sidebar.tsx index eab32b86..59ff8a26 100644 --- a/web/components/nav/sidebar.tsx +++ b/web/components/nav/sidebar.tsx @@ -20,8 +20,12 @@ import { firebaseLogin, firebaseLogout } from 'web/lib/firebase/users' import { ManifoldLogo } from './manifold-logo' import { MenuButton } from './menu' import { getNavigationOptions, ProfileSummary } from './profile-menu' -import { useHasCreatedContractToday } from 'web/hooks/use-has-created-contract-today' +import { + getUtcFreeMarketResetTimeToday, + useHasCreatedContractToday, +} from 'web/hooks/use-has-created-contract-today' import { Row } from '../layout/row' +import { useEffect, useState } from 'react' // Create an icon from the url of an image function IconFromUrl(url: string): React.ComponentType<{ className?: string }> { @@ -121,12 +125,30 @@ export default function Sidebar(props: { className?: string }) { const { className } = props const router = useRouter() const currentPage = router.pathname + const [countdown, setCountdown] = useState('...') + useEffect(() => { + const utcMidnightToLocalDate = new Date(getUtcFreeMarketResetTimeToday()) + const interval = setInterval(() => { + const timeUntil = utcMidnightToLocalDate.getTime() - new Date().getTime() + const hoursUntil = 24 + timeUntil / 1000 / 60 / 60 + const minutesUntil = Math.floor((hoursUntil * 60) % 60) + const secondsUntil = Math.floor((hoursUntil * 60 * 60) % 60) + const hoursUntilFloor = Math.floor(hoursUntil) + const timeString = + minutesUntil < 1 + ? `${secondsUntil}s` + : hoursUntilFloor < 1 + ? `${minutesUntil}m` + : `${hoursUntilFloor}h` + setCountdown(timeString) + }, 1000) + return () => clearInterval(interval) + }, []) const user = useUser() let folds = useFollowedFolds(user) || [] folds = sortBy(folds, 'followCount').reverse() - const deservesDailyFreeMarket = !useHasCreatedContractToday(user) - + const mustWaitForFreeMarketStatus = useHasCreatedContractToday(user) const navigationOptions = user === null ? signedOutNavigation @@ -186,13 +208,25 @@ export default function Sidebar(props: { className?: string }) { )} - {user && deservesDailyFreeMarket && ( + {user && + mustWaitForFreeMarketStatus != 'loading' && + mustWaitForFreeMarketStatus ? ( - - Daily free market - + ) : ( + user && + mustWaitForFreeMarketStatus != 'loading' && + !mustWaitForFreeMarketStatus && ( + + + Daily free market + + + ) )} ) diff --git a/web/hooks/use-has-created-contract-today.ts b/web/hooks/use-has-created-contract-today.ts index 2b4ec99a..265f2645 100644 --- a/web/hooks/use-has-created-contract-today.ts +++ b/web/hooks/use-has-created-contract-today.ts @@ -4,16 +4,22 @@ import { User } from 'common/user' let sessionCreatedContractToday = true +export function getUtcFreeMarketResetTimeToday() { + // Uses utc time like the server. + const utcFreeMarketResetTime = new Date() + utcFreeMarketResetTime.setUTCDate(utcFreeMarketResetTime.getUTCDate() - 1) + const utcFreeMarketMS = utcFreeMarketResetTime.setUTCHours(16, 0, 0, 0) + return utcFreeMarketMS +} + export const useHasCreatedContractToday = (user: User | null | undefined) => { - const [hasCreatedContractToday, setHasCreatedContractToday] = useState( - sessionCreatedContractToday - ) + const [hasCreatedContractToday, setHasCreatedContractToday] = useState< + boolean | 'loading' + >('loading') useEffect(() => { - // Uses utc time like the server. - const utcTimeString = new Date().toISOString() - const todayAtMidnight = new Date(utcTimeString).setUTCHours(0, 0, 0, 0) - + setHasCreatedContractToday('loading') + const todayAtMidnight = getUtcFreeMarketResetTimeToday() async function listUserContractsForToday() { if (!user) return diff --git a/web/pages/create.tsx b/web/pages/create.tsx index 9dd8b1da..1e01d2da 100644 --- a/web/pages/create.tsx +++ b/web/pages/create.tsx @@ -77,7 +77,7 @@ export function NewContract(props: { question: string; tag?: string }) { const [ante, setAnte] = useState(FIXED_ANTE) - const deservesDailyFreeMarket = !useHasCreatedContractToday(creator) + const mustWaitForDailyFreeMarketStatus = useHasCreatedContractToday(creator) // useEffect(() => { // if (ante === null && creator) { @@ -107,7 +107,9 @@ export function NewContract(props: { question: string; tag?: string }) { ante !== undefined && ante !== null && ante >= MINIMUM_ANTE && - (ante <= balance || deservesDailyFreeMarket) && + (ante <= balance || + (mustWaitForDailyFreeMarketStatus != 'loading' && + !mustWaitForDailyFreeMarketStatus)) && // closeTime must be in the future closeTime && closeTime > Date.now() && @@ -368,13 +370,15 @@ export function NewContract(props: { question: string; tag?: string }) {
- {deservesDailyFreeMarket ? ( + {mustWaitForDailyFreeMarketStatus != 'loading' && + !mustWaitForDailyFreeMarketStatus ? (
{formatMoney(ante)} @@ -382,21 +386,25 @@ export function NewContract(props: { question: string; tag?: string }) { FREE
) : ( -
- {formatMoney(ante)} -
- )} - {!deservesDailyFreeMarket && ante > balance && ( -
- Insufficient balance - -
+ mustWaitForDailyFreeMarketStatus != 'loading' && ( +
+ {formatMoney(ante)} +
+ ) )} + {mustWaitForDailyFreeMarketStatus != 'loading' && + mustWaitForDailyFreeMarketStatus && + ante > balance && ( +
+ Insufficient balance + +
+ )} {/*