diff --git a/kleros-sdk/src/dataMappings/utils/populateTemplate.ts b/kleros-sdk/src/dataMappings/utils/populateTemplate.ts index a70668ab7..68ae983ec 100644 --- a/kleros-sdk/src/dataMappings/utils/populateTemplate.ts +++ b/kleros-sdk/src/dataMappings/utils/populateTemplate.ts @@ -11,11 +11,23 @@ export const populateTemplate = (mustacheTemplate: string, data: any): DisputeDe throw validation.error; } - // Filter out any existing answer with id 0 and add our standard Refuse to Arbitrate option - (dispute as DisputeDetails).answers = [ - RefuseToArbitrateAnswer, - ...((dispute as DisputeDetails).answers.filter((answer) => answer.id && BigInt(answer.id) !== BigInt(0)) || []), - ]; + return findAndUpdateRTA(dispute); +}; + +// Filter out any existing answer with id 0 and add customised Refuse to Arbitrate option +const findAndUpdateRTA = (dispute: DisputeDetails) => { + const templateRTAIndex = (dispute as DisputeDetails).answers.findIndex( + (answer) => answer.id && BigInt(answer.id) === BigInt(0) + ); + + if (templateRTAIndex !== -1) { + dispute.answers[templateRTAIndex] = { + ...RefuseToArbitrateAnswer, + description: dispute.answers[templateRTAIndex].description ?? RefuseToArbitrateAnswer.description, + }; + } else { + dispute.answers = [RefuseToArbitrateAnswer, ...dispute.answers]; + } return dispute; }; diff --git a/kleros-sdk/test/getDispute.test.ts b/kleros-sdk/test/getDispute.test.ts index 0d1fadc0f..553a0ec27 100644 --- a/kleros-sdk/test/getDispute.test.ts +++ b/kleros-sdk/test/getDispute.test.ts @@ -105,7 +105,14 @@ describe("getDispute", () => { expect(result?.answers[2].id).toBe("0x2"); }); - it("should overwrite existing answer with id 0x0 or 0x00", async () => { + it("should only overwrite existing answer with id 0x0 or 0x00's title and not overwrite description", async () => { + const customRTAAnswer = { + id: "0x0", + title: "Custom Refuse Title", + description: "Custom Refuse Description", + reserved: true, + }; + // Test with 0x0 const mockTemplate0x0 = { disputeTemplate: { @@ -114,12 +121,7 @@ describe("getDispute", () => { description: "Test Description", question: "Test Question", answers: [ - { - id: "0x0", - title: "Custom Refuse Title", - description: "Custom Refuse Description", - reserved: true, - }, + customRTAAnswer, { id: "0x1", title: "Yes", @@ -145,7 +147,8 @@ describe("getDispute", () => { }); expect(result?.answers).toHaveLength(2); - expect(result?.answers[0]).toEqual(standardRefuseToArbitrateAnswer); + expect(result?.answers[0].title).toEqual(standardRefuseToArbitrateAnswer.title); + expect(result?.answers[0].description).toEqual(customRTAAnswer.description); expect(result?.answers[1].id).toBe("0x1"); // Test with 0x00 @@ -156,12 +159,7 @@ describe("getDispute", () => { description: "Test Description", question: "Test Question", answers: [ - { - id: "0x00", - title: "Custom Refuse Title", - description: "Custom Refuse Description", - reserved: true, - }, + customRTAAnswer, { id: "0x1", title: "Yes", @@ -186,7 +184,8 @@ describe("getDispute", () => { }); expect(result?.answers).toHaveLength(2); - expect(result?.answers[0]).toEqual(standardRefuseToArbitrateAnswer); + expect(result?.answers[0].title).toEqual(standardRefuseToArbitrateAnswer.title); + expect(result?.answers[0].description).toEqual(customRTAAnswer.description); expect(result?.answers[1].id).toBe("0x1"); }); diff --git a/web/src/pages/Cases/CaseDetails/Voting/Classic/OptionsContainer.tsx b/web/src/pages/Cases/CaseDetails/Voting/Classic/OptionsContainer.tsx index e3c4e2744..640c3dd9b 100644 --- a/web/src/pages/Cases/CaseDetails/Voting/Classic/OptionsContainer.tsx +++ b/web/src/pages/Cases/CaseDetails/Voting/Classic/OptionsContainer.tsx @@ -1,10 +1,10 @@ -import React, { useCallback, useState } from "react"; +import React, { useCallback, useMemo, useState } from "react"; import styled from "styled-components"; import ReactMarkdown from "react-markdown"; import { useParams } from "react-router-dom"; -import { Button } from "@kleros/ui-components-library"; +import { Button, Tooltip } from "@kleros/ui-components-library"; import { usePopulatedDisputeData } from "hooks/queries/usePopulatedDisputeData"; import { isUndefined } from "utils/index"; @@ -13,10 +13,13 @@ import { EnsureChain } from "components/EnsureChain"; import JustificationArea from "./JustificationArea"; import { Answer } from "@kleros/kleros-sdk"; +import { RefuseToArbitrateAnswer } from "@kleros/kleros-sdk/src/dataMappings/utils/disputeDetailsSchema"; const MainContainer = styled.div` width: 100%; height: auto; + display: flex; + flex-direction: column; `; const OptionsContainer = styled.div` @@ -40,6 +43,9 @@ const RefuseToArbitrateContainer = styled.div` justify-content: center; `; +const StyledEnsureChain = styled(EnsureChain)` + align-self: center; +`; interface IOptions { arbitrable: `0x${string}`; handleSelection: (arg0: bigint) => Promise; @@ -53,6 +59,12 @@ const Options: React.FC = ({ arbitrable, handleSelection, justificatio const [chosenOption, setChosenOption] = useState(BigInt(-1)); const [isSending, setIsSending] = useState(false); + const updatedRTA = useMemo(() => { + const RTAFromTemplate = disputeDetails?.answers?.find((answer) => BigInt(answer.id) === BigInt(0)); + if (!RTAFromTemplate) return RefuseToArbitrateAnswer; + return RTAFromTemplate; + }, [disputeDetails]); + const onClick = useCallback( async (id: bigint) => { setIsSending(true); @@ -71,30 +83,36 @@ const Options: React.FC = ({ arbitrable, handleSelection, justificatio {!isUndefined(justification) && !isUndefined(setJustification) ? ( ) : null} - - {disputeDetails?.answers?.map((answer: Answer) => { - return ( - -