#158: Add badge_toolbar_button and send_notification probes
Add badge_toolbar_button and send_notification probes: * Add an additional extra key, 'price_last_high' to 'send_notification' and 'open_external_page' (with 'element' value of 'system_notification') and update METRICS.md. * Add a 'sendTelemetry' flag for the 'sendProductToBackground' function to also be removed when the 'resend' code is removed in './src/extraction/index.js'. * Due to the fix for Issue #192, I was seeing some extra 'badge_toolbar_button' events (with 'badge_type' of 'add') as we are resending extracted product information 5 and 10 seconds after the product page loads. * Update METRICS.md to clarify when 'badge_toolbar_button' with a 'badge_type' of 'price_alert' fires, since it will continue to fire for the same price alert until that alert is dismissed which is not obvious.
This commit is contained in:
Родитель
3743b4cfca
Коммит
16a8fa3791
|
@ -143,6 +143,8 @@ Below is a sample ping for the `badge_toolbar_button` and `visit_supported_site`
|
|||
- `method`: The extraction method that was successful, if any. One of: 'fathom', 'fallback' or 'neither'. A value of 'neither' means that extraction failed.
|
||||
- `'price'`: The price of the product in subunits (e.g. a $10.00 product would have a value of `'1000'`). For the MVP, the units here are always cents (USD currency only).
|
||||
- `'price_alert'`: 'true' if the product has an active Price Alert; otherwise 'false'.
|
||||
- `'price_last_high'`: The last high price of the product in subunits (e.g. a $10.00 product would have a value of `'1000'`). For the MVP, the units here are always cents (USD currency only).
|
||||
- A high price is, semantically, the price that there's been an interesting drop from to warrant alerting the user. Practically, it is the highest price since the previous price alert.
|
||||
- `'price_orig'`: The original price of the product in subunits (e.g. a $10.00 product would have a value of `'1000'`). For the MVP, the units here are always cents (USD currency only).
|
||||
- `'price_prev'`: The previous price of the product when different from the latest price (`price`) in subunits (e.g. a $10.00 product would have a value of `'1000'`). For the MVP, the units here are always cents (USD currency only).
|
||||
- `'product_index'`: The index of the product in the product listing. The top most list item is index '0'. The list is sorted by date added, descending (#113).
|
||||
|
@ -216,6 +218,8 @@ Fired when the user clicks on a UI element in the extension that opens a page in
|
|||
- `'price_alert'`
|
||||
- `'price_orig'`
|
||||
- `'product_key'`
|
||||
- `'system_notification'` only:
|
||||
- `'price_last_high'`
|
||||
- `'product_card'` only:
|
||||
- `'product_index'`
|
||||
|
||||
|
@ -313,6 +317,7 @@ Fired whenever a price change (of any magnitude and in any direction) is detecte
|
|||
Fired whenever the toolbar is badged in response to:
|
||||
1. A successful product extraction or
|
||||
2. A Price Alert
|
||||
- Note: For Price Alerts, this event will continue to trigger after the initial Price Alert is shown to the user until the Price Alert is dismissed (per the [UX spec](https://mozilla.invisionapp.com/share/UFNSHAIMT4V#/screens/317130676_Artboard_1) and when a system notification is clicked).
|
||||
|
||||
#### Payload properties
|
||||
|
||||
|
@ -336,6 +341,7 @@ Fired whenever a system notification is sent to the user notifying them of a Pri
|
|||
- `'system_notification'`
|
||||
- `extra_keys`: Object
|
||||
- `'price'`
|
||||
- `'price_last_high'`
|
||||
- `'price_orig'`
|
||||
- `'product_key'`
|
||||
- `'tracked_prods'`
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
import config from 'commerce/config';
|
||||
import {updateProductWithExtracted} from 'commerce/background/price_updates';
|
||||
import {isValidExtractedProduct} from 'commerce/state/products';
|
||||
import {recordEvent} from 'commerce/telemetry/extension';
|
||||
|
||||
/**
|
||||
* Triggers background tasks when a product is extracted from a webpage. Along
|
||||
|
@ -20,7 +21,7 @@ import {isValidExtractedProduct} from 'commerce/state/products';
|
|||
* @param {MessageSender} sender
|
||||
* The sender for the content script that extracted this product
|
||||
*/
|
||||
export async function handleExtractedProductData({extractedProduct}, sender) {
|
||||
export async function handleExtractedProductData({extractedProduct, sendTelemetry = true}, sender) {
|
||||
// Do nothing if the extracted product isn't valid.
|
||||
if (!isValidExtractedProduct(extractedProduct)) {
|
||||
return;
|
||||
|
@ -51,6 +52,11 @@ export async function handleExtractedProductData({extractedProduct}, sender) {
|
|||
tabId,
|
||||
});
|
||||
browser.browserAction.setBadgeText({text: '✚', tabId});
|
||||
if (sendTelemetry) {
|
||||
await recordEvent('badge_toolbar_button', 'toolbar_button', null, {
|
||||
badge_type: 'add',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Update saved product data if it exists
|
||||
|
|
|
@ -28,13 +28,16 @@ import {recordEvent} from 'commerce/telemetry/extension';
|
|||
* Update the extension UI based on the current state of active price alerts.
|
||||
* Should be called whenever price alerts may have changed.
|
||||
*/
|
||||
export function handlePriceAlerts() {
|
||||
export async function handlePriceAlerts() {
|
||||
const state = store.getState();
|
||||
const activeAlerts = getActivePriceAlerts(state);
|
||||
|
||||
// Show the browser action badge if there are any active alerts.
|
||||
if (activeAlerts.length > 0) {
|
||||
browser.browserAction.setBadgeText({text: `${activeAlerts.length}`});
|
||||
await recordEvent('badge_toolbar_button', 'toolbar_button', null, {
|
||||
badge_type: 'price_alert',
|
||||
});
|
||||
} else {
|
||||
browser.browserAction.setBadgeText({text: null});
|
||||
}
|
||||
|
@ -61,6 +64,12 @@ export function handlePriceAlerts() {
|
|||
title: `Price Alert: ${product.title}`,
|
||||
message: `${vendorName} · Originally ${original}, high of ${high}, now ${now}`,
|
||||
});
|
||||
await recordEvent('send_notification', 'system_notification', null, { // eslint-disable-line no-await-in-loop
|
||||
price: alertPrice.amount.getAmount(),
|
||||
price_last_high: highPriceAmount.getAmount(),
|
||||
price_orig: originalPrice.amount.getAmount(),
|
||||
product_key: product.anonId,
|
||||
});
|
||||
|
||||
// Update state now that we've shown it
|
||||
store.dispatch(showPriceAlert(alert));
|
||||
|
@ -86,10 +95,12 @@ export async function handleNotificationClicked(notificationId) {
|
|||
// Record open_external_page event
|
||||
const latestPrice = getLatestPriceForProduct(state, product.id);
|
||||
const originalPrice = getOldestPriceForProduct(state, product.id);
|
||||
const highPriceAmount = Dinero({amount: alert.highPriceAmount});
|
||||
await recordEvent('open_external_page', 'ui_element', null, {
|
||||
element: 'system_notification',
|
||||
price: latestPrice.amount.getAmount(),
|
||||
price_alert: alert.active,
|
||||
price_last_high: highPriceAmount.getAmount(),
|
||||
price_orig: originalPrice.amount.getAmount(),
|
||||
product_key: product.anonId,
|
||||
});
|
||||
|
|
|
@ -99,7 +99,7 @@ export async function updateProductWithExtracted(data) {
|
|||
const updatedState = store.getState();
|
||||
const latestPrice = getLatestPriceForProduct(updatedState, id);
|
||||
const originalPrice = getOldestPriceForProduct(updatedState, id);
|
||||
recordEvent('detect_price_change', 'product_page', null, {
|
||||
await recordEvent('detect_price_change', 'product_page', null, {
|
||||
price: latestPrice.amount.getAmount(),
|
||||
price_prev: previousPrice.amount.getAmount(),
|
||||
price_orig: originalPrice.amount.getAmount(),
|
||||
|
|
|
@ -42,9 +42,10 @@ function extractProduct() {
|
|||
return null;
|
||||
}
|
||||
|
||||
async function sendProductToBackground(extractedProduct) {
|
||||
async function sendProductToBackground(extractedProduct, sendTelemetry) {
|
||||
return browser.runtime.sendMessage({
|
||||
type: 'extracted-product',
|
||||
sendTelemetry,
|
||||
extractedProduct: {
|
||||
...extractedProduct,
|
||||
url: document.location.href,
|
||||
|
@ -111,8 +112,9 @@ async function attemptExtraction() {
|
|||
|
||||
// Messy workaround for bug 1493470: Resend product info to the background
|
||||
// script twice in case subframe loads clear the toolbar icon.
|
||||
// TODO(osmose): Remove once Firefox 64 hits the release channel.
|
||||
const resend = () => sendProductToBackground(extractedProduct);
|
||||
// TODO(osmose): Remove once Firefox 64 hits the release channel, including second argument
|
||||
// to sendProductToBackground.
|
||||
const resend = () => sendProductToBackground(extractedProduct, false);
|
||||
setTimeout(resend, 5000);
|
||||
setTimeout(resend, 10000);
|
||||
|
||||
|
|
|
@ -52,6 +52,8 @@ const EVENTS = {
|
|||
'price_alert',
|
||||
'price_orig',
|
||||
'product_key',
|
||||
// For 'element' value of 'system_notification' only
|
||||
'price_last_high',
|
||||
// For 'element' value 'product_card' only
|
||||
'product_index',
|
||||
],
|
||||
|
@ -137,6 +139,7 @@ const EVENTS = {
|
|||
objects: ['system_notification'],
|
||||
extra_keys: [
|
||||
'price',
|
||||
'price_last_high',
|
||||
'price_orig',
|
||||
'product_key',
|
||||
...DEFAULT_EXTRAS,
|
||||
|
|
Загрузка…
Ссылка в новой задаче