Skip to content

Commit

Permalink
Merge branch 'dev' into feat/ui-improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
kemuru authored Dec 19, 2024
2 parents d93e2ff + f52ed9c commit 2a1f4d0
Show file tree
Hide file tree
Showing 10 changed files with 557 additions and 38 deletions.
3 changes: 3 additions & 0 deletions kleros-app/src/lib/atlas/hooks/useSessionStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export function useSessionStorage<T>(keyName: string, defaultValue: T) {

return value ? JSON.parse(value) : defaultValue;
} catch (err) {
// eslint-disable-next-line no-console
console.log("useSessionStorage:", { err });

return defaultValue;
}
});
Expand Down
35 changes: 33 additions & 2 deletions kleros-app/src/lib/atlas/providers/AtlasProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
import { GraphQLError } from "graphql";
import { isUndefined } from "../../../utils";
import { useSessionStorage } from "../hooks/useSessionStorage";
import { fetchRestrictions, Role } from "../utils/fetchRestrictions";

interface IAtlasProvider {
isVerified: boolean;
Expand All @@ -44,6 +45,7 @@ interface IAtlasProvider {
isError: boolean;
}
>;
roleRestrictions: Role[] | undefined;
}

const Context = createContext<IAtlasProvider | undefined>(undefined);
Expand Down Expand Up @@ -73,7 +75,7 @@ export const AtlasProvider: React.FC<{ config: AtlasConfig; children?: React.Rea
}
: undefined;
return new GraphQLClient(`${config.uri}/graphql`, { headers });
}, [authToken]);
}, [authToken, config.uri]);

/**
* @description verifies user authorisation
Expand Down Expand Up @@ -142,6 +144,22 @@ export const AtlasProvider: React.FC<{ config: AtlasConfig; children?: React.Rea
queryClient
);

const { data: roleRestrictions } = useQuery(
{
queryKey: [`RoleRestrictions`],
enabled: Boolean(config.product),
staleTime: Infinity,
queryFn: async () => {
try {
return await fetchRestrictions(atlasGqlClient, config.product);
} catch {
return undefined;
}
},
},
queryClient
);

useEffect(() => {
if (!isVerified) return;
refetchUser();
Expand Down Expand Up @@ -255,6 +273,17 @@ export const AtlasProvider: React.FC<{ config: AtlasConfig; children?: React.Rea
async (file: File, role: Roles) => {
try {
if (!address || !isVerified || !config.uri || !authToken) return null;

if (roleRestrictions) {
const restrictions = roleRestrictions.find((supportedRoles) => Roles[supportedRoles.name] === role);

if (!restrictions) throw new Error("Unsupported role.");
if (!restrictions.restriction.allowedMimeTypes.includes(file.type)) throw new Error("Unsupported file type.");
if (file.size > restrictions.restriction.maxSize)
throw new Error(
`File too big. Max allowed size : ${(restrictions.restriction.maxSize / (1024 * 1024)).toFixed(2)} mb.`
);
}
setIsUploadingFile(true);

const hash = await fetchWithAuthErrorHandling(() =>
Expand All @@ -267,7 +296,7 @@ export const AtlasProvider: React.FC<{ config: AtlasConfig; children?: React.Rea
setIsUploadingFile(false);
}
},
[address, isVerified, setIsUploadingFile, authToken, config.uri, config.product]
[address, isVerified, setIsUploadingFile, authToken, config.uri, config.product, roleRestrictions]
);

/**
Expand Down Expand Up @@ -309,6 +338,7 @@ export const AtlasProvider: React.FC<{ config: AtlasConfig; children?: React.Rea
isUploadingFile,
uploadFile,
confirmEmail,
roleRestrictions,
}),
[
isVerified,
Expand All @@ -324,6 +354,7 @@ export const AtlasProvider: React.FC<{ config: AtlasConfig; children?: React.Rea
isUploadingFile,
uploadFile,
confirmEmail,
roleRestrictions,
]
)}
>
Expand Down
40 changes: 40 additions & 0 deletions kleros-app/src/lib/atlas/utils/fetchRestrictions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { gql, type GraphQLClient } from "graphql-request";
import { Products } from ".";

export type Role = {
name: string;
restriction: {
maxSize: number;
allowedMimeTypes: string[];
};
};

type FetchRolesResponse = {
roles: Role[];
};

const query = gql`
query Roles($product: Products!) {
roles(product: $product) {
name
restriction {
maxSize
allowedMimeTypes
}
}
}
`;

export async function fetchRestrictions(client: GraphQLClient, product: Products): Promise<Role[]> {
return client
.request<FetchRolesResponse>(query, { product })
.then((response) => response.roles)
.catch((errors) => {
// eslint-disable-next-line no-console
console.log("Error fetching roles :", { errors });
const errorMessage = Array.isArray(errors?.response?.errors)
? errors.response.errors[0]?.message
: "Error fetching roles";
throw Error(errorMessage);
});
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"web-devtools",
"eslint-config",
"prettier-config",
"tsconfig"
"tsconfig",
"kleros-app"
],
"packageManager": "[email protected]",
"volta": {
Expand Down
4 changes: 4 additions & 0 deletions web/src/components/FileViewer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ const Wrapper = styled.div`

const StyledDocViewer = styled(DocViewer)`
background-color: ${({ theme }) => theme.whiteBackground} !important;
#pdf-controls {
z-index: 3;
}
`;

/**
Expand Down
17 changes: 14 additions & 3 deletions web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import React, { useState, useMemo, useEffect } from "react";
import styled from "styled-components";

import { hoverShortTransitionTiming } from "styles/commonStyles";

import { useParams } from "react-router-dom";
import { useDebounce } from "react-use";

Expand All @@ -12,6 +10,10 @@ import { commify, uncommify } from "utils/commify";
import { formatPNK, roundNumberDown } from "utils/format";
import { isUndefined } from "utils/index";

import { useCourtDetails } from "queries/useCourtDetails";

import { hoverShortTransitionTiming } from "styles/commonStyles";

import { NumberInputField } from "components/NumberInputField";

import StakeWithdrawButton, { ActionType } from "./StakeWithdrawButton";
Expand Down Expand Up @@ -75,6 +77,7 @@ const InputDisplay: React.FC<IInputDisplay> = ({ action, amount, setAmount }) =>

const { id } = useParams();
const { balance, jurorBalance } = usePnkData({ courtId: id });
const { data: courtDetails } = useCourtDetails(id);

const parsedBalance = formatPNK(balance ?? 0n, 0, true);

Expand All @@ -88,10 +91,18 @@ const InputDisplay: React.FC<IInputDisplay> = ({ action, amount, setAmount }) =>
setErrorMsg("Insufficient balance to stake this amount");
} else if (!isStaking && jurorBalance && parsedAmount > jurorBalance[2]) {
setErrorMsg("Insufficient staked amount to withdraw this amount");
} else if (
action === ActionType.stake &&
courtDetails &&
jurorBalance &&
parsedAmount !== 0n &&
jurorBalance[2] + parsedAmount < BigInt(courtDetails?.court?.minStake)
) {
setErrorMsg(`Min Stake in court is: ${formatPNK(courtDetails?.court?.minStake)} PNK`);
} else {
setErrorMsg(undefined);
}
}, [parsedAmount, isStaking, balance, jurorBalance]);
}, [parsedAmount, isStaking, balance, jurorBalance, action, courtDetails]);

return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ import {
useSimulatePnkIncreaseAllowance,
useWritePnkIncreaseAllowance,
} from "hooks/contracts/generated";
import { useCourtDetails } from "hooks/queries/useCourtDetails";
import { useLockOverlayScroll } from "hooks/useLockOverlayScroll";
import { usePnkData } from "hooks/usePNKData";
import { formatETH } from "utils/format";
import { isUndefined } from "utils/index";
import { parseWagmiError } from "utils/parseWagmiError";
import { refetchWithRetry } from "utils/refecthWithRetry";

import { useCourtDetails } from "queries/useCourtDetails";

import { EnsureChain } from "components/EnsureChain";

import StakeWithdrawPopup from "./StakeWithdrawPopup";
Expand Down Expand Up @@ -67,9 +67,8 @@ const StakeWithdrawButton: React.FC<IActionButton> = ({
const controllerRef = useRef<AbortController | null>(null);
useLockOverlayScroll(isPopupOpen);

const { data: courtDetails } = useCourtDetails(id);
const { balance, jurorBalance, allowance, refetchAllowance } = usePnkData({ courtId: id });

const { data: courtDetails } = useCourtDetails(id);
const publicClient = usePublicClient();

const isStaking = action === ActionType.stake;
Expand Down Expand Up @@ -181,6 +180,16 @@ const StakeWithdrawButton: React.FC<IActionButton> = ({
)
);
});
} else {
updatePopupState(
signal,
getStakeSteps(
StakeSteps.StakeFailed,
...commonArgs,
undefined,
new Error("Simulation Failed. Please restart the process.")
)
);
}
},
[setStake, setStakeConfig, publicClient, amount, theme, action]
Expand Down Expand Up @@ -248,20 +257,20 @@ const StakeWithdrawButton: React.FC<IActionButton> = ({

useEffect(() => {
if (isPopupOpen) return;
if (
action === ActionType.stake &&
targetStake !== 0n &&
courtDetails &&
targetStake < BigInt(courtDetails.court?.minStake)
) {
setErrorMsg(`Min Stake in court is: ${formatETH(courtDetails?.court?.minStake)}`);
} else if (setStakeError || allowanceError) {
if (setStakeError || allowanceError) {
setErrorMsg(parseWagmiError(setStakeError || allowanceError));
}
}, [setStakeError, setErrorMsg, targetStake, courtDetails, allowanceError, isPopupOpen, action]);
}, [setStakeError, setErrorMsg, targetStake, allowanceError, isPopupOpen]);

const isDisabled = useMemo(() => {
if (parsedAmount == 0n) return true;
if (
parsedAmount == 0n ||
(action === ActionType.stake &&
targetStake !== 0n &&
courtDetails &&
targetStake < BigInt(courtDetails?.court?.minStake))
)
return true;
if (isAllowance) {
return isUndefined(increaseAllowanceConfig) || isSimulatingAllowance || !isUndefined(allowanceError);
}
Expand All @@ -275,6 +284,9 @@ const StakeWithdrawButton: React.FC<IActionButton> = ({
setStakeError,
allowanceError,
isAllowance,
targetStake,
action,
courtDetails,
]);

const closePopup = () => {
Expand Down
4 changes: 2 additions & 2 deletions web/src/pages/Home/CourtOverview/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React from "react";
import styled from "styled-components";

import { responsiveSize } from "styles/responsiveSize";

import { Button } from "@kleros/ui-components-library";

import Bookmark from "svgs/icons/bookmark.svg";

import { responsiveSize } from "styles/responsiveSize";

import { InternalLink } from "components/InternalLink";

const StyledHeader = styled.div`
Expand Down
Loading

0 comments on commit 2a1f4d0

Please sign in to comment.