diff --git a/src/components/modal/components/Chat/components/EscalateModal/steps/EscalateStepTwo.tsx b/src/components/modal/components/Chat/components/EscalateModal/steps/EscalateStepTwo.tsx index 8359162ef..8fa1b2815 100644 --- a/src/components/modal/components/Chat/components/EscalateModal/steps/EscalateStepTwo.tsx +++ b/src/components/modal/components/Chat/components/EscalateModal/steps/EscalateStepTwo.tsx @@ -511,9 +511,9 @@ function EscalateStepTwo({ values?.disputeId || "", [FormModel.formFields.buyerAddress.name]: values?.buyerAddress ? values?.buyerAddress : "", - [`Unsigned message: ${FormModel.formFields.message.name}`]: + [`Signed message: ${FormModel.formFields.message.name}`]: values?.message - ? `Unsigned message: ${values?.message}` + ? `Signed message: ${values?.message}` : "", [FormModel.formFields.signature.name]: values?.signature || "" @@ -524,7 +524,7 @@ function EscalateStepTwo({ diff --git a/src/lib/utils/dispute.ts b/src/lib/utils/dispute.ts new file mode 100644 index 000000000..30647e214 --- /dev/null +++ b/src/lib/utils/dispute.ts @@ -0,0 +1,18 @@ +import { subgraph } from "@bosonprotocol/react-kit"; + +import { getDateTimestamp } from "./getDateTimestamp"; + +export const getDisputeDates = ( + dispute: subgraph.DisputeFieldsFragment | undefined +) => { + const endOfResolutionPeriod = dispute?.timeout + ? getDateTimestamp(dispute?.timeout) + : undefined; + const finishedResolutionPeriod = endOfResolutionPeriod + ? Date.now() > endOfResolutionPeriod + : false; + return { + endOfResolutionPeriod, + finishedResolutionPeriod + }; +}; diff --git a/src/lib/utils/exchange.ts b/src/lib/utils/exchange.ts index 521d9c826..89b3c7d51 100644 --- a/src/lib/utils/exchange.ts +++ b/src/lib/utils/exchange.ts @@ -39,12 +39,28 @@ export const getHasExchangeDisputeResolutionElapsed = ( return false; } return ( - Number(exchange.redeemedDate) * 1000 + - Number(offer.disputePeriodDuration) * 1000 < + getDateTimestamp(exchange.redeemedDate) + + getDateTimestamp(offer.disputePeriodDuration) < Date.now() ); }; +export const getHasExchangeEscalationPeriodElapsed = ( + escalationResponsePeriod: string | undefined | null, + escalatedDate: string | undefined | null +): boolean => { + if (!escalationResponsePeriod || !escalatedDate) { + return false; + } + const fixedEscalatedDate = getDateTimestamp(escalatedDate); + const escalationPeriodSecondsNumber = Number(escalationResponsePeriod); + if (!fixedEscalatedDate || isNaN(escalationPeriodSecondsNumber)) { + return false; + } + const escalationPeriodInMs = escalationPeriodSecondsNumber * 1000; + return fixedEscalatedDate + escalationPeriodInMs < Date.now(); +}; + const PROTOCOL_DEPLOYMENT_TIMES = { v221: { local: 0, @@ -69,10 +85,10 @@ export const getExchangeTokenId = ( }; export const getExchangeDisputeDates = (exchange: Exchange) => { - const raisedDisputeAt = new Date(Number(exchange.disputedDate) * 1000); + const raisedDisputeAt = new Date(getDateTimestamp(exchange.disputedDate)); const lastDayToResolveDispute = new Date( raisedDisputeAt.getTime() + - Number(exchange.offer.resolutionPeriodDuration) * 1000 + getDateTimestamp(exchange.offer.resolutionPeriodDuration) ); const totalDaysToResolveDispute = dayjs(lastDayToResolveDispute).diff( raisedDisputeAt, diff --git a/src/lib/utils/getDateTimestamp.ts b/src/lib/utils/getDateTimestamp.ts index 3f2c2db65..f64587144 100644 --- a/src/lib/utils/getDateTimestamp.ts +++ b/src/lib/utils/getDateTimestamp.ts @@ -1,4 +1,4 @@ -export const getDateTimestamp = (date: string) => { +export const getDateTimestamp = (date: string | undefined | null): number => { const number = Number(date); return !isNaN(number) ? number * 1000 : 0; diff --git a/src/lib/utils/hooks/useDisputeResolver.ts b/src/lib/utils/hooks/useDisputeResolver.ts index 083190a56..0931c5e63 100644 --- a/src/lib/utils/hooks/useDisputeResolver.ts +++ b/src/lib/utils/hooks/useDisputeResolver.ts @@ -28,12 +28,15 @@ interface Props { }; } -export function useDisputeResolver(id: string) { +export function useDisputeResolver(id: string | undefined | null) { const { config } = useConfigContext(); const { subgraphUrl } = config.envConfig; const props = { id }; const result = useQuery(["disputeResolver", props, subgraphUrl], async () => { + if (!id) { + return; + } const result = await fetchSubgraph( subgraphUrl, gql` diff --git a/src/pages/chat/components/ExchangeSidePreview.tsx b/src/pages/chat/components/ExchangeSidePreview.tsx index 1d8e06cb5..d4ad5f219 100644 --- a/src/pages/chat/components/ExchangeSidePreview.tsx +++ b/src/pages/chat/components/ExchangeSidePreview.tsx @@ -7,6 +7,8 @@ import { buyerAndSellerAgreementIncluding, customisedExchangePolicy } from "lib/constants/policies"; +import { getDisputeDates } from "lib/utils/dispute"; +import { useDisputeResolver } from "lib/utils/hooks/useDisputeResolver"; import { getExchangePolicyName } from "lib/utils/policy/getExchangePolicyName"; import { ArrowSquareOut } from "phosphor-react"; import { @@ -44,6 +46,7 @@ import { calcPercentage } from "../../../lib/utils/calcPrice"; import { getExchangeDisputeDates, getHasExchangeDisputeResolutionElapsed, + getHasExchangeEscalationPeriodElapsed, isExchangeCompletableByBuyer, isExchangeCompletableBySeller } from "../../../lib/utils/exchange"; @@ -377,7 +380,15 @@ export default memo(function ExchangeSidePreview({ }, { enabled: !!exchange } ); + const { disputeResolver } = useDisputeResolver( + exchange?.offer.disputeResolverId + ); + const dispute = disputes?.[0]; + const isElapsedEscalation = getHasExchangeEscalationPeriodElapsed( + disputeResolver?.escalationResponsePeriod, + dispute?.escalatedDate + ); const offer = exchange?.offer; const { showModal, modalTypes } = useModal(); const OFFER_DETAIL_DATA = useMemo( @@ -438,6 +449,7 @@ export default memo(function ExchangeSidePreview({ const isEscalated = !!dispute?.escalatedDate; const isRetracted = !!dispute?.retractedDate; const isFinalized = !!dispute?.finalizedDate; + const { finishedResolutionPeriod } = getDisputeDates(dispute); const { totalDaysToResolveDispute, daysLeftToResolveDispute } = getExchangeDisputeDates(exchange); @@ -521,7 +533,7 @@ export default memo(function ExchangeSidePreview({
- {isInDispute && iAmTheBuyer && !isEscalated && !isRetracted ? ( + {isInDispute && iAmTheBuyer && !isRetracted && !isElapsedEscalation ? ( - + {!finishedResolutionPeriod && !isEscalated && ( + + )} {CompleteExchangeButton} ) : isInRedeemed && iAmTheBuyer ? (