Skip to content

Commit 5099ea6

Browse files
authored
Consolidated Item Removal process which can be used on offshoot pages. (#417)
1 parent 7ef77af commit 5099ea6

File tree

7 files changed

+428
-61
lines changed

7 files changed

+428
-61
lines changed

src/app-root.ts

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -489,10 +489,8 @@ export class AppRoot extends LitElement {
489489
@baseQueryChanged=${this.baseQueryChanged}
490490
@searchTypeChanged=${this.searchTypeChanged}
491491
@manageModeChanged=${this.manageModeChanged}
492-
@itemRemovalRequested=${(e: CustomEvent) =>
493-
console.log(e.detail.items)}
494-
@itemManagerRequested=${(e: CustomEvent) =>
495-
console.log(e.detail.items)}
492+
@itemRemovalRequested=${this.handleItemRemovalRequest}
493+
@itemManagerRequested=${this.handleItemManagerRequest}
496494
>
497495
${this.toggleSlots
498496
? html`<div slot="sortbar-left-slot">Sort Slot</div>`
@@ -707,6 +705,36 @@ export class AppRoot extends LitElement {
707705
if (manageCheckbox) manageCheckbox.checked = e.detail;
708706
}
709707

708+
/**
709+
* Handler for item removal
710+
*/
711+
private handleItemRemovalRequest(e: CustomEvent) {
712+
this.collectionBrowser.showRemoveItemsProcessingModal();
713+
console.log('itemRemovalRequested: ', e.detail.items);
714+
715+
setTimeout(() => {
716+
// execute item-removal-service, and response is successfully deleted
717+
const status = false;
718+
719+
if (status) {
720+
// looking for success?
721+
this.collectionBrowser.isManageView = false;
722+
this.modalManager?.closeModal();
723+
this.modalManager?.classList.remove('remove-items');
724+
} else {
725+
// looking for failure?
726+
this.collectionBrowser.showRemoveItemsErrorModal();
727+
}
728+
}, 2000); // let's wait to see processing modal
729+
}
730+
731+
/**
732+
* Handler when item manage requested
733+
*/
734+
private handleItemManagerRequest(e: CustomEvent) {
735+
console.log('itemManagerRequested: ', e.detail.items);
736+
}
737+
710738
/**
711739
* Handler for when the dev panel's "Enable manage mode" checkbox is changed.
712740
*/
@@ -936,6 +964,12 @@ export class AppRoot extends LitElement {
936964
modal-manager[mode='open'] {
937965
display: block;
938966
}
967+
modal-manager.remove-items {
968+
--modalWidth: 58rem;
969+
--modalBorder: 2px solid var(--primaryButtonBGColor, #194880);
970+
--modalTitleLineHeight: 4rem;
971+
--modalTitleFontSize: 1.8rem;
972+
}
939973
modal-manager.more-search-facets {
940974
--modalWidth: 85rem;
941975
--modalBorder: 2px solid var(--primaryButtonBGColor, #194880);

src/collection-browser.ts

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ import type {
5757
} from './data-source/collection-browser-query-state';
5858
import { FACETLESS_PAGE_ELEMENTS } from './data-source/models';
5959
import type { CollectionFacets } from './collection-facets';
60-
import type { ManageableItem } from './manage/manage-bar';
6160
import type { CollectionBrowserDataSourceInterface } from './data-source/collection-browser-data-source-interface';
6261
import {
6362
analyticsActions,
@@ -66,9 +65,9 @@ import {
6665
import chevronIcon from './assets/img/icons/chevron';
6766
import { srOnlyStyle } from './styles/sr-only';
6867
import { sha1 } from './utils/sha1';
69-
import { formatDate } from './utils/format-date';
7068
import { log } from './utils/log';
7169
import type { PlaceholderType } from './empty-placeholder';
70+
import type { ManageBar } from './manage/manage-bar';
7271

7372
import './empty-placeholder';
7473
import './tiles/tile-dispatcher';
@@ -299,6 +298,8 @@ export class CollectionBrowser
299298

300299
@query('collection-facets') private collectionFacets?: CollectionFacets;
301300

301+
@query('manage-bar') private manageBar?: ManageBar;
302+
302303
@property({ type: Object, attribute: false })
303304
analyticsHandler?: AnalyticsManagerInterface;
304305

@@ -774,15 +775,23 @@ export class CollectionBrowser
774775
* showing the management view. This generally replaces the sort bar when present.
775776
*/
776777
private get manageBarTemplate(): TemplateResult {
778+
const manageViewModalMsg =
779+
this.profileElement === 'uploads'
780+
? 'Note: it may take a few minutes for these items to stop appearing in your uploads list.'
781+
: nothing;
782+
777783
return html`
778784
<manage-bar
779785
.label=${this.manageViewLabel}
780-
.pageContext=${this.pageContext}
786+
.modalManager=${this.modalManager}
787+
.selectedItems=${this.dataSource.checkedTileModels}
788+
.manageViewModalMsg=${manageViewModalMsg}
781789
showSelectAll
782790
showUnselectAll
791+
?showItemManageButton=${this.pageContext === 'search'}
783792
?removeAllowed=${this.dataSource.checkedTileModels.length !== 0}
784793
@removeItems=${this.handleRemoveItems}
785-
@itemsManager=${this.handleItemsManager}
794+
@manageItems=${this.handleManageItems}
786795
@selectAll=${() => this.dataSource.checkAllTiles()}
787796
@unselectAll=${() => this.dataSource.uncheckAllTiles()}
788797
@cancel=${() => {
@@ -799,13 +808,11 @@ export class CollectionBrowser
799808
*/
800809
private handleRemoveItems(): void {
801810
this.dispatchEvent(
802-
new CustomEvent<{ items: ManageableItem[] }>('itemRemovalRequested', {
811+
new CustomEvent<{ items: String[] }>('itemRemovalRequested', {
803812
detail: {
804-
items: this.dataSource.checkedTileModels.map(model => {
805-
const cloned = model.clone();
806-
cloned.dateStr = formatDate(model.datePublished, 'long');
807-
return cloned as ManageableItem;
808-
}),
813+
items: this.dataSource.checkedTileModels.map(model =>
814+
model?.identifier ? model.identifier : ''
815+
),
809816
},
810817
})
811818
);
@@ -814,19 +821,32 @@ export class CollectionBrowser
814821
/**
815822
* Handler when user request to bulk edit from /search/ page
816823
*/
817-
private handleItemsManager(): void {
824+
private handleManageItems(): void {
818825
this.dispatchEvent(
819-
new CustomEvent('itemManagerRequested', {
826+
new CustomEvent<{ items: String[] }>('itemManagerRequested', {
820827
detail: {
821-
items: this.dataSource.checkedTileModels
822-
.map(item => item.identifier)
823-
.filter(Boolean)
824-
.join(','),
828+
items: this.dataSource.checkedTileModels.map(model =>
829+
model?.identifier ? model.identifier : ''
830+
),
825831
},
826832
})
827833
);
828834
}
829835

836+
/**
837+
* Handler to show processing modal while removing item
838+
*/
839+
showRemoveItemsProcessingModal(): void {
840+
this.manageBar?.showRemoveItemsProcessingModal();
841+
}
842+
843+
/**
844+
* Handler to show error modal when item removal failed
845+
*/
846+
showRemoveItemsErrorModal(): void {
847+
this.manageBar?.showRemoveItemsErrorModal();
848+
}
849+
830850
/**
831851
* Removes all tile models that are currently checked & adjusts the paging
832852
* of the data source to account for any new gaps in the data.

src/manage/manage-bar.ts

Lines changed: 119 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import { msg } from '@lit/localize';
22
import { LitElement, html, css, TemplateResult, CSSResultGroup } from 'lit';
33
import { customElement, property } from 'lit/decorators.js';
44
import { when } from 'lit/directives/when.js';
5+
import {
6+
ModalConfig,
7+
type ModalManagerInterface,
8+
} from '@internetarchive/modal-manager';
9+
import type { ManageableItem } from '../models';
510
import iaButtonStyle from '../styles/ia-button';
6-
7-
export interface ManageableItem {
8-
identifier: string;
9-
title?: string;
10-
dateStr?: string;
11-
}
11+
import './remove-items-modal-content';
1212

1313
@customElement('manage-bar')
1414
export class ManageBar extends LitElement {
@@ -18,9 +18,19 @@ export class ManageBar extends LitElement {
1818
@property({ type: String }) label = msg('Select items to remove');
1919

2020
/**
21-
* Specifies the context in which the collection browser is being used
21+
* The shared modal manager component for displaying modal dialogs on this page
2222
*/
23-
@property({ type: String }) pageContext?: string;
23+
@property({ type: Object }) modalManager?: ModalManagerInterface;
24+
25+
/**
26+
* Array of items that have been selected for management
27+
*/
28+
@property({ type: Object }) selectedItems: Array<ManageableItem> = [];
29+
30+
/**
31+
* Message shows as note in the modal when removing items
32+
*/
33+
@property({ type: String }) manageViewModalMsg?: string;
2434

2535
/**
2636
* Whether to show the "Select All" button (default false)
@@ -32,6 +42,11 @@ export class ManageBar extends LitElement {
3242
*/
3343
@property({ type: Boolean }) showUnselectAll = false;
3444

45+
/**
46+
* Whether to show "Item Manager the items" button (default false)
47+
*/
48+
@property({ type: Boolean }) showItemManageButton = false;
49+
3550
/**
3651
* Whether to active delete button for selectable items
3752
*/
@@ -48,21 +63,20 @@ export class ManageBar extends LitElement {
4863
<button
4964
class="ia-button danger"
5065
?disabled=${!this.removeAllowed}
51-
@click=${this.removeClicked}
66+
@click=${this.showRemoveItemsModal}
5267
>
5368
${msg('Remove selected items')}
5469
</button>
55-
${this.pageContext === 'search'
56-
? html`
57-
<button
58-
class="ia-button warning"
59-
?disabled=${!this.removeAllowed}
60-
@click=${this.itemsManagerClicked}
61-
>
62-
${msg('Item Manager the items')}
63-
</button>
64-
`
65-
: ''}
70+
${when(
71+
this.showItemManageButton,
72+
() => html` <button
73+
class="ia-button warning"
74+
?disabled=${!this.removeAllowed}
75+
@click=${this.manageItemsClicked}
76+
>
77+
${msg('Item Manager the items')}
78+
</button>`
79+
)}
6680
<div class="selection-buttons">
6781
${when(
6882
this.showSelectAll,
@@ -92,12 +106,12 @@ export class ManageBar extends LitElement {
92106
this.dispatchEvent(new CustomEvent('cancel'));
93107
}
94108

95-
private removeClicked(): void {
109+
private removeItemsClicked(): void {
96110
this.dispatchEvent(new CustomEvent('removeItems'));
97111
}
98112

99-
private itemsManagerClicked(): void {
100-
this.dispatchEvent(new CustomEvent('itemsManager'));
113+
private manageItemsClicked(): void {
114+
this.dispatchEvent(new CustomEvent('manageItems'));
101115
}
102116

103117
private selectAllClicked(): void {
@@ -108,6 +122,88 @@ export class ManageBar extends LitElement {
108122
this.dispatchEvent(new CustomEvent('unselectAll'));
109123
}
110124

125+
/**
126+
* Shows a modal dialog confirming the list of items to be removed
127+
* @param items Which items to list in the modal
128+
*/
129+
private showRemoveItemsModal(): void {
130+
const customModalContent = html`
131+
<remove-items-modal-content
132+
.items=${this.selectedItems}
133+
.message=${this.manageViewModalMsg}
134+
@confirm=${() => this.removeItemsClicked()}
135+
></remove-items-modal-content>
136+
`;
137+
138+
const config = new ModalConfig({
139+
showProcessingIndicator: false,
140+
processingImageMode: 'processing',
141+
bodyColor: '#fff',
142+
headerColor: '#194880',
143+
showHeaderLogo: false,
144+
closeOnBackdropClick: true,
145+
title: html`${msg('Are you sure you want to remove these items?')}`,
146+
});
147+
148+
this.modalManager?.classList.add('remove-items');
149+
this.modalManager?.showModal({
150+
config,
151+
customModalContent,
152+
userClosedModalCallback: () => {
153+
this.modalManager?.classList.remove('remove-items');
154+
},
155+
});
156+
}
157+
158+
/**
159+
* Shows a modal dialog indicating that item removal is being processed
160+
*/
161+
showRemoveItemsProcessingModal(): void {
162+
const config = new ModalConfig({
163+
showProcessingIndicator: true,
164+
processingImageMode: 'processing',
165+
bodyColor: '#fff',
166+
headerColor: '#194880',
167+
showHeaderLogo: false,
168+
closeOnBackdropClick: true,
169+
title: html`${msg('Removing selected items...')}`,
170+
});
171+
172+
this.modalManager?.classList.add('remove-items');
173+
this.modalManager?.showModal({
174+
config,
175+
userClosedModalCallback: () => {
176+
this.modalManager?.classList.remove('remove-items');
177+
},
178+
});
179+
}
180+
181+
/**
182+
* Shows a modal dialog indicating that an error occurred while removing items
183+
*/
184+
showRemoveItemsErrorModal(): void {
185+
const config = new ModalConfig({
186+
showProcessingIndicator: false,
187+
processingImageMode: 'processing',
188+
bodyColor: '#fff',
189+
headerColor: '#691916',
190+
showHeaderLogo: false,
191+
closeOnBackdropClick: true,
192+
title: html`${msg('Error: unable to remove items')}`,
193+
message: html`${msg(
194+
'An error occurred while removing items. Please try again in a few minutes.'
195+
)}`,
196+
});
197+
198+
this.modalManager?.classList.add('remove-items');
199+
this.modalManager?.showModal({
200+
config,
201+
userClosedModalCallback: () => {
202+
this.modalManager?.classList.remove('remove-items');
203+
},
204+
});
205+
}
206+
111207
static get styles(): CSSResultGroup {
112208
return css`
113209
${iaButtonStyle}

0 commit comments

Comments
 (0)