import throttle from "lodash/throttle" ; import { Middleware , AnyAction } from "redux" ; import { createAsyncThunk , createAction } from "@reduxjs/toolkit" ; import { store } from "popup/App" ; import { settingsDataSharingSelector } from "popup/ducks/settings" ; type metricHandler < AppState > = ( state : AppState , action : AnyAction ) => void ; const handlersLookup = { } ; export function metricsMiddleware < State > ( ) { return ( { getState } ) => ( next ) => ( action ) => { const state = getState ( ) ; ( handlersLookup [ action . type ] || [ ] ) . forEach ( ( handler ) => handler ( state , action ) ) ; return next ( action ) ; } ; } const dummyThunk = createAsyncThunk < any , any > ( "dummy" , ( ) => { } ) ; const dummyAction = createAction < any > ( "also dummy" ) ; type ActionType = typeof dummyThunk . fulfilled | typeof dummyThunk . rejected | typeof dummyThunk . pending | typeof dummyAction ; param { ActionType } actionType param { function } handler returns { void } export function registerHandler < State > ( actionType , handler ) { const type = typeof actionType === "string" ? actionType : actionType . type ; if ( handlersLookup [ type ] ) { handlersLookup [ type ] . push ( handler ) ; } else { handlersLookup [ type ] = [ handler ] ; } } interface event { event_type : string ; event_properties : { [ key ] : any ; } ; user_id : string ; device_id : string ; } const METRICS_ENDPOINT = "https://api.amplitude.com/2/httpapi" ; let cache = [ ] ; const uploadMetrics = throttle ( ( ) => { const toUpload = cache ; cache = [ ] ; if ( ! process . env . AMPLITUDE_KEY ) { console . log ( "Not uploading metrics" , toUpload ) ; return ; } fetch ( METRICS_ENDPOINT , { method : "POST" , headers : { "Content-Type" : "application/json" , } , body : JSON . stringify ( { api_key : process . env . AMPLITUDE_KEY , events : toUpload , } ) , } ) ; } , 500 ) ; const getUserId = ( ) => { const storedId = localStorage . getItem ( "metrics_user_id" ) ; if ( ! storedId ) { const newId = Math . random ( ) . toString ( ) . split ( "." ) [ 1 ] ; localStorage . setItem ( "metrics_user_id" , newId ) ; return newId ; } return storedId ; } ; param { string } name param { object ? } body returns { void } export const emitMetric = ( name , body ? ) => { const isDataSharingAllowed = settingsDataSharingSelector ( store . getState ( ) ) ; if ( ! isDataSharingAllowed ) return ; cache . push ( { event_type : name , event_properties : body , user_id : getUserId ( ) , device_id : window . navigator . userAgent , } ) ; uploadMetrics ( ) ; } ;