| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'chrome://resources/cr_elements/cr_shared_vars.css.js'; |
| import '/strings.m.js'; |
| import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.js'; |
| |
| import type {PriceTrackingBrowserProxy} from '//resources/cr_components/commerce/price_tracking_browser_proxy.js'; |
| import {PriceTrackingBrowserProxyImpl} from '//resources/cr_components/commerce/price_tracking_browser_proxy.js'; |
| import type {BookmarkProductInfo, ProductInfo} from '//resources/cr_components/commerce/shared.mojom-webui.js'; |
| import type {PriceInsightsInfo} from '//resources/cr_components/commerce/shopping_service.mojom-webui.js'; |
| import {PriceInsightsInfo_PriceBucket} from '//resources/cr_components/commerce/shopping_service.mojom-webui.js'; |
| import type {ShoppingServiceBrowserProxy} from '//resources/cr_components/commerce/shopping_service_browser_proxy.js'; |
| import {ShoppingServiceBrowserProxyImpl} from '//resources/cr_components/commerce/shopping_service_browser_proxy.js'; |
| import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; |
| import type {String16} from 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-webui.js'; |
| import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; |
| |
| import {getTemplate} from './price_tracking_section.html.js'; |
| |
| export interface PriceTrackingSection { |
| $: { |
| toggleTitle: HTMLElement, |
| toggleAnnotation: HTMLElement, |
| toggle: HTMLElement, |
| }; |
| } |
| |
| function decodeString16(arr: String16) { |
| return arr.data.map(ch => String.fromCodePoint(ch)).join(''); |
| } |
| |
| export class PriceTrackingSection extends PolymerElement { |
| static get is() { |
| return 'price-tracking-section'; |
| } |
| |
| static get template() { |
| return getTemplate(); |
| } |
| |
| static get properties() { |
| return { |
| productInfo: Object, |
| |
| isProductTracked: { |
| type: Boolean, |
| value: false, |
| }, |
| |
| folderName_: String, |
| saveLocationEndText_: String, |
| saveLocationStartText_: String, |
| showSaveLocationText_: Boolean, |
| toggleAnnotationText_: String, |
| }; |
| } |
| |
| declare productInfo: ProductInfo; |
| declare isProductTracked: boolean; |
| declare private folderName_: string; |
| declare private saveLocationStartText_: string; |
| declare private saveLocationEndText_: string; |
| declare private showSaveLocationText_: boolean; |
| declare private toggleAnnotationText_: string; |
| |
| priceInsightsInfo: PriceInsightsInfo; |
| private listenerIds_: number[] = []; |
| private shoppingApi_: ShoppingServiceBrowserProxy = |
| ShoppingServiceBrowserProxyImpl.getInstance(); |
| private priceTrackingProxy_: PriceTrackingBrowserProxy = |
| PriceTrackingBrowserProxyImpl.getInstance(); |
| |
| override connectedCallback() { |
| super.connectedCallback(); |
| |
| const callbackRouter = this.priceTrackingProxy_.getCallbackRouter(); |
| this.listenerIds_.push( |
| callbackRouter.priceTrackedForBookmark.addListener( |
| (product: BookmarkProductInfo) => |
| this.onBookmarkPriceTracked(product)), |
| callbackRouter.priceUntrackedForBookmark.addListener( |
| (product: BookmarkProductInfo) => |
| this.onBookmarkPriceUntracked(product)), |
| callbackRouter.operationFailedForBookmark.addListener( |
| (product: BookmarkProductInfo, attemptedTrack: boolean) => |
| this.onBookmarkOperationFailed(product, attemptedTrack)), |
| callbackRouter.onProductBookmarkMoved.addListener( |
| (product: BookmarkProductInfo) => |
| this.onProductBookmarkMoved(product)), |
| ); |
| |
| this.updatePriceTrackingSection_(this.isProductTracked); |
| } |
| |
| private async updatePriceTrackingSection_(tracked: boolean) { |
| if (!tracked) { |
| this.folderName_ = ''; |
| this.toggleAnnotationText_ = |
| loadTimeData.getString('trackPriceDescription'); |
| } else { |
| const {name} = await this.priceTrackingProxy_ |
| .getParentBookmarkFolderNameForCurrentUrl(); |
| this.folderName_ = decodeString16(name); |
| |
| this.toggleAnnotationText_ = |
| loadTimeData.getString('trackPriceSaveDescription'); |
| } |
| this.updateSaveLocationText(this.folderName_); |
| this.isProductTracked = tracked; |
| } |
| |
| private updateSaveLocationText(folderName: string) { |
| if (folderName.length === 0) { |
| this.showSaveLocationText_ = false; |
| this.saveLocationStartText_ = ''; |
| this.saveLocationEndText_ = ''; |
| return; |
| } |
| |
| const fullText: string = |
| loadTimeData.getStringF('trackPriceSaveLocation', folderName); |
| |
| // TODO(crbug.com/40066115): Find a better way to dynamically add a link to a templated |
| // string and possibly avoid using substring. |
| this.saveLocationStartText_ = |
| fullText.substring(0, fullText.lastIndexOf(folderName)); |
| this.saveLocationEndText_ = fullText.substring( |
| fullText.lastIndexOf(folderName) + folderName.length); |
| this.showSaveLocationText_ = true; |
| } |
| |
| override disconnectedCallback() { |
| super.disconnectedCallback(); |
| |
| this.listenerIds_.forEach( |
| id => this.priceTrackingProxy_.getCallbackRouter().removeListener(id)); |
| } |
| |
| private onPriceTrackingToggled_() { |
| this.priceTrackingProxy_.setPriceTrackingStatusForCurrentUrl( |
| this.isProductTracked); |
| chrome.metricsPrivate.recordEnumerationValue( |
| this.isProductTracked ? |
| 'Commerce.PriceTracking.PriceInsightsSidePanel.Track' : |
| 'Commerce.PriceTracking.PriceInsightsSidePanel.Untrack', |
| this.priceInsightsInfo.bucket, |
| PriceInsightsInfo_PriceBucket.MAX_VALUE + 1); |
| } |
| |
| private onBookmarkPriceTracked(product: BookmarkProductInfo) { |
| if (product.info.clusterId !== this.productInfo.clusterId) { |
| return; |
| } |
| this.updatePriceTrackingSection_(true); |
| } |
| |
| private onBookmarkPriceUntracked(product: BookmarkProductInfo) { |
| if (product.info.clusterId !== this.productInfo.clusterId) { |
| return; |
| } |
| this.updatePriceTrackingSection_(false); |
| } |
| |
| private onFolderClicked_() { |
| this.priceTrackingProxy_.showBookmarkEditorForCurrentUrl(); |
| chrome.metricsPrivate.recordUserAction( |
| 'Commerce.PriceTracking.' + |
| 'EditedBookmarkFolderFromPriceInsightsSidePanel'); |
| } |
| |
| private onBookmarkOperationFailed( |
| product: BookmarkProductInfo, attemptedTrack: boolean) { |
| if (product.info.clusterId !== this.productInfo.clusterId) { |
| return; |
| } |
| this.toggleAnnotationText_ = loadTimeData.getString('trackPriceError'); |
| this.folderName_ = ''; |
| this.updateSaveLocationText(''); |
| this.isProductTracked = !attemptedTrack; |
| } |
| |
| private async onProductBookmarkMoved(product: BookmarkProductInfo) { |
| if (product.info.clusterId === this.productInfo.clusterId && |
| this.isProductTracked) { |
| const {name} = await this.priceTrackingProxy_ |
| .getParentBookmarkFolderNameForCurrentUrl(); |
| this.folderName_ = decodeString16(name); |
| } |
| } |
| } |
| |
| declare global { |
| interface HTMLElementTagNameMap { |
| 'price-tracking-section': PriceTrackingSection; |
| } |
| } |
| |
| customElements.define(PriceTrackingSection.is, PriceTrackingSection); |