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

Feat(web): cases filtering #1169

Merged
merged 39 commits into from
Oct 7, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
410428c
chore(web): make skeleton style global
alcercu Aug 18, 2023
f0264ef
feat(web): modularize cases query and add My cases section to dashboard
alcercu Aug 18, 2023
47223eb
style(web): improve color for light mode skeleton
alcercu Aug 18, 2023
e574146
Merge branch 'dev' into feat(web)/cases-filtering
alcercu Aug 18, 2023
c04e8c7
fix: empty CasesGrid when user has never staked
jaybuidl Aug 22, 2023
465cd8a
feat: implement filtering and search logic
nhestrompia Aug 25, 2023
91351b6
fix(web): dashboard dont show my courts if no staked anymore
kemuru Aug 28, 2023
1bdd14a
chore(web): abstract variables
kemuru Aug 28, 2023
4bed1b3
refactor: clear naming for condition
nhestrompia Aug 28, 2023
a69b335
feat: add court selection filtering and subgraph update
nhestrompia Sep 11, 2023
40ec2ca
refactor: code smell and some refactor
nhestrompia Sep 11, 2023
041c945
fix: page number and query param
nhestrompia Sep 11, 2023
bfe027c
Merge branch 'dev' into feat(web)/cases-filtering
alcercu Sep 12, 2023
23c21d8
refactor(subgraph): avoid contract binding and add numberVotingCases
alcercu Sep 13, 2023
efe8852
feat(subgraph): add blocknumber fields
alcercu Sep 13, 2023
a3b16ed
fix(web): add mainnet to chains, but in second position so it's not t…
alcercu Sep 13, 2023
3045e6c
refactor: fetching at pages
nhestrompia Sep 14, 2023
6f2228d
refactor: query naming
nhestrompia Sep 14, 2023
28547bb
fix: context states resetting
nhestrompia Sep 15, 2023
5127f0f
refactor: clear naming and query params
nhestrompia Sep 15, 2023
a29a3d8
fix: stake amount
nhestrompia Sep 15, 2023
504d5d7
feat(subgraph): add totalAppealingDisputes for user entity
alcercu Sep 15, 2023
41f261d
fix: query update based on subgraph changes
nhestrompia Sep 15, 2023
7a3ea07
refactor(web): move totalAppealingDisputes to useUser query
alcercu Sep 15, 2023
d9ef8f5
fix: dashboard new user problem
nhestrompia Sep 18, 2023
56cb87a
feat(subgraph): add periodDeadline field to dispute entity
alcercu Sep 18, 2023
4ba1cb1
chore(web): use devnet subgraph
alcercu Sep 18, 2023
5740f02
fix: dashboard pagination
nhestrompia Sep 19, 2023
36608f3
feat(web): cases filtering state tracked with url
alcercu Oct 4, 2023
61c67b6
chore(web): remove unused context
alcercu Oct 4, 2023
1596088
Merge branch 'dev' into feat(web)/cases-filtering
alcercu Oct 4, 2023
6211b52
fix(web): finish merging dev
alcercu Oct 4, 2023
0574615
fix(web): fix list view problems
alcercu Oct 5, 2023
9a09569
fix(web): code smells
alcercu Oct 5, 2023
2048cff
fix(web): wrong count and bad filter encoding
alcercu Oct 6, 2023
f29a40d
fix(subgraph): voting and appealing cases count
alcercu Oct 6, 2023
a0411a6
chore: filter ordering
jaybuidl Oct 6, 2023
a1c67ca
chore: dispute period banner more specific
jaybuidl Oct 6, 2023
f42cc14
fix: linter about shadowed variables
jaybuidl Oct 7, 2023
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
Prev Previous commit
Next Next commit
feat(web): modularize cases query and add My cases section to dashboard
  • Loading branch information
alcercu committed Aug 18, 2023
commit f0264efa50ff8cc27aec548780e8f9f6617e3a9a
31 changes: 17 additions & 14 deletions web/src/components/CasesDisplay/CasesGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React from "react";
import styled from "styled-components";
import Skeleton from "react-loading-skeleton";
import { StandardPagination } from "@kleros/ui-components-library";
import { CasesPageQuery } from "queries/useCasesQuery";
import { isUndefined } from "utils/index";
import { DisputeDetailsFragment } from "queries/useCasesQuery";
import DisputeCard from "components/DisputeCard";

const Container = styled.div`
Expand All @@ -11,6 +13,11 @@ const Container = styled.div`
gap: 8px;
`;

const StyledSkeleton = styled(Skeleton)`
height: 260px;
width: 310px;
`;

// 24px as margin-top since we already have 8px from the flex gap
const StyledPagination = styled(StandardPagination)`
margin-top: 24px;
Expand All @@ -19,30 +26,26 @@ const StyledPagination = styled(StandardPagination)`
`;

export interface ICasesGrid {
disputes: CasesPageQuery["disputes"];
disputes?: DisputeDetailsFragment[];
currentPage: number;
setCurrentPage: (newPage: number) => void;
numberDisputes: number;
numberDisputes?: number;
casesPerPage: number;
}

const CasesGrid: React.FC<ICasesGrid> = ({
disputes,
currentPage,
setCurrentPage,
numberDisputes,
casesPerPage,
}) => {
const CasesGrid: React.FC<ICasesGrid> = ({ disputes, currentPage, setCurrentPage, numberDisputes, casesPerPage }) => {
return (
<>
<Container>
{disputes.map((dispute, i) => {
return <DisputeCard key={i} {...dispute} />;
})}
{isUndefined(disputes)
? [...Array(casesPerPage)].map((_, i) => <StyledSkeleton key={i} />)
: disputes.map((dispute, i) => {
return <DisputeCard key={i} {...dispute} />;
})}
</Container>
<StyledPagination
{...{ currentPage }}
numPages={Math.ceil(numberDisputes / casesPerPage)}
numPages={Math.ceil((numberDisputes ?? 0) / casesPerPage)}
callback={(page: number) => setCurrentPage(page)}
/>
</>
Expand Down
16 changes: 8 additions & 8 deletions web/src/components/CasesDisplay/Stats.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from "react";
import styled from "styled-components";
import { useAllCasesQuery } from "hooks/queries/useAllCasesQuery";

const FieldWrapper = styled.div`
display: inline-flex;
Expand All @@ -21,17 +20,18 @@ const SeparatorLabel = styled.label`

const Separator: React.FC = () => <SeparatorLabel>|</SeparatorLabel>;

const Stats: React.FC = () => {
const { data } = useAllCasesQuery();
export interface IStats {
totalDisputes: number;
closedDisputes: number;
}

const totalDisputes = data?.counter?.cases;
const closedDisputes = data?.counter?.casesRuled;
const Stats: React.FC<IStats> = ({ totalDisputes, closedDisputes }) => {
const inProgressDisputes = (totalDisputes - closedDisputes).toString();

const fields = [
{ label: "Total", value: totalDisputes ?? "0" },
{ label: "In Progress", value: inProgressDisputes ?? "0" },
{ label: "Closed", value: closedDisputes ?? "0" },
{ label: "Total", value: totalDisputes.toString() },
{ label: "In Progress", value: inProgressDisputes },
{ label: "Closed", value: closedDisputes.toString() },
];

return (
Expand Down
6 changes: 3 additions & 3 deletions web/src/components/CasesDisplay/StatsAndFilters.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from "react";
import styled from "styled-components";
import Filters from "./Filters";
import Stats from "./Stats";
import Stats, { IStats } from "./Stats";

const Container = styled.div`
display: flex;
Expand All @@ -10,9 +10,9 @@ const Container = styled.div`
margin-top: 8px;
`;

const StatsAndFilters: React.FC = () => (
const StatsAndFilters: React.FC<IStats> = ({ totalDisputes, closedDisputes }) => (
<Container>
<Stats />
<Stats {...{ totalDisputes, closedDisputes }} />
<Filters />
</Container>
);
Expand Down
26 changes: 12 additions & 14 deletions web/src/components/CasesDisplay/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const StyledHR = styled.hr`
`;

interface ICasesDisplay extends ICasesGrid {
numberClosedDisputes?: number;
title?: string;
className?: string;
}
Expand All @@ -19,28 +20,25 @@ const CasesDisplay: React.FC<ICasesDisplay> = ({
currentPage,
setCurrentPage,
numberDisputes,
numberClosedDisputes,
casesPerPage,
title = "Cases",
className,
}) => (
<div {...{ className }}>
<h1>{title}</h1>
<Search />
<StatsAndFilters />
<StatsAndFilters totalDisputes={numberDisputes ?? 0} closedDisputes={numberClosedDisputes ?? 0} />
<StyledHR />
{disputes.length > 0 ? (
<CasesGrid
{...{
disputes,
currentPage,
setCurrentPage,
numberDisputes,
casesPerPage,
}}
/>
) : (
<h1>wow no cases</h1>
)}
<CasesGrid
{...{
disputes,
currentPage,
setCurrentPage,
numberDisputes,
casesPerPage,
}}
/>
</div>
);

Expand Down
10 changes: 2 additions & 8 deletions web/src/components/DisputeCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { formatEther } from "viem";
import Skeleton from "react-loading-skeleton";
import { Card } from "@kleros/ui-components-library";
import { Periods } from "consts/periods";
import { CasesPageQuery } from "queries/useCasesQuery";
import { DisputeDetailsFragment } from "queries/useCasesQuery";
import { useCourtPolicy } from "queries/useCourtPolicy";
import { useDisputeTemplate } from "queries/useDisputeTemplate";
import DisputeInfo from "./DisputeInfo";
Expand Down Expand Up @@ -39,13 +39,7 @@ export const getPeriodEndTimestamp = (
return parseInt(lastPeriodChange) + durationCurrentPeriod;
};

const DisputeCard: React.FC<CasesPageQuery["disputes"][number]> = ({
id,
arbitrated,
period,
lastPeriodChange,
court,
}) => {
const DisputeCard: React.FC<DisputeDetailsFragment> = ({ id, arbitrated, period, lastPeriodChange, court }) => {
const currentPeriodIndex = Periods[period];
const rewards = `≥ ${formatEther(court.feeForJuror)} ETH`;
const date =
Expand Down
74 changes: 52 additions & 22 deletions web/src/hooks/queries/useCasesQuery.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,67 @@
import { graphql } from "src/graphql";
import { Address } from "viem";
import { useQuery } from "@tanstack/react-query";
import { CasesPageQuery } from "src/graphql/graphql";
import { graphqlQueryFnHelper } from "~src/utils/graphqlQueryFnHelper";
export type { CasesPageQuery };
import { CasesPageQuery, Dispute_Filter, MyCasesQuery, DisputeDetailsFragment } from "src/graphql/graphql";
import { graphqlQueryFnHelper } from "utils/graphqlQueryFnHelper";
import { isUndefined } from "utils/index";
export type { CasesPageQuery, DisputeDetailsFragment };

export const disputeFragment = graphql(`
fragment DisputeDetails on Dispute {
id
arbitrated {
id
}
court {
id
policy
feeForJuror
timesPerPeriod
}
period
lastPeriodChange
}
`);

const casesQueryWhere = graphql(`
query CasesPageWhere($skip: Int, $where: Dispute_filter) {
disputes(first: 3, skip: $skip, orderBy: lastPeriodChange, orderDirection: desc, where: $where) {
...DisputeDetails
}
}
`);

const casesQuery = graphql(`
query CasesPage($skip: Int) {
disputes(first: 3, skip: $skip, orderBy: lastPeriodChange, orderDirection: desc) {
id
arbitrated {
id
}
court {
id
policy
feeForJuror
timesPerPeriod
}
period
lastPeriodChange
...DisputeDetails
}
counter(id: "0") {
cases
}
`);

const myCasesQuery = graphql(`
query MyCases($id: ID!, $skip: Int) {
user(id: $id) {
disputes(first: 3, skip: $skip, orderBy: lastPeriodChange, orderDirection: desc) {
...DisputeDetails
}
}
}
`);

export const useCasesQuery = (skip: number) => {
const isEnabled = skip !== undefined;
export const useCasesQuery = (skip = 0, where?: Dispute_Filter) => {
return useQuery<CasesPageQuery>({
queryKey: [`useCasesQuery`, skip],
queryFn: async () => await graphqlQueryFnHelper(isUndefined(where) ? casesQuery : casesQueryWhere, { skip, where }),
});
};

export const useMyCasesQuery = (user?: Address, skip = 0) => {
const isEnabled = !isUndefined(user);

return useQuery({
queryKey: [`useCasesQuery${skip}`],
return useQuery<MyCasesQuery>({
queryKey: [`useMyCasesQuery`, user, skip],
enabled: isEnabled,
queryFn: async () => await graphqlQueryFnHelper(casesQuery, { skip: skip }),
queryFn: async () => await graphqlQueryFnHelper(myCasesQuery, { skip, id: user?.toLowerCase() }),
});
};
20 changes: 20 additions & 0 deletions web/src/hooks/queries/useCounter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { graphql } from "src/graphql";
import { useQuery } from "@tanstack/react-query";
import { CounterQuery } from "src/graphql/graphql";
import { graphqlQueryFnHelper } from "utils/graphqlQueryFnHelper";

const counterQuery = graphql(`
query Counter {
counter(id: "0") {
alcercu marked this conversation as resolved.
Show resolved Hide resolved
cases
casesRuled
}
}
`);

export const useCounterQuery = () => {
return useQuery<CounterQuery>({
queryKey: [`useCounterQuery`],
queryFn: async () => await graphqlQueryFnHelper(counterQuery, {}),
});
};
7 changes: 4 additions & 3 deletions web/src/hooks/queries/useUser.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useQuery } from "@tanstack/react-query";
import { Address } from "viem";
import { graphql } from "src/graphql";
import { UserQuery } from "src/graphql/graphql";
import { graphqlQueryFnHelper } from "utils/graphqlQueryFnHelper";
Expand All @@ -24,12 +25,12 @@ const userQuery = graphql(`
}
`);

export const useUserQuery = (address?: string) => {
export const useUserQuery = (address?: Address) => {
const isEnabled = address !== undefined;

return useQuery<UserQuery>({
queryKey: [`userQuery${address}`],
queryKey: [`userQuery${address?.toLowerCase()}`],
enabled: isEnabled,
queryFn: async () => await graphqlQueryFnHelper(userQuery, { address }),
queryFn: async () => await graphqlQueryFnHelper(userQuery, { address: address?.toLowerCase() }),
});
};
17 changes: 9 additions & 8 deletions web/src/pages/Cases/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, { useState } from "react";
import styled from "styled-components";
import { Routes, Route } from "react-router-dom";
import { useCasesQuery } from "queries/useCasesQuery";
import { DisputeDetailsFragment, useCasesQuery } from "queries/useCasesQuery";
import { useCounterQuery } from "queries/useCounter";
import CasesDisplay from "components/CasesDisplay";
import CaseDetails from "./CaseDetails";

Expand All @@ -16,19 +17,19 @@ const Cases: React.FC = () => {
const [currentPage, setCurrentPage] = useState(1);
const casesPerPage = 3;
const { data } = useCasesQuery(casesPerPage * (currentPage - 1));
const { data: counterData } = useCounterQuery();
return (
<Container>
<Routes>
<Route
path=""
element={
data && (
<CasesDisplay
disputes={data.disputes}
numberDisputes={data.counter?.cases}
{...{ currentPage, setCurrentPage, casesPerPage }}
/>
)
<CasesDisplay
disputes={data?.disputes as DisputeDetailsFragment[]}
numberDisputes={counterData?.counter?.cases}
numberClosedDisputes={counterData?.counter?.casesRuled}
{...{ currentPage, setCurrentPage, casesPerPage }}
/>
}
/>
<Route path="/:id/*" element={<CaseDetails />} />
Expand Down
Loading