Add formatting for Cost and Sales numbers in Campaigns card in Marketing page (#44917)

* Return formatted cost and sales price for MarketingCampaigns.

* Display formatted cost and sales number in Campaigns card.

* Use price formatting.

* Format decimal places based on currency.

* Add changelog.

* Fix type issue is useCampaigns.test.ts.

* Use wp_strip_all_tags to respect currency symbol positioning settings.

Without wp_strip_all_tags, the result contains <bdi> element, and it causes browser to show the currency symbol in unexpected unwanted position.

* Fix PHP linting issue.

* Fix tests in useCampaigns.test.ts.

* Use html_entity_decode to remove dangerouslySetInnerHTML usage.

* Remove unneeded code formatting in Campaigns.tsx.

* Add explanation comment for `get_formatted_price`.

* Fix PHP lint error.

* Use map instead of filter to get price format.

* Add code comment.

* Get currency info based on user locale or default locale.

* Use locales in locale-info.php instead of currency-info.php.

Co-authored-by: Bartosz Budzanowski <bartosz.budzanowski@automattic.com>

* Code formatting and fix code comment.

* Fix lint errors.

---------

Co-authored-by: Bartosz Budzanowski <bartosz.budzanowski@automattic.com>
This commit is contained in:
Gan Eng Chin 2024-03-19 01:56:08 +08:00 committed by GitHub
parent f9c0d406ae
commit 718fe762fa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 73 additions and 17 deletions

View File

@ -58,10 +58,12 @@ export type Campaign = {
cost: {
value: string;
currency: string;
formatted: string;
} | null;
sales: {
value: string;
currency: string;
formatted: string;
} | null;
};

View File

@ -37,18 +37,22 @@ jest.mock( '@wordpress/api-fetch', () =>
const campaigns: Array< APICampaign > = Array.from( { length } ).map(
( _, index ) => {
const id = `${ page }_${ index + 1 }`;
const value = ( ( page * perPage + index ) * 0.25 ).toString();
return {
id,
channel: 'extension-foo',
title: `Campaign ${ id }`,
manage_url: `https://test/extension-foo?path=setup&id=${ id }`,
cost: {
value: ( ( page * perPage + index ) * 0.25 ).toString(),
value,
currency: 'USD',
formatted: `$${ value }`,
},
sales: {
value: ( ( page * perPage + index ) * 0.25 ).toString(),
value,
currency: 'USD',
formatted: `$${ value }`,
},
};
}
@ -119,8 +123,8 @@ describe( 'useCampaigns', () => {
id: 'extension-foo|1_1',
title: 'Campaign 1_1',
description: '',
cost: 'USD 1.25',
sales: 'USD 1.25',
cost: '$1.25',
sales: '$1.25',
manageUrl: 'https://test/extension-foo?path=setup&id=1_1',
icon: 'https://test/foo.png',
channelName: 'Extension Foo',

View File

@ -46,13 +46,8 @@ export const useCampaigns = ( page = 1, perPage = 5 ): UseCampaignsType => {
( el ) => el.slug === campaign.channel
);
const cost = campaign.cost
? `${ campaign.cost.currency } ${ campaign.cost.value }`
: '-';
const sales = campaign.sales
? `${ campaign.sales.currency } ${ campaign.sales.value }`
: '-';
const cost = campaign.cost ? campaign.cost.formatted : '-';
const sales = campaign.sales ? campaign.sales.formatted : '-';
return {
id: `${ campaign.channel }|${ campaign.id }`,

View File

@ -0,0 +1,4 @@
Significance: minor
Type: update
Add formatting for Cost and Sales numbers in Campaigns card in Marketing page.

View File

@ -132,6 +132,57 @@ class MarketingCampaigns extends WC_REST_Controller {
return $response;
}
/**
* Get formatted price based on Price type.
*
* This uses plugins/woocommerce/i18n/currency-info.php and plugins/woocommerce/i18n/locale-info.php to get option object based on $price->currency.
*
* Example:
*
* - When $price->currency is 'USD' and $price->value is '1000', it should return '$1000.00'.
* - When $price->currency is 'JPY' and $price->value is '1000', it should return '¥1,000'.
* - When $price->currency is 'AED' and $price->value is '1000', it should return '5.000,00 د.إ'.
*
* @param Price $price Price object.
* @return String formatted price.
*/
private function get_formatted_price( $price ) {
// Get $num_decimals to be passed to wc_price.
$locale_info_all = include WC()->plugin_path() . '/i18n/locale-info.php';
$locale_index = array_search( $price->get_currency(), array_column( $locale_info_all, 'currency_code' ), true );
$locale = array_values( $locale_info_all )[ $locale_index ];
$num_decimals = $locale['num_decimals'];
// Get $currency_info based on user locale or default locale.
$currency_locales = $locale['locales'];
$user_locale = get_user_locale();
$currency_info = $currency_locales[ $user_locale ] ?? $currency_locales['default'];
// Get $price_format to be passed to wc_price.
$currency_pos = $currency_info['currency_pos'];
$currency_formats = array(
'left' => '%1$s%2$s',
'right' => '%2$s%1$s',
'left_space' => '%1$s&nbsp;%2$s',
'right_space' => '%2$s&nbsp;%1$s',
);
$price_format = $currency_formats[ $currency_pos ] ?? $currency_formats['left'];
$price_value = wc_format_decimal( $price->get_value() );
$price_formatted = wc_price(
$price_value,
array(
'currency' => $price->get_currency(),
'decimal_separator' => $currency_info['decimal_sep'],
'thousand_separator' => $currency_info['thousand_sep'],
'decimals' => $num_decimals,
'price_format' => $price_format,
)
);
return html_entity_decode( wp_strip_all_tags( $price_formatted ) );
}
/**
* Prepares the item for the REST response.
*
@ -150,15 +201,17 @@ class MarketingCampaigns extends WC_REST_Controller {
if ( $item->get_cost() instanceof Price ) {
$data['cost'] = array(
'value' => wc_format_decimal( $item->get_cost()->get_value() ),
'currency' => $item->get_cost()->get_currency(),
'value' => wc_format_decimal( $item->get_cost()->get_value() ),
'currency' => $item->get_cost()->get_currency(),
'formatted' => $this->get_formatted_price( $item->get_cost() ),
);
}
if ( $item->get_sales() instanceof Price ) {
$data['sales'] = array(
'value' => wc_format_decimal( $item->get_sales()->get_value() ),
'currency' => $item->get_sales()->get_currency(),
'value' => wc_format_decimal( $item->get_sales()->get_value() ),
'currency' => $item->get_sales()->get_currency(),
'formatted' => $this->get_formatted_price( $item->get_sales() ),
);
}
@ -257,6 +310,4 @@ class MarketingCampaigns extends WC_REST_Controller {
return $params;
}
}