Skip to content
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 payments activity widget emoji survey #8309

Closed
wants to merge 17 commits into from
Binary file added assets/images/smilies/icon_love.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/smilies/icon_neutral.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/smilies/icon_sad1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/smilies/icon_sad2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/smilies/icon_smile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions client/overview/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import { useDisputes, useGetSettings, useSettings } from 'wcpay/data';
import strings from './strings';
import './style.scss';
import SetupLivePaymentsModal from './modal/setup-live-payments';
import Survey from 'wcpay/overview/survey';
import { WcPayOverviewSurveyContextProvider } from 'wcpay/overview/survey/context';

const OverviewPageError = () => {
const queryParams = getQuery();
Expand Down Expand Up @@ -117,11 +119,18 @@ const OverviewPage = () => {
return { payment_method: key, fee: value };
} )
.filter( ( e ) => e && e.fee !== undefined );
const isOverviewSurveySubmitted =
wcpaySettings.isOverviewSurveySubmitted ?? false;

return (
<Page isNarrow className="wcpay-overview">
<OverviewPageError />
<JetpackIdcNotice />
{ ! isOverviewSurveySubmitted && (
<WcPayOverviewSurveyContextProvider>
<Survey></Survey>
dpaun1985 marked this conversation as resolved.
Show resolved Hide resolved
</WcPayOverviewSurveyContextProvider>
) }
{ showLoanOfferError && (
<Notice status="error" isDismissible={ false }>
{ __(
Expand Down
70 changes: 70 additions & 0 deletions client/overview/survey/context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
oaratovskyi marked this conversation as resolved.
Show resolved Hide resolved
* External dependencies
*/
import React, { createContext, useState, useCallback, useContext } from 'react';
import { OverviewSurveyFields } from 'wcpay/overview/survey/types';
import apiFetch from '@wordpress/api-fetch';
import { NAMESPACE } from 'wcpay/data/constants';

const useContextValue = ( initialState = {} as OverviewSurveyFields ) => {
const [ surveySubmitted, setSurveySubmitted ] = useState(
Boolean( false )
);
const [ status, setStatus ] = useState( 'resolved' );
const [ surveyAnswers, setSurveyAnswers ] = useState( initialState );

const submitSurvey = useCallback(
async ( answers: OverviewSurveyFields ) => {
setStatus( 'pending' );
try {
await apiFetch( {
path: `${ NAMESPACE }/upe_survey/payments-overview`,
method: 'POST',
data: answers,
} );
setSurveySubmitted( true );
setStatus( 'resolved' );
} catch ( e ) {
setStatus( 'error' );
setSurveySubmitted( false );
}
},
[ setStatus, setSurveySubmitted ]
);

return {
setSurveySubmitted: submitSurvey,
status,
surveySubmitted,
surveyAnswers,
setSurveyAnswers,
};
};

type ContextValue = ReturnType< typeof useContextValue >;

const WcPayOverviewSurveyContext = createContext< ContextValue | null >( null );

export const WcPayOverviewSurveyContextProvider: React.FC< {
initialData?: OverviewSurveyFields;
} > = ( { children, initialData } ) => {
return (
<WcPayOverviewSurveyContext.Provider
value={ useContextValue( initialData ) }
>
{ children }
</WcPayOverviewSurveyContext.Provider>
);
};

export const useOverviewSurveyContext = (): ContextValue => {
const context = useContext( WcPayOverviewSurveyContext );
if ( ! context ) {
throw new Error(
'useOverviewSurveyContext() must be used within <WcPayOverviewSurveyContextProvider>'
dpaun1985 marked this conversation as resolved.
Show resolved Hide resolved
);
}
return context;
};

export default WcPayOverviewSurveyContext;
33 changes: 33 additions & 0 deletions client/overview/survey/emoticons.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* External dependencies
*/
import React from 'react';

const Emoticons = ( props ) => {
const { icon, rating, onClick, disabled, currentRating } = props;

const iconUrl =
'/wp-content/plugins/woocommerce-payments/dist/../assets/images/smilies/' +
dpaun1985 marked this conversation as resolved.
Show resolved Hide resolved
icon;

const buttonCss =
'components-button has-icon' +
( rating === currentRating ? ' selected' : '' );

return (
<>
<button
disabled={ disabled }
type="button"
className={ buttonCss }
onClick={ function () {
onClick( rating );
dpaun1985 marked this conversation as resolved.
Show resolved Hide resolved
} }
>
<img src={ iconUrl } alt="WooPayments" />
mordeth marked this conversation as resolved.
Show resolved Hide resolved
</button>
</>
);
};

export default Emoticons;
182 changes: 182 additions & 0 deletions client/overview/survey/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
/** @format **/

/**
* External dependencies
*/
import React from 'react';

/**
* Internal dependencies.
*/
import { Card, CardBody, Button, TextareaControl } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
import './style.scss';
import Emoticons from 'wcpay/overview/survey/emoticons';
import { HorizontalRule } from '@wordpress/primitives';
oaratovskyi marked this conversation as resolved.
Show resolved Hide resolved
import { useOverviewSurveyContext } from './context';
import { OverviewSurveyFields } from 'wcpay/overview/survey/types';

const Survey = () => {
const { status } = useOverviewSurveyContext();
const {
setSurveySubmitted,
surveySubmitted,
surveyAnswers,
setSurveyAnswers,
} = useOverviewSurveyContext();

const setReviewRating = function ( value: number ) {
const answers: OverviewSurveyFields = {
...surveyAnswers,
rating: value,
};
setSurveyAnswers( answers );
if ( value > 3 ) {
setSurveySubmitted( answers );
}
};

return (
<Card>
<CardBody className="wcpay-overview__survey__container">
{ ! surveySubmitted && (
<>
<div className="survey_container">
<div className="emoticons_container">
<span>
How do you like your new finance overview?
mordeth marked this conversation as resolved.
Show resolved Hide resolved
</span>
<Emoticons
icon={ 'icon_sad1.png' }
disabled={ 'pending' === status }
rating="1"
onClick={ setReviewRating }
currentRating={ surveyAnswers.rating ?? 0 }
oaratovskyi marked this conversation as resolved.
Show resolved Hide resolved
/>
<Emoticons
icon={ 'icon_sad2.png' }
disabled={ 'pending' === status }
rating="2"
onClick={ setReviewRating }
currentRating={ surveyAnswers.rating ?? 0 }
/>
<Emoticons
icon={ 'icon_neutral.png' }
disabled={ 'pending' === status }
rating="3"
onClick={ setReviewRating }
currentRating={ surveyAnswers.rating ?? 0 }
/>
<Emoticons
icon={ 'icon_smile.png' }
disabled={ 'pending' === status }
rating="4"
onClick={ setReviewRating }
currentRating={ surveyAnswers.rating ?? 0 }
/>
<Emoticons
icon={ 'icon_love.png' }
disabled={ 'pending' === status }
rating="5"
onClick={ setReviewRating }
currentRating={ surveyAnswers.rating ?? 0 }
/>
</div>
{ ( surveyAnswers.rating ?? 0 ) <= 3 &&
( surveyAnswers.rating ?? 0 ) > 0 && (
<button
type="button"
className="components-button has-icon"
aria-label="Close dialog"
onClick={ () => {
setReviewRating( 0 );
} }
>
<svg
dpaun1985 marked this conversation as resolved.
Show resolved Hide resolved
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
aria-hidden="true"
focusable="false"
>
<path d="M12 13.06l3.712 3.713 1.061-1.06L13.061 12l3.712-3.712-1.06-1.06L12 10.938 8.288 7.227l-1.061 1.06L10.939 12l-3.712 3.712 1.06 1.061L12 13.061z"></path>
</svg>
</button>
) }
</div>
</>
) }

{ ! surveySubmitted &&
( surveyAnswers.rating ?? 0 ) <= 3 &&
( surveyAnswers.rating ?? 0 ) > 0 && (
<>
<HorizontalRule />
<TextareaControl
className="ssr-text-field"
label={ __(
'Why do you feel that way? (optional)',
'woocommerce-payments'
) }
onChange={ ( text ) => {
setSurveyAnswers(
(
prev: OverviewSurveyFields
): OverviewSurveyFields => ( {
...prev,
comments: text,
} )
);
} }
value={ surveyAnswers.comments ?? '' }
readOnly={ 'pending' === status }
/>
<p className="survey-bottom-disclaimer">
{ sprintf(
/* translators: %s: WooPayments */
__(
'Your feedback will be only be shared with WooCommerce and treated pursuant to our privacy policy.',
oaratovskyi marked this conversation as resolved.
Show resolved Hide resolved
'woocommerce-payments'
),
'WooPayments'
) }
</p>
<div className="wcpay-confirmation-modal__footer">
<Button
variant={ 'secondary' }
disabled={ 'pending' === status }
onClick={ () => {
setReviewRating( 0 );
} }
>
{ __( 'Cancel', 'woocommerce-payments' ) }
</Button>
<Button
variant={ 'primary' }
isBusy={ 'pending' === status }
disabled={ 'pending' === status }
onClick={ () =>
setSurveySubmitted( surveyAnswers )
}
>
{ __( 'Send', 'woocommerce-payments' ) }
</Button>
</div>
</>
) }
{ surveySubmitted && (
<div className="survey_container">
<span>
<span role="img" aria-label="Thank you!">
🙌
</span>
We appreciate your feedback!
mordeth marked this conversation as resolved.
Show resolved Hide resolved
</span>
</div>
) }
</CardBody>
</Card>
);
};
export default Survey;
27 changes: 27 additions & 0 deletions client/overview/survey/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.wcpay-overview__survey__container {
.survey_container {
display: flex;
flex-direction: row;

span {
margin: auto;
}

.emoticons_container {
line-height: 45px;
align-items: center;
flex-grow: 1;
justify-content: left;

span {
vertical-align: middle;
}
button {
vertical-align: middle;
}
.selected {
background-color: #ecf2f8;
}
}
}
}
8 changes: 8 additions & 0 deletions client/overview/survey/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Internal dependencies
*/

export type OverviewSurveyFields = {
rating?: number;
comments?: string;
};
Loading