From a04fc87d35d4d8b502de2af455261ffb41eccf5c Mon Sep 17 00:00:00 2001 From: Rafael Meneses Date: Thu, 29 May 2025 17:58:55 -0300 Subject: [PATCH 01/42] layout and basic style --- client/disputes/new-evidence/index.tsx | 194 ++++++++++++++++++++---- client/disputes/new-evidence/style.scss | 33 ++++ 2 files changed, 196 insertions(+), 31 deletions(-) create mode 100644 client/disputes/new-evidence/style.scss diff --git a/client/disputes/new-evidence/index.tsx b/client/disputes/new-evidence/index.tsx index d3bb3ee0147..01713f173c3 100644 --- a/client/disputes/new-evidence/index.tsx +++ b/client/disputes/new-evidence/index.tsx @@ -3,18 +3,27 @@ /** * External dependencies */ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; /** * Internal dependencies. */ -import { Button } from 'wcpay/components/wp-components-wrapped'; -import '../style.scss'; +import { Button, HorizontalRule } from 'wcpay/components/wp-components-wrapped'; +import { getAdminUrl } from 'wcpay/utils'; import { Stepper, StepperPanel, useStepperContext, } from 'wcpay/components/stepper'; +import { + Accordion, + AccordionBody, + AccordionRow, +} from 'wcpay/components/accordion'; +import Page from 'wcpay/components/page'; + +import '../style.scss'; +import './style.scss'; interface StepProps { name: string; @@ -26,9 +35,6 @@ const StepOne: React.FC< StepProps > = () => {

General evidence

Provide general evidence for your dispute.

-
); }; @@ -39,12 +45,6 @@ const StepTwo: React.FC< StepProps > = () => {

Shipping information

Provide shipping details if applicable.

- -
); }; @@ -55,12 +55,6 @@ const StepThree: React.FC< StepProps > = () => {

Review

Review your information before submitting.

- -
); }; @@ -69,20 +63,158 @@ const steps = [ 'General evidence', 'Shipping information', 'Review' ]; export default () => { const [ currentStep, setCurrentStep ] = useState( 0 ); + const [ isAccordionOpen, setIsAccordionOpen ] = useState( + currentStep === 0 + ); - return ( - <> - - - setCurrentStep( steps.indexOf( step ) ) - } + useEffect( () => { + setIsAccordionOpen( currentStep === 0 ); + }, [ currentStep ] ); + + // TODO: Replace with real dispute ID from props or router + const disputeId = '123'; + + const handleCancel = () => { + window.location.href = getAdminUrl( { + page: 'wc-admin', + path: '/payments/disputes/details', + id: disputeId, + } ); + }; + + const handleSaveForLater = () => { + // TODO: Implement save for later logic + alert( 'Save for later (not implemented)' ); + }; + + const handleNext = () => setCurrentStep( ( s ) => s + 1 ); + const handleBack = () => setCurrentStep( ( s ) => s - 1 ); + const handleSubmit = () => { + // TODO: Implement submit logic + alert( 'Submit (not implemented)' ); + }; + + const renderButtons = () => { + if ( currentStep === 0 ) { + return ( +
+ +
+ + +
+
+ ); + } + if ( currentStep === 1 ) { + return ( +
+ +
+ + +
+
+ ); + } + // Step 2 (index 2): Review + return ( +
- - - - - + +
+ + +
+
+ ); + }; + + return ( + +
+ { /* Section 1: Accordion */ } + + + +
+ { /* Placeholder: Replace with summary and notice content in next step */ } +

Dispute summary and details go here.

+
+
+
+
+ + { /* Section 2: Stepper */ } +
+ + +
+ + setCurrentStep( steps.indexOf( step ) ) + } + > + + + + + { renderButtons() } +
+
+
+
); }; diff --git a/client/disputes/new-evidence/style.scss b/client/disputes/new-evidence/style.scss new file mode 100644 index 00000000000..d51d72a095c --- /dev/null +++ b/client/disputes/new-evidence/style.scss @@ -0,0 +1,33 @@ +// Container for the new-evidence page +.wcpay-dispute-evidence-new { + display: flex; + flex-direction: column; + gap: 24px; + + &__stepper-divider { + margin: 0; + } +} + +// Stepper section background to match accordion +.wcpay-dispute-evidence-new__stepper-section { + background: $white; // Same as .wcpay-accordion + border: $border-width solid $gray-200; + padding: 0 24px 24px 24px; +} + +// Optional: Card spacing and button spacing, copied from disputes style +.wcpay-dispute-evidence-new .components-card { + margin-bottom: 24px; +} + +.wcpay-dispute-evidence-new .components-button + .components-button { + margin-left: 10px; +} + +// Limit the width of the stepper content and center it +.wcpay-dispute-evidence-new__stepper-content { + max-width: 500px; + margin-left: auto; + margin-right: auto; +} From 067dd8982dd2ddfeccffd4c55dc548ce94b91205 Mon Sep 17 00:00:00 2001 From: Rafael Meneses Date: Thu, 29 May 2025 18:37:14 -0300 Subject: [PATCH 02/42] styles and fixing navigation --- client/disputes/new-evidence/index.tsx | 132 +++++++++++------------- client/disputes/new-evidence/style.scss | 39 +++++++ 2 files changed, 97 insertions(+), 74 deletions(-) diff --git a/client/disputes/new-evidence/index.tsx b/client/disputes/new-evidence/index.tsx index 01713f173c3..53b51c45541 100644 --- a/client/disputes/new-evidence/index.tsx +++ b/client/disputes/new-evidence/index.tsx @@ -10,11 +10,7 @@ import React, { useState, useEffect } from 'react'; */ import { Button, HorizontalRule } from 'wcpay/components/wp-components-wrapped'; import { getAdminUrl } from 'wcpay/utils'; -import { - Stepper, - StepperPanel, - useStepperContext, -} from 'wcpay/components/stepper'; +import { StepperPanel } from 'wcpay/components/stepper'; import { Accordion, AccordionBody, @@ -22,44 +18,62 @@ import { } from 'wcpay/components/accordion'; import Page from 'wcpay/components/page'; -import '../style.scss'; import './style.scss'; interface StepProps { - name: string; + heading: string; + subheading: string; } -const StepOne: React.FC< StepProps > = () => { - const { nextStep } = useStepperContext(); +const Step: React.FC< StepProps > = ( { heading, subheading } ) => { return (
-

General evidence

-

Provide general evidence for your dispute.

+

+ { heading } +

+

+ { subheading } +

); }; -const StepTwo: React.FC< StepProps > = () => { - const { nextStep, prevStep } = useStepperContext(); - return ( -
-

Shipping information

-

Provide shipping details if applicable.

-
- ); -}; - -const StepThree: React.FC< StepProps > = () => { - const { prevStep } = useStepperContext(); - return ( -
-

Review

-

Review your information before submitting.

-
- ); -}; - -const steps = [ 'General evidence', 'Shipping information', 'Review' ]; +const panelHeadings = [ 'General evidence', 'Shipping information', 'Review' ]; + +const steps = [ + { + heading: 'Let’s gather the basics', + subheading: + 'To make a stronger case, please provide as much info as possible. We prefilled some fields for you, please double check and upload all the necessary documents.', + }, + { + heading: 'Shipping details', + subheading: 'Please make sure all the shipping information is correct.', + }, + { + heading: 'Review the cover letter', + subheading: + 'Please review the cover letter that will be submitted to the bank based on the information you provided. You can make changes to it or add additional details.', + }, +]; + +const stepComponents = [ + , + , + , +]; export default () => { const [ currentStep, setCurrentStep ] = useState( 0 ); @@ -97,21 +111,14 @@ export default () => { const renderButtons = () => { if ( currentStep === 0 ) { return ( -
+
-
+
@@ -124,21 +131,14 @@ export default () => { } if ( currentStep === 1 ) { return ( -
+
-
+
@@ -151,22 +151,12 @@ export default () => { } // Step 2 (index 2): Review return ( -
+
-
-
+ } + /> + ) } + + ), + }, + { + title: __( 'Respond By', 'woocommerce-payments' ), + content: ( + + ), + }, + { + title: __( 'Order', 'woocommerce-payments' ), + content: , + }, + ]; + }, [ dispute ] ); + + // --- Step content --- + const renderStepContent = () => { + if ( ! fields.length ) return null; + // Helper to render a field with readOnly logic + const renderField = ( field: any ) => { + if ( field.type === 'file' ) { + return readOnly ? ( + {} } + onFileRemove={ () => {} } + /> + ) : ( + + doUploadFile( field.key, file ) + } + onFileRemove={ () => doRemoveFile( field.key ) } + accept={ '.pdf, image/png, image/jpeg' } + isDone={ !! evidence[ field.key ] } + isLoading={ false } + error={ '' } + disabled={ false } + /> + ); + } + if ( field.type === 'text' ) { + return ( + + updateEvidence( field.key, e.target.value, field ) + } + className="components-text-control__input" + disabled={ readOnly } + /> + ); + } + if ( field.type === 'date' ) { + return ( + + updateEvidence( field.key, e.target.value, field ) + } + className="components-text-control__input" + disabled={ readOnly } + /> + ); + } + // textarea + return ( +