diff --git a/web/src/hooks/useClassicAppealContext.tsx b/web/src/hooks/useClassicAppealContext.tsx index a0f123a71..4a32f38b7 100644 --- a/web/src/hooks/useClassicAppealContext.tsx +++ b/web/src/hooks/useClassicAppealContext.tsx @@ -28,7 +28,7 @@ interface ISelectedOptionContext { } const SelectedOptionContext = createContext({ selectedOption: undefined, - //eslint-disable-next-line @typescript-eslint/no-empty-function + setSelectedOption: () => {}, }); diff --git a/web/src/pages/Cases/CaseDetails/Appeal/Classic/Fund.tsx b/web/src/pages/Cases/CaseDetails/Appeal/Classic/Fund.tsx index ed7cb79b8..c74664886 100644 --- a/web/src/pages/Cases/CaseDetails/Appeal/Classic/Fund.tsx +++ b/web/src/pages/Cases/CaseDetails/Appeal/Classic/Fund.tsx @@ -33,7 +33,7 @@ const StyledField = styled(Field)` &:before { position: absolute; content: "ETH"; - right: 12px; + right: 32px; top: 50%; transform: translateY(-50%); color: ${({ theme }) => theme.primaryText}; @@ -112,8 +112,15 @@ const Fund: React.FC = ({ amount, setAmount, setIsOpen }) => { const { fundAppealConfig, fundAppeal, isLoading, isError } = useFundAppeal(parsedAmount, insufficientBalance); const isFundDisabled = useMemo( - () => isDisconnected || isSending || !balance || insufficientBalance || Number(parsedAmount) <= 0 || isError, - [isDisconnected, isSending, balance, insufficientBalance, parsedAmount, isError] + () => + isDisconnected || + isSending || + !balance || + insufficientBalance || + Number(parsedAmount) <= 0 || + isError || + isLoading, + [isDisconnected, isSending, balance, insufficientBalance, parsedAmount, isError, isLoading] ); return needFund ? ( diff --git a/web/src/pages/Cases/CaseDetails/Appeal/index.tsx b/web/src/pages/Cases/CaseDetails/Appeal/index.tsx index b50a217f1..fb0d71070 100644 --- a/web/src/pages/Cases/CaseDetails/Appeal/index.tsx +++ b/web/src/pages/Cases/CaseDetails/Appeal/index.tsx @@ -46,15 +46,13 @@ const Appeal: React.FC<{ currentPeriodIndex: number }> = ({ currentPeriodIndex } const [isAppealMiniGuideOpen, toggleAppealMiniGuide] = useToggle(false); return ( - - - {Periods.appeal === currentPeriodIndex ? ( - - ) : ( - - )} - - + + {Periods.appeal === currentPeriodIndex ? ( + + ) : ( + + )} + ); }; diff --git a/web/src/pages/Cases/CaseDetails/MaintenanceButtons/DrawButton.tsx b/web/src/pages/Cases/CaseDetails/MaintenanceButtons/DrawButton.tsx index 34733470a..b0332e022 100644 --- a/web/src/pages/Cases/CaseDetails/MaintenanceButtons/DrawButton.tsx +++ b/web/src/pages/Cases/CaseDetails/MaintenanceButtons/DrawButton.tsx @@ -1,6 +1,8 @@ import React, { useMemo, useState } from "react"; import styled from "styled-components"; +import { Link } from "react-router-dom"; +import { isAddress } from "viem"; import { usePublicClient } from "wagmi"; import { Button, Field } from "@kleros/ui-components-library"; @@ -11,15 +13,13 @@ import { wrapWithToast } from "utils/wrapWithToast"; import useDisputeMaintenanceQuery from "queries/useDisputeMaintenanceQuery"; +import { isKlerosUniversity } from "src/consts"; import { Period } from "src/graphql/graphql"; import { isUndefined } from "src/utils"; import { Phases } from "components/Phase"; import { IBaseMaintenanceButton } from "."; -import { Link } from "react-router-dom"; -import { isKlerosUniversity } from "src/consts"; -import { isAddress } from "viem"; const StyledButton = styled(Button)` width: 100%; diff --git a/web/src/pages/Cases/CaseDetails/Timeline.tsx b/web/src/pages/Cases/CaseDetails/Timeline.tsx index 8c2bf6c2e..7a90b25b8 100644 --- a/web/src/pages/Cases/CaseDetails/Timeline.tsx +++ b/web/src/pages/Cases/CaseDetails/Timeline.tsx @@ -1,18 +1,23 @@ import React, { useMemo } from "react"; import styled, { css } from "styled-components"; -import { landscapeStyle } from "styles/landscapeStyle"; -import { responsiveSize } from "styles/responsiveSize"; - import { Box, Steps } from "@kleros/ui-components-library"; +import HourglassIcon from "svgs/icons/hourglass.svg"; + import { Periods } from "consts/periods"; +import { useCountdownContext, useFundingContext } from "hooks/useClassicAppealContext"; import { useCountdown } from "hooks/useCountdown"; import useIsDesktop from "hooks/useIsDesktop"; import { secondsToDayHourMinute } from "utils/date"; import { DisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; +import { isUndefined } from "src/utils"; + +import { landscapeStyle } from "styles/landscapeStyle"; +import { responsiveSize } from "styles/responsiveSize"; + import { StyledSkeleton } from "components/StyledSkeleton"; const TimeLineContainer = styled(Box)` @@ -43,19 +48,56 @@ const StyledSteps = styled(Steps)` )} `; +const AppealBannerContainer = styled.div` + background-color: ${({ theme }) => theme.whiteBackground}; + border-radius: 3px; + margin-top: 16px; + padding: 12px; + display: flex; + gap: 8px; + align-items: center; + justify-content: center; + & > svg { + width: 14px; + fill: ${({ theme }) => theme.secondaryPurple}; + } +`; + const Timeline: React.FC<{ dispute: DisputeDetailsQuery["dispute"]; currentPeriodIndex: number; }> = ({ currentPeriodIndex, dispute }) => { const currentItemIndex = currentPeriodToCurrentItem(currentPeriodIndex, dispute?.court.hiddenVotes); const items = useTimeline(dispute, currentItemIndex, currentItemIndex); + return ( + {currentPeriodIndex === Periods.appeal ? : null} ); }; +const AppealBanner: React.FC = () => { + const { loserSideCountdown, winnerSideCountdown } = useCountdownContext(); + const { fundedChoices } = useFundingContext(); + + const text = useMemo(() => { + if (loserSideCountdown) + return `${secondsToDayHourMinute(loserSideCountdown)} left until losing options can be funded`; + // only show if loosing option was funded and winner needs funding, else no action is needed from user + if (winnerSideCountdown && !isUndefined(fundedChoices) && fundedChoices.length > 0) + return `${secondsToDayHourMinute(winnerSideCountdown)} left until winning option can be funded`; + return; + }, [loserSideCountdown, winnerSideCountdown, fundedChoices]); + + return text ? ( + + {text} + + ) : null; +}; + const currentPeriodToCurrentItem = (currentPeriodIndex: number, hiddenVotes?: boolean): number => { if (hiddenVotes) return currentPeriodIndex; if (currentPeriodIndex <= Periods.commit) return currentPeriodIndex; diff --git a/web/src/pages/Cases/CaseDetails/index.tsx b/web/src/pages/Cases/CaseDetails/index.tsx index 6ff24cc21..ab4c0b0a9 100644 --- a/web/src/pages/Cases/CaseDetails/index.tsx +++ b/web/src/pages/Cases/CaseDetails/index.tsx @@ -6,6 +6,7 @@ import { Route, Routes, useParams, Navigate } from "react-router-dom"; import { Card } from "@kleros/ui-components-library"; import { Periods } from "consts/periods"; +import { ClassicAppealProvider } from "hooks/useClassicAppealContext"; import { VotingContextProvider } from "hooks/useVotingContext"; import { useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; @@ -58,32 +59,34 @@ const CaseDetails: React.FC = () => { return ( - - -
- Case #{id} {id ? : null} -
+ + + +
+ Case #{id} {id ? : null} +
- -
- - - - - - } - /> - } /> - } /> - } /> - } /> - - - -
+ +
+ + + + + + } + /> + } /> + } /> + } /> + } /> + + + +
+
); };