-
Notifications
You must be signed in to change notification settings - Fork 69
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
Add Dispute Challenge and Accept buttons to Transaction Details #7093
Changes from 60 commits
991dd84
46c3f31
59190f2
b8ef1be
026d905
10e42da
1a53f0e
7cc279b
a85fea3
194677b
3f7168d
347198a
484b60d
83474fe
b64d04b
9ea2586
004aaf6
341d83d
da679bc
62cd852
8a349b6
3545ae9
2fb3cfb
c355a77
2f59597
0d0616d
b134595
39e0d7f
9d341a0
9091394
163d427
1165d67
dc3a79a
1b2bbc3
fe0955b
3412ae0
47a9324
cae2394
db85448
81738f0
c072af5
85490fc
cfb3709
156c298
5961f5f
be9ff75
0bb32c9
c5a5ffe
dcc5d45
395a111
49158aa
f7ffc1c
ef03f65
b6eed3b
13a4fa3
b52093d
939c40d
d8ca8e6
3709cc0
340b5a1
203f161
163514b
eb23605
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
Significance: patch | ||
Type: add | ||
Comment: Behind a feature flag: add challenge and accept action buttons to Transaction Details screen | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,17 +3,35 @@ | |
/** | ||
* External dependencies | ||
*/ | ||
import React from 'react'; | ||
import React, { useState } from 'react'; | ||
import moment from 'moment'; | ||
import { __ } from '@wordpress/i18n'; | ||
import { Card, CardBody } from '@wordpress/components'; | ||
import { edit } from '@wordpress/icons'; | ||
import { __, sprintf } from '@wordpress/i18n'; | ||
import { backup, edit, lock } from '@wordpress/icons'; | ||
import { createInterpolateElement } from '@wordpress/element'; | ||
import { Link } from '@woocommerce/components'; | ||
import { | ||
Button, | ||
Card, | ||
CardBody, | ||
Flex, | ||
FlexItem, | ||
Icon, | ||
Modal, | ||
} from '@wordpress/components'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import type { Dispute } from 'wcpay/types/disputes'; | ||
import { isAwaitingResponse } from 'wcpay/disputes/utils'; | ||
import wcpayTracks from 'tracks'; | ||
import { useDisputeAccept } from 'wcpay/data'; | ||
import { | ||
getDisputeFee, | ||
isAwaitingResponse, | ||
isInquiry, | ||
} from 'wcpay/disputes/utils'; | ||
import { getAdminUrl } from 'wcpay/utils'; | ||
import { formatCurrency } from 'wcpay/utils/currency'; | ||
import DisputeNotice from './dispute-notice'; | ||
import IssuerEvidenceList from './evidence-list'; | ||
import DisputeSummaryRow from './dispute-summary-row'; | ||
|
@@ -25,10 +43,19 @@ interface Props { | |
} | ||
|
||
const DisputeAwaitingResponseDetails: React.FC< Props > = ( { dispute } ) => { | ||
const { doAccept, isLoading } = useDisputeAccept( dispute ); | ||
const [ isModalOpen, setModalOpen ] = useState( false ); | ||
|
||
const now = moment(); | ||
const dueBy = moment.unix( dispute.evidence_details?.due_by ?? 0 ); | ||
const countdownDays = Math.floor( dueBy.diff( now, 'days', true ) ); | ||
const hasStagedEvidence = dispute.evidence_details?.has_evidence; | ||
const disputeFee = getDisputeFee( dispute ); | ||
const showDisputeActions = ! isInquiry( dispute ); | ||
|
||
const onModalClose = () => { | ||
setModalOpen( false ); | ||
}; | ||
|
||
return ( | ||
<div className="transaction-details-dispute-details-wrapper"> | ||
|
@@ -61,6 +88,147 @@ const DisputeAwaitingResponseDetails: React.FC< Props > = ( { dispute } ) => { | |
/> | ||
</> | ||
) } | ||
|
||
{ /* Dispute Actions */ } | ||
{ showDisputeActions && ( | ||
<div className="transaction-details-dispute-details-body__actions"> | ||
<Link | ||
href={ getAdminUrl( { | ||
page: 'wc-admin', | ||
path: '/payments/disputes/challenge', | ||
id: dispute.id, | ||
} ) } | ||
onClick={ () => { | ||
wcpayTracks.recordEvent( | ||
wcpayTracks.events | ||
.DISPUTE_CHALLENGE_CLICK, | ||
{ | ||
dispute_status: dispute.status, | ||
} | ||
); | ||
} } | ||
> | ||
<span className="components-button is-primary"> | ||
{ hasStagedEvidence | ||
? __( | ||
'Continue with challenge', | ||
'woocommerce-payments' | ||
) | ||
: __( | ||
'Challenge dispute', | ||
'woocommerce-payments' | ||
) } | ||
</span> | ||
</Link> | ||
|
||
<Button | ||
variant="tertiary" | ||
disabled={ isLoading } | ||
onClick={ () => { | ||
wcpayTracks.recordEvent( | ||
wcpayTracks.events | ||
.DISPUTE_ACCEPT_MODAL_VIEW, | ||
{ | ||
dispute_status: dispute.status, | ||
} | ||
); | ||
setModalOpen( true ); | ||
} } | ||
> | ||
{ __( | ||
'Accept dispute', | ||
'woocommerce-payments' | ||
) } | ||
</Button> | ||
|
||
{ isModalOpen && ( | ||
<Modal | ||
title="Accept the dispute?" | ||
onRequestClose={ onModalClose } | ||
className="transaction-details-dispute-accept-modal" | ||
> | ||
<p> | ||
<strong> | ||
{ __( | ||
'Before proceeding, please take note of the following:', | ||
'woocommerce-payments' | ||
) } | ||
</strong> | ||
</p> | ||
<Flex justify="start"> | ||
<FlexItem className="transaction-details-dispute-accept-modal__icon"> | ||
<Icon icon={ backup } size={ 24 } /> | ||
</FlexItem> | ||
<FlexItem> | ||
{ createInterpolateElement( | ||
sprintf( | ||
/* translators: %s: dispute fee, <em>: emphasis HTML element. */ | ||
__( | ||
'Accepting the dispute marks it as <em>Lost</em>. The disputed amount will be returned to the cardholder, with a %s dispute fee deducted from your account.', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we need to review this language. This implies the fee will only be deducted if they accept the dispute. When the fee has already been deducted. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll log a follow-up issue to allow this PR to be shipped and we can iterate on the wording. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. New issue for this: #7254 |
||
'woocommerce-payments' | ||
), | ||
disputeFee && | ||
formatCurrency( | ||
disputeFee.fee, | ||
disputeFee.currency | ||
) | ||
), | ||
{ | ||
em: <em />, | ||
} | ||
) } | ||
</FlexItem> | ||
</Flex> | ||
<Flex justify="start"> | ||
<FlexItem className="transaction-details-dispute-accept-modal__icon"> | ||
<Icon icon={ lock } size={ 24 } /> | ||
</FlexItem> | ||
<FlexItem> | ||
{ __( | ||
'Accepting the dispute is final and cannot be undone.', | ||
'woocommerce-payments' | ||
) } | ||
</FlexItem> | ||
</Flex> | ||
|
||
<Flex | ||
className="transaction-details-dispute-accept-modal__actions" | ||
justify="end" | ||
> | ||
<Button | ||
variant="tertiary" | ||
onClick={ onModalClose } | ||
> | ||
{ __( | ||
'Cancel', | ||
'woocommerce-payments' | ||
) } | ||
</Button> | ||
<Button | ||
variant="primary" | ||
onClick={ () => { | ||
wcpayTracks.recordEvent( | ||
wcpayTracks.events | ||
.DISPUTE_ACCEPT_CLICK, | ||
{ | ||
dispute_status: | ||
dispute.status, | ||
} | ||
); | ||
setModalOpen( false ); | ||
doAccept(); | ||
} } | ||
> | ||
{ __( | ||
'Accept dispute', | ||
'woocommerce-payments' | ||
) } | ||
</Button> | ||
</Flex> | ||
</Modal> | ||
) } | ||
</div> | ||
) } | ||
</CardBody> | ||
</Card> | ||
</div> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than modify the existing
acceptDispute
action (used on the Dispute → Details screen), I've created a new one since there are some differences in the approach:Once the feature flag is lifted,
_wcpay_feature_dispute_on_transaction_page
, we can remove and replace the previous action with the new one.I've left a TODO item on #6883 to make this change.