Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testnets #128

Merged
merged 3 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions public/logo/exclamation.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/app/[pohid]/[chain]/[request]/ActionBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,8 @@ export default withClientConnected<ActionBarProps>(function ActionBar({
challenger={currentChallenge.challenger?.id}
currentChallenge={currentChallenge}
chainId={chain.id}
revocation={revocation}
expired={expired}
/>

<ExternalLink
Expand Down
258 changes: 168 additions & 90 deletions src/app/[pohid]/[chain]/[request]/Appeal.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
"use client";

import { useEffectOnce } from "@legendapp/state/react";
import Accordion from "components/Accordion";
import Arrow from "components/Arrow";
import BulletedNumber from "components/BulletedNumber";
import ExternalLink from "components/ExternalLink";
import Field from "components/Field";
import Identicon from "components/Identicon";
import Modal from "components/Modal";
Expand All @@ -18,8 +20,10 @@ import { APIPoH, StakeMultipliers } from "contracts/apis/APIPoH";
import usePoHWrite from "contracts/hooks/usePoHWrite";
import { RequestQuery } from "generated/graphql";
import { useLoading } from "hooks/useLoading";
import Image from "next/image";
import { useMemo, useRef, useState } from "react";
import { toast } from "react-toastify";
import { camelToTitle } from "utils/case";
import { eth2Wei, formatEth } from "utils/misc";
import { Address } from "viem";

Expand Down Expand Up @@ -47,6 +51,8 @@ const SideFunding: React.FC<SideFundingProps> = ({
loosingSideHasEnd,
}) => {
const title = side === SideEnum.claimer ? "Claimer" : "Challenger";
const shrunkAddress: string =
requester.substring(0, 6) + " ... " + requester.slice(-4);
const [requesterInput, setRequesterInput] = useState(0n);
const loading = useLoading();
const errorRef = useRef(false);
Expand Down Expand Up @@ -78,43 +84,41 @@ const SideFunding: React.FC<SideFundingProps> = ({
);

return (
<Accordion className="mb-4" title={title}>
<div className="w-full border p-4">
<div className="mb-2 flex gap-2">
<Identicon diameter={32} address={requester} />
<div className="flex flex-col">
<span className="text-sm">{requester}</span>
<span className="text-xs">{title}</span>
</div>
</div>
<div className="flex gap-1">
<Field
type="number"
onChange={(v) => setRequesterInput(eth2Wei(+v.target.value))}
/>
<button
className={`gradient rounded px-4 text-white ${
!contributor || errorRef.current || loosingSideHasEnd
? "cursor-not-allowed opacity-50"
: ""
}`}
disabled={!contributor || errorRef.current || loosingSideHasEnd}
onClick={async () => {
prepareFundAppeal({
args: [arbitrator as Address, BigInt(disputeId), side],
value: requesterInput,
});
}}
>
Fund
</button>
<div className="w-full border p-4">
<div className="mb-2 flex gap-2">
<Identicon diameter={32} address={requester} />
<div className="flex flex-col">
<span>{title}</span>
<span className="text-sm">{shrunkAddress}</span>
</div>
<Progress
value={valueProgress}
label={`${formatEth(requesterFunds)} ${unit} of ${formatEth(appealCost)} ${unit}`}
</div>
<div className="flex gap-1">
<Field
type="number"
onChange={(v) => setRequesterInput(eth2Wei(+v.target.value))}
/>
<button
className={`gradient rounded px-4 text-white ${
!contributor || errorRef.current || loosingSideHasEnd
? "cursor-not-allowed opacity-50"
: ""
}`}
disabled={!contributor || errorRef.current || loosingSideHasEnd}
onClick={async () => {
prepareFundAppeal({
args: [arbitrator as Address, BigInt(disputeId), side],
value: requesterInput,
});
}}
>
Fund
</button>
</div>
</Accordion>
<Progress
value={valueProgress}
label={`${formatEth(requesterFunds)} ${unit} out of ${formatEth(appealCost)} ${unit}`}
/>
</div>
);
};

Expand All @@ -131,6 +135,8 @@ interface AppealProps {
currentChallenge: ArrayElement<
NonNullable<NonNullable<RequestQuery>["request"]>["challenges"]
>;
revocation: boolean;
expired: boolean;
}

const Appeal: React.FC<AppealProps> = ({
Expand All @@ -144,6 +150,8 @@ const Appeal: React.FC<AppealProps> = ({
claimer,
challenger,
currentChallenge,
revocation,
expired,
}) => {
const [totalClaimerCost, setTotalClaimerCost] = useState(0n);
const [totalChallengerCost, setTotalChallengerCost] = useState(0n);
Expand Down Expand Up @@ -297,62 +305,132 @@ const Appeal: React.FC<AppealProps> = ({
<h1 className="mb-4 text-xl">
Appeal the decision: {formatedCurrentRuling}
</h1>
<p className="txt">
In order to appeal the decision, you need to fully fund the
crowdfunding deposit. The dispute will be sent to the jurors when the
full deposit is reached. Note that if the previous round loser funds
its side, the previous round winner should also fully fund its side,
in order not to lose the case.
</p>
<br />
<h1 className="mb-4 text-xl">Appeal timeframes</h1>
<p className="txt">
Appeal timeframe ends&nbsp;
<TimeAgo time={parseInt(String(period[1]))} />
</p>
{loosingSideHasEnd ? (
<p className="txt">
Loosing side ended&nbsp;
<TimeAgo time={loosingSideDeadline} />
</p>
) : (
<p className="txt">
Loosing side ends&nbsp;
<TimeAgo time={loosingSideDeadline} />
</p>
)}
<br />
<SideFunding
side={SideEnum.claimer}
disputeId={disputeId}
arbitrator={arbitrator!}
contributor={contributor}
requester={claimer}
requesterFunds={claimerFunds}
appealCost={totalClaimerCost}
chainId={chainId}
loosingSideHasEnd={
currentRulingFormatted === SideEnum.challenger
? loosingSideHasEnd
: false
}
/>
<div className="gradient-border relative overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-r from-[#FF9966] to-[#FF8CA9]"></div>
<div className="absolute inset-0 border-2 border-solid border-transparent"></div>
<div className="mb-1"></div>
</div>
Comment on lines +308 to +312
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider simplifying gradient border implementation

The gradient border implementation could be simplified using a single div with border-image.

-<div className="gradient-border relative overflow-hidden">
-  <div className="absolute inset-0 bg-gradient-to-r from-[#FF9966] to-[#FF8CA9]"></div>
-  <div className="absolute inset-0 border-2 border-solid border-transparent"></div>
-  <div className="mb-1"></div>
-</div>
+<div className="h-1 w-full border-2 border-solid" style={{
+  borderImage: 'linear-gradient(to right, #FF9966, #FF8CA9) 1'
+}}></div>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div className="gradient-border relative overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-r from-[#FF9966] to-[#FF8CA9]"></div>
<div className="absolute inset-0 border-2 border-solid border-transparent"></div>
<div className="mb-1"></div>
</div>
<div className="h-1 w-full border-2 border-solid" style={{
borderImage: 'linear-gradient(to right, #FF9966, #FF8CA9) 1'
}}></div>

<div className="container mt-4">
<div className="flex items-center">
<BulletedNumber number={1} />
{!revocation ? (
<span className="mx-2 mt-2 text-sm">
The profile was challenged for{" "}
<strong className="text-status-challenged">
{camelToTitle(
currentChallenge.reason.id,
revocation,
expired,
)}
</strong>
.
</span>
) : (
<span className="mx-2 mt-2 text-sm">
The profile was challenged.
</span>
)}
</div>
<div className="flex items-center">
<BulletedNumber number={2} />

<span className="mx-2 mt-2 text-sm">
Independent jurors evaluated the evidence, policy compliance, and
voted in favor of:{" "}
{currentRulingFormatted === SideEnum.challenger
? "Challenger"
: currentRulingFormatted === SideEnum.claimer
? "Claimer"
: "Shared"}
.
<div className="mt-[-1.4rem]">
<ExternalLink
className="text-orange mx-2 flex flex-row flex-wrap justify-end gap-x-[8px] text-sm font-semibold leading-none hover:text-orange-500 md:gap-2 lg:gap-3"
href={`https://resolve.kleros.io/cases/${currentChallenge.disputeId}`}
>
<span className="mt-1 text-right text-sm font-semibold leading-none">
Check how the jury voted
</span>
<Arrow />
</ExternalLink>
</div>
</span>
</div>
<div className="flex items-center">
<BulletedNumber number={3} current={!loosingSideHasEnd} />
{loosingSideHasEnd ? (
<span className="mx-2 mt-2 text-sm">
The losing party's appeal time ended&nbsp;
<TimeAgo time={loosingSideDeadline} />.
</span>
) : (
<span className="mx-2 mt-2 text-sm">
The losing party's appeal time ends&nbsp;
<TimeAgo time={loosingSideDeadline} />.
</span>
)}
</div>
<div className="flex items-center">
<BulletedNumber number={4} current />
<span className="mx-2 mt-2 text-sm">
Appeal timeframe ends&nbsp;
<TimeAgo time={parseInt(String(period[1]))} />.
</span>
</div>
<div className="mb-4 mt-4">
<span className="text-sm">
In order to appeal the decision, you need to fully fund the
crowdfunding deposit. The dispute will be sent to the jurors when
the full deposit is reached. Note that if the previous round loser
funds its side, the previous round winner should also fully fund
its side, in order not to lose the case.
</span>
<div className="mt-4 flex items-center opacity-75">
<Image
alt="warning"
src="/logo/exclamation.svg"
height={24}
width={24}
/>
<span className="mx-2 text-sm opacity-75">
External contributors can also crowdfund the appeal.
</span>
</div>
</div>
</div>
<br />
<SideFunding
side={SideEnum.challenger}
disputeId={disputeId}
arbitrator={arbitrator!}
contributor={contributor}
requester={challenger}
requesterFunds={challengerFunds}
appealCost={totalChallengerCost}
chainId={chainId}
loosingSideHasEnd={
currentRulingFormatted === SideEnum.claimer
? loosingSideHasEnd
: false
}
/>
<div className="flex items-center">
<SideFunding
side={SideEnum.claimer}
disputeId={disputeId}
arbitrator={arbitrator!}
contributor={contributor}
requester={claimer}
requesterFunds={claimerFunds}
appealCost={totalClaimerCost}
chainId={chainId}
loosingSideHasEnd={
currentRulingFormatted === SideEnum.challenger
? loosingSideHasEnd
: false
}
/>
<SideFunding
side={SideEnum.challenger}
disputeId={disputeId}
arbitrator={arbitrator!}
contributor={contributor}
requester={challenger}
requesterFunds={challengerFunds}
appealCost={totalChallengerCost}
chainId={chainId}
loosingSideHasEnd={
currentRulingFormatted === SideEnum.claimer
? loosingSideHasEnd
: false
}
/>
</div>
Comment on lines +402 to +433
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Simplify funding section conditional logic

The nested ternary operators for loosingSideHasEnd could be simplified using a function.

+const isLoosingSide = (side: SideEnum, currentRuling: SideEnum) => {
+  return (side === SideEnum.claimer && currentRuling === SideEnum.challenger) ||
+         (side === SideEnum.challenger && currentRuling === SideEnum.claimer);
+};

 <SideFunding
   // ... other props
-  loosingSideHasEnd={
-    currentRulingFormatted === SideEnum.challenger
-      ? loosingSideHasEnd
-      : false
-  }
+  loosingSideHasEnd={isLoosingSide(SideEnum.claimer, currentRulingFormatted) && loosingSideHasEnd}
 />

Committable suggestion skipped: line range outside the PR's diff.

</div>
</Modal>
) : null;
Expand Down
10 changes: 6 additions & 4 deletions src/app/[pohid]/[chain]/[request]/Info.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
"use client";

import Modal from "components/Modal";
import InfoIcon from "icons/info.svg";
import Image from "next/image";
import Modal from "components/Modal";

interface InfoProps {
nbRequests: number;
label: string;
}

export default function Info({ nbRequests }: InfoProps) {
export default function Info({ nbRequests, label }: InfoProps) {
return (
<Modal
formal
className="flex flex-col p-8"
trigger={
<span className="flex cursor-pointer gap-x-[4px] text-slate-500">
<InfoIcon className="h-6 w-6 stroke-slate-500 stroke-2" />
<span className="flex cursor-pointer gap-x-[4px] text-slate-500 hover:text-slate-700">
{label}&nbsp;
<InfoIcon className="h-6 w-6 stroke-slate-500 stroke-2 hover:stroke-slate-700" />
</span>
Comment on lines +18 to 21
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Consider improving accessibility of the modal trigger.

The current implementation has accessibility limitations:

  1. Using a span with cursor-pointer for an interactive element instead of a semantic button
  2. Missing keyboard interaction support
  3. No ARIA labels for screen readers

Consider applying these improvements:

-        <span className="flex cursor-pointer gap-x-[4px] text-slate-500 hover:text-slate-700">
+        <button
+          type="button"
+          className="flex items-center gap-x-[4px] text-slate-500 hover:text-slate-700"
+          aria-label={`Information about ${label}`}
+        >
           {label}&nbsp;
           <InfoIcon className="h-6 w-6 stroke-slate-500 stroke-2 hover:stroke-slate-700" />
-        </span>
+        </button>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<span className="flex cursor-pointer gap-x-[4px] text-slate-500 hover:text-slate-700">
{label}&nbsp;
<InfoIcon className="h-6 w-6 stroke-slate-500 stroke-2 hover:stroke-slate-700" />
</span>
<button
type="button"
className="flex items-center gap-x-[4px] text-slate-500 hover:text-slate-700"
aria-label={`Information about ${label}`}
>
{label}&nbsp;
<InfoIcon className="h-6 w-6 stroke-slate-500 stroke-2 hover:stroke-slate-700" />
</button>

}
>
Expand Down
29 changes: 15 additions & 14 deletions src/app/[pohid]/[chain]/[request]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -361,17 +361,13 @@ export default async function Request({ params }: PageProps) {
</div>
<div className="mb-4 h-1 w-full border-b"></div>
<div className="mb-2 flex flex-col-reverse justify-between md:flex-row">
<div className="flex items-center">
<span className="flex items-center text-slate-400">POH ID</span>
<div className="mx-[10px]">
<Info
nbRequests={
+request.humanity.nbRequests +
+request.humanity.nbLegacyRequests
}
/>
</div>
</div>
<Info
label="POH ID"
nbRequests={
+request.humanity.nbRequests +
+request.humanity.nbLegacyRequests
}
/>
</div>
<div className="text-orange mb-8 flex flex-wrap gap-x-[8px] gap-y-[8px] font-medium">
<Link
Expand Down Expand Up @@ -432,10 +428,15 @@ export default async function Request({ params }: PageProps) {
className="text-primaryText ml-2"
>
<div className="text-primaryText group relative flex py-[8px]">
Policy in force at submission
<div className="\\ \\ \\ \\ \\ \\ \\ \\ outline-color: #E5E5E5 \\ bg-whiteBackground text-secondaryText invisible absolute left-1/2 z-10 m-4 mx-auto w-[260px] flex-shrink-0 -translate-x-1/2 transform place-content-center content-between rounded-[3px] border-[1px] border-[solid] bg-[var(--Light-Mode-White-background,_#FFF)] p-[8px] text-justify text-[14px] font-normal not-italic leading-[normal] outline-black transition-opacity ease-in-out [box-shadow:0px_2px_3px_0px_rgba(0,_0,_0,_0.06)] group-hover:visible md:w-[400px]">
<Image
alt="warning"
src="/logo/exclamation.svg"
height={24}
width={24}
/>
&nbsp; Policy in force at submission
<div className="outline-color: #E5E5E5 bg-whiteBackground text-secondaryText invisible absolute left-1/2 z-10 m-4 mx-auto w-[260px] flex-shrink-0 -translate-x-1/2 transform place-content-center content-between rounded-[3px] border-[1px] border-[solid] bg-[var(--Light-Mode-White-background,_#FFF)] p-[8px] text-justify text-[14px] font-normal not-italic leading-[normal] outline-black transition-opacity ease-in-out [box-shadow:0px_2px_3px_0px_rgba(0,_0,_0,_0.06)] group-hover:visible md:w-[400px]">
Comment on lines +431 to +438
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider improving tooltip accessibility and readability.

While the warning icon and tooltip provide valuable context about policy versioning, consider these improvements:

  1. The tooltip's visibility relies on CSS hover, which isn't touch-device friendly.
  2. The tooltip text is quite dense and could benefit from better formatting.

Consider these enhancements:

-<div className="text-primaryText group relative flex py-[8px]">
+<div className="text-primaryText group relative flex py-[8px]"
+     role="button"
+     tabIndex={0}
+     onClick={() => setTooltipVisible(!tooltipVisible)}
+     onKeyPress={(e) => e.key === 'Enter' && setTooltipVisible(!tooltipVisible)}>
   <Image
     alt="warning"
     src="/logo/exclamation.svg"
     height={24}
     width={24}
   />
   &nbsp; Policy in force at submission
-  <div className="outline-color: #E5E5E5 bg-whiteBackground text-secondaryText invisible absolute left-1/2 z-10 m-4 mx-auto w-[260px] flex-shrink-0 -translate-x-1/2 transform place-content-center content-between rounded-[3px] border-[1px] border-[solid] bg-[var(--Light-Mode-White-background,_#FFF)] p-[8px] text-justify text-[14px] font-normal not-italic leading-[normal] outline-black transition-opacity ease-in-out [box-shadow:0px_2px_3px_0px_rgba(0,_0,_0,_0.06)] group-hover:visible md:w-[400px]">
+  <div className={`outline-color: #E5E5E5 bg-whiteBackground text-secondaryText absolute left-1/2 z-10 m-4 mx-auto w-[260px] flex-shrink-0 -translate-x-1/2 transform place-content-center content-between rounded-[3px] border-[1px] border-[solid] bg-[var(--Light-Mode-White-background,_#FFF)] p-[8px] text-[14px] font-normal not-italic leading-[normal] outline-black transition-opacity ease-in-out [box-shadow:0px_2px_3px_0px_rgba(0,_0,_0,_0.06)] md:w-[400px] ${tooltipVisible ? 'visible' : 'invisible'}`}
+       role="tooltip">
     <span>
-      This is the policy that was in effect when this submission was made. Why is this important? Policies may change over time, and it's crucial to know the policy that was in force at the time of a submission before challenging or removing a profile. If you challenge this submission, this version of the policy will be enforced by Kleros jurors if the case goes to arbitration. Also, if you revoke this profile citing "incorrect submission," but the submission complied with this policy, your revocation request may be rejected, and you may lose your deposit.
+      <p className="mb-2"><strong>Why is this important?</strong></p>
+      <p className="mb-2">This is the policy that was in effect when this submission was made. Policies may change over time, and it's crucial to know the applicable policy before challenging or removing a profile.</p>
+      <p className="mb-2">If you challenge this submission, this version of the policy will be enforced by Kleros jurors during arbitration.</p>
+      <p>Note: Revoking this profile for "incorrect submission" when it complied with this policy may result in rejection and deposit loss.</p>
     </span>
   </div>
 </div>

You'll need to add state management at the component level:

const [tooltipVisible, setTooltipVisible] = useState(false);

<span>
{/* (Policy in force since {new Date(policyUpdate * 1000).toDateString()}) */}
This is the policy that was in effect when this
submission was made. Why is this important? Policies
may change over time, and it's crucial to know the
Expand Down
Loading
Loading