diff --git a/web/src/components/DisputeCard/index.tsx b/web/src/components/DisputeCard/index.tsx index 55dccd0b6..49f56a168 100644 --- a/web/src/components/DisputeCard/index.tsx +++ b/web/src/components/DisputeCard/index.tsx @@ -9,13 +9,11 @@ import { useIsList } from "context/IsListProvider"; import { DisputeDetailsFragment } from "queries/useCasesQuery"; import { landscapeStyle } from "styles/landscapeStyle"; import { useCourtPolicy } from "queries/useCourtPolicy"; -import { useDisputeTemplate } from "queries/useDisputeTemplate"; +import { usePopulatedDisputeData } from "hooks/queries/usePopulatedDisputeData"; import DisputeInfo from "./DisputeInfo"; import PeriodBanner from "./PeriodBanner"; import { isUndefined } from "utils/index"; import { responsiveSize } from "styles/responsiveSize"; -import { populateTemplate } from "@kleros/kleros-sdk/src/dataMappings/utils/populateTemplate"; -import { DisputeDetails } from "@kleros/kleros-sdk/src/dataMappings/utils/disputeDetailsTypes"; import { INVALID_DISPUTE_DATA_ERROR } from "consts/index"; const StyledCard = styled(Card)` @@ -106,18 +104,11 @@ const DisputeCard: React.FC = ({ currentPeriodIndex === 4 ? lastPeriodChange : getPeriodEndTimestamp(lastPeriodChange, currentPeriodIndex, court.timesPerPeriod); - const { data: disputeTemplate } = useDisputeTemplate(id, arbitrated.id as `0x${string}`); - let disputeDetails: DisputeDetails | undefined; - try { - if (disputeTemplate) { - disputeDetails = populateTemplate(disputeTemplate.templateData, {}); - } - } catch (e) { - console.error(e); - } + const { data: disputeDetails } = usePopulatedDisputeData(id, arbitrated.id as `0x${string}`); + const { data: courtPolicy } = useCourtPolicy(court.id); const courtName = courtPolicy?.name; - const category = disputeTemplate?.category; + const category = disputeDetails?.category; const navigate = useNavigate(); return ( <> @@ -125,7 +116,7 @@ const DisputeCard: React.FC = ({ navigate(`/cases/${id.toString()}`)}> - {isUndefined(disputeTemplate) ? ( + {isUndefined(disputeDetails) ? ( ) : ( diff --git a/web/src/components/DisputePreview/DisputeContext.tsx b/web/src/components/DisputePreview/DisputeContext.tsx index 8f425f20d..997466526 100644 --- a/web/src/components/DisputePreview/DisputeContext.tsx +++ b/web/src/components/DisputePreview/DisputeContext.tsx @@ -7,6 +7,7 @@ import { Answer as IAnswer } from "context/NewDisputeContext"; import AliasDisplay from "./Alias"; import { responsiveSize } from "styles/responsiveSize"; import { DisputeDetails } from "@kleros/kleros-sdk/src/dataMappings/utils/disputeDetailsTypes"; +import { INVALID_DISPUTE_DATA_ERROR } from "consts/index"; const StyledH1 = styled.h1` margin: 0; @@ -65,11 +66,7 @@ export const DisputeContext: React.FC = ({ disputeDetails }) => return ( <> - {isUndefined(disputeDetails) ? ( - - ) : ( - disputeDetails?.title ?? "The dispute's template is not correct please vote refuse to arbitrate" - )} + {isUndefined(disputeDetails) ? : disputeDetails?.title ?? INVALID_DISPUTE_DATA_ERROR} {!isUndefined(disputeDetails) && ( diff --git a/web/src/components/Verdict/DisputeTimeline.tsx b/web/src/components/Verdict/DisputeTimeline.tsx index 11bfd211b..a5f14ef2b 100644 --- a/web/src/components/Verdict/DisputeTimeline.tsx +++ b/web/src/components/Verdict/DisputeTimeline.tsx @@ -8,7 +8,7 @@ import AppealedCaseIcon from "assets/svgs/icons/close-circle.svg"; import { Periods } from "consts/periods"; import { ClassicRound } from "src/graphql/graphql"; import { DisputeDetailsQuery, useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; -import { useDisputeTemplate } from "queries/useDisputeTemplate"; +import { usePopulatedDisputeData } from "hooks/queries/usePopulatedDisputeData"; import { useVotingHistory } from "queries/useVotingHistory"; import { getLocalRounds } from "utils/getLocalRounds"; import { responsiveSize } from "styles/responsiveSize"; @@ -56,7 +56,7 @@ type TimelineItems = [_TimelineItem1, ..._TimelineItem1[]]; const useItems = (disputeDetails?: DisputeDetailsQuery, arbitrable?: `0x${string}`) => { const { id } = useParams(); const { data: votingHistory } = useVotingHistory(id); - const { data: disputeTemplate } = useDisputeTemplate(id, arbitrable); + const { data: disputeData } = usePopulatedDisputeData(id, arbitrable); const localRounds: ClassicRound[] = getLocalRounds(votingHistory?.dispute?.disputeKitDispute) as ClassicRound[]; const rounds = votingHistory?.dispute?.rounds; const theme = useTheme(); @@ -75,7 +75,7 @@ const useItems = (disputeDetails?: DisputeDetailsQuery, arbitrable?: `0x${string const roundTimeline = rounds?.[index].timeline; const icon = dispute.ruled && !rulingOverride && index === localRounds.length - 1 ? ClosedCaseIcon : ""; - const answers = disputeTemplate?.answers; + const answers = disputeData?.answers; acc.push({ title: `Jury Decision - Round ${index + 1}`, party: isOngoing ? "Voting is ongoing" : getVoteChoice(parsedRoundChoice, answers), @@ -121,7 +121,7 @@ const useItems = (disputeDetails?: DisputeDetailsQuery, arbitrable?: `0x${string ); } return; - }, [disputeDetails, disputeTemplate, localRounds, theme]); + }, [disputeDetails, disputeData, localRounds, theme]); }; interface IDisputeTimeline { diff --git a/web/src/components/Verdict/FinalDecision.tsx b/web/src/components/Verdict/FinalDecision.tsx index e168f3989..489fe585f 100644 --- a/web/src/components/Verdict/FinalDecision.tsx +++ b/web/src/components/Verdict/FinalDecision.tsx @@ -4,7 +4,7 @@ import styled from "styled-components"; import ArrowIcon from "assets/svgs/icons/arrow.svg"; import { useKlerosCoreCurrentRuling } from "hooks/contracts/generated"; import { useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; -import { useDisputeTemplate } from "queries/useDisputeTemplate"; +import { usePopulatedDisputeData } from "hooks/queries/usePopulatedDisputeData"; import LightButton from "../LightButton"; import VerdictBanner from "./VerdictBanner"; import { responsiveSize } from "styles/responsiveSize"; @@ -61,14 +61,14 @@ interface IFinalDecision { const FinalDecision: React.FC = ({ arbitrable }) => { const { id } = useParams(); const { isDisconnected } = useAccount(); - const { data: disputeTemplate } = useDisputeTemplate(id, arbitrable); + const { data: populatedDisputeData } = usePopulatedDisputeData(id, arbitrable); const { data: disputeDetails } = useDisputeDetailsQuery(id); const { wasDrawn, hasVoted, isLoading, isCommitPeriod, isVotingPeriod, commited, isHiddenVotes } = useVotingContext(); const ruled = disputeDetails?.dispute?.ruled ?? false; const navigate = useNavigate(); const { data: currentRulingArray } = useKlerosCoreCurrentRuling({ args: [BigInt(id ?? 0)], watch: true }); const currentRuling = Number(currentRulingArray?.[0]); - const answer = disputeTemplate?.answers?.[currentRuling! - 1]; + const answer = populatedDisputeData?.answers?.[currentRuling! - 1]; const buttonText = useMemo(() => { if (!wasDrawn || isDisconnected) return "Check how the jury voted"; if (isCommitPeriod && !commited) return "Commit your vote"; diff --git a/web/src/hooks/queries/useDisputeTemplate.ts b/web/src/hooks/queries/usePopulatedDisputeData.ts similarity index 65% rename from web/src/hooks/queries/useDisputeTemplate.ts rename to web/src/hooks/queries/usePopulatedDisputeData.ts index 9238745d6..b48980c58 100644 --- a/web/src/hooks/queries/useDisputeTemplate.ts +++ b/web/src/hooks/queries/usePopulatedDisputeData.ts @@ -4,9 +4,12 @@ import { PublicClient } from "viem"; import { usePublicClient } from "wagmi"; import { getIArbitrableV2 } from "hooks/contracts/generated"; import { isUndefined } from "utils/index"; -import { graphqlQueryFnHelper, graphqlUrl } from "utils/graphqlQueryFnHelper"; +import { graphqlQueryFnHelper } from "utils/graphqlQueryFnHelper"; import { useIsCrossChainDispute } from "../useIsCrossChainDispute"; import { GENESIS_BLOCK_ARBSEPOLIA } from "consts/index"; +import { populateTemplate } from "@kleros/kleros-sdk/src/dataMappings/utils/populateTemplate"; +import { executeActions } from "@kleros/kleros-sdk/src/dataMappings/executeActions"; +import { DisputeDetails } from "@kleros/kleros-sdk/src/dataMappings/utils/disputeDetailsTypes"; const disputeTemplateQuery = graphql(` query DisputeTemplate($id: ID!) { @@ -19,31 +22,41 @@ const disputeTemplateQuery = graphql(` } `); -export const useDisputeTemplate = (disputeID?: string, arbitrableAddress?: `0x${string}`) => { +export const usePopulatedDisputeData = (disputeID?: string, arbitrableAddress?: `0x${string}`) => { const publicClient = usePublicClient(); const { data: crossChainData } = useIsCrossChainDispute(disputeID, arbitrableAddress); const isEnabled = !isUndefined(disputeID) && !isUndefined(crossChainData) && !isUndefined(arbitrableAddress); - return useQuery({ + return useQuery({ queryKey: [`DisputeTemplate${disputeID}${arbitrableAddress}`], enabled: isEnabled, staleTime: Infinity, queryFn: async () => { if (isEnabled) { try { - const { isCrossChainDispute, crossChainId, crossChainTemplateId } = crossChainData; + const { isCrossChainDispute, crossChainTemplateId } = crossChainData; const templateId = isCrossChainDispute ? crossChainTemplateId : await getTemplateId(arbitrableAddress, disputeID, publicClient); + const { disputeTemplate } = await graphqlQueryFnHelper( disputeTemplateQuery, { id: templateId.toString() }, true ); - console.log("useDisputeTemplate:", disputeTemplate); + const templateData = disputeTemplate?.templateData; + const dataMappings = disputeTemplate?.templateDataMappings; + + const initialContext = { + disputeID: disputeID, + arbitrable: arbitrableAddress, + }; + + const data = dataMappings ? await executeActions(JSON.parse(dataMappings), initialContext) : {}; + const disputeDetails = populateTemplate(templateData, data); - return disputeTemplate; + return disputeDetails; } catch { - return {}; + return {} as DisputeDetails; } } else throw Error; }, diff --git a/web/src/hooks/useClassicAppealContext.tsx b/web/src/hooks/useClassicAppealContext.tsx index 067d30b2c..65a936c30 100644 --- a/web/src/hooks/useClassicAppealContext.tsx +++ b/web/src/hooks/useClassicAppealContext.tsx @@ -2,7 +2,7 @@ import React, { useMemo, useState, createContext, useContext } from "react"; import { useParams } from "react-router-dom"; import { ONE_BASIS_POINT } from "consts/index"; import { Periods } from "consts/periods"; -import { useDisputeTemplate } from "queries/useDisputeTemplate"; +import { usePopulatedDisputeData } from "hooks/queries/usePopulatedDisputeData"; import { useAppealCost } from "queries/useAppealCost"; import { useDisputeKitClassicMultipliers } from "queries/useDisputeKitClassicMultipliers"; import { useClassicAppealQuery, ClassicAppealQuery } from "queries/useClassicAppealQuery"; @@ -52,10 +52,10 @@ export const ClassicAppealProvider: React.FC<{ const winningChoice = getWinningChoice(data?.dispute); const { data: appealCost } = useAppealCost(id); const arbitrable = data?.dispute?.arbitrated.id; - const { data: disputeTemplate } = useDisputeTemplate(id, arbitrable); + const { data: disputeDetails } = usePopulatedDisputeData(id, arbitrable); const { data: multipliers } = useDisputeKitClassicMultipliers(); const options = ["Refuse to Arbitrate"].concat( - disputeTemplate?.answers?.map((answer: { title: string; description: string }) => { + disputeDetails?.answers?.map((answer: { title: string; description: string }) => { return answer.title; }) ); diff --git a/web/src/pages/Cases/CaseDetails/Overview/index.tsx b/web/src/pages/Cases/CaseDetails/Overview/index.tsx index c91d255c9..8bd5e7c3c 100644 --- a/web/src/pages/Cases/CaseDetails/Overview/index.tsx +++ b/web/src/pages/Cases/CaseDetails/Overview/index.tsx @@ -1,15 +1,10 @@ -import React, { useMemo, useState, useEffect } from "react"; +import React, { useMemo } from "react"; import styled from "styled-components"; import { useParams } from "react-router-dom"; import { formatEther } from "viem"; import { useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; -import { useDisputeTemplate } from "queries/useDisputeTemplate"; +import { usePopulatedDisputeData } from "hooks/queries/usePopulatedDisputeData"; import { useCourtPolicy } from "queries/useCourtPolicy"; -import { populateTemplate } from "@kleros/kleros-sdk/src/dataMappings/utils/populateTemplate"; -import { executeActions } from "@kleros/kleros-sdk/src/dataMappings/executeActions"; -import { configureSDK } from "@kleros/kleros-sdk/src/sdk"; -import { alchemyApiKey } from "context/Web3Provider"; -import { DisputeDetails } from "@kleros/kleros-sdk/src/dataMappings/utils/disputeDetailsTypes"; import DisputeInfo from "components/DisputeCard/DisputeInfo"; import Verdict from "components/Verdict/index"; import { useVotingHistory } from "hooks/queries/useVotingHistory"; @@ -44,48 +39,15 @@ interface IOverview { const Overview: React.FC = ({ arbitrable, courtID, currentPeriodIndex }) => { const { id } = useParams(); - const { data: disputeTemplate } = useDisputeTemplate(id, arbitrable); + const { data: disputeDetails } = usePopulatedDisputeData(id, arbitrable); const { data: dispute } = useDisputeDetailsQuery(id); const { data: courtPolicy } = useCourtPolicy(courtID); const { data: votingHistory } = useVotingHistory(id); - const [disputeDetails, setDisputeDetails] = useState(undefined); const localRounds = getLocalRounds(votingHistory?.dispute?.disputeKitDispute); const courtName = courtPolicy?.name; const court = dispute?.dispute?.court; const rewards = useMemo(() => (court ? `≥ ${formatEther(court.feeForJuror)} ETH` : undefined), [court]); - const category = disputeTemplate?.category ?? undefined; - const disputeTemplateInput = disputeTemplate?.templateData; - const dataMappingsInput = disputeTemplate?.templateDataMappings; - - useEffect(() => { - configureSDK({ apiKey: alchemyApiKey }); - const initialContext = { - disputeID: id, - arbitrable: arbitrable, - }; - - if (!disputeTemplateInput) return; - - const fetchData = async () => { - try { - console.log("dataMappingsInput", dataMappingsInput); - let data = {}; - if (dataMappingsInput) { - const parsedMappings = JSON.parse(dataMappingsInput); - console.log("parsedMappings", parsedMappings); - data = await executeActions(parsedMappings, initialContext); - } - console.log("data", data); - const finalDisputeDetails = populateTemplate(disputeTemplateInput, data); - setDisputeDetails(finalDisputeDetails); - } catch (e) { - console.error(e); - setDisputeDetails(undefined); - } - }; - - fetchData(); - }, [disputeTemplateInput, dataMappingsInput, arbitrable, id]); + const category = disputeDetails?.category; return ( <> diff --git a/web/src/pages/Cases/CaseDetails/Voting/Classic/OptionsContainer.tsx b/web/src/pages/Cases/CaseDetails/Voting/Classic/OptionsContainer.tsx index ff550b96c..3bbbd4b48 100644 --- a/web/src/pages/Cases/CaseDetails/Voting/Classic/OptionsContainer.tsx +++ b/web/src/pages/Cases/CaseDetails/Voting/Classic/OptionsContainer.tsx @@ -4,7 +4,7 @@ import { useParams } from "react-router-dom"; import ReactMarkdown from "react-markdown"; import { Button } from "@kleros/ui-components-library"; import { isUndefined } from "utils/index"; -import { useDisputeTemplate } from "queries/useDisputeTemplate"; +import { usePopulatedDisputeData } from "hooks/queries/usePopulatedDisputeData"; import { EnsureChain } from "components/EnsureChain"; import JustificationArea from "./JustificationArea"; @@ -43,7 +43,7 @@ interface IOptions { const Options: React.FC = ({ arbitrable, handleSelection, justification, setJustification }) => { const { id } = useParams(); - const { data: disputeTemplate } = useDisputeTemplate(id, arbitrable); + const { data: disputeDetails } = usePopulatedDisputeData(id, arbitrable); const [chosenOption, setChosenOption] = useState(-1); const [isSending, setIsSending] = useState(false); @@ -61,12 +61,12 @@ const Options: React.FC = ({ arbitrable, handleSelection, justificatio return id ? ( <> - {disputeTemplate?.question} + {disputeDetails?.question} {!isUndefined(justification) && !isUndefined(setJustification) ? ( ) : null} - {disputeTemplate?.answers?.map((answer: { title: string; description: string }, i: number) => { + {disputeDetails?.answers?.map((answer: { title: string; description: string }, i: number) => { return (