Skip to content

Commit 6eb7c89

Browse files
WEBDEV-7532 Move all reviews logic into the component (#33)
* Draft new reviews component * Include one's own review in reviews count * Update current review even if undefined * Move container styling into higher-level component * Support replacing reviews with display reviews message * Adjust review spacing to match prod * Support no reviews case * Remove double fetch-handler instantiation * Add add icon * Tidy up * Add review icon * Support freezing or disabling reviews * Add ia-reviews to exports * Tidy up * Prevent demo app reviews from being anonymous or over-increasing count * Handle undefined review in update cycle * Support displaying full reviews by default * Adjust property name * Tidy up * Remove unnecessary toggle * Remove unused recaptcha toggles * Tidy up review toggles * Improve test coverage * Tidy up following CR * Filter out patron's review within the component * Support adjusted review filtering in the demo app
1 parent d8c548e commit 6eb7c89

12 files changed

Lines changed: 1069 additions & 245 deletions

demo/app-root.ts

Lines changed: 87 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { css, html, LitElement, nothing } from 'lit';
2-
import { customElement, query, state } from 'lit/decorators.js';
1+
import { css, html, HTMLTemplateResult, LitElement } from 'lit';
2+
import { customElement, state } from 'lit/decorators.js';
33

44
import { Review } from '@internetarchive/metadata-service';
55
import {
@@ -9,9 +9,10 @@ import {
99

1010
import '../src/review-form';
1111
import '../src/review';
12+
import '../src/ia-reviews';
13+
1214
import { MockFetchHandler } from '../test/mocks/mock-fetch-handler';
1315
import type { FetchHandlerInterface } from '@internetarchive/fetch-handler-service';
14-
import { ReviewForm } from '../src/review-form';
1516

1617
@customElement('app-root')
1718
export class AppRoot extends LitElement {
@@ -57,59 +58,72 @@ export class AppRoot extends LitElement {
5758
reviewer_itemname: '@foo-bar',
5859
});
5960

61+
private reviews = [
62+
this.mockOldReview,
63+
new Review({
64+
stars: 2,
65+
reviewtitle: 'Eh, just ok',
66+
reviewbody: 'It was fine.',
67+
reviewer: 'Bar Baz',
68+
reviewdate: '04/20/2025',
69+
createdate: '04/19/2025',
70+
reviewer_itemname: '@bar-baz',
71+
}),
72+
new Review({
73+
stars: 5,
74+
reviewtitle: 'My favorite book!!!!!',
75+
reviewbody: 'Wow, what a great read',
76+
reviewer: 'Bar Foo',
77+
reviewdate: '04/19/2025',
78+
createdate: '04/19/2025',
79+
reviewer_itemname: '@bar-foo',
80+
}),
81+
];
82+
6083
private fetchHandler: FetchHandlerInterface = new MockFetchHandler();
6184

62-
private goodRecaptchaManager: RecaptchaManagerInterface =
85+
private mockRecaptchaManager: RecaptchaManagerInterface =
6386
new RecaptchaManager({
6487
defaultSiteKey: 'demo-key',
6588
});
6689

67-
private badRecaptchaManager: RecaptchaManagerInterface = new RecaptchaManager(
68-
{
69-
defaultSiteKey: 'i-am-a-bad-key-that-will-fail',
70-
},
71-
);
72-
73-
@state()
74-
private recaptchaManager?: RecaptchaManagerInterface;
75-
7690
@state()
7791
private bypassRecaptcha: boolean = true;
7892

7993
@state()
8094
private unrecoverableError: boolean = false;
8195

82-
@state()
83-
private recoverableError: boolean = false;
84-
8596
@state()
8697
private useCharCounts: boolean = true;
8798

8899
@state()
89100
private allowDeletion: boolean = false;
90101

102+
@state()
103+
private useExistingReviews: boolean = true;
104+
91105
@state()
92106
private review: Review = this.mockOldReview;
93107

94-
@query('ia-review-form')
95-
private reviewForm!: ReviewForm;
108+
@state()
109+
private reviewsDisabled: boolean = false;
110+
111+
@state()
112+
private reviewsFrozen: boolean = false;
96113

97114
render() {
98-
return html` <h2>Toggle ReCaptcha</h2>
99-
${!this.recaptchaManager
100-
? html`
101-
<button
102-
@click=${() =>
103-
(this.recaptchaManager = this.goodRecaptchaManager)}
104-
>
105-
Turn on ReCaptcha (good site key)</button
106-
><button
107-
@click=${() => (this.recaptchaManager = this.badRecaptchaManager)}
108-
>
109-
Turn on ReCaptcha (bad site key)
110-
</button>
111-
`
112-
: nothing}
115+
return html` <h2>General Settings</h2>
116+
<button
117+
@click=${() => (this.useExistingReviews = !this.useExistingReviews)}
118+
>
119+
${this.useExistingReviews ? 'Remove' : 'Show'} existing reviews
120+
</button>
121+
<button @click=${() => (this.reviewsDisabled = !this.reviewsDisabled)}>
122+
${this.reviewsDisabled ? 'Enable' : 'Disable'} reviews
123+
</button>
124+
<button @click=${() => (this.reviewsFrozen = !this.reviewsFrozen)}>
125+
${this.reviewsFrozen ? 'Unfreeze' : 'Freeze'} reviews
126+
</button>
113127
<button @click=${() => (this.bypassRecaptcha = !this.bypassRecaptcha)}>
114128
${!this.bypassRecaptcha ? 'Bypass' : 'Enable'} ReCaptcha
115129
</button>
@@ -119,75 +133,71 @@ export class AppRoot extends LitElement {
119133
>
120134
${this.unrecoverableError ? 'Hide' : 'Show'} unrecoverable error
121135
</button>
122-
<button
123-
@click=${() => {
124-
this.unrecoverableError = false;
125-
this.recoverableError = !this.recoverableError;
126-
}}
127-
>
128-
${this.recoverableError ? 'Hide' : 'Show'} recoverable error
129-
</button>
130136
<button @click=${() => (this.useCharCounts = !this.useCharCounts)}>
131137
${this.useCharCounts ? 'Remove' : 'Use'} char count limits
132138
</button>
133139
<h2>Toggle review display</h2>
134-
<button
135-
@click=${() => {
136-
this.reviewForm.displayMode = 'form';
137-
}}
138-
>
139-
Switch to form view
140-
</button>
141-
${this.review !== this.mockOldReview
142-
? html`<button @click=${() => (this.review = this.mockOldReview)}>
143-
Prefill normal review
144-
</button>`
145-
: nothing}
146-
${this.review !== this.longReview
147-
? html`<button @click=${() => (this.review = this.longReview)}>
148-
Prefill long review
149-
</button>`
150-
: nothing}
151-
${this.review !== this.reviewWithLink
152-
? html`<button @click=${() => (this.review = this.reviewWithLink)}>
153-
Prefill review with link
154-
</button>`
155-
: nothing}
156-
${this.review !== this.reviewWithTextLink
157-
? html`<button @click=${() => (this.review = this.reviewWithTextLink)}>
158-
Prefill review with text link
159-
</button>`
160-
: nothing}
140+
${this.renderReviewToggle(this.mockOldReview, 'normal review')}
141+
${this.renderReviewToggle(this.longReview, 'long review')}
142+
${this.renderReviewToggle(this.reviewWithLink, 'review with link')}
143+
${this.renderReviewToggle(
144+
this.reviewWithTextLink,
145+
'review with text link',
146+
)}
161147
<button @click=${() => (this.allowDeletion = !this.allowDeletion)}>
162148
${this.allowDeletion ? 'Prevent' : 'Allow'} deletion
163149
</button>
164150
165151
<div class="container">
166-
<ia-review-form
152+
<ia-reviews
167153
.identifier=${'goody'}
168-
.oldReview=${this.review}
169-
.recaptchaManager=${this.recaptchaManager}
170-
.unrecoverableError=${this.unrecoverableError
154+
.reviews=${this.useExistingReviews ? this.reviews : undefined}
155+
.recaptchaManager=${this.mockRecaptchaManager}
156+
.submitterItemname=${'@foo-bar'}
157+
.submitterScreenname=${'Foo Bar'}
158+
.reviewSubmissionError=${this.unrecoverableError
171159
? 'You must be logged in to write reviews.'
172160
: undefined}
173-
.recoverableError=${this.recoverableError
174-
? "There's a problem submitting your review, please try again later."
175-
: undefined}
176161
.maxSubjectLength=${this.useCharCounts ? 100 : undefined}
177162
.maxBodyLength=${this.useCharCounts ? 1000 : undefined}
178163
.fetchHandler=${this.fetchHandler}
179164
?canDelete=${this.allowDeletion}
180165
?bypassRecaptcha=${this.bypassRecaptcha}
181-
?submissionInProgress=${true}
182-
></ia-review-form>
166+
?reviewsDisabled=${this.reviewsDisabled}
167+
?reviewsFrozen=${this.reviewsFrozen}
168+
></ia-reviews>
183169
</div>`;
184170
}
185171

172+
private renderReviewToggle(
173+
review: Review,
174+
reviewName: string,
175+
): HTMLTemplateResult {
176+
return html`
177+
<button
178+
@click=${() => {
179+
this.switchInOutReview(review);
180+
}}
181+
>
182+
${this.review !== review ? 'Prefill' : 'Remove'} ${reviewName}
183+
</button>
184+
`;
185+
}
186+
187+
private switchInOutReview(review: Review): void {
188+
this.useExistingReviews = true;
189+
190+
if (this.review !== review) {
191+
this.review = review;
192+
} else this.review = this.mockOldReview;
193+
}
194+
186195
static styles = css`
187196
.container {
188197
max-width: 750px;
189198
margin: 10px auto;
190199
font-size: 1.4rem;
200+
margin-top: 50px;
191201
}
192202
193203
h2,

index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export { ReviewForm } from './src/review-form';
2+
export { IaReviews } from './src/ia-reviews';

src/assets/add-icon.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { svg } from 'lit';
2+
3+
export default svg`
4+
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" class="add-icon">
5+
<path d="m49.9459358 0c13.7978412 0 25.5896453 4.88776371 35.3754122 14.6632911 9.7857669 9.7755275 14.678654 21.554993 14.678654 35.3383967 0 13.7800281-4.8928871 25.5594936-14.678654 35.3350211-9.7857669 9.7755274-21.577571 14.6632911-35.3754122 14.6632911s-25.5716235-4.8877637-35.3213471-14.6632911c-9.74972353-9.7755275-14.624587-21.554993-14.624587-35.3383967-.00225101-9.0014064 2.23243609-17.3524613 6.70406299-25.0531645 4.47162691-7.7007033 10.54380341-13.7834037 18.21652941-18.24810129 7.6727261-4.46469761 16.0145067-6.69704641 25.0253417-6.69704641zm8.0540642 20h-16l-.001 22h-21.999v16h21.999l.001 22h16v-22h22v-16h-22z" />
6+
</svg>
7+
`;

src/assets/reviews-icon.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { svg } from 'lit';
2+
3+
export default svg`
4+
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" class="reviews-icon" fill="currentColor">
5+
<path d="m100 7.78013601c0-2.14552613-.7593357-3.978597-2.278007-5.4992126-1.5186713-1.52061561-3.3493984-2.28092341-5.4921813-2.28092341h-84.54977287c-2.08268321 0-3.88336049.7603078-5.40203183 2.28092341-1.51867133 1.5206156-2.278007 3.35368647-2.278007 5.4992126v51.49262709c0 2.0853495.75933567 3.8883321 2.278007 5.4089477 1.51867134 1.5206156 3.31934862 2.2809234 5.40203183 2.2809234h10.53361537l.3571304 33.0373658 32.4087237-33.0373658h41.2468361c2.1427829 0 3.97351-.7603078 5.4921813-2.2809234s2.278007-3.3235982 2.278007-5.4089477z"/>
6+
</svg>
7+
`;

0 commit comments

Comments
 (0)