Set in-app product card price meta dynamically (#51170)

* Set product card price currency and suffix dynamically based on endpoint data

* Add changefile(s) from automation for the following project(s): woocommerce

* Remove unnecessary comment

* Update types to match data received from WCCOM after further changes to the API

* Apply suggestions from code review

Allow for future currencies that might switch the symbol/value order

Co-authored-by: Dan Q <dan@danq.me>

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Dan Q <dan@danq.me>
This commit is contained in:
Herman 2024-09-10 08:57:52 +02:00 committed by GitHub
parent 3b35e22c99
commit 904dfaa2ff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 80 additions and 5 deletions

View File

@ -2,7 +2,7 @@
* External dependencies * External dependencies
*/ */
import { Button, Icon } from '@wordpress/components'; import { Button, Icon } from '@wordpress/components';
import { __ } from '@wordpress/i18n'; import { __, sprintf } from '@wordpress/i18n';
import { useContext } from '@wordpress/element'; import { useContext } from '@wordpress/element';
import { recordEvent } from '@woocommerce/tracks'; import { recordEvent } from '@woocommerce/tracks';
import { navigateTo, getNewPath } from '@woocommerce/navigation'; import { navigateTo, getNewPath } from '@woocommerce/navigation';
@ -64,8 +64,17 @@ function ProductCardFooter( props: { product: Product } ) {
return true; return true;
} }
// We hardcode this for now while we only display prices in USD. const currencyFormats: { [ key: string ]: string } = {
const currencySymbol = '$'; USD: '$%s',
AUD: 'A$%s',
CAD: 'C$%s',
EUR: '€%s',
GBP: '£%s',
};
const getCurrencyFormat = ( currencyCode: string ) => {
return currencyFormats[ currencyCode ] || '%s';
};
function getPriceLabel(): string { function getPriceLabel(): string {
if ( product.price === 0 ) { if ( product.price === 0 ) {
@ -76,7 +85,51 @@ function ProductCardFooter( props: { product: Product } ) {
return __( 'Free plan available', 'woocommerce' ); return __( 'Free plan available', 'woocommerce' );
} }
return currencySymbol + product.price; return sprintf( getCurrencyFormat( product.currency ), product.price );
}
function getPriceSuffix(): string {
// Paid simple products have a billing period of ''.
if (
product.billingPeriodInterval === 1 ||
product.billingPeriod === ''
) {
switch ( product.billingPeriod ) {
case 'day':
return __( 'daily', 'woocommerce' );
case 'week':
return __( 'weekly', 'woocommerce' );
case 'month':
return __( 'monthly', 'woocommerce' );
case 'year':
case '':
return __( 'annually', 'woocommerce' );
default:
return '';
}
}
let period;
switch ( product.billingPeriod ) {
case 'day':
period = __( 'days', 'woocommerce' );
break;
case 'week':
period = __( 'weeks', 'woocommerce' );
break;
case 'month':
period = __( 'months', 'woocommerce' );
break;
default:
period = __( 'years', 'woocommerce' );
}
return sprintf(
// translators: %1$d: billing period interval, %2$s: billing period (e.g. days, weeks, months, years)
__( 'every %1$d %2$s', 'woocommerce' ),
product.billingPeriodInterval,
period
);
} }
function getBillingText(): string { function getBillingText(): string {
@ -85,7 +138,7 @@ function ProductCardFooter( props: { product: Product } ) {
} }
if ( product.price !== 0 ) { if ( product.price !== 0 ) {
return __( ' annually', 'woocommerce' ); return getPriceSuffix();
} }
return ''; return '';

View File

@ -47,6 +47,9 @@ function ProductCard( props: ProductCardProps ): JSX.Element {
featuredImage: '', featuredImage: '',
color: '', color: '',
productCategory: '', productCategory: '',
billingPeriod: '',
billingPeriodInterval: 0,
currency: '',
}; };
function isSponsored(): boolean { function isSponsored(): boolean {

View File

@ -105,6 +105,10 @@ export default function ProductListContent( props: {
color: product.color, color: product.color,
featuredImage: product.featuredImage, featuredImage: product.featuredImage,
productCategory: product.productCategory, productCategory: product.productCategory,
billingPeriod: product.billingPeriod,
billingPeriodInterval:
product.billingPeriodInterval,
currency: product.currency,
} } } }
tracksData={ { tracksData={ {
position: index + 1, position: index + 1,

View File

@ -24,6 +24,9 @@ export type SearchAPIProductType = {
featured_image: string; featured_image: string;
product_category: string; product_category: string;
color: string; color: string;
billing_period: string;
billing_period_interval: number;
currency: string;
}; };
export interface Product { export interface Product {
@ -52,6 +55,9 @@ export interface Product {
featuredImage?: string; featuredImage?: string;
productCategory?: string; productCategory?: string;
color?: string; color?: string;
billingPeriod?: string;
billingPeriodInterval?: number;
currency: string;
} }
export interface ProductTracksData { export interface ProductTracksData {

View File

@ -144,6 +144,10 @@ async function fetchSearchResults(
featuredImage: product.featured_image, featuredImage: product.featured_image,
productCategory: product.product_category, productCategory: product.product_category,
color: product.color, color: product.color,
billingPeriod: product.billing_period,
billingPeriodInterval:
product.billing_period_interval,
currency: product.currency,
}; };
} }
); );
@ -407,6 +411,7 @@ const subscriptionToProduct = ( subscription: Subscription ): Product => {
averageRating: null, averageRating: null,
reviewsCount: null, reviewsCount: null,
isInstallable: false, isInstallable: false,
currency: '',
}; };
}; };

View File

@ -0,0 +1,4 @@
Significance: patch
Type: update
Product cards in the in-app marketplace show currency and billing period data dynamically, based on data received from WooCommerce.com