Skip to content
1 change: 1 addition & 0 deletions subgraph/core/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ type ClassicEvidence implements Evidence @entity(immutable: true) {
sender: User!
senderAddress: String!
timestamp: BigInt!
transactionHash: Bytes!
name: String
description: String
fileURI: String
Expand Down
1 change: 1 addition & 0 deletions subgraph/core/src/EvidenceModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
23 changes: 21 additions & 2 deletions web/src/components/DisputeView/DisputeInfo/DisputeInfoCard.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import React, { useMemo } from "react";
import styled, { css } from "styled-components";

import { Link } from "react-router-dom";

import LawBalanceIcon from "svgs/icons/law-balance.svg";

import { useScrollTop } from "hooks/useScrollTop";
import { useCourtTree } from "hooks/queries/useCourtTree";

import { landscapeStyle } from "styles/landscapeStyle";
Expand All @@ -12,7 +15,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;
Expand Down Expand Up @@ -59,6 +62,19 @@ const StyledField = styled(Field)`
margin-left: 8px;
overflow: hidden;
text-overflow: ellipsis;
text-wrap: auto;
}
}
`;

const StyledLink = styled(Link)`
:hover {
label {
&.value {
cursor: pointer;
color: ${({ theme }) => theme.primaryBlue};
text-decoration: underline;
}
}
}
`;
Expand All @@ -74,6 +90,7 @@ const DisputeInfoCard: React.FC<IDisputeInfoCard> = ({
disputeID,
round,
}) => {
const scrollTop = useScrollTop();
const { data } = useCourtTree();
const courtPath = getCourtsPath(data?.court, courtId);
const items = useMemo(
Expand All @@ -86,7 +103,9 @@ const DisputeInfoCard: React.FC<IDisputeInfoCard> = ({
<Container>
{court && courtId && isOverview && (
<CourtBranchFieldContainer>
<StyledField icon={LawBalanceIcon} name="Court Branch" value={courtBranchValue} {...{ isOverview }} />
<StyledLink to={`/courts/${courtId}`} onClick={() => scrollTop()}>
<StyledField icon={LawBalanceIcon} name="Court Branch" value={courtBranchValue} {...{ isOverview }} />
</StyledLink>
</CourtBranchFieldContainer>
)}
<RestOfFieldsContainer {...{ isOverview }}>
Expand Down
47 changes: 41 additions & 6 deletions web/src/components/EvidenceCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from "react";
import React, { useMemo } from "react";
import styled, { css } from "styled-components";

import Identicon from "react-identicons";
Expand All @@ -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";
Expand Down Expand Up @@ -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 = () => (
<>
<DesktopText>View attached file</DesktopText>
Expand All @@ -128,7 +142,24 @@ interface IEvidenceCard extends Pick<Evidence, "evidence" | "timestamp" | "name"
index: number;
}

const EvidenceCard: React.FC<IEvidenceCard> = ({ evidence, sender, index, timestamp, name, description, fileURI }) => {
const EvidenceCard: React.FC<IEvidenceCard> = ({
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 (
<StyledCard>
<TextContainer>
Expand All @@ -145,15 +176,19 @@ const EvidenceCard: React.FC<IEvidenceCard> = ({ evidence, sender, index, timest
<BottomShade>
<AccountContainer>
<Identicon size="24" string={sender} />
<p>{shortenAddress(sender)}</p>
<StyledA href={addressExplorerLink} rel="noopener noreferrer" target="_blank">
<p>{shortenAddress(sender)}</p>
</StyledA>
</AccountContainer>
<Timestamp>{formatDate(Number(timestamp), true)}</Timestamp>
{fileURI && (
<StyledA href={transactionExplorerLink} rel="noopener noreferrer" target="_blank">
<Timestamp>{formatDate(Number(timestamp), true)}</Timestamp>
</StyledA>
{fileURI && fileURI !== "-" ? (
<StyledLink to={`attachment/?url=${getIpfsUrl(fileURI)}`}>
<AttachmentIcon />
<AttachedFileText />
</StyledLink>
)}
) : null}
</BottomShade>
</StyledCard>
);
Expand Down
1 change: 1 addition & 0 deletions web/src/hooks/queries/useEvidences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const evidenceFragment = graphql(`
id
}
timestamp
transactionHash
name
description
fileURI
Expand Down
12 changes: 12 additions & 0 deletions web/src/hooks/useScrollTop.ts
Original file line number Diff line number Diff line change
@@ -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;
};
22 changes: 12 additions & 10 deletions web/src/pages/Cases/CaseDetails/Evidence/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,16 @@ const Evidence: React.FC = () => {
<EvidenceSearch {...{ search, setSearch, evidenceGroup: disputeData?.dispute?.externalDisputeId }} />
<ScrollButton small Icon={DownArrow} text="Scroll to latest" onClick={scrollToLatest} />
{evidences?.realEvidences ? (
evidences?.realEvidences.map(({ evidence, sender, timestamp, name, description, fileURI, evidenceIndex }) => (
<EvidenceCard
key={timestamp}
index={parseInt(evidenceIndex)}
sender={sender?.id}
{...{ evidence, timestamp, name, description, fileURI }}
/>
))
evidences?.realEvidences.map(
({ evidence, sender, timestamp, transactionHash, name, description, fileURI, evidenceIndex }) => (
<EvidenceCard
key={timestamp}
index={parseInt(evidenceIndex)}
sender={sender?.id}
{...{ evidence, timestamp, transactionHash, name, description, fileURI }}
/>
)
)
) : (
<SkeletonEvidenceCard />
)}
Expand All @@ -111,12 +113,12 @@ const Evidence: React.FC = () => {
<Divider />
{showSpam ? (
evidences?.spamEvidences.map(
({ evidence, sender, timestamp, name, description, fileURI, evidenceIndex }) => (
({ evidence, sender, timestamp, transactionHash, name, description, fileURI, evidenceIndex }) => (
<EvidenceCard
key={timestamp}
index={parseInt(evidenceIndex)}
sender={sender?.id}
{...{ evidence, timestamp, name, description, fileURI }}
{...{ evidence, timestamp, transactionHash, name, description, fileURI }}
/>
)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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 (
<TitleContainer>
<AddressContainer>
<Identicon size="20" string={juror} />
<StyledLabel variant="secondaryText">{shortenAddress(juror)}</StyledLabel>
<StyledA href={addressExplorerLink} rel="noopener noreferrer" target="_blank">
<StyledLabel variant="secondaryText">{shortenAddress(juror)}</StyledLabel>
</StyledA>
</AddressContainer>
<VoteStatus {...{ choice, period, answers, isActiveRound, commited, hiddenVotes }} />
<StyledLabel variant="secondaryPurple">
Expand Down
21 changes: 19 additions & 2 deletions web/src/pages/Home/TopJurors/JurorCard/JurorTitle.tsx
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<IJurorTitle> = ({ address }) => {
const addressExplorerLink = useMemo(() => {
return `${getChain(DEFAULT_CHAIN)?.blockExplorers?.default.url}/address/${address}`;
}, [address]);

return (
<Container>
<IdenticonOrAvatar address={address} />
<AddressOrName address={address} />
<StyledA href={addressExplorerLink} rel="noopener noreferrer" target="_blank">
<AddressOrName address={address} />
</StyledA>
</Container>
);
};
Expand Down
Loading