diff --git a/web/src/components/Popup/MiniGuides/JurorLevels.tsx b/web/src/components/Popup/MiniGuides/JurorLevels.tsx
index b8043e26f..a250cc355 100644
--- a/web/src/components/Popup/MiniGuides/JurorLevels.tsx
+++ b/web/src/components/Popup/MiniGuides/JurorLevels.tsx
@@ -31,64 +31,73 @@ const Card = styled(_Card)`
`;
const leftPageContents = [
+ {
+ title: "Juror Level 0: Diogenes",
+ paragraphs: [
+ "Coherence Score below 25.",
+ "This level is for new jurors or those frequently voting incoherently. A few coherent votes can help climb out of this level quickly.",
+ ],
+ },
{
title: "Juror Level 1: Pythagoras",
paragraphs: [
- "Jurors are classified into distinct levels according to their performance starting from Level 1.",
- "Level 1: Jurors with ≥ 1 case arbitrated with 0-70% of coherent votes.",
+ "Coherence Score between 25 and 49.",
+ "Jurors here are gaining experience and starting to build voting reliability.",
],
},
{
title: "Juror Level 2: Socrates",
- paragraphs: ["Level 2: Jurors with ≥ 3 cases arbitrated with more than 70% coherent votes."],
+ paragraphs: [
+ "Coherence Score between 50 and 69.",
+ "Mid-tier performance. Jurors at this level have demonstrated reasonable consistency in coherent voting.",
+ ],
},
{
title: "Juror Level 3: Plato",
- paragraphs: ["Level 3: Jurors with ≥ 7 cases arbitrated with more than 80% of coherent votes."],
+ paragraphs: [
+ "Coherence Score between 70 and 89.",
+ "Reliable jurors with a consistent track record of coherent votes. Just a few more coherent votes away from reaching the top.",
+ ],
},
{
title: "Juror Level 4: Aristotle",
- paragraphs: ["Level 4: Jurors with ≥ 10 cases arbitrated with more than 90% of coherent votes."],
- },
- {
- title: "Juror Level 0: Diogenes",
paragraphs: [
- "There's a level for the low-performance/lazy jurors. Level 0: Jurors with ≥ 3 cases arbitrated" +
- " with less than 50% of coherent votes.",
+ "Coherence Score between 90 and 100.",
+ "Top-tier jurors with excellent coherence. Trusted members of the platform.",
],
},
];
const userLevelData = [
+ {
+ level: 0,
+ title: "Diogenes",
+ totalCoherentVotes: 2,
+ totalResolvedVotes: 10,
+ },
{
level: 1,
title: "Pythagoras",
totalCoherentVotes: 6,
- totalResolvedVotes: 10,
+ totalResolvedVotes: 12,
},
{
level: 2,
title: "Socrates",
- totalCoherentVotes: 7,
- totalResolvedVotes: 10,
+ totalCoherentVotes: 22,
+ totalResolvedVotes: 34,
},
{
level: 3,
title: "Plato",
- totalCoherentVotes: 8,
- totalResolvedVotes: 10,
+ totalCoherentVotes: 52,
+ totalResolvedVotes: 65,
},
{
level: 4,
title: "Aristotle",
- totalCoherentVotes: 9,
- totalResolvedVotes: 10,
- },
- {
- level: 0,
- title: "Diogenes",
- totalCoherentVotes: 3,
- totalResolvedVotes: 10,
+ totalCoherentVotes: 90,
+ totalResolvedVotes: 90,
},
];
diff --git a/web/src/pages/Home/TopJurors/Header/Coherence.tsx b/web/src/pages/Home/TopJurors/Header/Coherence.tsx
index b4823abcb..d65aa4c9b 100644
--- a/web/src/pages/Home/TopJurors/Header/Coherence.tsx
+++ b/web/src/pages/Home/TopJurors/Header/Coherence.tsx
@@ -11,7 +11,7 @@ const Container = styled.div`
display: flex;
font-size: 12px !important;
&::before {
- content: "Coherence";
+ content: "Coherent\u00a0Votes";
}
color: ${({ theme }) => theme.secondaryText};
align-items: center;
@@ -25,18 +25,17 @@ const Container = styled.div`
`;
const coherentVotesTooltipMsg =
- "This is the percentage of coherent votes made by a juror." +
- " Hover to see the ratio of coherent votes: " +
+ "This is the ratio of coherent votes made by a juror: " +
"the number in the left is the number of times where the juror " +
"voted coherently and the number in the right is the total number of times " +
- "the juror voted";
+ "the juror voted. Hover to see the percentage of coherent votes.";
const Coherence: React.FC = () => {
const isDesktop = useIsDesktop();
return (
-
+
);
};
diff --git a/web/src/pages/Home/TopJurors/Header/DesktopHeader.tsx b/web/src/pages/Home/TopJurors/Header/DesktopHeader.tsx
index d19f39094..c4fe7f51f 100644
--- a/web/src/pages/Home/TopJurors/Header/DesktopHeader.tsx
+++ b/web/src/pages/Home/TopJurors/Header/DesktopHeader.tsx
@@ -16,6 +16,7 @@ import JurorLevels from "components/Popup/MiniGuides/JurorLevels";
import Coherence from "./Coherence";
import Rewards from "./Rewards";
+import Score from "./Score";
const Container = styled.div<{ renderIcon?: boolean }>`
display: none;
@@ -32,9 +33,9 @@ const Container = styled.div<{ renderIcon?: boolean }>`
() => css`
display: grid;
grid-template-columns: ${renderIcon
- ? `min-content repeat(3, ${responsiveSize(160, 180, 900)}) auto`
- : `repeat(3, ${responsiveSize(160, 180, 900)}) auto`};
- column-gap: ${responsiveSize(12, 28, 900)};
+ ? `min-content minmax(160px, 1fr) minmax(60px, 1fr) minmax(80px, 0.8fr) minmax(180px, 1.5fr) minmax(100px, 1fr)`
+ : `minmax(160px, 1fr) minmax(60px, 1fr) minmax(80px, 0.8fr) minmax(180px, 1.5fr) minmax(100px, 1fr)`};
+ column-gap: ${responsiveSize(12, 24, 900)};
align-items: center;
`
)}
@@ -65,8 +66,9 @@ export const DesktopHeader: React.FC = () => {
{renderIcon ? : null}
Juror
-
+
+
theme.secondaryText};
+ align-items: center;
+
+ ${landscapeStyle(
+ () => css`
+ font-size: 14px !important;
+ justify-content: center;
+ `
+ )}
+`;
+
+const scoreTooltipMsg =
+ "A score from 0 to 100 reflecting coherent voting, smoothed " +
+ "to prevent jurors with low vote counts from ranking too high.";
+
+const Score: React.FC = () => {
+ const isDesktop = useIsDesktop();
+
+ return (
+
+
+
+ );
+};
+export default Score;
diff --git a/web/src/pages/Home/TopJurors/JurorCard/Coherence.tsx b/web/src/pages/Home/TopJurors/JurorCard/Coherence.tsx
index 5cdef3e32..0d1a9a83c 100644
--- a/web/src/pages/Home/TopJurors/JurorCard/Coherence.tsx
+++ b/web/src/pages/Home/TopJurors/JurorCard/Coherence.tsx
@@ -12,6 +12,7 @@ const Container = styled.div`
color: ${({ theme }) => theme.primaryText};
flex-wrap: wrap;
justify-content: center;
+ margin-top: 2px;
`;
interface ICoherence {
@@ -24,8 +25,8 @@ const Coherence: React.FC = ({ totalCoherentVotes, totalResolvedVote
return (
-
- {getCoherencePercent(Number(totalCoherentVotes), Number(totalResolvedVotes))}
+
+ {coherenceRatio}
);
diff --git a/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx b/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx
index 1538dcd67..e17c32b03 100644
--- a/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx
+++ b/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx
@@ -10,6 +10,7 @@ import JurorLevel from "./JurorLevel";
import JurorTitle from "./JurorTitle";
import Rank from "./Rank";
import Rewards from "./Rewards";
+import Score from "./Score";
const Container = styled.div<{ renderRank?: boolean }>`
${hoverShortTransitionTiming}
@@ -26,9 +27,9 @@ const Container = styled.div<{ renderRank?: boolean }>`
() => css`
display: grid;
grid-template-columns: ${renderRank
- ? `min-content repeat(3, ${responsiveSize(160, 180, 900)}) auto`
- : `repeat(3, ${responsiveSize(160, 180, 900)}) auto`};
- column-gap: ${responsiveSize(12, 28, 900)};
+ ? `min-content minmax(160px, 1fr) minmax(60px, 1fr) minmax(80px, 0.8fr) minmax(180px, 1.5fr) minmax(100px, 1fr)`
+ : `minmax(160px, 1fr) minmax(60px, 1fr) minmax(80px, 0.8fr) minmax(180px, 1.5fr) minmax(100px, 1fr)`};
+ column-gap: ${responsiveSize(12, 24, 900)};
`
)}
@@ -40,17 +41,17 @@ const Container = styled.div<{ renderRank?: boolean }>`
interface IDesktopCard {
rank?: number;
address: string;
+ coherenceScore: string;
totalCoherentVotes: string;
totalResolvedVotes: string;
- totalResolvedDisputes: string;
}
const DesktopCard: React.FC = ({
rank,
address,
+ coherenceScore,
totalCoherentVotes,
totalResolvedVotes,
- totalResolvedDisputes,
}) => {
const renderRank = !!rank;
@@ -58,9 +59,10 @@ const DesktopCard: React.FC = ({
{renderRank && }
-
+
-
+
+
);
};
diff --git a/web/src/pages/Home/TopJurors/JurorCard/JurorLevel.tsx b/web/src/pages/Home/TopJurors/JurorCard/JurorLevel.tsx
index eba34f350..c961b8e61 100644
--- a/web/src/pages/Home/TopJurors/JurorCard/JurorLevel.tsx
+++ b/web/src/pages/Home/TopJurors/JurorCard/JurorLevel.tsx
@@ -4,7 +4,6 @@ import styled, { css } from "styled-components";
import { landscapeStyle } from "styles/landscapeStyle";
import { getUserLevelData } from "utils/userLevelCalculation";
-import { getCoherencePercent } from "utils/getCoherencePercent";
import PixelArt from "pages/Profile/JurorInfo/PixelArt";
@@ -40,14 +39,11 @@ const StyledLabel = styled.label`
`;
interface IJurorLevel {
- totalCoherentVotes: string;
- totalResolvedVotes: string;
- totalResolvedDisputes: string;
+ coherenceScore: number;
}
-const JurorLevel: React.FC = ({ totalCoherentVotes, totalResolvedVotes, totalResolvedDisputes }) => {
- const coherencePercentage = getCoherencePercent(Number(totalCoherentVotes), Number(totalResolvedVotes));
- const userLevelData = getUserLevelData(coherencePercentage, Number(totalResolvedDisputes));
+const JurorLevel: React.FC = ({ coherenceScore }) => {
+ const userLevelData = getUserLevelData(coherenceScore);
const level = userLevelData.level;
return (
diff --git a/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx b/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx
index faffb821a..c748b505b 100644
--- a/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx
+++ b/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx
@@ -4,6 +4,7 @@ import styled, { css } from "styled-components";
import { landscapeStyle } from "styles/landscapeStyle";
import { hoverShortTransitionTiming } from "styles/commonStyles";
+import HeaderScore from "../Header/Score";
import HeaderCoherence from "../Header/Coherence";
import HeaderRewards from "../Header/Rewards";
@@ -12,6 +13,7 @@ import JurorLevel from "./JurorLevel";
import JurorTitle from "./JurorTitle";
import Rank from "./Rank";
import Rewards from "./Rewards";
+import Score from "./Score";
const Container = styled.div`
${hoverShortTransitionTiming}
@@ -49,32 +51,40 @@ const TopSide = styled.div`
const RankAndTitle = styled.div`
display: flex;
flex-direction: row;
+ align-items: center;
gap: 8px;
`;
-const HeaderRewardsAndRewards = styled.div`
+const BottomSide = styled.div`
+ width: 100%;
display: flex;
flex-direction: column;
- width: 100%;
+ justify-content: space-between;
gap: 8px;
`;
-const BottomSide = styled.div`
- width: 100%;
+const HeaderScoreAndScore = styled.div`
display: flex;
+ width: 100%;
flex-direction: row;
- justify-content: space-between;
+ align-items: center;
+ gap: 8px;
`;
const HeaderCoherenceAndCoherence = styled.div`
display: flex;
- flex-direction: column;
- align-items: flex-end;
+ width: 100%;
+ flex-direction: row;
+ align-items: center;
gap: 8px;
+`;
- svg {
- margin-right: 0;
- }
+const HeaderRewardsAndRewards = styled.div`
+ display: flex;
+ width: 100%;
+ flex-direction: row;
+ align-items: center;
+ gap: 8px;
`;
interface IMobileCard {
@@ -82,7 +92,7 @@ interface IMobileCard {
address: string;
totalCoherentVotes: string;
totalResolvedVotes: string;
- totalResolvedDisputes: string;
+ coherenceScore: string;
}
const MobileCard: React.FC = ({
@@ -90,26 +100,30 @@ const MobileCard: React.FC = ({
address,
totalCoherentVotes,
totalResolvedVotes,
- totalResolvedDisputes,
+ coherenceScore,
}) => {
return (
- {rank ? : null}
-
+ {rank ? : null}
+
-
+
-
-
-
-
+
+
+
+
+
+
+
+
);
diff --git a/web/src/pages/Home/TopJurors/JurorCard/Rewards.tsx b/web/src/pages/Home/TopJurors/JurorCard/Rewards.tsx
index 59ba64f6c..bc998158d 100644
--- a/web/src/pages/Home/TopJurors/JurorCard/Rewards.tsx
+++ b/web/src/pages/Home/TopJurors/JurorCard/Rewards.tsx
@@ -17,6 +17,7 @@ const Container = styled.div`
gap: 8px;
align-items: center;
flex-wrap: wrap;
+ margin-top: 2px;
${landscapeStyle(
() => css`
diff --git a/web/src/pages/Home/TopJurors/JurorCard/Score.tsx b/web/src/pages/Home/TopJurors/JurorCard/Score.tsx
new file mode 100644
index 000000000..f98fa0b82
--- /dev/null
+++ b/web/src/pages/Home/TopJurors/JurorCard/Score.tsx
@@ -0,0 +1,29 @@
+import React from "react";
+
+import styled from "styled-components";
+
+import { Tooltip } from "@kleros/ui-components-library";
+
+const Container = styled.div`
+ display: flex;
+ align-items: center;
+ font-weight: 600;
+ color: ${({ theme }) => theme.primaryText};
+ flex-wrap: wrap;
+ justify-content: center;
+ margin-top: 2px;
+`;
+
+interface IScore {
+ coherenceScore: string;
+}
+
+const Score: React.FC = ({ coherenceScore }) => {
+ return (
+
+ {coherenceScore}
+
+ );
+};
+
+export default Score;
diff --git a/web/src/pages/Home/TopJurors/JurorCard/index.tsx b/web/src/pages/Home/TopJurors/JurorCard/index.tsx
index e849eecc6..e6b4143a5 100644
--- a/web/src/pages/Home/TopJurors/JurorCard/index.tsx
+++ b/web/src/pages/Home/TopJurors/JurorCard/index.tsx
@@ -6,19 +6,13 @@ import MobileCard from "./MobileCard";
interface IJurorCard {
rank: number;
address: `0x${string}`;
+ coherenceScore: string;
totalCoherentVotes: string;
totalResolvedVotes: string;
- totalResolvedDisputes: string;
}
-const JurorCard: React.FC = ({
- rank,
- address,
- totalCoherentVotes,
- totalResolvedVotes,
- totalResolvedDisputes,
-}) => {
- const allProps = { rank, address, totalCoherentVotes, totalResolvedVotes, totalResolvedDisputes };
+const JurorCard: React.FC = ({ rank, address, coherenceScore, totalCoherentVotes, totalResolvedVotes }) => {
+ const allProps = { rank, address, coherenceScore, totalCoherentVotes, totalResolvedVotes };
return (
<>
diff --git a/web/src/pages/Profile/JurorInfo/index.tsx b/web/src/pages/Profile/JurorInfo/index.tsx
index f85122738..87071c220 100644
--- a/web/src/pages/Profile/JurorInfo/index.tsx
+++ b/web/src/pages/Profile/JurorInfo/index.tsx
@@ -4,7 +4,6 @@ import styled, { css } from "styled-components";
import { Card as _Card } from "@kleros/ui-components-library";
import { getUserLevelData } from "utils/userLevelCalculation";
-import { getCoherencePercent } from "utils/getCoherencePercent";
import { useUserQuery } from "queries/useUser";
@@ -46,9 +45,8 @@ const JurorInfo: React.FC = ({ addressToQuery }) => {
const { data } = useUserQuery(addressToQuery);
const totalCoherentVotes = data?.user ? parseInt(data?.user?.totalCoherentVotes) : 0;
const totalResolvedVotes = data?.user ? parseInt(data?.user?.totalResolvedVotes) : 0;
- const totalResolvedDisputes = data?.user ? parseInt(data?.user?.totalResolvedDisputes) : 0;
- const coherencePercentage = getCoherencePercent(Number(totalCoherentVotes), Number(totalResolvedVotes));
- const userLevelData = getUserLevelData(coherencePercentage, totalResolvedDisputes);
+ const coherenceScore = data?.user ? parseInt(data?.user?.coherenceScore) : 0;
+ const userLevelData = getUserLevelData(coherenceScore);
return (
diff --git a/web/src/utils/userLevelCalculation.ts b/web/src/utils/userLevelCalculation.ts
index 52d504256..c5d1424a5 100644
--- a/web/src/utils/userLevelCalculation.ts
+++ b/web/src/utils/userLevelCalculation.ts
@@ -1,32 +1,23 @@
interface ILevelCriteria {
level: number;
title: string;
- minDisputes: number;
- minCoherencePercentage: number;
- maxCoherencePercentage: number;
+ minCoherenceScore: number;
+ maxCoherenceScore: number;
}
const levelCriteria: ILevelCriteria[] = [
- { level: 4, title: "Aristotle", minDisputes: 10, minCoherencePercentage: 90, maxCoherencePercentage: 100 },
- { level: 3, title: "Plato", minDisputes: 7, minCoherencePercentage: 80, maxCoherencePercentage: 100 },
- { level: 2, title: "Socrates", minDisputes: 3, minCoherencePercentage: 70, maxCoherencePercentage: 100 },
- { level: 1, title: "Pythagoras", minDisputes: 1, minCoherencePercentage: 0, maxCoherencePercentage: 70 },
- { level: 0, title: "Diogenes", minDisputes: 3, minCoherencePercentage: 0, maxCoherencePercentage: 49 },
+ { level: 0, title: "Diogenes", minCoherenceScore: 0, maxCoherenceScore: 24 },
+ { level: 1, title: "Pythagoras", minCoherenceScore: 25, maxCoherenceScore: 49 },
+ { level: 2, title: "Socrates", minCoherenceScore: 50, maxCoherenceScore: 69 },
+ { level: 3, title: "Plato", minCoherenceScore: 70, maxCoherenceScore: 89 },
+ { level: 4, title: "Aristotle", minCoherenceScore: 90, maxCoherenceScore: 100 },
];
-export const getUserLevelData = (coherencePercentage: string, totalResolvedDisputes: number) => {
- const percentageToNumber = (percentage: string) => parseFloat(percentage.replace("%", ""));
- const coherenceValue = percentageToNumber(coherencePercentage);
-
+export const getUserLevelData = (coherenceScore: number) => {
for (const criteria of levelCriteria) {
- if (
- totalResolvedDisputes >= criteria.minDisputes &&
- coherenceValue >= criteria.minCoherencePercentage &&
- coherenceValue <= criteria.maxCoherencePercentage
- ) {
+ if (coherenceScore >= criteria.minCoherenceScore && coherenceScore <= criteria.maxCoherenceScore) {
return criteria;
}
}
-
- return levelCriteria.find(({ level }) => level === 1);
+ return levelCriteria[0];
};