diff --git a/subgraph/core/schema.graphql b/subgraph/core/schema.graphql index d75c3b101..e2700a5f3 100644 --- a/subgraph/core/schema.graphql +++ b/subgraph/core/schema.graphql @@ -56,6 +56,7 @@ interface Evidence { sender: User! senderAddress: String! timestamp: BigInt! + transactionHash: Bytes! name: String description: String fileURI: String @@ -318,6 +319,7 @@ type ClassicEvidence implements Evidence @entity(immutable: true) { sender: User! senderAddress: String! timestamp: BigInt! + transactionHash: Bytes! name: String description: String fileURI: String diff --git a/subgraph/core/src/EvidenceModule.ts b/subgraph/core/src/EvidenceModule.ts index a4dfd8e70..03a15c3b4 100644 --- a/subgraph/core/src/EvidenceModule.ts +++ b/subgraph/core/src/EvidenceModule.ts @@ -17,6 +17,7 @@ export function handleEvidenceEvent(event: EvidenceEvent): void { evidence.evidenceIndex = evidenceIndex.plus(ONE).toString(); const userId = event.params._party.toHexString(); evidence.timestamp = event.block.timestamp; + evidence.transactionHash = event.transaction.hash; evidence.evidence = event.params._evidence; evidence.evidenceGroup = evidenceGroupID.toString(); evidence.sender = userId; diff --git a/subgraph/package.json b/subgraph/package.json index 1ffe01673..44f07b9a4 100644 --- a/subgraph/package.json +++ b/subgraph/package.json @@ -1,6 +1,6 @@ { "name": "@kleros/kleros-v2-subgraph", - "version": "0.9.0", + "version": "0.9.1", "license": "MIT", "scripts": { "update:core:arbitrum-sepolia-devnet": "./scripts/update.sh arbitrumSepoliaDevnet arbitrum-sepolia core/subgraph.yaml", diff --git a/web/src/assets/svgs/icons/calendar.svg b/web/src/assets/svgs/icons/calendar.svg index a17a2d98e..7f8393539 100644 --- a/web/src/assets/svgs/icons/calendar.svg +++ b/web/src/assets/svgs/icons/calendar.svg @@ -1,4 +1,4 @@ - + diff --git a/web/src/assets/svgs/icons/law-balance.svg b/web/src/assets/svgs/icons/law-balance.svg index 696375f30..c8a97deec 100644 --- a/web/src/assets/svgs/icons/law-balance.svg +++ b/web/src/assets/svgs/icons/law-balance.svg @@ -1,4 +1,4 @@ - + diff --git a/web/src/components/DisputePreview/Policies.tsx b/web/src/components/DisputePreview/Policies.tsx index 080e7d304..f30bce9ef 100644 --- a/web/src/components/DisputePreview/Policies.tsx +++ b/web/src/components/DisputePreview/Policies.tsx @@ -1,6 +1,8 @@ import React from "react"; import styled, { css } from "styled-components"; +import { Link } from "react-router-dom"; + import PaperclipIcon from "svgs/icons/paperclip.svg"; import PolicyIcon from "svgs/icons/policy.svg"; @@ -59,6 +61,12 @@ const LinkContainer = styled.div` display: flex; gap: ${responsiveSize(16, 24)}; flex-wrap: wrap; + align-items: center; +`; + +const StyledLink = styled(Link)` + display: flex; + gap: 4px; `; type Attachment = { @@ -83,10 +91,10 @@ export const Policies: React.FC = ({ disputePolicyURI, courtId, attac ) : null} {isUndefined(disputePolicyURI) ? null : ( - + Dispute Policy - + )} {isUndefined(courtId) ? null : ( diff --git a/web/src/components/DisputeView/DisputeInfo/DisputeInfoCard.tsx b/web/src/components/DisputeView/DisputeInfo/DisputeInfoCard.tsx index 5e300c4b8..2985fa3f2 100644 --- a/web/src/components/DisputeView/DisputeInfo/DisputeInfoCard.tsx +++ b/web/src/components/DisputeView/DisputeInfo/DisputeInfoCard.tsx @@ -12,7 +12,7 @@ import { getCourtsPath } from "pages/Courts/CourtDetails"; import CardLabel from "../CardLabels"; -import { FieldItem, IDisputeInfo } from "."; +import { FieldItem, IDisputeInfo } from "./index"; const Container = styled.div` display: flex; @@ -59,6 +59,7 @@ const StyledField = styled(Field)` margin-left: 8px; overflow: hidden; text-overflow: ellipsis; + text-wrap: auto; } } `; @@ -86,7 +87,13 @@ const DisputeInfoCard: React.FC = ({ {court && courtId && isOverview && ( - + )} diff --git a/web/src/components/EvidenceCard.tsx b/web/src/components/EvidenceCard.tsx index cf30bb0bc..75eb614d8 100644 --- a/web/src/components/EvidenceCard.tsx +++ b/web/src/components/EvidenceCard.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useMemo } from "react"; import styled, { css } from "styled-components"; import Identicon from "react-identicons"; @@ -9,6 +9,7 @@ import { Card } from "@kleros/ui-components-library"; import AttachmentIcon from "svgs/icons/attachment.svg"; +import { DEFAULT_CHAIN, getChain } from "consts/chains"; import { formatDate } from "utils/date"; import { getIpfsUrl } from "utils/getIpfsUrl"; import { shortenAddress } from "utils/shortenAddress"; @@ -116,6 +117,19 @@ const StyledLink = styled(Link)` )} `; +const StyledA = styled.a` + :hover { + text-decoration: underline; + p { + color: ${({ theme }) => theme.primaryBlue}; + } + label { + cursor: pointer; + color: ${({ theme }) => theme.primaryBlue}; + } + } +`; + const AttachedFileText: React.FC = () => ( <> View attached file @@ -126,9 +140,27 @@ const AttachedFileText: React.FC = () => ( interface IEvidenceCard extends Pick { sender: string; index: number; + transactionHash: string; } -const EvidenceCard: React.FC = ({ evidence, sender, index, timestamp, name, description, fileURI }) => { +const EvidenceCard: React.FC = ({ + evidence, + sender, + index, + timestamp, + transactionHash, + name, + description, + fileURI, +}) => { + const addressExplorerLink = useMemo(() => { + return `${getChain(DEFAULT_CHAIN)?.blockExplorers?.default.url}/address/${sender}`; + }, [sender]); + + const transactionExplorerLink = useMemo(() => { + return `${getChain(DEFAULT_CHAIN)?.blockExplorers?.default.url}/tx/${transactionHash}`; + }, [transactionHash]); + return ( @@ -145,15 +177,19 @@ const EvidenceCard: React.FC = ({ evidence, sender, index, timest -

{shortenAddress(sender)}

+ +

{shortenAddress(sender)}

+
- {formatDate(Number(timestamp), true)} - {fileURI && ( + + {formatDate(Number(timestamp), true)} + + {fileURI && fileURI !== "-" ? ( - )} + ) : null} ); diff --git a/web/src/components/Field.tsx b/web/src/components/Field.tsx index 8f785e221..d3abd80e9 100644 --- a/web/src/components/Field.tsx +++ b/web/src/components/Field.tsx @@ -1,9 +1,10 @@ import React from "react"; import styled, { css } from "styled-components"; +import { landscapeStyle } from "styles/landscapeStyle"; import { Link } from "react-router-dom"; -import { landscapeStyle } from "styles/landscapeStyle"; +import { useScrollTop } from "hooks/useScrollTop"; const FieldContainer = styled.div` display: flex; @@ -61,6 +62,8 @@ const LinkContainer = styled.div``; const StyledLink = styled(Link)` color: ${({ theme }) => theme.primaryBlue}; + text-wrap: auto; + justify-content: end; `; type FieldContainerProps = { @@ -93,6 +96,8 @@ const Field: React.FC = ({ isJurorBalance, className, }) => { + const scrollTop = useScrollTop(); + return ( @@ -103,6 +108,7 @@ const Field: React.FC = ({ to={link} onClick={(event) => { event.stopPropagation(); + scrollTop(); }} > {value} diff --git a/web/src/hooks/queries/useEvidences.ts b/web/src/hooks/queries/useEvidences.ts index ae4bc00a4..743869619 100644 --- a/web/src/hooks/queries/useEvidences.ts +++ b/web/src/hooks/queries/useEvidences.ts @@ -15,6 +15,7 @@ export const evidenceFragment = graphql(` id } timestamp + transactionHash name description fileURI diff --git a/web/src/hooks/useScrollTop.ts b/web/src/hooks/useScrollTop.ts new file mode 100644 index 000000000..216a42901 --- /dev/null +++ b/web/src/hooks/useScrollTop.ts @@ -0,0 +1,12 @@ +import { useContext } from "react"; +import { OverlayScrollContext } from "context/OverlayScrollContext"; + +export const useScrollTop = () => { + const osInstanceRef = useContext(OverlayScrollContext); + + const scrollTop = () => { + osInstanceRef?.current?.osInstance().elements().viewport.scroll({ top: 0 }); + }; + + return scrollTop; +}; diff --git a/web/src/layout/Header/navbar/DappList.tsx b/web/src/layout/Header/navbar/DappList.tsx index 84c3a4267..9c1db313d 100644 --- a/web/src/layout/Header/navbar/DappList.tsx +++ b/web/src/layout/Header/navbar/DappList.tsx @@ -125,9 +125,9 @@ const ITEMS = [ url: "https://klerosscout.eth.limo", }, { - text: "POH V1", + text: "POH V2", Icon: POH, - url: "https://app.proofofhumanity.id", + url: "https://v2.proofofhumanity.id", }, { text: "Governor", diff --git a/web/src/pages/Cases/AttachmentDisplay/Header.tsx b/web/src/pages/Cases/AttachmentDisplay/Header.tsx index 270d8fa43..98faa738b 100644 --- a/web/src/pages/Cases/AttachmentDisplay/Header.tsx +++ b/web/src/pages/Cases/AttachmentDisplay/Header.tsx @@ -1,7 +1,7 @@ import React from "react"; import styled from "styled-components"; -import { useNavigate, useParams } from "react-router-dom"; +import { useNavigate, useLocation, useParams } from "react-router-dom"; import { Button } from "@kleros/ui-components-library"; @@ -57,16 +57,23 @@ const StyledButton = styled(Button)` `; const Header: React.FC = () => { - const { id } = useParams(); const navigate = useNavigate(); + const { id } = useParams(); + const location = useLocation(); + + const handleReturn = () => { + navigate(-1); + }; + + const title = location.pathname.includes("policy") ? `Policy File - Case #${id}` : "Attachment File"; return ( - Attachment File{" "} + {title} - navigate(`/cases/${id}/evidence`)} /> + ); }; diff --git a/web/src/pages/Cases/AttachmentDisplay/index.tsx b/web/src/pages/Cases/AttachmentDisplay/index.tsx index 3838e701e..6aa74f19a 100644 --- a/web/src/pages/Cases/AttachmentDisplay/index.tsx +++ b/web/src/pages/Cases/AttachmentDisplay/index.tsx @@ -37,7 +37,7 @@ const StyledNewTabIcon = styled(NewTabIcon)` } `; -const EvidenceAttachmentDisplay: React.FC = () => { +const AttachmentDisplay: React.FC = () => { const [searchParams] = useSearchParams(); const url = searchParams.get("url"); @@ -64,4 +64,4 @@ const EvidenceAttachmentDisplay: React.FC = () => { ); }; -export default EvidenceAttachmentDisplay; +export default AttachmentDisplay; diff --git a/web/src/pages/Cases/CaseDetails/Evidence/index.tsx b/web/src/pages/Cases/CaseDetails/Evidence/index.tsx index f4fc1955a..488893801 100644 --- a/web/src/pages/Cases/CaseDetails/Evidence/index.tsx +++ b/web/src/pages/Cases/CaseDetails/Evidence/index.tsx @@ -95,14 +95,16 @@ const Evidence: React.FC = () => { {evidences?.realEvidences ? ( - evidences?.realEvidences.map(({ evidence, sender, timestamp, name, description, fileURI, evidenceIndex }) => ( - - )) + evidences?.realEvidences.map( + ({ evidence, sender, timestamp, transactionHash, name, description, fileURI, evidenceIndex }) => ( + + ) + ) ) : ( )} @@ -111,12 +113,12 @@ const Evidence: React.FC = () => { {showSpam ? ( evidences?.spamEvidences.map( - ({ evidence, sender, timestamp, name, description, fileURI, evidenceIndex }) => ( + ({ evidence, sender, timestamp, transactionHash, name, description, fileURI, evidenceIndex }) => ( ) ) diff --git a/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx b/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx index b10866975..4eaed0799 100644 --- a/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx +++ b/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx @@ -1,9 +1,10 @@ -import React from "react"; +import React, { useMemo } from "react"; import styled, { css } from "styled-components"; import Identicon from "react-identicons"; import { Answer } from "context/NewDisputeContext"; +import { DEFAULT_CHAIN, getChain } from "consts/chains"; import { getVoteChoice } from "utils/getVoteChoice"; import { isUndefined } from "utils/index"; import { shortenAddress } from "utils/shortenAddress"; @@ -24,11 +25,13 @@ const TitleContainer = styled.div` ` )} `; + const AddressContainer = styled.div` display: flex; gap: 8px; align-items: center; `; + const StyledLabel = styled.label<{ variant?: string }>` color: ${({ theme, variant }) => (variant ? theme[variant] : theme.primaryText)}; font-size: 16px; @@ -38,6 +41,16 @@ const StyledSmall = styled.small` font-size: 16px; `; +const StyledA = styled.a` + :hover { + text-decoration: underline; + label { + cursor: pointer; + color: ${({ theme }) => theme.primaryBlue}; + } + } +`; + const VoteStatus: React.FC<{ choice?: string; period: string; @@ -75,11 +88,17 @@ const AccordionTitle: React.FC<{ commited: boolean; hiddenVotes: boolean; }> = ({ juror, choice, voteCount, period, answers, isActiveRound, commited, hiddenVotes }) => { + const addressExplorerLink = useMemo(() => { + return `${getChain(DEFAULT_CHAIN)?.blockExplorers?.default.url}/address/${juror}`; + }, [juror]); + return ( - {shortenAddress(juror)} + + {shortenAddress(juror)} + diff --git a/web/src/pages/Cases/index.tsx b/web/src/pages/Cases/index.tsx index 44ce69e09..555724987 100644 --- a/web/src/pages/Cases/index.tsx +++ b/web/src/pages/Cases/index.tsx @@ -5,7 +5,7 @@ import { Routes, Route } from "react-router-dom"; import { responsiveSize } from "styles/responsiveSize"; -import EvidenceAttachmentDisplay from "./AttachmentDisplay"; +import AttachmentDisplay from "./AttachmentDisplay"; import CaseDetails from "./CaseDetails"; import CasesFetcher from "./CasesFetcher"; @@ -21,7 +21,8 @@ const Cases: React.FC = () => ( } /> - } /> + } /> + } /> } /> diff --git a/web/src/pages/Home/TopJurors/JurorCard/JurorTitle.tsx b/web/src/pages/Home/TopJurors/JurorCard/JurorTitle.tsx index e4b52af2b..6d2c68963 100644 --- a/web/src/pages/Home/TopJurors/JurorCard/JurorTitle.tsx +++ b/web/src/pages/Home/TopJurors/JurorCard/JurorTitle.tsx @@ -1,7 +1,8 @@ -import React from "react"; +import React, { useMemo } from "react"; import styled from "styled-components"; import { IdenticonOrAvatar, AddressOrName } from "components/ConnectWallet/AccountDisplay"; +import { DEFAULT_CHAIN, getChain } from "consts/chains"; const Container = styled.div` display: flex; @@ -19,15 +20,31 @@ const Container = styled.div` } `; +const StyledA = styled.a` + :hover { + text-decoration: underline; + label { + cursor: pointer; + color: ${({ theme }) => theme.primaryBlue}; + } + } +`; + interface IJurorTitle { address: string; } const JurorTitle: React.FC = ({ address }) => { + const addressExplorerLink = useMemo(() => { + return `${getChain(DEFAULT_CHAIN)?.blockExplorers?.default.url}/address/${address}`; + }, [address]); + return ( - + + + ); };