Skip to content
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
23 changes: 13 additions & 10 deletions web/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import "react-toastify/dist/ReactToastify.css";
import Web3Provider from "context/Web3Provider";
import QueryClientProvider from "context/QueryClientProvider";
import StyledComponentsProvider from "context/StyledComponentsProvider";
import { FilterProvider } from "context/FilterProvider";
import RefetchOnBlock from "context/RefetchOnBlock";
import Layout from "layout/index";
import Home from "./pages/Home";
Expand All @@ -20,16 +21,18 @@ const App: React.FC = () => {
<QueryClientProvider>
<RefetchOnBlock />
<Web3Provider>
<SentryRoutes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="cases/*" element={<Cases />} />
<Route path="courts/*" element={<Courts />} />
<Route path="dashboard" element={<Dashboard />} />
<Route path="disputeTemplate" element={<DisputeTemplateView />} />
<Route path="*" element={<h1>Justice not found here ¯\_( ͡° ͜ʖ ͡°)_/¯</h1>} />
</Route>
</SentryRoutes>
<FilterProvider>
<SentryRoutes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="cases/*" element={<Cases />} />
<Route path="courts/*" element={<Courts />} />
<Route path="dashboard" element={<Dashboard />} />
<Route path="disputeTemplate" element={<DisputeTemplateView />} />
<Route path="*" element={<h1>Justice not found here ¯\_( ͡° ͜ʖ ͡°)_/¯</h1>} />
</Route>
</SentryRoutes>
</FilterProvider>
</Web3Provider>
</QueryClientProvider>
</StyledComponentsProvider>
Expand Down
3 changes: 3 additions & 0 deletions web/src/assets/svgs/icons/grid.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions web/src/assets/svgs/icons/list.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 45 additions & 7 deletions web/src/components/CasesDisplay/CasesGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,38 @@
import React from "react";
import styled from "styled-components";
import styled, { css } from "styled-components";
import { StandardPagination } from "@kleros/ui-components-library";
import { landscapeStyle } from "styles/landscapeStyle";
import { useFiltersContext } from "context/FilterProvider";
import { CasesPageQuery } from "queries/useCasesQuery";
import DisputeCard from "components/DisputeCard";
import CasesListHeader from "./CasesListHeader";
import { useLocation } from "react-router-dom";

const Container = styled.div`
const GridContainer = styled.div<{ path: string }>`
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
gap: 8px;
${({ path }) =>
landscapeStyle(() =>
path === "/dashboard"
? css`
display: flex;
`
: css`
display: grid;
row-gap: 16px;
column-gap: 8px;
grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
justify-content: space-between;
`
)}
`;
const ListContainer = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
gap: 8px;
`;

Expand All @@ -26,13 +51,26 @@ export interface ICasesGrid {
}

const CasesGrid: React.FC<ICasesGrid> = ({ disputes, currentPage, setCurrentPage, numberDisputes, casesPerPage }) => {
const { isList } = useFiltersContext();
const location = useLocation();

const path = location.pathname;
return (
<>
<Container>
{disputes.map((dispute, i) => {
return <DisputeCard key={i} {...dispute} />;
})}
</Container>
{!isList ? (
<GridContainer path={path}>
{disputes.map((dispute) => {
return <DisputeCard key={dispute?.id} {...dispute} />;
})}
</GridContainer>
) : (
<ListContainer>
{isList && <CasesListHeader />}
{disputes.map((dispute) => {
return <DisputeCard key={dispute?.id} {...dispute} />;
})}
</ListContainer>
)}
<StyledPagination
{...{ currentPage }}
numPages={Math.ceil(numberDisputes / casesPerPage)}
Expand Down
73 changes: 73 additions & 0 deletions web/src/components/CasesDisplay/CasesListHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React from "react";
import styled, { css } from "styled-components";
import { landscapeStyle } from "styles/landscapeStyle";
import WithHelpTooltip from "pages/Dashboard/WithHelpTooltip";

const Container = styled.div`
display: flex;
justify-content: space-between;
gap: calc(15vw + (40 - 15) * ((100vw - 300px) / (1250 - 300)));
width: 100%;
height: 100%;
`;

const CasesData = styled.div`
display: flex;
align-items: center;
justify-content: space-around;
width: 100%;
margin-left: calc(0px + (33) * (100vw - 370px) / (1250 - 370));
flex-wrap: wrap;
padding: 0 3%;
gap: calc(24px + (48 - 24) * ((100vw - 300px) / (1250 - 300)));
`;

const CaseTitle = styled.div`
display: none;
margin-left: 32px;
gap: 36px;
label {
font-weight: 400;
font-size: 14px;
line-height: 19px;
color: ${({ theme }) => theme.secondaryText} !important;
}

${landscapeStyle(
() =>
css`
display: flex;
`
)}
`;

const StyledLabel = styled.label`
padding-left: calc(4px + (8 - 4) * ((100vw - 300px) / (900 - 300)));
`;

const tooltipMsg =
"Users have an economic interest in serving as jurors in Kleros: " +
"collecting the Juror Rewards in exchange for their work. Each juror who " +
"is coherent with the final ruling receive the Juror Rewards composed of " +
"arbitration fees (ETH) + PNK redistribution between jurors.";

const CasesListHeader: React.FC = () => {
return (
<Container>
<CaseTitle>
<label>#</label>
<label>Title</label>
</CaseTitle>
<CasesData>
<StyledLabel>Court</StyledLabel>
<StyledLabel>Category</StyledLabel>
<WithHelpTooltip place="top" {...{ tooltipMsg }}>
<label> Rewards: </label>
</WithHelpTooltip>
<label>Next Deadline</label>
</CasesData>
</Container>
);
};

export default CasesListHeader;
55 changes: 54 additions & 1 deletion web/src/components/CasesDisplay/Filters.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import React from "react";
import styled, { useTheme } from "styled-components";
import styled, { useTheme, css } from "styled-components";
import { useWindowSize } from "react-use";
import { DropdownSelect } from "@kleros/ui-components-library";
import { useFiltersContext } from "context/FilterProvider";
import { BREAKPOINT_LANDSCAPE } from "styles/landscapeStyle";
import ListIcon from "svgs/icons/list.svg";
import GridIcon from "svgs/icons/grid.svg";

const Container = styled.div`
display: flex;
Expand All @@ -9,8 +14,44 @@ const Container = styled.div`
width: fit-content;
`;

const glowingEffect = css`
filter: drop-shadow(0 0 4px ${({ theme }) => theme.klerosUIComponentsSecondaryPurple});
`;

const StyledGridIcon = styled(GridIcon)<{ isList: boolean }>`
cursor: pointer;
transition: filter 0.2s ease;
fill: ${({ theme }) => theme.primaryBlue};
width: 16px;
height: 16px;
overflow: hidden;
${({ isList }) => !isList && glowingEffect}
`;

const IconsContainer = styled.div`
display: flex;
justify-content: center;
align-items: center;
gap: 4px;
`;

const StyledListIcon = styled(ListIcon)<{ isList: boolean; isScreenBig: boolean }>`
cursor: pointer;
display: ${({ isScreenBig }) => (isScreenBig ? "block" : "none")};
transition: filter 0.2s ease;
fill: ${({ theme }) => theme.primaryBlue};
width: 16px;
height: 16px;
overflow: hidden;
${({ isList }) => isList && glowingEffect}
`;

const Filters: React.FC = () => {
const theme = useTheme();
const { width } = useWindowSize();
const { isList, setIsList } = useFiltersContext();
const screenIsBig = width > BREAKPOINT_LANDSCAPE;

return (
<Container>
<DropdownSelect
Expand All @@ -35,6 +76,18 @@ const Filters: React.FC = () => {
defaultValue={0}
callback={() => {}}
/>
<IconsContainer>
<StyledGridIcon isList={isList} onClick={() => setIsList(false)} />
<StyledListIcon
isList={isList}
isScreenBig={screenIsBig}
onClick={() => {
if (screenIsBig) {
setIsList(true);
}
}}
/>
</IconsContainer>
</Container>
);
};
Expand Down
35 changes: 30 additions & 5 deletions web/src/components/DisputeCard/DisputeInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from "react";
import styled from "styled-components";
import styled, { css } from "styled-components";
import { useFiltersContext } from "context/FilterProvider";
import { Periods } from "consts/periods";
import BookmarkIcon from "svgs/icons/bookmark.svg";
import CalendarIcon from "svgs/icons/calendar.svg";
Expand All @@ -8,10 +9,20 @@ import PileCoinsIcon from "svgs/icons/pile-coins.svg";
import RoundIcon from "svgs/icons/round.svg";
import Field from "../Field";

const Container = styled.div`
const Container = styled.div<{ isList: boolean }>`
display: flex;
flex-direction: column;
flex-direction: ${({ isList }) => (isList ? "row" : "column")};
gap: 8px;

${({ isList }) =>
isList &&
css`
gap: calc(4px + (24px - 4px) * ((100vw - 300px) / (900 - 300)));
`};
justify-content: ${({ isList }) => (isList ? "space-around" : "center")};
align-items: center;
width: 100%;
height: 100%;
`;

const getPeriodPhrase = (period: Periods): string => {
Expand All @@ -37,15 +48,29 @@ export interface IDisputeInfo {
round?: number;
}

const formatDate = (date: number) => {
const options: Intl.DateTimeFormatOptions = { year: "numeric", month: "long", day: "numeric" };
const startingDate = new Date(date * 1000);
const formattedDate = startingDate.toLocaleDateString("en-US", options);
return formattedDate;
};

const DisputeInfo: React.FC<IDisputeInfo> = ({ courtId, court, category, rewards, period, date, round }) => {
const { isList } = useFiltersContext();

return (
<Container>
<Container isList={isList}>
{court && courtId && <Field icon={LawBalanceIcon} name="Court" value={court} link={`/courts/${courtId}`} />}
{category && <Field icon={BookmarkIcon} name="Category" value={category} />}
{!category && isList && <Field icon={BookmarkIcon} name="Category" value="General" />}
{round && <Field icon={RoundIcon} name="Round" value={round.toString()} />}
{rewards && <Field icon={PileCoinsIcon} name="Juror Rewards" value={rewards} />}
{typeof period !== "undefined" && date && (
<Field icon={CalendarIcon} name={getPeriodPhrase(period)} value={new Date(date * 1000).toLocaleString()} />
<Field
icon={CalendarIcon}
name={getPeriodPhrase(period)}
value={!isList ? new Date(date * 1000).toLocaleString() : formatDate(date)}
/>
)}
</Container>
);
Expand Down
15 changes: 8 additions & 7 deletions web/src/components/DisputeCard/PeriodBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import styled, { Theme } from "styled-components";
import { Periods } from "consts/periods";

const Container = styled.div<Omit<IPeriodBanner, "id">>`
height: 45px;
height: ${({ isCard }) => (isCard ? "45px" : "100%")};
width: auto;
border-top-right-radius: 3px;
border-top-left-radius: 3px;
Expand All @@ -21,11 +21,11 @@ const Container = styled.div<Omit<IPeriodBanner, "id">>`
margin-right: 8px;
}
}
${({ theme, period }) => {
${({ theme, period, isCard }) => {
const [frontColor, backgroundColor] = getPeriodColors(period, theme);
return `
border-top: 5px solid ${frontColor};
background-color: ${backgroundColor};
${isCard ? `border-top: 5px solid ${frontColor}` : `border-left: 5px solid ${frontColor}`};
${isCard && `background-color: ${backgroundColor}`};
.front-color {
color: ${frontColor};
}
Expand All @@ -41,6 +41,7 @@ const Container = styled.div<Omit<IPeriodBanner, "id">>`
export interface IPeriodBanner {
id: number;
period: Periods;
isCard?: boolean;
}

const getPeriodColors = (period: Periods, theme: Theme): [string, string] => {
Expand All @@ -65,9 +66,9 @@ const getPeriodLabel = (period: Periods): string => {
}
};

const PeriodBanner: React.FC<IPeriodBanner> = ({ id, period }) => (
<Container {...{ period }}>
<label className="front-color dot">{getPeriodLabel(period)}</label>
const PeriodBanner: React.FC<IPeriodBanner> = ({ id, period, isCard = true }) => (
<Container period={period} isCard={isCard}>
{isCard && <label className="front-color dot">{getPeriodLabel(period)}</label>}
<label className="front-color">#{id}</label>
</Container>
);
Expand Down
Loading