From c133787c1d2498bf7861777ce9d61799bf2e0083 Mon Sep 17 00:00:00 2001 From: David Chee Date: Thu, 13 Jun 2024 22:42:05 -0700 Subject: [PATCH 1/2] N/A all contracts on independent multi --- .../answers/answer-resolve-panel.tsx | 61 +++++++++++++++++-- .../buttons/confirmation-button.tsx | 45 ++++++++++++++ 2 files changed, 101 insertions(+), 5 deletions(-) diff --git a/web/components/answers/answer-resolve-panel.tsx b/web/components/answers/answer-resolve-panel.tsx index 74a27cc396..abba873490 100644 --- a/web/components/answers/answer-resolve-panel.tsx +++ b/web/components/answers/answer-resolve-panel.tsx @@ -11,7 +11,10 @@ import { Col } from '../layout/col' import { APIError, api } from 'web/lib/firebase/api' import { Row } from '../layout/row' import { ChooseCancelSelector } from '../bet/yes-no-selector' -import { ResolveConfirmationButton } from '../buttons/confirmation-button' +import { + CancelAllConfirmationButton, + ResolveConfirmationButton, +} from '../buttons/confirmation-button' import { removeUndefinedProps } from 'common/util/object' import { BETTORS } from 'common/user' import { Button } from '../buttons/button' @@ -32,7 +35,7 @@ import { ClosedProb, OpenProb, } from './answer-components' -import { useAdmin } from 'web/hooks/use-admin' +import { useAdmin, useAdminOrMod } from 'web/hooks/use-admin' import { GradientContainer } from '../widgets/gradient-container' import { AmountInput } from '../widgets/amount-input' import { getAnswerColor } from '../charts/contract/choice' @@ -419,12 +422,49 @@ export const IndependentAnswersResolvePanel = (props: { const isAdmin = useAdmin() const user = useUser() + const answers = useAnswersCpmm(contract.id) ?? contract.answers + const isAdminorMod = useAdminOrMod() + + const [isSubmitting, setIsSubmitting] = useState(false) + const [error, setError] = useState(undefined) + + const onCancelAll = async () => { + setIsSubmitting(true) + try { + for (const answer of answers) { + const resolutionProps = removeUndefinedProps({ + contractId: contract.id, + outcome: 'CANCEL', + answerId: answer.id, + }) + + try { + const result = await api( + 'market/:contractId/resolve', + resolutionProps as any + ) + console.log('resolved', resolutionProps, 'result:', result) + } catch (e) { + if (e instanceof APIError) { + setError(e.toString()) + } else { + console.error(e) + setError('Error resolving question') + } + } + } + console.log('All contracts canceled') + } catch (e) { + console.error(e) + setError('Error canceling all contracts') + } + setIsSubmitting(false) + } - const { answers, addAnswersMode } = contract const sortedAnswers = sortBy( answers, (a) => (a.resolution ? -a.subsidyPool : -Infinity), - (a) => (addAnswersMode === 'ANYONE' ? -1 * a.prob : a.index) + (a) => a.index ) return ( @@ -435,6 +475,16 @@ export const IndependentAnswersResolvePanel = (props: { isCreator={user?.id === contract.creatorId} onClose={onClose} /> + {isAdminorMod && ( + + + + )} {sortedAnswers.map((answer) => ( + {!!error &&
{error}
} ) } @@ -470,7 +521,7 @@ function IndependentResolutionAnswerItem(props: { const addAnswersMode = contract.addAnswersMode ?? 'DISABLED' return ( - + ) } + +export function CancelAllConfirmationButton(props: { + onResolve: () => void + isSubmitting: boolean + openModalButtonClass?: string + marketTitle: string + + color: ColorType + disabled?: boolean +}) { + const { + onResolve, + isSubmitting, + openModalButtonClass, + color, + marketTitle, + disabled, + } = props + return ( + +

+ Are you sure you want to resolve all answers on "{marketTitle}" to N/A? + This can take a while. +
+

+
+ ) +} From 5fe303a2e049d5ebab33fb4718766164317a5052 Mon Sep 17 00:00:00 2001 From: David Chee Date: Fri, 21 Jun 2024 15:03:29 +0100 Subject: [PATCH 2/2] Make improvements to cancel all --- .../answers/answer-resolve-panel.tsx | 68 ++++++++++--------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/web/components/answers/answer-resolve-panel.tsx b/web/components/answers/answer-resolve-panel.tsx index abba873490..129571958a 100644 --- a/web/components/answers/answer-resolve-panel.tsx +++ b/web/components/answers/answer-resolve-panel.tsx @@ -19,7 +19,7 @@ import { removeUndefinedProps } from 'common/util/object' import { BETTORS } from 'common/user' import { Button } from '../buttons/button' import { useUser } from 'web/hooks/use-user' -import { Answer, OTHER_TOOLTIP_TEXT } from 'common/answer' +import { Answer, OTHER_TOOLTIP_TEXT, sortAnswers } from 'common/answer' import { getAnswerProbability } from 'common/calculate' import { useDisplayUserByIdOrAnswer } from 'web/hooks/use-user-supabase' import { @@ -40,6 +40,10 @@ import { GradientContainer } from '../widgets/gradient-container' import { AmountInput } from '../widgets/amount-input' import { getAnswerColor } from '../charts/contract/choice' import { useAnswersCpmm } from 'web/hooks/use-answers' +import { resolveMarketProps } from 'common/api/market-types' +import { z } from 'zod' + +type ResolutionProps = z.infer function getAnswerResolveButtonColor( resolveOption: string | undefined, @@ -119,18 +123,21 @@ function AnswersResolveOptions(props: { const resolutionProps = removeUndefinedProps({ contractId: contract.id, - outcome: resolveOption, + outcome: + resolveOption === 'CANCEL' + ? 'CANCEL' + : resolveOption === 'CHOOSE_ONE' + ? 'MKT' + : resolveOption, resolutions: resolveOption === 'CHOOSE_MULTIPLE' ? resolutions : undefined, answerId: resolveOption === 'CHOOSE_ONE' ? answerIds[0] : undefined, }) try { - // NOTE(James): I don't understand why this doesn't work without the cast to any. - const result = await api( - 'market/:contractId/resolve', - resolutionProps as any - ) + const validatedProps: ResolutionProps = + resolveMarketProps.parse(resolutionProps) // Validate props with Zod schema + const result = await api('market/:contractId/resolve', validatedProps) console.log('resolved', resolutionProps, 'result:', result) } catch (e) { if (e instanceof APIError) { @@ -423,49 +430,48 @@ export const IndependentAnswersResolvePanel = (props: { const isAdmin = useAdmin() const user = useUser() const answers = useAnswersCpmm(contract.id) ?? contract.answers - const isAdminorMod = useAdminOrMod() + const isAdminOrMod = useAdminOrMod() const [isSubmitting, setIsSubmitting] = useState(false) const [error, setError] = useState(undefined) const onCancelAll = async () => { setIsSubmitting(true) - try { - for (const answer of answers) { - const resolutionProps = removeUndefinedProps({ - contractId: contract.id, - outcome: 'CANCEL', - answerId: answer.id, - }) + setError(undefined) - try { - const result = await api( - 'market/:contractId/resolve', - resolutionProps as any - ) + const cancelPromises = answers.map((answer) => { + const resolutionProps: ResolutionProps = removeUndefinedProps({ + contractId: contract.id, + outcome: 'CANCEL', + answerId: answer.id, + }) + + return api('market/:contractId/resolve', resolutionProps) + .then((result) => { console.log('resolved', resolutionProps, 'result:', result) - } catch (e) { + }) + .catch((e) => { if (e instanceof APIError) { setError(e.toString()) } else { console.error(e) setError('Error resolving question') } - } - } - console.log('All contracts canceled') + }) + }) + + try { + await Promise.all(cancelPromises) + console.log('All contracts canceled successfully') } catch (e) { console.error(e) setError('Error canceling all contracts') + } finally { + setIsSubmitting(false) } - setIsSubmitting(false) } - const sortedAnswers = sortBy( - answers, - (a) => (a.resolution ? -a.subsidyPool : -Infinity), - (a) => a.index - ) + const sortedAnswers = sortAnswers(contract, answers) return ( @@ -475,7 +481,7 @@ export const IndependentAnswersResolvePanel = (props: { isCreator={user?.id === contract.creatorId} onClose={onClose} /> - {isAdminorMod && ( + {isAdminOrMod && (