Skip to content
This repository was archived by the owner on Feb 23, 2024. It is now read-only.

Commit 064ec47

Browse files
authored
Convert frontend-block.js to frontend-block.tsx and replace propTypes with TypeScript definitions (#10677)
1 parent 036fcd8 commit 064ec47

File tree

8 files changed

+243
-83
lines changed

8 files changed

+243
-83
lines changed

assets/js/base/components/reviews/review-list-item/index.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import { __, sprintf } from '@wordpress/i18n';
55
import classNames from 'classnames';
66
import ReadMore from '@woocommerce/base-components/read-more';
7-
import type { BlockAttributes } from '@wordpress/blocks';
7+
import { ReviewBlockAttributes } from '@woocommerce/blocks/reviews/attributes';
88

99
/**
1010
* Internal dependencies
@@ -154,8 +154,9 @@ function getReviewRating( review: Review ): JSX.Element {
154154
</div>
155155
);
156156
}
157+
157158
interface ReviewListItemProps {
158-
attributes: BlockAttributes;
159+
attributes: ReviewBlockAttributes;
159160
review?: Review;
160161
}
161162

assets/js/base/components/reviews/review-list/index.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,28 @@
22
* External dependencies
33
*/
44
import { getSetting } from '@woocommerce/settings';
5-
import type { BlockAttributes } from '@wordpress/blocks';
5+
import { ReviewBlockAttributes } from '@woocommerce/blocks/reviews/attributes';
66

77
/**
88
* Internal dependencies
99
*/
1010
import ReviewListItem from '../review-list-item';
1111
import type { Review } from '../types';
1212
import './style.scss';
13-
1413
interface ReviewListProps {
15-
attributes: BlockAttributes;
14+
attributes: ReviewBlockAttributes;
1615
reviews: Review[];
1716
}
1817

1918
const ReviewList = ( {
2019
attributes,
2120
reviews,
2221
}: ReviewListProps ): JSX.Element => {
23-
const showAvatars = getSetting( 'showAvatars', true );
24-
const reviewRatingsEnabled = getSetting( 'reviewRatingsEnabled', true );
22+
const showAvatars = getSetting< boolean >( 'showAvatars', true );
23+
const reviewRatingsEnabled = getSetting< boolean >(
24+
'reviewRatingsEnabled',
25+
true
26+
);
2527
const showReviewImage =
2628
( showAvatars || attributes.imageType === 'product' ) &&
2729
attributes.showReviewImage;

assets/js/blocks/reviews/attributes.js renamed to assets/js/blocks/reviews/attributes.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import { BlockAttributes } from '@wordpress/blocks';
5+
import { Review } from '@woocommerce/base-components/reviews/types';
6+
17
export default {
28
/**
39
* Toggle for edit mode in the block preview.
@@ -100,3 +106,19 @@ export default {
100106
default: null,
101107
},
102108
};
109+
110+
export type ReviewBlockAttributes = BlockAttributes & {
111+
editMode: boolean;
112+
imageType: string;
113+
orderby: string;
114+
reviewsOnLoadMore: number;
115+
reviewsOnPageLoad: number;
116+
showLoadMore: boolean;
117+
showOrderby: boolean;
118+
showReviewDate: boolean;
119+
showReviewerName: boolean;
120+
showReviewImage: boolean;
121+
showReviewRating: boolean;
122+
showReviewContent: boolean;
123+
previewReviews: Review[];
124+
};

assets/js/blocks/reviews/frontend-block.js

Lines changed: 0 additions & 75 deletions
This file was deleted.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import { __ } from '@wordpress/i18n';
5+
import { getSetting } from '@woocommerce/settings';
6+
import LoadMoreButton from '@woocommerce/base-components/load-more-button';
7+
import {
8+
ReviewList,
9+
ReviewSortSelect,
10+
} from '@woocommerce/base-components/reviews';
11+
import withReviews from '@woocommerce/base-hocs/with-reviews';
12+
import type { ChangeEventHandler, MouseEventHandler } from 'react';
13+
import { Review } from '@woocommerce/base-components/reviews/types';
14+
15+
/**
16+
* Internal dependencies
17+
*/
18+
import { ReviewBlockAttributes } from './attributes';
19+
20+
interface FrontendBlockProps {
21+
attributes: ReviewBlockAttributes;
22+
onAppendReviews: MouseEventHandler;
23+
onChangeOrderby: ChangeEventHandler< HTMLSelectElement >;
24+
sortSelectValue: 'most-recent' | 'highest-rating' | 'lowest-rating';
25+
reviews: Review[];
26+
totalReviews: number;
27+
}
28+
29+
const FrontendBlock = ( {
30+
attributes,
31+
onAppendReviews,
32+
onChangeOrderby,
33+
reviews,
34+
sortSelectValue,
35+
totalReviews,
36+
}: FrontendBlockProps ) => {
37+
if ( reviews.length === 0 ) {
38+
return null;
39+
}
40+
41+
const reviewRatingsEnabled = getSetting< boolean >(
42+
'reviewRatingsEnabled',
43+
true
44+
);
45+
46+
return (
47+
<>
48+
{ attributes.showOrderby && reviewRatingsEnabled && (
49+
<ReviewSortSelect
50+
value={ sortSelectValue }
51+
onChange={ onChangeOrderby }
52+
readOnly
53+
/>
54+
) }
55+
<ReviewList attributes={ attributes } reviews={ reviews } />
56+
{ attributes.showLoadMore && totalReviews > reviews.length && (
57+
<LoadMoreButton
58+
onClick={ onAppendReviews }
59+
screenReaderLabel={ __(
60+
'Load more reviews',
61+
'woo-gutenberg-products-block'
62+
) }
63+
/>
64+
) }
65+
</>
66+
);
67+
};
68+
69+
export default withReviews( FrontendBlock );

assets/js/blocks/reviews/frontend.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,13 @@ const selector = `
1515
`;
1616

1717
const getProps = ( el ) => {
18+
const showOrderby = el.dataset.showOrderby === 'true';
19+
const showLoadMore = el.dataset.showLoadMore === 'true';
20+
1821
return {
1922
attributes: {
23+
showOrderby,
24+
showLoadMore,
2025
showReviewDate: el.classList.contains( 'has-date' ),
2126
showReviewerName: el.classList.contains( 'has-name' ),
2227
showReviewImage: el.classList.contains( 'has-image' ),

assets/js/blocks/reviews/reviews-by-category/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { Icon, commentContent } from '@wordpress/icons';
99
* Internal dependencies
1010
*/
1111
import { Edit } from './edit';
12-
import sharedAttributes from '../attributes.js';
12+
import sharedAttributes from '../attributes';
1313
import save from '../save.js';
1414
import { example } from '../example.js';
1515

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
jest.mock( '../utils', () => ( {
2+
...jest.requireActual( '../utils' ),
3+
getReviews: jest
4+
.fn()
5+
.mockReturnValue( Promise.resolve( { reviews: [], totalReviews: 0 } ) ),
6+
} ) );
7+
8+
jest.mock( '@woocommerce/settings', () => ( {
9+
...jest.requireActual( '@woocommerce/settings' ),
10+
getSetting: jest.fn().mockReturnValue( true ),
11+
} ) );
12+
13+
/**
14+
* External dependencies
15+
*/
16+
import { render } from '@testing-library/react';
17+
import { getSetting } from '@woocommerce/settings';
18+
19+
/**
20+
* Internal dependencies
21+
*/
22+
import ReviewsFrontendBlock from '../frontend-block';
23+
import { getReviews } from '../utils';
24+
25+
describe( 'ReviewsFrontendBlock', () => {
26+
const dummyReview = {
27+
date_created: '2021-08-04T15: 00: 00',
28+
date_created_gmt: '2021-08-04T15: 00: 00',
29+
formatted_date_created: 'August 4, 2021',
30+
product_name: 'Product Name',
31+
product_permalink: 'https://example.com/product/product-name/',
32+
review: 'This is a review.',
33+
reviewer: 'Reviewer',
34+
id: 1,
35+
product_id: 1,
36+
product_image: {
37+
alt: 'Product Name',
38+
thumbnail: 'https://example.com/product/product-name.jpg',
39+
name: 'product-name',
40+
sizes: '(max-width: 800px) 100vw, 800px',
41+
src: 'https://example.com/product/product-name.jpg',
42+
srcset: 'logo-1.jpg 800w, logo-1-300x300.jpg 300w, logo-1-150x150.jpg 150w, logo-1-768x767.jpg 768w, logo-1-324x324.jpg 324w, logo-1-416x415.jpg 416w, logo-1-100x100.jpg 100w',
43+
},
44+
reviewer_avatar_urls: { 48: '' },
45+
verified: true,
46+
rating: 1,
47+
};
48+
49+
it( 'Does not render when there are no reviews', () => {
50+
const { container } = render(
51+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
52+
// @ts-ignore - withReviews HOC will need refactoring to TS to fix this.
53+
<ReviewsFrontendBlock
54+
attributes={ {} }
55+
sortSelectValue={ 'most-recent' }
56+
reviewsToDisplay={ 0 }
57+
orderby={ 'reviewer' }
58+
order={ 'asc' }
59+
onAppendReviews={ jest.fn() }
60+
onChangeOrderby={ jest.fn() }
61+
/>
62+
);
63+
64+
expect( container.firstChild ).toBeNull();
65+
} );
66+
67+
it( 'Shows load more button when there are more reviews than displayed.', async () => {
68+
( getReviews as jest.Mock ).mockResolvedValue( {
69+
reviews: [ dummyReview, dummyReview, dummyReview ],
70+
totalReviews: 3,
71+
} );
72+
73+
const { findByText } = render(
74+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
75+
// @ts-ignore - we can't fix this until withReviews is converted to TS.
76+
<ReviewsFrontendBlock
77+
attributes={ { showLoadMore: 'true' } }
78+
sortSelectValue={ 'most-recent' }
79+
reviewsToDisplay={ 1 }
80+
orderby={ 'reviewer' }
81+
order={ 'asc' }
82+
onChangeOrderby={ jest.fn() }
83+
/>
84+
);
85+
86+
const loadMoreButton = await findByText( 'Load more' );
87+
expect( loadMoreButton ).toBeInTheDocument();
88+
} );
89+
90+
it( 'renders a order by select when showOrderby is passed as attribute and reviewRatingsEnabled is not set (defaults to true).', async () => {
91+
( getReviews as jest.Mock ).mockResolvedValue( {
92+
reviews: [ dummyReview, dummyReview, dummyReview ],
93+
totalReviews: 3,
94+
} );
95+
96+
const { findByText } = render(
97+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
98+
// @ts-ignore - we can't fix this until withReviews is converted to TS.
99+
<ReviewsFrontendBlock
100+
attributes={ { showLoadMore: true, showOrderby: true } }
101+
sortSelectValue={ 'most-recent' }
102+
reviewsToDisplay={ 1 }
103+
orderby={ 'reviewer' }
104+
order={ 'asc' }
105+
onChangeOrderby={ jest.fn() }
106+
/>
107+
);
108+
109+
const orderBySelect = await findByText( 'Order by' );
110+
expect( orderBySelect ).toBeInTheDocument();
111+
} );
112+
113+
it( 'when reviewRatingsEnabled is set to false the order by select is not shown.', async () => {
114+
( getReviews as jest.Mock ).mockResolvedValue( {
115+
reviews: [ dummyReview, dummyReview, dummyReview ],
116+
totalReviews: 3,
117+
} );
118+
119+
( getSetting as jest.Mock ).mockReturnValue( false );
120+
121+
const { findByText } = render(
122+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
123+
// @ts-ignore - we can't fix this until withReviews is converted to TS.
124+
<ReviewsFrontendBlock
125+
attributes={ { showLoadMore: true, showOrderby: true } }
126+
sortSelectValue={ 'most-recent' }
127+
reviewsToDisplay={ 1 }
128+
orderby={ 'reviewer' }
129+
order={ 'asc' }
130+
onChangeOrderby={ jest.fn() }
131+
/>
132+
);
133+
134+
expect( () => findByText( 'Order by' ) ).rejects.toThrow();
135+
} );
136+
} );

0 commit comments

Comments
 (0)