Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
ac6662b
fix: add cx-read-more component (for product reviews)
ulates-sap Apr 30, 2025
e51eafa
Merge branch 'develop' into feature/CXSPA-9967
uroslates Apr 30, 2025
30cd526
Merge branch 'develop' into feature/CXSPA-9967
uroslates May 2, 2025
1f2ba77
Merge branch 'develop' into feature/CXSPA-9967
uroslates May 5, 2025
4afe15e
fix: add review title/comments/reviewrName characters limit (for prod…
ulates-sap May 5, 2025
706a30f
fix: fixing failed test
ulates-sap May 5, 2025
f18eccd
fix: add feature flags
ulates-sap May 5, 2025
31ae890
fix: fix feature flags prettier issues
ulates-sap May 5, 2025
bfa7c2e
Merge branch 'develop' into feature/CXSPA-9967
uroslates May 5, 2025
f1b7838
Merge branch 'develop' into feature/CXSPA-9967
uroslates May 6, 2025
08c6e45
Merge branch 'develop' into feature/CXSPA-9967
uroslates May 8, 2025
763a4f0
Merge branch 'develop' into feature/CXSPA-9967
uroslates May 12, 2025
1acc3bb
fix: address PR comments - add docs
ulates-sap May 12, 2025
5f35d81
fix: addressing PR comments
ulates-sap May 12, 2025
5397a80
Merge branch 'develop' into feature/CXSPA-9967
uroslates May 12, 2025
ac9ef3f
Merge branch 'develop' into feature/CXSPA-9967
uroslates May 12, 2025
fde983c
Merge branch 'develop' into feature/CXSPA-9967
uroslates May 13, 2025
602d712
Merge branch 'develop' into feature/CXSPA-9967
uroslates May 19, 2025
0320717
Merge branch 'develop' into feature/CXSPA-9967
uroslates May 20, 2025
227d352
fix: addressing PR comments
ulates-sap May 20, 2025
3cdb270
Merge branch 'develop' into feature/CXSPA-9967
uroslates May 21, 2025
35e9fce
Merge branch 'develop' into feature/CXSPA-9967
uroslates May 22, 2025
1657f61
Merge branch 'develop' into feature/CXSPA-9967
uroslates May 27, 2025
3e27277
fix: address some UX comments
ulates-sap May 27, 2025
01ef3ef
fix: fix prettier issues
ulates-sap May 28, 2025
d000d60
Merge branch 'develop' into feature/CXSPA-9967
uroslates May 28, 2025
1f97930
Merge branch 'develop' into feature/CXSPA-9967
uroslates May 28, 2025
65fe4b8
Merge branch 'develop' into feature/CXSPA-9967
uroslates May 28, 2025
6e460e7
Merge branch 'develop' into feature/CXSPA-9967
uroslates Jun 3, 2025
2865d69
Merge branch 'develop' into feature/CXSPA-9967
uroslates Jun 4, 2025
b961442
fix: address PR comments
ulates-sap Jun 4, 2025
0580631
Merge branch 'develop' into feature/CXSPA-9967
uroslates Jun 4, 2025
9ebc4c0
Merge branch 'develop' into feature/CXSPA-9967
uroslates Jun 4, 2025
3127247
Merge branch 'develop' into feature/CXSPA-9967
uroslates Jun 5, 2025
7f370b7
Merge branch 'develop' into feature/CXSPA-9967
Zeyber Jun 9, 2025
d20dc90
Merge branch 'develop' into feature/CXSPA-9967
uroslates Jun 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion projects/assets/src/translations/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@
"zoomOut": "Zoom out",
"selected": "Selected",
"expand": "Expand",
"collapse": "Collapse"
"collapse": "Collapse",
"readMore": "Read More",
"readLess": "Read Less"
},
"pageMetaResolver": {
"category": {
Expand Down
4 changes: 3 additions & 1 deletion projects/assets/src/translations/en/product.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"overallRating": "Overall Rating",
"reviewTitle": "Review Title",
"writeYourComments": "Write your comments",
"commentPlaceholder": "What did you like? \nWhat could be improved? \nHow long have you used it?",
"rating": "Rating",
"ratingRequired": "Product rating, required",
"addRate": "Add rate: {{count}} star",
Expand All @@ -70,7 +71,8 @@
"less": "Show Less Reviews",
"thankYouForReview": "Thank you for the review! Note that reviews may require review before appearing here.",
"postReviewFail": "Something went wrong while posting your review. Please try again later.",
"ratedOutOf": "Rated: {{rating}} out of 5"
"ratedOutOf": "Rated: {{rating}} out of 5",
"charactersLeft": "characters left: {{count}}"
},
"productCarousel": {
"carouselLabel": "Carousel, {{title}}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,18 @@ export interface FeatureTogglesInterface {
*/
a11yNgSelectLayering?: boolean;

/**
* Introduces read more directive for presenting elements with long text.
* Affects: ProductReviewsComponent
*/
readMoreDirective?: boolean;

/**
* Introduces characters left for product review form elements.
* Affects: ProductReviewsComponent
*/
productReviewCharactersLeft?: boolean;

/**
* The optional `aria-controls` attribute will override on the NgSelect implementation.
* The updated library employs the `aria-controls` attribute to indicate the relationship between the button and the dropdown.
Expand Down Expand Up @@ -831,6 +843,8 @@ export const defaultFeatureToggles: Required<FeatureTogglesInterface> = {
a11yWideScreenImprovements: false,
a11yOptimizedMenuSpacing: false,
a11yNgSelectLayering: false,
readMoreDirective: false,
productReviewCharactersLeft: false,
a11yNgSelectAriaControls: false,
enableSecurePasswordValidation: true,
enableCarouselCategoryProducts: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,8 @@ if (environment.cpq) {
a11yWrapReviewOrderInSection: true,
a11yOptimizedMenuSpacing: true,
a11yNgSelectLayering: true,
readMoreDirective: true,
productReviewCharactersLeft: true,
a11yNgSelectAriaControls: true,
enableCarouselCategoryProducts: true,
enableSecurePasswordValidation: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,14 @@ <h3>{{ 'productReview.overallRating' | cxTranslate }}</h3>
{{ review.alias ? review.alias : review.principal?.name }}
</div>
<div class="date">{{ review.date | cxDate }}</div>
<div class="text">{{ review.comment }}</div>
<div *cxFeature="'!readMoreDirective'" class="text">
{{ review.comment }}
</div>
<cx-read-more
*cxFeature="'readMoreDirective'"
class="text"
[text]="review.comment!"
></cx-read-more>
</div>
<div *ngIf="reviews.length > initialMaxListItems">
<button
Expand Down Expand Up @@ -87,6 +94,20 @@ <h3>{{ 'productReview.overallRating' | cxTranslate }}</h3>
<cx-form-required-asterisks />
</span>
<input
*cxFeature="'!productReviewCharactersLeft'"
required="true"
#titleInput
type="text"
class="form-control"
formControlName="title"
[attr.aria-invalid]="
reviewForm.get('title')?.touched &&
reviewForm.get('title')?.invalid
"
[attr.aria-errormessage]="'titleError'"
/>
<input
*cxFeature="'productReviewCharactersLeft'"
required="true"
#titleInput
type="text"
Expand All @@ -97,6 +118,7 @@ <h3>{{ 'productReview.overallRating' | cxTranslate }}</h3>
reviewForm.get('title')?.invalid
"
[attr.aria-errormessage]="'titleError'"
[maxLength]="maxLengthReviewTitle"
/>

<!-- TODO: (CXSPA-7315) Remove feature toggle in the next major -->
Expand All @@ -113,6 +135,21 @@ <h3>{{ 'productReview.overallRating' | cxTranslate }}</h3>
*cxFeature="'!formErrorsDescriptiveMessages'"
[control]="reviewForm.get('title')"
></cx-form-errors>

<p
*cxFeature="'productReviewCharactersLeft'"
class="cx-customer-ticket-input-hint text-right"
>
{{
'productReview.charactersLeft'
| cxTranslate
: {
count:
maxLengthReviewTitle -
(reviewForm.get('title')?.value?.length || 0),
}
}}
</p>
</label>
</div>
<div class="form-group">
Expand All @@ -122,6 +159,7 @@ <h3>{{ 'productReview.overallRating' | cxTranslate }}</h3>
<cx-form-required-asterisks />
</span>
<textarea
*cxFeature="'!productReviewCharactersLeft'"
required="true"
class="form-control"
rows="3"
Expand All @@ -132,6 +170,20 @@ <h3>{{ 'productReview.overallRating' | cxTranslate }}</h3>
"
[attr.aria-errormessage]="'commentError'"
></textarea>
<textarea
*cxFeature="'productReviewCharactersLeft'"
required="true"
class="form-control"
rows="3"
[placeholder]="'productReview.commentPlaceholder' | cxTranslate"
formControlName="comment"
[attr.aria-invalid]="
reviewForm.get('comment')?.touched &&
reviewForm.get('comment')?.invalid
"
[attr.aria-errormessage]="'commentError'"
[maxLength]="maxLengthReviewComment"
></textarea>

<!-- TODO: (CXSPA-7315) Remove feature toggle in the next major -->
<cx-form-errors
Expand All @@ -147,6 +199,21 @@ <h3>{{ 'productReview.overallRating' | cxTranslate }}</h3>
*cxFeature="'!formErrorsDescriptiveMessages'"
[control]="reviewForm.get('comment')"
></cx-form-errors>

<p
*cxFeature="'productReviewCharactersLeft'"
class="cx-customer-ticket-input-hint text-right"
>
{{
'productReview.charactersLeft'
| cxTranslate
: {
count:
maxLengthReviewComment -
(reviewForm.get('comment')?.value?.length || 0),
}
}}
</p>
</label>
</div>
<div class="form-group">
Expand Down Expand Up @@ -195,13 +262,49 @@ <h3>{{ 'productReview.overallRating' | cxTranslate }}</h3>
>{{ 'productReview.reviewerName' | cxTranslate }}
</span>
<input
*cxFeature="'!productReviewCharactersLeft'"
type="text"
class="form-control"
formControlName="reviewerName"
/>
<input
*cxFeature="'productReviewCharactersLeft'"
type="text"
class="form-control"
formControlName="reviewerName"
[maxLength]="maxLengthReviewerName"
/>
<!-- TODO: (CXSPA-7315) Remove feature toggle in the next major -->
<cx-form-errors
*cxFeature="'formErrorsDescriptiveMessages'"
id="titleError"
[translationParams]="{
label: 'productReview.reviewerName' | cxTranslate,
}"
[control]="reviewForm.get('reviewerName')"
></cx-form-errors>

<cx-form-errors
*cxFeature="'!formErrorsDescriptiveMessages'"
[control]="reviewForm.get('reviewerName')"
></cx-form-errors>
<p
*cxFeature="'productReviewCharactersLeft'"
class="cx-customer-ticket-input-hint text-right"
>
{{
'productReview.charactersLeft'
| cxTranslate
: {
count:
maxLengthReviewerName -
(reviewForm.get('reviewerName')?.value?.length ?? 0),
}
}}
</p>
</label>
</div>
<div class="form-group row">
<div class="form-group row justify-content-md-end">
<div class="col-12 col-md-4">
<button
type="button"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
ChangeDetectorRef,
Component,
ElementRef,
inject,
Input,
ViewChild,
} from '@angular/core';
import {
Expand All @@ -17,6 +19,7 @@ import {
Validators,
} from '@angular/forms';
import {
FeatureConfigService,
isNotNullable,
Product,
ProductReviewService,
Expand All @@ -43,12 +46,16 @@ export class ProductReviewsComponent {
@ViewChild('writeReviewButton', { static: false })
writeReviewButton: ElementRef;

@Input() maxLengthReviewTitle = 255;
@Input() maxLengthReviewComment = 2200;
@Input() maxLengthReviewerName = 64;
isWritingReview = false;

// TODO: configurable
initialMaxListItems = 5;
maxListItems: number;
reviewForm: UntypedFormGroup;
private featureConfigService = inject(FeatureConfigService);

product$: Observable<Product | null> =
this.currentProductService.getProduct();
Expand Down Expand Up @@ -128,11 +135,31 @@ export class ProductReviewsComponent {
}

private resetReviewForm(): void {
const isProductReviewCharactersLeftEnabled =
this.featureConfigService.isEnabled('productReviewCharactersLeft');
this.reviewForm = this.fb.group({
title: ['', Validators.required],
comment: ['', Validators.required],
title: [
'',
!isProductReviewCharactersLeftEnabled
? Validators.required
: [
Validators.required,
Validators.maxLength(this.maxLengthReviewTitle),
],
],
comment: [
'',
!isProductReviewCharactersLeftEnabled
? Validators.required
: [
Validators.required,
Validators.maxLength(this.maxLengthReviewComment),
],
],
rating: [null, Validators.required],
reviewerName: '',
reviewerName: !isProductReviewCharactersLeftEnabled
? ''
: ['', Validators.maxLength(this.maxLengthReviewerName)],
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
FormErrorsModule,
FormRequiredAsterisksComponent,
FormRequiredLegendComponent,
ReadMoreComponent,
StarRatingModule,
} from '../../../../shared/index';
import { ProductReviewsComponent } from './product-reviews.component';
Expand All @@ -33,6 +34,7 @@ import { ProductReviewsComponent } from './product-reviews.component';
FeaturesConfigModule,
FormRequiredAsterisksComponent,
FormRequiredLegendComponent,
ReadMoreComponent,
],
providers: [
provideDefaultConfig(<CmsConfig>{
Expand Down
1 change: 1 addition & 0 deletions projects/storefrontlib/shared/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ export * from './ng-select-a11y/index';
export * from './assistive-technology-message/index';
export * from './captcha/index';
export * from './chat-messaging/index';
export * from './read-more';
7 changes: 7 additions & 0 deletions projects/storefrontlib/shared/components/read-more/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* SPDX-FileCopyrightText: 2025 SAP Spartacus team <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0
*/

export * from './read-more.component';
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<ng-container *ngIf="isCollapsed">
{{ text.slice(0, maxLength) }}
</ng-container>
<ng-container *ngIf="!isCollapsed">
{{ text }}
</ng-container>

<button
class="btn-link"
*ngIf="showReadMore"
(click)="isCollapsed = !isCollapsed"
>
{{ (isCollapsed ? readMoreI18nKey! : readLessI18nKey!) | cxTranslate }}
</button>
Loading
Loading