kleros/kleros-v2

View on GitHub
web/src/context/NewDisputeContext.tsx

Summary

Maintainability
A
2 hrs
Test Coverage
import React, { createContext, useState, useContext, useMemo, useCallback } from "react";

import { Address } from "viem";

import { DEFAULT_CHAIN } from "consts/chains";
import { klerosCoreAddress } from "hooks/contracts/generated";
import { useLocalStorage } from "hooks/useLocalStorage";
import { isEmpty, isUndefined } from "utils/index";

export type Answer = {
  id: string;
  title: string;
  description: string;
  reserved?: boolean;
};

export type AliasArray = {
  id?: string;
  name: string;
  address: string | Address;
  isValid?: boolean;
};

export type Alias = Record<string, string>;
export interface IDisputeTemplate {
  answers: Answer[];
  arbitrableAddress?: string;
  arbitrableChainID?: string;
  arbitratorAddress?: string;
  arbitratorChainID?: string;
  category?: string;
  description: string;
  frontendUrl?: string;
  lang?: string;
  policyURI?: string;
  question: string;
  specification?: string;
  title: string;
  aliases?: Alias;
  version: string;
  // attachment: Attachment;
  // type: string;
}

interface IDisputeData extends IDisputeTemplate {
  courtId?: string;
  numberOfJurors: number;
  arbitrationCost?: string;
  aliasesArray?: AliasArray[];
}

interface INewDisputeContext {
  disputeData: IDisputeData;
  setDisputeData: (disputeData: IDisputeData) => void;
  disputeTemplate: IDisputeTemplate;
  resetDisputeData: () => void;
  isSubmittingCase: boolean;
  setIsSubmittingCase: (isSubmittingCase: boolean) => void;
  isPolicyUploading: boolean;
  setIsPolicyUploading: (isPolicyUploading: boolean) => void;
}

const initialDisputeData: IDisputeData = {
  numberOfJurors: 3,
  title: "",
  description: "",
  question: "",
  category: "",
  answers: [
    { title: "", id: "1", description: "" },
    { title: "", id: "2", description: "" },
  ],
  aliasesArray: [{ name: "", address: "", id: "1" }],
  version: "1.0",
};

const NewDisputeContext = createContext<INewDisputeContext | undefined>(undefined);

export const useNewDisputeContext = () => {
  const context = useContext(NewDisputeContext);
  if (!context) {
    throw new Error("Context Provider not found.");
  }
  return context;
};

export const NewDisputeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const [disputeData, setDisputeData] = useLocalStorage<IDisputeData>("disputeData", initialDisputeData);
  const [isSubmittingCase, setIsSubmittingCase] = useState<boolean>(false);
  const [isPolicyUploading, setIsPolicyUploading] = useState<boolean>(false);

  const disputeTemplate = useMemo(() => constructDisputeTemplate(disputeData), [disputeData]);

  const resetDisputeData = useCallback(() => {
    setDisputeData(initialDisputeData);
  }, [setDisputeData]);

  const contextValues = useMemo(
    () => ({
      disputeData,
      setDisputeData,
      disputeTemplate,
      resetDisputeData,
      isSubmittingCase,
      setIsSubmittingCase,
      isPolicyUploading,
      setIsPolicyUploading,
    }),
    [disputeData, disputeTemplate, resetDisputeData, isSubmittingCase, isPolicyUploading, setDisputeData]
  );

  return <NewDisputeContext.Provider value={contextValues}>{children}</NewDisputeContext.Provider>;
};

const constructDisputeTemplate = (disputeData: IDisputeData) => {
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  const { courtId, numberOfJurors, arbitrationCost, ...baseTemplate } = disputeData;

  if (!isUndefined(baseTemplate.aliasesArray)) {
    baseTemplate.aliasesArray = baseTemplate.aliasesArray.filter((item) => item.address !== "" && item.isValid);
    if (baseTemplate.aliasesArray.length === 0) delete baseTemplate.aliasesArray;
    else {
      const aliases: Alias = {};

      for (const alias of baseTemplate.aliasesArray) {
        aliases[alias.name] = alias.address;
      }

      baseTemplate.aliases = aliases;
    }
  }

  for (const answer of baseTemplate.answers) {
    answer.id = "0x" + BigInt(answer.id).toString(16);
  }
  if (!isUndefined(baseTemplate.policyURI) && isEmpty(baseTemplate.policyURI)) delete baseTemplate.policyURI;

  baseTemplate.arbitratorAddress = klerosCoreAddress[DEFAULT_CHAIN];
  baseTemplate.arbitratorChainID = DEFAULT_CHAIN.toString();

  return baseTemplate as IDisputeTemplate;
};