// ==UserScript== // @name Improve SCC // @description Adds shortcut buttons; Colour codes search results; additional package history information; and more… // @version 13.0.4 // @author David King (dkingamz@) // Translator-de Stephanie Petke (petke@) // Translator-es Carlos de la Peña (cacalzad@) // Translator-fr Karl-Emmanuel Etifier (karleme@) // Translator-it Andrea La Rosa (anrosam@) // Thanks-cortex Dennis Leonhardt (leoden@) // @namespace https://phonetool.amazon.com/users/dkingamz // @updateURL https://axzile.corp.amazon.com/-/carthamus/download_script/improve-scc.user.js // @downloadURL https://axzile.corp.amazon.com/-/carthamus/download_script/improve-scc.user.js // @supportURL https://sim.amazon.com/issues/create?template=5ee8e705-a508-4820-86f4-1d87b978d630 // @match https://*/station/dashboard/* // @match https://*.last-mile.amazon.dev/?* // @match https://midway-auth.amazon.com/* // @match https://siw-eu-dub.dub.proxy.amazon.com/* // @match https://siw-na-iad.iad.proxy.amazon.com/* // @match https://www.royalmail.com/find-a-postcode* // @exclude https://global.eagle.routeiq.last-mile.amazon.dev/* // @exclude https://*.geostudio.last-mile.amazon.dev/* // @exclude https://*.utr-shift-plan-management-website.last-mile.amazon.dev/* // @grant GM.xmlHttpRequest // @grant GM.info // @grant GM.setValue // @grant GM_getValue // @connect midway-auth.amazon.com // @connect routingtools-viz-dub.dub.proxy.amazon.com // @connect logistics.amazon.co.uk // @connect ie-logistics.amazon.co.uk // @connect logistics.amazon.de // @connect at-logistics.amazon.de // @connect logistics.amazon.es // @connect logistics.amazon.fr // @connect logistics.amazon.it // @connect logistics.amazon.nl // @connect logistics.amazon.sa // @connect logistics.amazon.com // @connect logistics.amazon.com.mx // @connect logistics.amazon.ca // @connect logistics.amazon.com.br // @connect logistics.amazon.in // @connect logistics.amazon.ae // @connect logistics.amazon.eg // @connect logistics.amazon.co.jp // @connect logistics.amazon.com.au // @connect gamtools-eu.aka.amazon.com // @connect gamtools-na.aka.amazon.com // @connect eagleeye-eu.amazon.com // @connect eagleeye-na.amazon.com // @connect geoweb-eu.amazon.com // @connect geoweb-na.amazon.com // @connect amazonlogistics-eu.com // @connect amazonlogistics.com // @connect pandash.amazon.com // @connect corp.amazon.com // @connect last-mile.amazon.dev // @connect trans-logistics-eu.amazon.com // @connect trans-logistics.amazon.com // @connect routingtools-viz-dub.dub.proxy.amazon.com // @connect routingtools-viz-iad.iad.proxy.amazon.com // @connect transportation-taxonomy-dub.aka.amazon.com // @connect transportation-taxonomy-iad.aka.amazon.com // @connect hero.eu.picking.aft.a2z.com // @connect hero.na.picking.aft.a2z.com // @connect trans-app-prod-eu.amazon.com // @connect trans-app-prod-na.amazon.com // @connect honeypot.amazon.dev // @run-at document-end // @require https://internal-cdn.amazon.com/sentry.amazon.com/public/javascripts/openid.xhr/1.0.2/openid.xhr.min.js // @require https://cdn.jsdelivr.net/gh/klingondragon/simple-dom/index.min.js // @require https://cdn.jsdelivr.net/gh/davidshimjs/qrcodejs/qrcode.min.js // ==/UserScript== //#region Utilities/Types /// /// /// const { _, _svg, $, $$, wait$, delay, _css, O, dict, lock } = simpleDOM; const /** @type {(...bindArgs: A) => (cb: (...boundArgs: A) => R) => R} */ bindWith = (...args) => (cb) => cb(...args), /** @type {(href:string, filename?:string)=>void} */ download = (href, filename) => _('a', { href, download: filename ?? "" }).do('click').remove(); //#endregion //#region: Config data const debug = GM_getValue('debugMode', false), ver = GM.info.script.version, s = dict({ en: { //Script Name broken into 3 pieces Text before phonetool link, phonetool link, and text after phonetool link scriptNameBefore: 'Improve SCC Script by ', scriptNameAfter: '', translatedBy: 'Translated by {{name}}', translatorName: 'David King', translatorAlias: 'dkingamz', formatTable: 'Format History Table:', onRoadOption: 'On Road', inStationOption: 'In Station', pleaseWait: 'Please Wait', EagleEye: 'EagleEye', EagleEye2: 'EagleEye 2.0', getContents: 'Get Package Contents', CSC: 'CSC', SIM: 'Search SIM Issues', COMP: 'COMP', Hero: 'Hero', SlamOps: 'SlamOps', DEXTER: 'DEXTER', FixIt: 'Fixit Details & History (Rodeo)', TT: 'Troubleshooting Tool', OBLT: 'Outbound Lookup Tool', GDE: 'Geo Data Editor', oId: 'Order ID: ', customerId: 'Customer ID: ', sameOrderID: 'Same Order ID: ', shipMethod: 'Ship Method: ', shipOption: 'Ship Option: ', serviceType: 'Service Type: ', lTId: 'Linked Tracking ID: ', AVD: 'AVD', OTP: 'OTP', SIG: 'Signature', HAZMAT: 'HAZMAT', HV: 'High Value', VH: 'Very Heavy', H: 'Heavy', LB: 'Letterbox Sized', OVER: 'Oversize', metPDD: 'Met Promise Date', metEAD: 'Met Estimated Date', missPDD: 'Missed Promise Date', missEAD: 'Missed Estimated Date', calcText: '(approx. {{ft#}} / {{m#}} from delivery location', // move the {{}} in the sentence, these will be filled with the correct numbers BH: 'Business hours: ', Driver: 'Driver: ', Route: 'Route Code: ', RouteVis: 'Route Visualisation', RouteDiver: 'Route Diver', RouteEagle: 'RouteIQ: Eagle', cortexItinerary: 'Driver itinerary (Cortex)', cortexLinkRoute: 'Cortex (Route)', cortexLinkStop: 'Cortex (Stop {{stop#}})', // move the {{}} in the sentence, this will be filled with the correct number GAM: 'GAM Tools', Hours: 'Hours:', LockerStatus: 'Locker Status', LockerReserve: 'Locker Reservation', Address: 'Address', Locker: 'Locker', Counter: 'Counter', LatLon: 'Lat Lon', GAM404: 'Address not in GAM', GAMnoHours: 'No Hours in GAM', FailedAttempt: 'Failed Attempts:', GAMhint: 'GAM DELIVERY_HINT', qrCode: 'QR Code', viewPOD: 'View POD Images', honeypot: 'Honeypot', GCRS: 'GCRS', Passage: 'Passage', RoyalMail: 'Royal Mail', TransTax: 'Transportation Taxonomy', plannedTime: 'Planned Delivery Time: {{time}}', // move the {{}} in the sentence, this will be filled with the correct time plannedStartTime: 'Planned Start Time: {{time}}', // move the {{}} in the sentence, this will be filled with the correct time windowTime: 'Time Window: {{time}}', // move the {{}} in the sentence, this will be filled with the correct time delTo: 'Delivered To', NoHistData: 'No History Data: {{reason}}', // move the {{}} in the sentence, this will be filled with the correct reason NoSiteData: 'No Sitemap Data: {{reason}}', // move the {{}} in the sentence, this will be filled with the correct reason NoPackData: 'No Package Data: {{reason}}', // move the {{}} in the sentence, this will be filled with the correct reason NoGeoData: 'No Geo Data: {{reason}}', // move the {{}} in the sentence, this will be filled with the correct reason NoGAMData: 'No GAM Data: {{reason}}', // move the {{}} in the sentence, this will be filled with the correct reason }, 'en-US': { RouteVis: 'Route Visualization', }, de: { scriptNameBefore: 'Improve SCC Script von ', scriptNameAfter: '', translatedBy: 'Translated von {{name}}', translatorName: 'Stephanie Petke', translatorAlias: 'petke', formatTable: 'Format History Tabelle:', onRoadOption: 'On Road', inStationOption: 'In der Station', pleaseWait: 'Bitte warten', getContents: 'Inhalt anzeigen', metPDD: 'PDD eingehalten', metEAD: 'EAD eingehalten', missPDD: 'PDD verfehlt', missEAD: 'EAD verfehlt', calcText: '(ca. {{ft#}} / {{m#}} vom Geopunkt', BH: 'Öffnungszeiten: ', Hours: 'Uhrzeit:', LockerReserve: 'Locker Reservierung', Address: 'Adresse', LatLon: 'Breiten/Längengrad', GAM404: 'Addresse nicht in GAM', GAMnoHours: 'Keine Öffnungszeiten in GAM', FailedAttempt: 'fehlgeschlagene Zustellversuche:', }, es: { translatedBy: 'Traducido por {{name}}', translatorName: 'Carlos de la Peña', translatorAlias: 'cacalzad', formatTable: 'Formato de tabla:', onRoadOption: 'En carretera', inStationOption: 'En estación', pleaseWait: 'Por favor espere', getContents: 'Obtener productos', FixIt: 'Detalles & Histórico FixIt (Rodeo)', GDE: 'Editor Geo Data', oId: 'Número de Pedido: ', shipMethod: 'Método de envío: ', lTId: 'Código ID relacionado: ', HV: 'Alto Valor', VH: 'Muy Pesado', H: 'Pesado', LB: 'Sobre', OVER: 'Voluminoso (Oversize)', metPDD: 'Fecha Entrega Prometida Cumplida', metEAD: 'Fecha Llegada Estimada Cumplida', missPDD: 'Fecha Entrega Prometida Fallada', missEAD: 'Fecha Entrega Estimada Fallada', calcText: '(aprox. {{ft#}} / {{m#}} del punto de entrga', BH: 'Horario de Apertura: ', RouteVis: 'Visualizador de Ruta', cortexItinerary: 'Itinerario del Conductor (Cortex)', cortexLinkRoute: 'Cortex (Ruta)', cortexLinkStop: 'Cortex (Parada {{stop#}})', Hours: 'Horario:', LockerStatus: 'Estado del locker', Address: 'Dirección', LatLon: 'Lat y Long', GAM404: 'Dirección no en GAM', GAMnoHours: 'Horario no en GAM', FailedAttempt: 'Intento de Entrega Fallido:', qrCode: 'Código QR ', plannedTime: 'Hora Prevista de Reparto: {{time}}', plannedStartTime: 'Planned Start Time: {{time}}', }, fr: { translatorName: 'etifier, karl-emmanuel', translatorAlias: 'karleme', }, it: { translatorName: 'Andrea La Rosa', translatorAlias: 'anrosam', formatTable: 'Formato Tabella Cronologica:', onRoadOption: 'In Transito', inStationOption: 'In Station', pleaseWait: 'Prego Attendere', getContents: 'Vedi Contenuto Pacco', FixIt: 'Dettaglio e Cronologia da Fixit (Rodeo)', oId: 'ID Ordine: ', lTId: 'Tracking Id Collegato: ', HV: 'Alto Valore', VH: 'Molto Pesante', H: 'Pesante', LB: 'Tasca Di Libro', metPDD: 'Data Promessa Corretta', metEAD: 'Data Stimata Corretta', missPDD: 'Data Promessa Mancata', missEAD: 'Data Stimata Mancata', calcText: '(appross. {{ft#}} / {{m#}} dall\'indirizzo di spedizione', BH: 'Orario d\'Apertura: ', RouteVis: 'Visualizza Rotta', cortexLinkRoute: 'Cortex (Rotta)', cortexLinkStop: 'Cortex (Fermata {{stop#}})', Hours: 'Orario Tentativi:', LockerStatus: 'Stato del Locker', LockerReserve: 'Locker Reservation', Address: 'Indirizzo', LatLon: 'Lat e Lon', GAM404: 'Indirizzo non in GAM', GAMnoHours: 'Orario non in GAM', FailedAttempt: 'Tentativi di Consegna Falliti:', }, jp: { translatedBy: 'Translated by {{name}}', translatorName: 'Saki Uchida', translatorAlias: 'duchidsa', } }), /** Strings that must match what's already in SCC so that the script can detect it. */ searchStrings = { en: { //Search/Package details searchHeader: 'Search', //The header at the top of the search page packageHeader: 'Package', //(partial match)The header at the top of the detail (search results) page GAMdays: '|SUN|MON|TUE|WED|THU|FRI|SAT|', //Days as seen in GAM Business Hours separated by |. I've tested and it seems these will probably match english. ShipMethod: 'Ship Method', //Search results column header //Outbound > Pick/Stage tabs associate: 'Associate', cartID: 'Cart ID', driver: 'Driver', //Problem Solve tabs Reportedby: 'Reported by' }, de: { //Search/Package details searchHeader: 'Suche', packageHeader: 'Paket', ShipMethod: 'Ship Method', //Outbound > Pick/Stage tabs associate: 'Mitarbeiter', cartID: 'Wagen-ID', //Problem Solve tabs Reportedby: 'Reported by' }, es: { //Search/Package details searchHeader: 'Búsqueda', packageHeader: 'Paquete', ShipMethod: 'Ship Method', //Outbound > Pick/Stage tabs associate: 'Asociado', cartID: 'Código ID Carro', //Problem Solve tabs Reportedby: 'Reportado por' }, fr: { //Search/Package details searchHeader: 'Rechercher', packageHeader: 'Colis', ShipMethod: 'Ship Method', //Outbound > Pick/Stage tabs associate: 'Associé', cartID: 'ID de l\'itinéraire', //Problem Solve tabs Reportedby: 'Signalé par' }, it: { //Search/Package details searchHeader: 'Cerca', packageHeader: 'Pacco', ShipMethod: 'Ship Method', //Outbound > Pick/Stage tabs associate: 'Associate', cartID: 'ID carrello', //Problem Solve tabs Reportedby: 'Reported by' }, jp: { //Search/Package details searchHeader: '検索', packageHeader: 'パッケージ', ShipMethod: 'パッケージ概要', //Outbound > Pick/Stage tabs associate: 'アソシエイト', cartID: 'ルートID', driver: 'ドライバー', //Problem Solve tabs Reportedby: '修正対象' } }, /** @type {string[]} */ logData = [], /** @type {(...log: any[]) => void} */ debuglog = debug ? (...log) => { logData.push(`${Date.now()}: ${log.map(line => { try { return JSON.stringify(line); } catch (e) { return line.toString(); } }).join('\n\t')}`); console.log(location.origin, '[Improve-SCC]', ...log); } : (...log) => { }, superlog = debug ? debuglog : console.log, mutationComment = document.createComment("Mutate"); //#endregion //#region: Global Defaults, State, and Constants let /** @type {PageInfo} */ page, /** @type {SCCPromises} */ promises, /** @type {WindowProxy?} */ midwayWindow = null, /** @type {string?} */ globalOrigin, /** @type {Notification?} */ notification; function defaults() { debuglog('defaults()'); page = { url: window.location.href.split('/') }; promises = /** @type {SCCPromises} */ ({}); midwayWindow = null; } const now = new Date().getTime(); //#endregion //#region: Prototypes and DOM Functions const /** @type {FormatterFunction} */ dateTimeFormatter = options => { const /** @type {Record} */ cache = {}; return (value, timeZone) => ((`${timeZone}`) in cache ? cache[`${timeZone}`] : (cache[`${timeZone}`] = new Intl.DateTimeFormat(navigator.languages, { ...options, timeZone }))).format((typeof value === 'string') ? new Date(value) : value); }, toLocaleTZString = dateTimeFormatter({ hour: '2-digit', minute: '2-digit', second: '2-digit', }), toWeekdayDateString = dateTimeFormatter({ weekday: "short", year: "2-digit", month: "2-digit", day: "2-digit", }), toWeekdayDateTimeString = dateTimeFormatter({ weekday: "short", year: "2-digit", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: '2-digit' }); class ExtendedDate extends Date { toISODateString() { return `${this.getFullYear()}-${(this.getMonth() + 1).toString().padStart(2, "0")}-${this.getDate().toString().padStart(2, "0")}`; } toISODateTimeString() { return `${this.toISODateString()} ${this.getHours().toString().padStart(2, "0")}:${this.getMinutes().toString().padStart(2, "0")}:${this.getSeconds().toString().padStart(2, "0")}`; } /** @type {DateToString} */ toYMDKey(timeZone) { return `${this.toLocaleString('en-GB', { timeZone, year: 'numeric' })}${this.toLocaleString('en-GB', { timeZone, month: '2-digit' })}${this.toLocaleString('en-GB', { timeZone, day: '2-digit' })}`; } toMidnightLocal() { return new Date(this.getFullYear(), this.getMonth(), this.getDate()).valueOf(); } }; /** @type {(value?: number | string | Date) => ExtendedDate} */ const D = (value) => value ? new ExtendedDate(value) : new ExtendedDate(); class ExtendedString extends String { /** @type {TestString} */ in(test) { return test.toLowerCase().includes(this.toLowerCase()); } /** @type {TestString} */ contains(test) { return this.toLowerCase().includes(test.toLowerCase()); } /** @type {(...tests: string[]) => boolean} */ containsAny(...tests) { return tests.reduce((bool, test) => bool || this.contains(test), false); } toSentenceCase() { return `${this.charAt(0).toUpperCase()}${this.slice(1).toLowerCase()}`; } toWordCase() { return this.toLowerCase().replace(/(^|\s)\S/g, letter => letter.toUpperCase()); } /** @type {TestString} */ inDict(key) { return O(searchStrings).reduce((bool, [_, langDict]) => (bool || this.in(langDict[key])), false); } /** @type {TestString} */ dictContains(key) { return O(searchStrings).reduce((bool, [_, langDict]) => (bool || this.contains(langDict[key])), false); }; } /** @type {(value: any) => ExtendedString} */ const S = (value) => new ExtendedString(value); const /** @type {(test: string)=>boolean} */ hrefContains = (test) => S(location.href).contains(test); // Cortex auth/signing code provided by Dennis Leonhardt (leoden@) let /** @type {CortexSession | undefined} */ cortexAuthPromise = undefined; /** @type {()=>CortexSession} */ const initializeCortexAuth = () => cortexAuthPromise ?? (cortexAuthPromise = XHR('GET', `${globalOrigin}/internal/operations/execution`).then( (response) => new Promise((resolve) => ([...new DOMParser().parseFromString(response.text, 'text/html').querySelectorAll('script[type="a-state"][data-a-state*="hmacSession"]')].reduce((flagFound, script) => { if (flagFound) return flagFound; const data = JSON.parse(script.textContent.trim()); if (!(data.hmacSession && data.hmacSession.enabled)) return false; crypto.subtle.importKey( 'raw', new TextEncoder().encode(data.hmacSession.sessionKey), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign'] ).then(cryptoKey => (debuglog(data.hmacSession), resolve({ sessionKey: data.hmacSession.sessionKey, sessionId: data.hmacSession.sessionId, cryptoKey }))); return true; }, false))) ).catch( error => debuglog('Cortex authentication failed:', error) )); /** @type {(method: "GET"|"POST", url: string, json?: any) => Promise} */ const XHR = (method, url, json) => (!globalOrigin || !url.includes(globalOrigin) || location.origin === globalOrigin) ? systemXHR(method, url, json) : new Promise((resolve, reject) => { debuglog(`${method} XHR Request: ${url}`, json); const id = `${Date.now().toString(36)}-${Math.random().toString(36).substring(2, 10)}`, /** @type {(data:any)=>void} */ handler = ({ data }) => { if (data.method !== 'XHR') return; if (data.id !== id) return; debuglog(`${data.response.status} XHR Response: ${url}`, data.response); window.removeEventListener("message", handler); (data.response.ok ? resolve : reject)({ ...data.response, json: () => JSON.parse(data.response.text) }); }; debuglog('Posting XHR', id, url); window.addEventListener("message", handler); window.parent.postMessage({ method: 'XHR', id, params: { method, url, json } }, globalOrigin ?? ''); }); /** @type {(method: "GET"|"POST", url: string, json?: any) => Promise} */ const systemXHR = (method, url, json) => new Promise((resolve, reject) => { debuglog(`${method} XHR Request: ${url}`, json); /** @type {XHROptions} */ const options = { method, url, onload: (response) => { debuglog(`${response.status} XHR Response: ${url}`, response.responseText); const r = { status: response.status, statusText: response.statusText, text: response.responseText, ok: response.status >= 200 && response.status <= 299, json: () => JSON.parse(response.responseText) }; (r.ok ? resolve : reject)(r); }, headers: {} }; json !== null && (options.headers['Content-Type'] = 'application/json', options.data = (typeof json) === 'string' ? json : JSON.stringify(json)); // Cortex auth/signing code provided by Dennis Leonhardt (leoden@) (url.includes(`${globalOrigin}/internal/operations/execution/api`) ? initializeCortexAuth().then(({ sessionId, cryptoKey }) => { const { pathname, searchParams } = new URL(url), timestamp = Date.now().toString(); return crypto.subtle.sign( 'HMAC', cryptoKey, new TextEncoder().encode([ method, pathname, searchParams.toString(), `x-cortex-session:${sessionId}`, `x-cortex-timestamp:${timestamp}`, '', 'x-cortex-session;x-cortex-timestamp' ].join('\n')) ).then(signature => { options.headers['X-Cortex-Hmac-Signature'] = btoa(String.fromCharCode(...new Uint8Array(signature))); options.headers['X-Cortex-Session'] = sessionId; options.headers['X-Cortex-Timestamp'] = timestamp; }).finally(() => debuglog(`${method} XHR Headers: ${url}`, options.headers)); }) : Promise.resolve()).then(() => { GM.xmlHttpRequest(options); delay(10).then(() => reject(`Timed-out: ${method} ${url}`)); }, reject); }); /** @type {({json}:{json:()=>T})=>T} */ const json = ({ json }) => json(); const unitMap = { cm: 'centimeter', kg: 'kilogram' }, /** @type {({value, unit}:{value:number, unit:string})=>string} */ formatUnit = ({ value, unit }) => { try { if (unit in unitMap) unit = unitMap[unit]; return new Intl.NumberFormat(navigator.languages, { style: 'unit', unit }).format(value).replace(/\s/g, '\u00A0'); } catch (e) { debuglog(e); return `${value}_${unit}`; } }, /** @type {({value, currency}:{value:number, currency:string})=>string} */ formatCurrency = ({ value, currency }) => { try { return new Intl.NumberFormat(navigator.languages, { style: 'currency', currency }).format(value).replace(/\s/g, '\u00A0'); } catch (e) { debuglog(e); return `${value}_${currency}`; } }; //#endregion //#region: Pages and Tabs function startup() { wait$('html').then(() => { if (hrefContains('logistics.amazon.')) return SCCStartup(); document.documentElement.dataset.improveSccCssIframe = ''; window.addEventListener("message", ({ data }) => { switch (data.method) { case 'sendDarkModeStatus': return void (document.documentElement.dataset.improveSccCssDarkMode = data.childData.capability); case 'sendOrigin': return void (globalOrigin = data.childData); case 'sendLocaleResponse': return; default: debuglog('postMessage', data); } }); new Promise((resolve) => { const interval = setInterval(() => { if (!globalOrigin) return; clearInterval(interval); resolve(globalOrigin); debuglog('Origin:', globalOrigin); }, 500); }).then(initialise); }); } function SCCStartup() { document.documentElement.dataset.improveSccCssNoframe = ''; globalOrigin = location.origin; console.log(`%c${s('scriptNameBefore')} David King (dkingamz@) ${s('scriptNameAfter')} %c${ver}`, 'font-size: 200%; font-weight: bold;', 'font-size: 200%; color: red; text-decoration: underline;'); console.log(`%c${s('translatedBy').replace('{{name}}', `${s('translatorName')} (${s('translatorAlias')}@)`)}`, 'font-size: 150%'); console.log(`%cFormatting: ${new Intl.ListFormat(navigator.languages, { type: 'conjunction' }).format(navigator.languages.map(lang => new Intl.DisplayNames(navigator.languages, { type: 'language' }).of(lang)).filter(lang => lang !== undefined))}`, 'font-size: 125%; color: cyan;'); wait$('.boson-meridian-frame-dimension', { style: { top: '' } }); wait$('#main_row').then(mainRow => { const verdiv = _('div', { id: 'verdiv' })._(_('strong')._( s('scriptNameBefore'), _('a', { href: 'https://phonetool.amazon.com/users/dkingamz', target: '_blank' })._('David King (dkingamz@)'), s('scriptNameAfter'), `\u2003 ${ver}`, )).on('click', () => verdiv.classList.toggle('hidden')); mainRow._(verdiv); new MutationObserver(() => { $$('iframe', { attributeList: { 'allow': 'clipboard-write https://ui.package-summary-eu.last-mile.amazon.dev https://ui.package-summary-na.last-mile.amazon.dev https://onebox.ui.package-summary-eu.last-mile.amazon.dev https://onebox.ui.package-summary-na.last-mile.amazon.dev;' } }); }).observe(mainRow, { characterData: false, attributes: false, childList: true, subtree: true }); }); wait$('ul[role=tree]').then(ul => { $("#Help > div > span")?._(' (River)'); const updateAvailableLi = _('li'); let lastCheckDate, /** @type {string?}*/ master; const updateAvailable = () => { updateAvailableLi.__(master && GM.info.script.downloadURL && (ver == master ? null : _('a', { href: GM.info.script.downloadURL, target: '_blank', classList: ['css-11g0wa3'] })._(_('div', { classList: ['css-1u8dqdz'] })._(_('span', { classList: ['css-1bkd0di'] })._(`Update to version ${master}`))))); }, updateCheck = () => GM.info.script.downloadURL ? XHR('GET', GM.info.script.downloadURL).then(response => { master = (/@version\s+(.*)/i.exec(response.text) ?? '')[1]; debuglog(`masterVer: ${master}`); if (!master) return; localStorage.setItem('ImproveSCCupdateTimestamp', `${Date.now()}`); localStorage.setItem('ImproveSCCmaster', master); }) : Promise.resolve(); ((master = localStorage.getItem('ImproveSCCmaster')) && ((lastCheckDate = localStorage.getItem('ImproveSCCupdateTimestamp')) && Number(lastCheckDate) > Date.now() - 24 * 60 * 60 * 1000) ? () => Promise.resolve() : updateCheck)().then(updateAvailable); ul._( ($('#dkingamzNav') || _('div', { id: 'dkingamzNav' })).__( _('strong')._(s('scriptNameBefore'), _('a', { href: 'https://phonetool.amazon.com/users/dkingamz', target: '_blank' })._('David King (dkingamz@)'), s('scriptNameAfter'), `\u2003 ${ver}`,), _('li')._(_('button', { classList: ['css-11g0wa3'] })._(_('div', { classList: ['css-1u8dqdz'] })._(_('span', { classList: ['css-1bkd0di'] })._('Check For Updates'))).on('click', () => updateCheck().then(updateAvailable))), updateAvailableLi, _('li')._(_('a', { href: 'https://axzile.corp.amazon.com/-/carthamus/download_script/improve-scc-show-top-nav-menu.user.js', target: '_blank', classList: ['css-11g0wa3'] })._(_('div', { classList: ['css-1u8dqdz'] })._(_('span', { classList: ['css-1bkd0di'] })._('Show Top Nav Menu')))), _('li')._(_('button', { classList: ['css-11g0wa3'] })._(_('div', { classList: ['css-1u8dqdz'] })._(_('span', { classList: ['css-1bkd0di'] })._(`Toggle Debug Mode ${debug ? 'Off' : 'On'}`))).on('click', () => GM.setValue('debugMode', !debug).then(() => location.reload(true)))), debug && _('li')._(_('button', { classList: ['css-11g0wa3'] })._(_('div', { classList: ['css-1u8dqdz'] })._(_('span', { classList: ['css-1bkd0di'] })._('Export Improve-SCC Sidebar logs'))).on('click', () => { const modal = _('dialog', { style: { background: 'canvas' } })._( _('div', { id: 'debugModalButtons' })._( _('button')._('Export').on('click', () => bindWith(URL.createObjectURL(new Blob([logData.join('\n')], { type: 'text/plain' })))(blobUrl => (download(blobUrl, `Improve-SCC-Log-Export${Date.now()}.txt`), URL.revokeObjectURL(blobUrl)))), _('button')._('Close').on('click', () => modal.close()), ), ...logData.map(line => _('div')._(line)), ).on('close', () => modal.remove()); $('body')?._(modal); queueMicrotask(() => modal.showModal()); })), _('li')._(_('a', { href: 'https://sim.amazon.com/issues/create?template=5ee8e705-a508-4820-86f4-1d87b978d630', target: '_blank', classList: ['css-11g0wa3'] })._(_('div', { classList: ['css-1u8dqdz'] })._(_('span', { classList: ['css-1bkd0di'] })._('Create SIM', _('br'), _('small')._('Improve SCC Script'))))), ) ); }); wait$('body').then(body => { (new MutationObserver(() => (document.documentElement.dataset.improveSccCssDarkMode = body.classList.contains('dark-mode') ? 'dark' : 'light'))).observe(body, { attributes: true, subtree: false, childList: false, characterData: false }); debug && body._(_('iframe', { dataset: { debug: '' }, srcdoc: `${Date.now()}
SCC: ${globalOrigin}
UA: ${navigator.userAgent}
Default Language: ${navigator.language}
All Languages: ${JSON.stringify(navigator.languages)}`, style: { position: 'fixed', insetInlineEnd: '1rem', insetBlockEnd: '1rem', width: '36rem', height: '12rem' } })); }); hrefContains('/search') && (document.documentElement.dataset.improveSccCssHideAlerts = ''); navigator.languages.includes('en-GB') && Promise.all([wait$('title'), wait$('h4')]).then(texts => texts.forEach(text => (text.textContent = text.textContent?.replace('Center', 'Centre') ?? 'SCC'))); const iframe = () => wait$('iframe', undefined, 2).then(iframe => ({ contentWindow: iframe.contentWindow, origin: new URL(iframe.src).origin })).catch((...e) => { throw debuglog('Selecting iFrame', ...e); }); window.addEventListener("message", ({ data }) => { switch (data.method) { case 'XHR': Promise.all([systemXHR(data.params.method, data.params.url, data.params.json).catch(r => r), iframe()]).then(([{ json, ...response }, { contentWindow, origin }]) => contentWindow?.postMessage({ method: 'XHR', id: data.id, response }, origin)); break; case 'requestUsername': // wait$('iframe').then(iframe => iframe.contentWindow?.postMessage({ method: "sendUsername", childData: sessionStorage.getItem('boson.tcpEmployeeLogin') }, new URL(iframe.src).origin)); break; default: debuglog('postMessage', data); } }); setInterval(() => iframe().then(({ contentWindow, origin }) => contentWindow?.postMessage({ method: "sendOrigin", childData: globalOrigin }, origin)), 1000); } function initialise() { defaults(); debuglog('initialise()'); wait$('body').then(body => { const oldURL = window.location.href; new MutationObserver((_, observer) => { // debuglog(`${oldURL} - ${window.location.href}`); if (oldURL != window.location.href && !(hrefContains('receive'))) {//hrefContains('ui.package-summary-')) { observer.disconnect(); window.ImproveSCC = false; startup(); } }).observe(body, { characterData: true, attributes: false, childList: true, subtree: true }); debug && body._(_('button', { id: 'exportLogs', style: { background: 'canvas' } })._('Export Improve-SCC Page logs').on('click', () => { const modal = _('dialog', { style: { background: 'canvas' } })._( _('div', { id: 'debugModalButtons' })._( _('button')._('Export').on('click', () => bindWith(URL.createObjectURL(new Blob([logData.join('\n')], { type: 'text/plain' })))(blobUrl => (download(blobUrl, `Improve-SCC-Log-Export${Date.now()}.txt`), URL.revokeObjectURL(blobUrl)))), _('button')._('Close').on('click', () => modal.close()), ), ...logData.map(line => _('div')._(line)), ).on('close', () => modal.remove()); body._(modal); queueMicrotask(() => modal.showModal()); })); }); if (hrefContains('/settings')) return; if (hrefContains('ui.package-summary-')) { page.region = window.location.href.split('ui.package-summary-')[1].split('.')[0]; page.region == 'in' && (page.region = 'eu'); page.regionCode = { na: 'iad', eu: 'dub', fe: 'PDX', cn: 'PEK' }[page.region]; if (!hrefContains('packageSearch') && (hrefContains('ageingBoard') || hrefContains('scrubBoard'))) return void debuglog('kill searchLoad()'); sessionStorage.setItem('loadCount', `${Number(sessionStorage.getItem('loadCount')) + 1}`); if (!(document?.featurePolicy?.allowsFeature?.('clipboard-write') ?? true)) { if (Number(sessionStorage.getItem('loadCount')) < 5) { location.reload(); return; } } else { sessionStorage.setItem('loadCount', '0'); } wait$('h1, h2, h3, table', undefined, 12).then(h => { debuglog(`main(${h.innerText})`); if (S(h.innerText).inDict('searchHeader')) return queueMicrotask(searchPage); if (S(h.innerText).dictContains('packageHeader')) return queueMicrotask(detailPage); }).catch(() => (debuglog("Can't find header… Reloading"), (debug ? confirm("Can't find header\n\nReload") : true) && location.reload(true))); return; } if (hrefContains('associate')) return associate(); if (hrefContains('ui.pvs') || hrefContains('ui.stagewebsite') || hrefContains('outbound')) return outbound(); if (hrefContains('ui.ivs') || hrefContains('prod.svs')) return associate(); if (hrefContains('node-exceptions')) return psTab(); if (hrefContains('sort-paths')) return; } async function detailPage() { if (promises.detailPage) return; promises.detailPage = true; page.trackingId = await wait$('h1').then((h1) => wait$('h1 > span').then(() => h1.lastChild?.textContent?.trim())); superlog(`-${page.trackingId}-`); debuglog('detailPage()'); document.documentElement.dataset.improveSccCssDetailsPage = ''; $('ul.css-1duca4b')?.__(historyFormatMenu().menuElement); promises.topBar = new Promise(resolve => { const improveBox = $('div#improveRoot') || _('div', { id: 'improveRoot' }), improveBoxes = {}; wait$('#root [role=tablist]').then(tabList => tabList.before(improveBox)); improveBox.__( improveBoxes.head = _('div', { id: 'improveHead' }), improveBoxes.items = _('div'), improveBoxes.transport = _('div', { id: 'transport' })._(improveBoxes.van = _('div')), improveBoxes.gam = _('div', { id: 'gamrow' }), improveBoxes.buttons = _('div', { id: 'buttons' }), improveBoxes.podContainer = _('div', { id: 'podContainer' }), improveBoxes.taxonomyError = _('div', { id: 'taxonomyError', classList: ['errMsg'] }), improveBoxes.histTableError = _('div', { id: 'histTableError', classList: ['errMsg'] }) ); resolve(improveBoxes); }); promises.sitemap = siteMap(); promises.geo = getGeoData(); promises.package = getPackageData(); promises.gam = promises.package.then(getGAMData); // promises.oblt = getOBLT(); promises.package.then(addrbuts); promises.boxes = Promise.all([promises.topBar, promises.package]).then(usePackageData); promises.topBar.then((improveBoxes) => { XHR('POST', `${globalOrigin}/station/proxyapigateway/data`, { resourcePath: '/os/batchGetPackageSummary', httpMethod: 'post', processName: 'oculus', requestBody: { idType: 'TRACKING_ID', identifiers: [page.trackingId], includeFields: [] } }).then(json).then(({ packageSummaryList }) => packageSummaryList[0]).then(packageDetailData => { improveBoxes.van.__( packageDetailData.driverId && _('strong')._(packageDetailData.driverId), packageDetailData.currentRouteCode && _('span')._(`Route: ${packageDetailData.currentRouteCode}`), packageDetailData.routeSequence && _('span')._(`Route Sequence: ${packageDetailData.routeSequence}`), (packageDetailData.vehicleStopNumber || packageDetailData.taskStopNumber) && _('span')._(`Van Stop: ${packageDetailData.vehicleStopNumber}-(${packageDetailData.taskStopNumber})`) ); }); }); promises.topBar.then(() => { specialButtons(); // _('button')._().on('click', () => buttonclick(`https://honeypot.amazon.dev/?id=${page.trackingId}&searchType=TRACKING_ID&imageType=PHOTO_ON_DELIVERY®ion=${AWS_POD_REGION_MAPPING[page.region]}&tab=pod-search`)), addButton(`https://honeypot.amazon.dev/?id=${page.trackingId}&searchType=TRACKING_ID&imageType=PHOTO_ON_DELIVERY®ion=${AWS_POD_REGION_MAPPING[page.region ?? '']}&tab=pod-search`, s('honeypot'), -1, { id: 'Honeypot' }); addButton(`https://sim.amazon.com/issues/search?q=(${page.trackingId})&sort=lastUpdatedConversationDate`, s('SIM'), -1, { id: 'SIM' }); addButton(`https://eagleeye.amazon.dev/search?searchId=${page.trackingId}&format=leg&nodeInfo=&shipmentType=scannable&®ion=${page.region?.toUpperCase()}`, s('EagleEye2'), 1); addButton(`https://trans-app-prod-${page.region}.amazon.com/outboundLookup/trackingEventLookup.cgi?id=${page.trackingId}`, s('OBLT'), 2); addButton(`https://siw-${page.region}-${page.regionCode}.${page.regionCode}.proxy.amazon.com/query#${page.trackingId}`, s('GCRS'), 2, { name: 'GCRSsearch' }); addButton(`https://geoweb-${page.region}.amazon.com/GeoDataEditor/app/partials/edit_index.jsp?country=eu&type=TrackingId&id=${page.trackingId}`, s('GDE'), 2); addButton(`https://${page.region}.geostudio.last-mile.amazon.dev/?searchId=${page.trackingId}#background=MAPNIK`, 'GeoStudio', 2); addButton(`https://${page.region}.geostudio.last-mile.amazon.dev/place?searchId=${page.trackingId}`, 'GeoStudio 2.0', 2); if (page.region == 'na') addButton(`https://ate-portal-na.amazon.com/single/getAttributes?inputId=${page.trackingId}&inputIdType=Tracking%20Id`, 'ATE Portal', 2); }); Promise.all([promises.topBar, promises.package]).then(([_, packageData]) => addButton(`https://trans-logistics${(page.region != 'na' ? `-${page.region}` : '')}.amazon.com/sortcenter/tantei?nodeId=${packageData.routeInfo.stationCode}&searchType=Container&searchId=${page.trackingId}`, s('TT'), 2)); Promise.all([promises.boxes, promises.geo]).then(useGeoData); Promise.all([promises.topBar, promises.gam, promises.histPromise]).then(useGAMData); // Promise.all([promises.topBar, promises.oblt]).then(useOBLTData); // promises.oblt.catch((e) => promises.boxes?.then(improveBoxes => improveBoxes.customerId.__('OBLT Error', e))); wait$('#root').then(root => { debuglog('DetailMutationObserver'); new MutationObserver((_, observer) => { if ($('#SCC_Search_CONFIG') && $('h1, h2')) return void (($('table:not([data-improve-scc=true]')) && setTimeout(histTable)); observer.disconnect(); initialise(); }).observe(root, { characterData: true, attributes: false, childList: true, subtree: true }); }).then(() => { debuglog('clicking History button'); Promise.all([wait$('.css-1gnngbt > .css-r8kn69'), wait$('[role=tablist] label:nth-of-type(4)')]).then(([_, label]) => label.do('click')); }); } function searchPage() { debuglog('searchPage()'); document.documentElement.dataset.improveSccCssSearchPage = ''; wait$('#root .css-1gnngbt').then(searchArea => { debuglog('SearchMutationObserver'); new MutationObserver(() => { const resultsTable = $('table'); if (!resultsTable || resultsTable.dataset.improveScc == 'true' || resultsTable.$$('tr').length <= 1) return; resultsTable.dataset.improveScc = 'true'; const /** @type {string[]} */trackingIdList = []; const /** @type {Record>} */ rowMap = {}, methodColumn = resultsTable.$$('th').reduce((/**@type {false | number}*/methodColumn, th, i) => methodColumn || S(th.innerText).dictContains('ShipMethod') && (i + 1), false); resultsTable.$$('tr').forEach(tr => { const a = tr.$('a'); if (!a) return; debuglog(a.innerText); rowMap[a.innerText] = tr; trackingIdList.push(a.innerText); methodColumn && colourResult(tr.$(`td:nth-of-type(${methodColumn})`)?.innerText, tr); }); if (methodColumn) return; XHR('POST', `${globalOrigin}/station/proxyapigateway/data`, { resourcePath: '/os/batchGetPackageSummary', httpMethod: 'post', processName: 'oculus', requestBody: { idType: 'TRACKING_ID', identifiers: trackingIdList, nodeId: (/.*stationCode=([A-Z0-9]+).*/.exec(page.url[3]) ?? '')[1], includeFields: [] } }).then(json).then(searchResult => searchResult.packageSummaryList.forEach((resultRow) => { debuglog(`${resultRow.trackingId} - ${resultRow.shipMethod} - ${resultRow.shipOption}`); colourResult(resultRow.shipMethod, rowMap[resultRow.trackingId]); rowMap[resultRow.trackingId].dataset.exchangeId = resultRow.exchangeId; })); }).observe(searchArea, { characterData: true, attributes: false, childList: true, subtree: true }); }); } /** @type {(text: string, dateTime: string?, type?: string?) => void} */ function newCustNote(text, dateTime, type) { promises.boxes?.then((improveBoxes) => { if (!S(improveBoxes.notes.textContent).contains(text)) { improveBoxes.notes._(custNoteDiv(text, dateTime, type)); } }); } /** @type {(text: string, dateTime: string?, type?: string?) => Extended} */ function custNoteDiv(text, dateTime, type) { return _('div')._(S(text).contains('dog') && _('span', { style: { fontSize: '2em' } })._('\uD83D\uDC3A'), ...(dateTime ? [toWeekdayDateString(dateTime), '\u2003-\u2003'] : []), type ? `${type}\u2003-\u2003` : undefined, text); } const historyTableLock = lock('history-table'), histTable = () => historyTableLock(() => (debuglog('histTable()'), Promise.allSettled([ wait$('table:not([data-improve-scc-table])', { dataset: { improveSccTable: '' } }, 20), getHistoryData(), promises.sitemap, promises.package, promises.geo, promises.gam ]).then(([tablePromise, histPromise, sitePromise, packPromise, geoPromise, gamPromise]) => { debuglog('histTable() allSettled', { status: tablePromise.status }, histPromise, sitePromise, packPromise, geoPromise, gamPromise); if (tablePromise.status == 'rejected') throw `Could not find history table\n\t${JSON.stringify(tablePromise.reason)}`; if (histPromise.status == 'rejected') throw (debuglog('History Promise Failed… Reloading'), /*(debug ? confirm('History Promise Failed\n\nReload') : true) && location.reload(true),*/ `Could not get history data\n\t${JSON.stringify(histPromise.reason)}`); if (packPromise.status == 'rejected') throw (debuglog('Package Promise Failed… Reloading'), /*(debug ? confirm('Package Promise Failed\n\nReload') : true) && location.reload(true),*/ `Could not get package data\n\t${JSON.stringify(packPromise.reason)}`); const historytable = tablePromise.value, historyData = histPromise.value, sitemap = sitePromise.status == 'fulfilled' ? sitePromise.value.data : undefined, packageData = packPromise.value, geoData = geoPromise.status == 'fulfilled' && geoPromise.value, gamData = gamPromise.status == 'fulfilled' && gamPromise.value; if (historytable.dataset.improveScc == 'true') return; historytable.dataset.improveScc = 'true'; debuglog(historytable); const logBox = _('th', { colSpan: 99 }); historytable._( _('thead')._(_('tr')._(_('th', { colSpan: 99 })._( sitePromise.status == 'rejected' && _('div')._(s('NoSiteData').replace('{{reason}}', JSON.stringify(sitePromise.reason))), geoPromise.status == 'rejected' && _('div')._(s('NoGeoData').replace('{{reason}}', JSON.stringify(geoPromise.reason))), // gamPromise.status == 'rejected' && _('div')._(s('NoGAMData').replace('{{reason}}', JSON.stringify(gamPromise.reason))) ))), _('tfoot')._(_('tr')._(logBox)) ); historytable.dataset.colours = JSON.parse(localStorage.getItem('SCC_Search_CONFIG') ?? '{}').colours ?? 'OnRoad'; historytable.$$('tr:not(:first-child)').forEach((tr, i) => { const thisRow = tr.$$('td'), timestamp = D(historyData[i].stateTime); Object.assign(historyData[i], { timestamp, dateISO: timestamp.toISODateString(), YMDKey: timestamp.toYMDKey(), operation: historyData[i].operation?.[0] ?? '', reason: thisRow[5].innerText, user: thisRow[6].innerText, other: thisRow[10].innerText }); }); debuglog(historyData); historytable.$$('tr:not(:first-child)').forEach((tr, i) => setTimeout(() => { const newRow = {}, thisRow = tr.$$('td'), thisHistory = historyData[i]; tr.$("td:nth-child(3) > span > p", { style: { width: 'max-content' } }); tr.before(newRow.tr = _('tr', { classList: ['newRow'] })._(newRow.td = _('td', { colSpan: 99, style: { fontWeight: 'bold' } }))); if (thisHistory.timestamp.toString() != 'Invalid Date') { (i == 0 || thisHistory.YMDKey != historyData[i - 1].YMDKey) && (tr.classList.add('newDay'), newRow.tr.classList.add('newDay')); thisRow[0].__(toWeekdayDateTimeString(thisHistory.timestamp, packageData.stationTimeZone)); } if (thisHistory.deliveryLatitude && thisHistory.deliveryLongitude) { const copy = _('button', { title: `${thisHistory.deliveryLatitude} ${thisHistory.deliveryLongitude}`, classList: ['copyButton'] },)._('\uD83D\uDCCB').on('click', () => copyText(copy.title)); thisRow[10].$('p')?.before(copy); } //if (thisHistory.stateTime == historyData[i - 1]?.stateTime && thisHistory.packageState == historyData[i - 1]?.packageState && thisHistory.reasonCode == historyData[i - 1]?.reasonCode) return void (tr.classList.add('die'), newRow.tr.remove()); if (historytable.dataset.colours == 'OnRoad') { const serviceAreaId = sitemap && (thisHistory.destination && thisHistory.destination in sitemap ? sitemap[thisHistory.destination] : (thisHistory.source && thisHistory.source in sitemap ? sitemap[thisHistory.source] : undefined)); if (thisHistory.packageState == 'DELIVERED' && thisHistory.operation == 'PACKAGE_STATE_UPDATE') { tr.classList.add('delSuc'); newRow.tr.classList.add('delSuc'); newRow.td._( ...(thisHistory.recipientName ? [_('span')._(`${s('delTo')}: ${thisHistory.recipientName} (${S(thisHistory.reasonCode.replace('DELIVERED_TO_', '').replace('_', ' ')).toWordCase().trim()})`, _('br'))] : []), packageData.pddDate && (packageData.pddYMDKey >= thisHistory.YMDKey ? _('span', { classList: ['goodTime'] })._(`\u2713 ${s('metPDD')}`) : _('span', { classList: ['badTime'] })._(`\u2717 ${s('missPDD')}`)), packageData.eadDate && (packageData.eadYMDKey >= thisHistory.YMDKey ? _('span', { classList: ['goodTime'] })._(`\u2713 ${s('metEAD')}`) : _('span', { classList: ['poorTime'] })._(`\u2717 ${s('missEAD')}`)), geoPromise.status == 'fulfilled' && thisHistory.deliveryLatitude && thisHistory.deliveryLongitude && distanceNode(thisHistory.deliveryLatitude, thisHistory.deliveryLongitude) ); } if (thisHistory.packageState == 'DELIVERY_FAILED' && thisHistory.operation == 'PACKAGE_STATE_UPDATE') { tr.classList.add("delFail"); newRow.tr.classList.add('delFail'); newRow.td._( _('span')._(thisHistory.reasonCode == 'BUSINESS_CLOSED' && gamPromise.status == 'fulfilled' && gamData && gamData.hourText ? `${s('BH')}\u2002${gamData.hourText}` : thisHistory.reason), geoPromise.status == 'fulfilled' && thisHistory.deliveryLatitude && thisHistory.deliveryLongitude && distanceNode(thisHistory.deliveryLatitude, thisHistory.deliveryLongitude) ); } if (thisHistory.operation == 'ROUTE_ASSIGNMENT') { const buttons = _('span'), startTime = _('span'), deliveryTime = _('span'); newRow.td._( _('span')._(_('strong')._(`${s('Route')} ${thisHistory.routeCode}`)), buttons, startTime, deliveryTime ); // serviceAreaId && buttons._(_('button')._(s('cortexLinkRoute')).on('click', () => buttonclick(`${globalOrigin}/internal/operations/execution/dv/routes?provider=ALL_DRIVERS&selectedDay=${thisHistory.dateISO}&serviceAreaId=${serviceAreaId}&summariesText=${thisHistory.routeCode}`))); new Promise((ok, x) => { if (!serviceAreaId) { x('No serviceAreaId'); throw 'No serviceAreaId'; }; if (!(thisHistory.timestamp.getTime() > (now - 14 * 24 * 60 * 60 * 1000))) { x('Too old'); throw 'Too old'; }; XHR('GET', `${globalOrigin}/internal/operations/execution/api/route-summaries?localDate=${thisHistory.dateISO}&serviceAreaId=${serviceAreaId}`).then(json).then(cortex => { debuglog('cortex XHR()', cortex); cortex.rmsRouteSummaries.filter((route) => route.routeCode == thisHistory.routeCode).forEach((route) => { debuglog(route); routeVisButton(route.routeId, buttons, thisHistory.timestamp); return XHR('GET', `${globalOrigin}/internal/operations/execution/api/routes/${route.routeId}`).then(json).then(cortex => { debuglog('inner cortex XHR()', cortex); if (cortex.routePlan.plannedStartTime) { startTime.__(`${s('plannedStartTime').replace('{{time}}', toLocaleTZString(cortex.routePlan.plannedStartTime, packageData.stationTimeZone))}`); } cortex.routePlan.stopList.filter((stop) => stop.stopPlanContext.stopType == 'DropOff').forEach((stop, i) => { stop.stopDetails.packageList.filter((package) => package.scannableId == page.trackingId).forEach((package) => { if (package.plannedDeliveryTime) { deliveryTime.__(`${s('plannedTime').replace('{{time}}', toLocaleTZString(package.plannedDeliveryTime, packageData.stationTimeZone))}`); } return XHR('POST', `${globalOrigin}/internal/operations/execution/api/trs/trDetails`, { "trAndObjectState": [{ "trId": package.trId, "objectState": package.trObjectState }] }).then(json).then(packData => { debuglog('package cortex XHR()', packData); packData.trStateDetails.filter((stateDetails) => stateDetails.packageNotes).forEach((stateDetails) => stateDetails.packageNotes.forEach((notes) => { debuglog(notes); notes.noteContent.forEach((/** @type {string} */ noteText) => newCustNote(noteText.replace(/\\\\\\\\r/gim, '\r').replace(/\\\\\\\\n/gim, '\n'), toWeekdayDateString(thisHistory.timestamp), `Cortex ${notes.packageNoteType}`)); })); ok('Got Cortex Data'); }).catch(x); }); }); }).catch(x); }); }).catch(x); }).then(debuglog, (e) => { debuglog('Skipping Route Cortex: ', e, thisHistory); logBox._(_('span')._('Skipping Route Cortex: ', JSON.stringify(e))); XHR('GET', `https://routingtools-viz-${page.regionCode}.${page.regionCode}.proxy.amazon.com/route/query.json?query=%7B%22routeCodeTime%22:%22${thisHistory.dateISO}%22,%22stationCode%22:%22${thisHistory.source}%22,%22type%22:%22ROUTE_CODE%22,%22routeCode%22:%22${thisHistory.routeCode}%22%7D`).then(response => { debuglog('routeVisXHR()'); routeVisButton(response.json()?.routes?.[0]?.unitPlanIdentifier, buttons, thisHistory.timestamp); }).catch(debuglog); }); } if (thisHistory.operation == 'DRIVER_ASSIGNMENT') { const amConsoleBut = _('button')._(thisHistory.driverId), dspSpan = _('span'), cortexButtons = _('span'), plannedTime = _('span'), windowTime = _('span'); newRow.td._( thisHistory.driverName && _('span')._(`${s('Driver')} ${thisHistory.driverName}`), thisHistory.driverId && [amConsoleBut, dspSpan], cortexButtons, plannedTime, windowTime ); if (thisHistory.driverId) { amConsoleBut.on('click', () => buttonclick(`${globalOrigin}/amconsole/transporter/${thisHistory.driverId}`)); XHR('GET', `${globalOrigin}/amconsole/da/dsp-info/template?id=${thisHistory.driverId}&type=transporter`).then(response => { if (response.text && S(response.text).contains('Business Name:')) { dspSpan.__(response.text.split('Business Name:')?.[1]?.split('>')?.[1]?.split(' buttonclick(`${globalOrigin}/internal/operations/execution/dv/routes?provider=ALL_DRIVERS&selectedDay=${thisHistory.dateISO}&serviceAreaId=${serviceAreaId}&summariesText=${thisHistory.driverId}`))); new Promise((ok, x) => { if (!serviceAreaId) { x('No serviceAreaId'); throw 'No serviceAreaId'; }; XHR('GET', `${globalOrigin}/internal/operations/execution/api/summaries?localDate=${thisHistory.dateISO}&serviceAreaId=${serviceAreaId}`).then(json).then(cortex => { cortex.itinerarySummaries?.filter((itinerary) => itinerary.transporterId == thisHistory.driverId).forEach((itinerary) => { cortexButtons._(_('button')._(s('cortexItinerary')).on('click', () => buttonclick(`${globalOrigin}/internal/operations/execution/itineraries/${itinerary.itineraryId}/documentType/Itinerary?operationView=true&selectedDay=${thisHistory.dateISO}&serviceAreaId=${serviceAreaId}`))); return XHR('GET', `${globalOrigin}/internal/operations/execution/api/itineraries/${itinerary.itineraryId}?documentType=Itinerary&itineraryId=${itinerary.itineraryId}`).then(json).then(cortex => { let offset = 0; cortex.itineraryDetails.stops.forEach((stop) => { if (!stop.sequenceNumber) { offset++; } stop.tasks.filter((task) => task.taskType == 'DROP_OFF' && task.domainMap.scannableId == page.trackingId).forEach((task) => { if (stop.sequenceNumber) cortexButtons._(_('button')._(s('cortexLinkStop').replace('{{stop#}}', stop.sequenceNumber)).on('click', () => buttonclick(`${globalOrigin}/internal/operations/execution/itineraries/${itinerary.itineraryId}/documentType/Itinerary/stops/${stop.sequenceNumber - 1 + offset}?operationView=true&selectedDay=${thisHistory.dateISO}&serviceAreaId=${serviceAreaId}`))); if (stop.plannedStartTime || stop.plannedEndTime) { plannedTime._(`\u2003${s('plannedTime').replace('{{time}}', `${toLocaleTZString(stop.plannedStartTime, packageData.stationTimeZone)} - ${toLocaleTZString(stop.plannedEndTime, packageData.stationTimeZone)}`)}`); } else if (task.expectedExecutionTime) { plannedTime._(`\u2003${s('plannedTime').replace('{{time}}', toLocaleTZString(task.expectedExecutionTime, packageData.stationTimeZone))}`); } if (task.timeWindowed && (task.windowStartTime || task.windowEndTime)) { windowTime._(`\u2003${s('windowTime').replace('{{time}}', `${toLocaleTZString(1000 * task.windowStartTime, packageData.stationTimeZone)} - ${toLocaleTZString(1000 * task.windowEndTime, packageData.stationTimeZone)}`)}`); } return ok('Got Cortex Data'); }); }); }).catch(x); }); }).catch(x); }).catch(e => { debuglog('Skipping Driver Cortex: ', e, thisHistory); logBox._(_('span')._('Skipping Driver Cortex: ', JSON.stringify(e))); }); } } S(thisHistory.destination).contains('CUSTOMER_ADDRESS') && (thisHistory.operation == 'PACKAGE_STATE_UPDATE' || thisHistory.operation == 'ASSOCIATE_DEBRIEF') && (thisHistory.packageState == 'RECEIVED' || thisHistory.packageState == 'MARKED_FOR_REPROCESS') && tr.classList.add("rts"); } if (historytable.dataset.colours == 'InStation') { if (thisHistory.operation == 'PACKAGE_STATE_UPDATE') { thisHistory.packageState == 'INDUCTED' && tr.classList.add('delSuc'); thisHistory.packageState == 'STOWED' && tr.classList.add('delFail'); thisHistory.packageState == 'PICKED' || thisHistory.packageState == ('STAGED') && tr.classList.add('rts'); S(thisHistory.destination).contains('CUSTOMER_ADDRESS') && (thisHistory.packageState == 'RECEIVED' || thisHistory.packageState == 'MARKED_FOR_REPROCESS') && tr.classList.add('delSuc'); thisHistory.reasonCode == 'STOW_INVALID_SCAN_DONE' && tr.classList.add('endFail'); } else if (thisHistory.operation == 'SIDELINED') { tr.classList.add('delFail', 'bold4'); } } if (thisHistory.packageState == 'IN_TRANSIT' && thisHistory.operation == 'PACKAGE_STATE_UPDATE') { tr.classList.add("oor"); thisRow[2].$('div')?._(svg(S(thisHistory.destination).contains('CUSTOMER_ADDRESS') ? 'van' : thisHistory.destination?.[0] == 'D' ? 'in_trailer' : 'trailer')); } thisHistory.packageState == 'INDUCTED' && thisHistory.operation == 'PACKAGE_STATE_UPDATE' && thisRow[2].$('div')?._(svg('avery', thisHistory.scanLocation)); if (thisHistory.operation == 'CANCELLED_BY_CUSTOMER' || (thisHistory.packageState == 'MARKED_FOR_REPROCESS' && thisHistory.destination == 'MIDDLE_MILE_NODE') || ['MARKED_FOR_PROBLEM', 'DELIVERY_REJECTED', 'MARKED_AS_MISSING', 'MARKED_AS_LOST', 'DISPOSED'].includes(thisHistory.packageState) || ['WRONG_NODE', 'OBJECT_MISSING', 'DAMAGED_FC_RETURN', 'LOCALLY_DISPOSED'].includes(thisHistory.reasonCode)) { tr.classList.add('endFail'); newRow.tr.classList.add('endFail'); } if (S(thisHistory.user).contains('@')) { const username = thisHistory.user.split('@')[0]; thisRow[6].$('div')?._(_('a', { href: `https://fclm-portal.amazon.com/employee/ppaTimeDetails?employeeId=${username}`, target: '_blank', classList: ['minibadge'] })._(_('img', { src: `https://internal-cdn.amazon.com/badgephotos.amazon.com/?login=${username}`, loading: 'lazy', classList: ['minibadge'] },))); } if (thisHistory.scanContainer && S(thisHistory.scanContainer).contains('EU_')) { thisRow[2].$('div')?._(svg('bag', thisHistory.scanContainer, thisHistory.scanContainer.slice(-3))); } if ((S(thisHistory.scanContainer).containsAny('OVER-', 'CRT2-', '_DOLLY_')) || (thisHistory.packageState == 'PICKED' && S(thisHistory.scanLocation).contains('CRT2-'))) { thisRow[2].$('div')?._(svg('cart', thisHistory.scanLocation)); } if (thisHistory.imageUrl) { const photoImg = _('img', { src: thisHistory.imageUrl, loading: 'lazy', classList: ['photoImg', 'hide'] }); newRow.td._(_('button')._('Show/Hide Photo').on('click', () => { photoImg.classList.toggle('hide'); }), photoImg); } setTimeout(() => newRow.td.textContent == '' && newRow.tr.remove()); })); }).catch((e) => promises.topBar.then(improveBoxes => { debuglog('histTableError', e); improveBoxes.histTableError.__(`${e}`); })))); function outbound() { debuglog('outbound()'); wait$('#root').then(root => { document.documentElement.dataset.improveSccCssOutboundPage = ''; new MutationObserver(() => queueMicrotask(() => { const thead = $('thead'), tbody = $('tbody'); if (!thead || !tbody) return; const [badgeCol, cartCol, driverCol] = thead?.$$('th').map(th => S(th?.innerText)).reduce(([badgeCol, cartCol, driverCol], th, i) => [ th.dictContains('associate') ? i + 1 : badgeCol, th.dictContains('cartID') ? i + 1 : cartCol, th.dictContains('driver') ? i + 1 : driverCol ], [0, 0, 0]); debuglog(badgeCol, cartCol, driverCol); tbody?.$$('tr').forEach(tr => { if (badgeCol) { tr.$$(`td:nth-child(${badgeCol}) a`).forEach(a => { if (a?.$('input')) return; if (a?.$('img') || a?.parentNode?.querySelector('img')) { a?.classList.add('badge'); return; } [...a?.parentNode?.childNodes ?? []].filter((text) => (text.nodeName == '#text')).forEach((text) => text.remove()); miniBadge(a, 1); }); } if (driverCol) { const driver = tr.$(`td:nth-child(${driverCol}) span > p[mdn-text][title]`); if (driver?.classList) { driver.parentNode?.append(_('a', { href: `${globalOrigin}/amconsole/transporter/${driver.title}`, target: '_blank' })._(driver)); } } }); })).observe(root, { characterData: true, attributes: false, childList: true, subtree: true }); }); } function associate() { debuglog('associate()'); document.documentElement.dataset.improveSccCssBadgesPage = ''; if (hrefContains('receive')) { const tabs = $$("[role=tablist] label"); if (!tabs.length) { setTimeout(associate, 500); return; } debuglog(tabs); tabs.at(-1)?.do('click'); page.region = window.location.href.split('ivs')[1].split('.')[0]; document.documentElement.dataset.improveSccCssReceivePage = ''; wait$('#root').then(root => new MutationObserver(() => setTimeout(() => { $$('#root table tbody > tr > [scope=row]:first-child:not(.fmcload)').forEach(td => { debuglog(td); td.classList.add('fmcload'); const vrId = td.textContent; XHR('GET', `https://trans-logistics${page.region == 'na' ? '' : `-${page.region}`}.amazon.com/fmc/api/v2/execution/load/${vrId}/mapFeature/stops`).then(json).then(responseJSON => { td.title = responseJSON.reduce((prev, next) => `${prev}${next.timelineEvent.title}:\n${next.timelineEvent.stopActions.reduce((prev, next) => `${prev}${next.actualCompletedTime?.utcMillis ? `\u2003${next.yardActionType} - ${toWeekdayDateTimeString(next.actualCompletedTime?.utcMillis)}\n` : ''}`, '')}\n`, ''); td.classList.add('fmcdone'); }); }); })).observe(root, { characterData: true, attributes: false, childList: true, subtree: true })); return; } // if (hrefContains('induct')) return; if (hrefContains('packageList')) { packageList(); return; }// WIP does not work yet. wait$('#root').then(root => { setInterval(() => root.append(mutationComment), 6000); new MutationObserver(() => { setTimeout(() => { const badgeCol = $$('thead th').reduce((/**@type {false | number}*/bool, th, i) => bool || S(th?.innerText).dictContains('associate') && i + 1, false); if (!badgeCol) return; $$(`tbody tr :is(th, td):nth-child(${badgeCol}) span`).forEach(a => { if (a?.$('input')) return; if (a?.$('img')) { a?.classList.add('badge'); return; } miniBadge(a, 0); }); }); }).observe(root, { characterData: true, attributes: false, childList: true, subtree: true }); }); } function packageList() { debuglog('packageList()'); wait$('tbody').then(tbody => { $('thead tr')?._(_('th', { classList: ['css-1j7l84d'] })._(_('span')._('PDD'))); packageListXHR(); new MutationObserver(packageListXHR).observe(tbody, { characterData: true, attributes: false, childList: true, subtree: true }); }); } function psTab() { debuglog('psTab()'); document.documentElement.dataset.improveSccCssBadgesPage = ''; wait$('body').then(body => { new MutationObserver(() => setTimeout(() => { const badgeCol = $('thead')?.$$('th').reduce((/**@type {false | number}*/badgeCol, th, i) => badgeCol || S(th?.innerText).dictContains('Reportedby') && (i + 1), false); badgeCol && $('tbody')?.$$('tr').forEach(tr => { debuglog(tr); const a = tr.$(`td:nth-child(${badgeCol}) span`); if (a?.$('img')) { a.classList.add('badge'); return; } a && miniBadge(a, 0); }); })).observe(body, { characterData: true, attributes: false, childList: true, subtree: true }); }); debuglog('psTab - MO - Start'); } //#endregion //#region: XHR Functions /** @type {() => Promise} */ function getPackageData() { debuglog('getPackageData()'); return XHR('POST', `${globalOrigin}/station/proxyapigateway/data`, { "resourcePath": "/os/getPackageDetailData", "httpMethod": "get", "processName": "oculus", "requestParams": { "trackingId": [page.trackingId] } }).then(response => { debuglog('getPackageDataXHR()'); const packageData = response.json().packageDetail.packageData; packageData.amxl = S(packageData.shipInfo.shipMethod).contains('_SH'); packageData.pddDate = packageData.shipInfo.promisedDeliveryTime ? D(packageData.shipInfo.promisedDeliveryTime) : undefined; packageData.eadDate = packageData.shipInfo.estimatedArrivalTime ? D(packageData.shipInfo.estimatedArrivalTime) : undefined; packageData.pddYMDKey = packageData.pddDate?.toYMDKey(); packageData.eadYMDKey = packageData.eadDate?.toYMDKey(); packageData.oversize = ((m, l, w, h) => { packageData.volume = l * w * h; packageData.letterbox = (h <= 3.8 && w <= 25.4); return (m > 5 || packageData.volume > 50000 || l > 73 || w > 73 || h > 73 || (l > 53 && (w > 40 || h > 40)) || (w > 53 && (l > 40 || h > 40)) || (h > 53 && (w > 40 || l > 40)) ); })( packageData.packageDimensions.packageWeight.unit == 'ounces' ? 0.02834952 * packageData.packageDimensions.packageWeight.value : packageData.packageDimensions.packageWeight.value, packageData.packageDimensions.packageLength.value, packageData.packageDimensions.packageWidth.value, packageData.packageDimensions.packageHeight.value ); packageData.pcd = packageData.customerInfo.customerAddress?.split(',')?.slice(-1)[0]; superlog('package', packageData); return packageData; }); } /** @type {([improveRoot, packageData]:[ImproveRoot, PackageData]) => ImproveBoxes} */ function usePackageData([improveRoot, packageData]) { debuglog('usePackageData()', improveRoot, packageData); const improveBoxes = /** @type {ImproveBoxes} */(improveRoot); document.documentElement.dataset.improveSccXhr = ''; if (packageData.shipInfo.itemDescription) { improveBoxes.items.__(packageData.shipInfo.itemDescription); }; addButton(`https://sim.amazon.com/issues/search?q=(${packageData.orderInfo.orderId}+OR+${packageData.trackingId})&sort=lastUpdatedConversationDate`, s('SIM'), -1, { id: 'SIM' }); if (packageData.amxl && page.region == 'na') { addButton(`http://amxl-ba.corp.amazon.com/Passage/#${packageData.trackingId}`, s('Passage'), 2); } colourResult(packageData.shipInfo.shipMethod, improveBoxes.head); improveBoxes.head.__( _('div')._( improveBoxes.trackingId = _('h1')._(page.trackingId).on('click', () => copyText(page.trackingId)), _('div')._(_('strong')._(s('shipMethod')), packageData.shipInfo.shipMethod), _('div')._(_('strong')._(s('shipOption')), packageData.shipInfo.shipOption), // packageData.serviceType?.length && _('div')._(_('strong')._(s('serviceType')), packageData.serviceType) : undefined, packageData.orderInfo.orderId && (improveBoxes.orderId = _('div', { id: 'oid', classList: [S(packageData.orderInfo.orderId).containsAny('VRET', 'S02-') ? 'vret' : undefined] })._(_('strong')._(s('oId')), packageData.orderInfo.orderId).on('click', () => copyText(packageData.orderInfo.orderId))), // improveBoxes.customerId = _('div')._(_('strong')._(s('customerId')), improveBoxes.customerIdText = _('span')._('…')).on('click', () => copyText(improveBoxes.customerIdText.innerText)), packageData.linkedTrackingIds.map((linktid) => _('div', { classList: ['linktid'] })._(_('strong')._(s('lTId')), _('a', { href: `${globalOrigin}/station/dashboard/search?shareableLink=detailPage%2F${linktid}`, target: '_blank' })._(linktid))), improveBoxes.multiPart = _('div'), ), _('div', { id: 'flags' })._( improveBoxes.OTP = packageData.hasOtp ? _('strong', { id: 'OTP', style: { color: 'red' } })._(s('OTP')) : undefined, (S(packageData.shipInfo.shipMethod).contains('AGEVER') || packageData.isAvdPackage) && _('strong', { style: { color: 'red' } })._(s('AVD')), packageData.isHazmat && _('strong', { style: { color: 'darkorange' } })._(s('HAZMAT')), packageData.orderInfo.orderAmount >= ((cur) => cur == 'INR' ? 10000 : cur == 'JPY' ? 20000 : cur == 'BRL' ? 500 : 100)(packageData.orderInfo.orderCurrency) && _('strong', { style: { color: 'forestgreen' } })._(s('HV').replace(/ /g, '\u00a0')), (packageData.amxl ? [_('strong', { style: { color: 'royalblue' } })._('AMXL')] : [ packageData.letterbox && _('strong', { style: { color: 'royalblue' } })._(s('LB')), (packageData.oversize || packageData.isOv) && _('strong', { style: { color: 'royalblue' } })._(s('OVER')), packageData.packageDimensions.packageWeight.value > 20 ? _('strong', { style: { color: 'royalblue' } })._(s('VH').replace(/ /g, '\u00a0')) : packageData.packageDimensions.packageWeight.value > 10 ? _('strong', { style: { color: 'royalblue' } })._(s('H')) : undefined ]) ), _('div')._( _('div')._(`${formatUnit(packageData.packageDimensions.packageLength)} x ${formatUnit(packageData.packageDimensions.packageWidth)} x ${formatUnit(packageData.packageDimensions.packageHeight)}`), _('div', { classList: ['spaced'] })._( _('span')._(`${packageData.volume.toFixed(0)}\u00a0cm³`), _('span')._(`${formatUnit(packageData.packageDimensions.packageWeight)}`), _('span')._(formatCurrency({ currency: packageData.orderInfo.orderCurrency, value: packageData.orderInfo.orderAmount })) ), improveBoxes.fc = _('div', { id: 'fcBox' }), packageData.eadDate && _('div')._(_('strong')._('EAD:'), `\u2002${toWeekdayDateTimeString(packageData.eadDate)}`), packageData.pddDate && _('div')._(_('strong')._('PDD:'), `\u2002${(['AMZN_DE_SAME_SD', ' AMZN_ES_SAME_SD', 'AMZN_FR_SAME_SD', 'AMZN_IT_SAME_SD', 'AMZN_UK_SAME_SD'].includes(packageData.shipInfo.shipMethod) && packageData.shipInfo.shipOption == 'rush' ? toWeekdayDateString : toWeekdayDateTimeString)(packageData.pddDate)}`), !!(packageData.shipInfo.scheduledDeliveryTime && packageData.shipInfo.scheduledDeliveryTimeEnd) && _('div', { classList: ['simple-flex'] })._(_('strong')._('Scheduled:'), _('span')._(_('div')._(toWeekdayDateTimeString(packageData.shipInfo.scheduledDeliveryTime, packageData.stationTimeZone)), _('div')._(toWeekdayDateTimeString(packageData.shipInfo.scheduledDeliveryTimeEnd, packageData.stationTimeZone)))) ), improveBoxes.customerCol = _('div', { id: 'customerColumn' })._( _('div')._(packageData.customerInfo.customerName), _('div')._(packageData.customerInfo.customerAddress.replace(/,/g, ', ').replace(/\s+/g, ' ')), _('strong')._(packageData.customerInfo.customerAddressType), improveBoxes.nak = _('div', { id: 'NAK' }), improveBoxes.phr = _('div', { id: 'PHR' }), _('strong')._('Customer Notes:'), improveBoxes.notes = _('div', { id: 'custNotes' })._(...packageData.customerNotes.map((note) => custNoteDiv(note.customerNoteContent, note.dateAdded))) ) ); if (packageData.amxl) { XHR('POST', `${globalOrigin}/station/proxyapigateway/data`, { "resourcePath": "/os/batchGetPackageSummary", "httpMethod": "post", "processName": "oculus", "requestBody": { "idType": "TRACKING_ID", "identifiers": [packageData.orderInfo.orderId], "nodeId": packageData.routeInfo.stationCode, "includeFields": [] } }).then(json).then(searchResult => { const items = searchResult.packageSummaryList.filter((resultRow) => (page.trackingId != resultRow.trackingId)).map((resultRow) => _('a', { href: `${globalOrigin}/station/dashboard/search?shareableLink=detailPage%2F${resultRow.trackingId}`, target: '_blank' })._(resultRow.trackingId)); if (items.length) improveBoxes.multiPart.__(s('sameOrderID'), items); }); } return improveBoxes; } /** @type {() => Promise} */ function siteMap() { let sitemap; if ((sitemap = localStorage.getItem('sitemap')) && (sitemap = JSON.parse(sitemap)) && (sitemap.timestamp > now - 7 * 24 * 60 * 60 * 1000) && sitemap.hasOwnProperty('data')) { return Promise.resolve(sitemap); } return XHR('GET', `${globalOrigin}/flex/api/getOperationalRegions`).then(response => { debuglog('sitemap', response); const sitemap = { timestamp: now, data: {} }; response.json().forEach((region) => region.basicServiceAreas.forEach((site) => (sitemap.data[site.defaultStationCode] = site.serviceAreaID))); localStorage.setItem('sitemap', JSON.stringify(sitemap)); return sitemap; }, error => { if ('text' in error) delete error.text; throw error; }); } /** @type {() => Promise} */ function getGeoData() { debuglog('getGeoData()'); return XHR('POST', `https://api-gam.${page.region}.prod.geostudio.last-mile.amazon.dev/api/getAddressInfo`, { "id": page.trackingId, "idType": "Auto", "gdeView": "" }).then(json, json).then(geoData => { debuglog('geoData', geoData); const message = (geoData.message ?? geoData.Message); if (message == 'Unauthenticated' || S(message)?.contains('not authorized')) throw message; /**@type {GeoData} */ const returnGeoData = Object.assign({ deliveryHint: geoData.deliveryHint, nak: (geoData?.geocodingServiceResult ?? geoData?.geospatialData)?.scope10NAK ?? geoData?.geocodingServiceResult?.scope10NAK, phr: geoData?.preferredDeliveryLocations?.length && geoData?.preferredDeliveryLocations?.reduce((a, b) => `${a}, ${b}`), }, ((geoData?.geocodingServiceResult ?? geoData?.geospatialData)?.bestDeliveryPoint ?? geoData?.addressServiceGeocode)?.coordinates); returnGeoData.validLatLon = !(returnGeoData.latitude === undefined || returnGeoData.latitude === null || returnGeoData.longitude === undefined || returnGeoData.longitude === null); if (returnGeoData.validLatLon) { return returnGeoData; } throw `Geo data has invalid lat/lon: ${JSON.stringify(geoData)}`; }).catch(e => { throw e; }); } /** @type {([improveBoxes, geoData]:[ImproveBoxes, GeoData]) => void} */ function useGeoData([improveBoxes, geoData]) { superlog('useGeoData()', geoData); if (geoData.nak) { improveBoxes.nak._(_('strong')._('NAK:\u2002'), geoData.nak.replace(/(\!+)/g, ' $1 ')); } if (geoData.phr) { improveBoxes.phr._(_('strong')._('Safe Place(s):\u2002'), geoData.phr); } if (!geoData.validLatLon) return; improveBoxes.buttons._(($('#latlonbuts') || _('div', { id: 'latlonbuts', style: { order: `${4}` } })).__( s('LatLon'), miniButton(`http://maps.google.com/maps?t=h&q=loc:${geoData.latitude}+${geoData.longitude}`), miniButton(`https://bing.com/maps?style=a&where1=${geoData.latitude} ${geoData.longitude}`), miniButton(`https://www.openstreetmap.org/#map=17/${geoData.latitude}/${geoData.longitude}`), miniButton(`https://duckduckgo.com/?iaxm=maps&q=${geoData.latitude}+${geoData.longitude}`), miniButton(`https://explore.osmaps.com/en?lat=${geoData.latitude}&lon=${geoData.longitude}&zoom=16.0000`) )); } /** @type {(packageData:PackageData) => Promise} */ function getGAMData(packageData) { debuglog('getGAMData()'); return Promise.reject('GAM requests disabled'); const countryCode = packageData.shipInfo.shipMethod.split('_')[1]; return XHR('GET', `https://gamtools-${page.region}.aka.amazon.com/searchResults?searchId=${page.trackingId}&idType=TRACKING_ID&countryCode=${countryCode == 'UK' ? 'GB' : countryCode}`).then(response => { try { return response.json(); } catch (e) { throw response.text; } }).then(json => { debuglog('gam', json); if (!('step_up_methods' in json)) { throw 'Unknown JSON'; } if (midwayWindow == null || midwayWindow == undefined || midwayWindow.closed) { midwayWindow = window.open(json.step_up_methods[0].cap_url, 'midwayAuth', 'width=1200, height=800'); if (midwayWindow == null || midwayWindow == undefined || midwayWindow.closed) { throw 'Midway Popup Blocked'; } } midwayWindow.focus(); throw (json.step_up_methods[0].cap_display_string || 'Please login with Midway'); }, text => { debuglog('gam', text); if (text.contains("Oops, something has gone wrong") || text.contains("not authorized")) { return { hourText: undefined }; } if (text.contains('is not yet in GAM. Addresses may take a few days to reflect.')) { return { hourText: s('GAM404') }; } const gam = _('html', { innerHTML: text.replace(/\/gim, '') }); let hoursList = []; hoursList.push(...gam.$$("#canonicalAttributes div.canonical-attribute-values > b"), ...gam.$$("#Business-Hours-canonical-values > b")); return { unitImg: gam.$("img.unit-icon")?.src, hourText: hoursList.filter(b => S(b.innerText.replace(/ /gim, '').slice(0, 3)).inDict('GAMdays') && Number.isNaN(Number(b.innerText.slice(0, 4)))).map(b => b.innerText).join('\u2003') || s('GAMnoHours'), hintText: gam.$$('#canonicalAttributes li').reduce((hintText, li) => `${hintText}${S(li.innerText).contains('Delivery Hint') && li.$('b') ? li.$('b')?.innerHTML : ''}`, '') }; }); } /** @type {([improveBoxes, gamData, historyData]:[ImproveRoot, GAMData, HistDataRow[]]) => void} */ function useGAMData([improveBoxes, gamData, historyData]) { superlog('useGAMData()', gamData); addButton(`https://gamtools-${page.region}.aka.amazon.com/search?searchId=${page.trackingId}&idType=TRACKING_ID`, s('GAM'), 2); const bizClosed = historyData.filter((row) => row.reasonCode == 'BUSINESS_CLOSED'); gamData.hourText !== null && improveBoxes.gam.__(`${s('Hours')} ${gamData.hourText}`, !!bizClosed.length && _('div', { id: 'gamfail' })._(`${s('FailedAttempt')}\u2003`, bizClosed.map(row => toWeekdayDateString(row.stateTime)).join(' | '))); gamData.hintText && newCustNote(gamData.hintText, null, s('GAMhint')); } // function getTaxonomy([improveBoxes, eeData]) { // XHR('GET', `https://transportation-taxonomy-${page.regionCode}.aka.amazon.com/loadContainer?containerId=${eeData.tcdaId}&versionNumber=`).then(response => response.text.replace(/\s+/gim, ' ')).then(responseText => { // debuglog(responseText); // if (responseText.contains('Content is hidden because of Access control on Transportation Taxonomy')) { throw 'No Access to Transportation Taxonomy'; } // try { // let tempText = responseText.split('"transactionType":')[1].split(',')[0].replaceAll('\\', '').replaceAll('"', '').trim(); // if (tempText == 'null') { throw ''; } // improveBoxes.transactionType.__(tempText); // } catch (e) { improveBoxes.transactionType.remove(); } // try { // improveBoxes.replacementType.__(responseText.split('"replacementType":')[1].split(',')[0].replaceAll('\\', '').replaceAll('"', '').trim()); // } catch (e) { improveBoxes.replacementType.remove(); } // const fragments = responseText.split('java.util.HashMap'); // new Promise((resolve, reject) => { fragments.filter((fragment) => fragment.contains('OTPRequired')).forEach((fragment) => fragment.split(',').filter((HashMap) => HashMap.contains('OTPRequired') && HashMap.contains('true')).forEach(resolve)); reject(); }).then( // () => { improveBoxes.OTP.__(s('OTP')); improveBoxes.SIG.remove(); }, // () => new Promise((resolve, reject) => { fragments.filter((fragment) => fragment.contains('SignatureRequired')).forEach((fragment) => fragment.split(',').filter((HashMap) => HashMap.contains('SignatureRequired') && HashMap.contains('true')).forEach(resolve)); reject(); }).then( // () => { improveBoxes.SIG.__(s('SIG')); improveBoxes.OTP.remove(); }, // () => new Promise((resolve, reject) => { responseText.split('"name":"ServiceOfferings"').filter((fragment) => fragment.split('"targetEntityName":')[1]?.contains('"OTP"')).forEach(resolve); reject(); }).then( // () => { improveBoxes.OTP.__(s('OTP')); improveBoxes.SIG.remove(); }, // () => { improveBoxes.OTP.remove(); improveBoxes.SIG.remove(); } // ) // ) // ); // }).catch(e => { // improveBoxes.OTP.remove(); // improveBoxes.SIG.remove(); // improveBoxes.taxonomyError._('No OTP or Sig Data: ', e); // }); // } // function getOBLT() { // debuglog('getOBLT()'); // return XHR('GET', `https://trans-app-prod-${page.region}.amazon.com/outboundLookup/packageLookup.cgi?submitForm=Submit;data_type=TRACKING_ID;id=${page.trackingId}`).then(response => response.text).then(html => { // const oblt_row = _('html', { innerHTML: html.replace(/\/gim, '') }).$$('table#resultsTable tr[rownum="0"] td'); // return { // fulfillmentShipmentId: oblt_row[3]?.textContent, // orderingShipmentId: oblt_row[5]?.textContent, // customerId: oblt_row[9]?.textContent, // FC: oblt_row[10]?.textContent // }; // }); // } // function useOBLTData([improveBoxes, obltData]) { // debuglog('useOBLTData()', obltData); // improveBoxes.customerIdText.__(obltData.customerId); // addButton(`https://hero.${page.region}.picking.aft.a2z.com/fc/${obltData.FC}/pick-events/customer-shipment/${obltData.fulfillmentShipmentId}`, s('Hero'), 1); // XHR('GET', `https://hero.${page.region}.picking.aft.a2z.com/api/fcs/${obltData.FC}/entities/type/CUSTOMER_SHIPMENT/id/${obltData.fulfillmentShipmentId}/events`).then(response => { // response.json().EventList.filter((event) => event.eventType == 'COMPLETE_PACKAGE').forEach((event) => { // XHR('GET', `https://hero.${page.region}.picking.aft.a2z.com/api/fcs/${obltData.FC}/entities/type/CUSTOMER_SHIPMENT/id/${obltData.fulfillmentShipmentId}/events/id/${event.requestId}/details/key/${encodeURIComponent(event.eventDetailsKey)}`).then(response => { // if (!response.text.contains('boxRecommendation=')) return; // improveBoxes.fc.__(_('strong')._('FC Box Recommendation: '), response.text.split('boxRecommendation=')[1].split(',')[0]); // }); // }); // }); // addButton(`https://slamops-dub.amazon.com/packageHistory/?warehouseId=${obltData.FC}&shipmentId=${obltData.fulfillmentShipmentId}`, s('SlamOps'), 1); // } /** @type {() => Promise} */ function getHistoryData() { debuglog('getHistoryData()'); return XHR('POST', `${globalOrigin}/station/proxyapigateway/data`, { "resourcePath": "/os/getPackageHistoryData", "httpMethod": "post", "processName": "oculus", "requestBody": { "packageId": page.trackingId, "pageSize": 100, "pageToken": null, "startTime": null, "endTime": null } }).then(json).then(({ packageHistory }) => packageHistory); } /** @type {(routeId: string, node: Extended, timestamp: ExtendedDate) => void} */ function routeVisButton(routeId, node, timestamp) { debuglog('routeVisButton()', routeId, node, timestamp); node._( _('button')._(s('RouteVis')).on('click', () => buttonclick(`https://routingtools-viz-${page.regionCode}.${page.regionCode}.proxy.amazon.com/route/routevisualize.jsp#/search?routeId=${routeId}`)), (timestamp.toMidnightLocal() < D().toMidnightLocal()) && _('button')._(s('RouteDiver')).on('click', () => buttonclick(`https://routediver-${page.regionCode}.${page.regionCode}.proxy.amazon.com/#?routeId=${routeId}`)), _('button')._(s('RouteEagle')).on('click', () => buttonclick(`https://global.eagle.routeiq.last-mile.amazon.dev/?routes=${routeId}®ion=${page.region?.toUpperCase()}`)) ); } function packageListXHR() { const searchXHRpayload = { "resourcePath": "/os/batchGetPackageSummary", "httpMethod": "post", "processName": "oculus", "requestBody": { "idType": "TRACKING_ID", /** @type {(string | undefined)[]} */ "identifiers": [], "nodeId": (/.*stationCode=([A-Z0-9]+).*/.exec(page.url[3]) || '')[1], "includeFields": [] } }, trMap = {}; $$('tbody tr').forEach(tr => { const tId = tr.$('td span')?.innerText; if (tr.tId == tId) return; tr.tId = tId; trMap[tId] = tr; searchXHRpayload.requestBody.identifiers.push(tId); tr.$('.pdd')?.remove?.(); tr.classList.remove('AVD', 'SWA', 'LOCK', 'SAME'); }); debuglog(searchXHRpayload); if (searchXHRpayload.requestBody.identifiers.length) { XHR('POST', `${globalOrigin}/station/proxyapigateway/data`, searchXHRpayload).then(json).then(searchResult => { searchResult.packageSummaryList.forEach((resultRow) => { const td = $(`row_${resultRow.trackingId} .pdd`) || _('td', { classList: ['pdd'] }); if (resultRow.promisedDeliveryDate) { td.__(_('div', { style: { display: 'inline-block', width: '140px' } })._(toWeekdayDateString(resultRow.promisedDeliveryDate))); } trMap[resultRow.trackingId]._(td); colourResult(resultRow.shipMethod, trMap[resultRow.trackingId]); }); }); } } const /** @type {Record} */ AWS_POD_REGION_MAPPING = { eu: "eu-west-1", na: "us-east-1", fe: "us-west-2" }; function getPODData() { promises.topBar.then(improveBoxes => { improveBoxes.podContainer.__('POD: Please wait…'); XHR('GET', `https://honeypot.amazon.dev/api/searchImageByIndex?input=${encodeURIComponent(JSON.stringify({ "imageIndex": page.trackingId, "imageType": "PHOTO_ON_DELIVERY", "searchBy": "TRACKING_ID", "region": AWS_POD_REGION_MAPPING[page.region ?? ''] }))}`).then(r => r.json(), r => r.json()).then((/** @type {PODResponse} */ data) => { improveBoxes.podContainer.__( _('div', { classList: ['button-align'] })._( _('button', { classList: ['close'] })._('X').on('click', () => improveBoxes.podContainer.__()), ), _('section')._( ('error' in data) ? data.error : data.result.data.imageList.length ? data.result.data.imageList.map( ({ imageInfo, imagePresignedUrl }) => _('div', { classList: ['pod-item'] })._( _('img', { src: imagePresignedUrl, classList: ['pod-img'] }), _('span')._(imageInfo.imageAttributeData.imageType), _('span')._(D(imageInfo.photographedDate * 1e3).toISODateTimeString()), _('span')._(imageInfo.metadataMap.REASON_CODE), _('div')._( _('span')._(`${formatUnit({ value: imageInfo.geocode.latitude, unit: 'degree' })}, ${formatUnit({ value: imageInfo.geocode.longitude, unit: 'degree' })}`), distanceNode(imageInfo.geocode.latitude, imageInfo.geocode.longitude)) ) ) : 'No Results Found' ) ); }).catch(e => improveBoxes.podContainer.__(JSON.stringify(e))); }); } //#endregion //#region: Mini Functions /** Add svg css */ _css(`svg[data-improve-scc-svg] { path { stroke-linecap: round; stroke-linejoin: round; } path.bag { stroke: black; fill-opacity: 0.75; } path.bag.out { fill-opacity: 1; } path.box { fill: #FF7F00; } path.tape { fill: #000000; } path.label { fill: #FFFFFF; } &.cart { path.cage { stroke: yellow; fill: none; } path.cage.floor { fill: #000000; } circle.wheel { fill: #7F7F7F; } } &.van { .van { fill: #232F3E; stroke: #0096D6; } .window { fill: white; stroke: #0096D6; } .smile { fill: #0096D6; stroke: #0096D6; } .wheel { fill: white; stroke: white; } path.wheelnut { fill: #0096D6; stroke: #0096D6; } } &:is(.trailer, .in_trailer) { path.cab { fill: #232f3e; stroke: black; } path.trailer { fill: #0096d6; stroke: black; } path.window { fill: #afafFF; stroke: black; } path.tsmile { fill: #ffffff; stroke: #ffffff; } circle.wheel { fill: #404040; stroke: black; } } &:is(.avery){ path.print { fill: black; } path.deco { fill: #bb0000; } path.clip { fill: #bbbb00; } } }`); /** @type {(type: string, title?: string?, colour?: string) => Extended} */ function svg(type, title, colour) { const svg = _svg('svg', { dataset: { improveSccSvg: '' }, attributeList: { viewBox: '0 0 60 60' }, classList: [type, 'bag', colour] })._(title && _svg('title')._(title)); switch (type) { case 'bag': svg.setAttribute('viewBox', '0 10 60 40'); svg._( _svg('path', { classList: ['bag', 'colour'], attributeList: { d: 'M 20,15 h 40 v 20 h -40 z' } }), _svg('path', { classList: ['bag', 'colour'], attributeList: { d: 'M 0,45 L 20,35 h 40 L 40,45 z' } }), _svg('path', { classList: ['bag', 'colour'], attributeList: { d: 'M 0,25 L 20,15 v 20 L 0,45 z' } }), _svg('path', { classList: ['bag', 'out', 'colour'], attributeList: { d: 'M 0,25 L 20,15 h 40 L 40,25 z' } }), _svg('path', { classList: ['bag', 'out', 'colour'], attributeList: { d: 'M 40,25 L 60,15 v 20 L 40,45 z' } }), _svg('path', { classList: ['box'], attributeList: { d: 'M 15,34 h 15 v 10 h -15 z' } }), _svg('path', { classList: ['box'], attributeList: { d: 'M 15,34 l 5,-5 h 15 l -5,5 z' } }), _svg('path', { classList: ['box'], attributeList: { d: 'M 30,34 l 5,-5 v 10 l -5,5 z' } }), _svg('path', { classList: ['tape'], attributeList: { d: 'M 21,34 h 3 v 10 h -3 z' } }), _svg('path', { classList: ['tape'], attributeList: { d: 'M 21,34 l 5,-5 h 3 l -5,5 z' } }), _svg('path', { classList: ['label'], attributeList: { d: 'M 19,33 l 3,-3 h 5 l -3,3 z' } }), _svg('path', { classList: ['label'], attributeList: { d: 'M 0,25 h 40 v 20 h -40 z' }, style: { stroke: '#000000', fillOpacity: '0.25' } }), ); break; case 'cart': svg._( _svg('title')._(title), _svg('circle', { classList: ['wheel'], attributeList: { r: '2', cx: '3', cy: '56' } }), _svg('circle', { classList: ['wheel'], attributeList: { r: '2', cx: '37', cy: '56' } }), _svg('circle', { classList: ['wheel'], attributeList: { r: '2', cx: '57', cy: '47' } }), _svg('path', { classList: ['cage'], attributeList: { d: 'M 20,45 v-40 h 40 v 40 z h 4 v -40 v 40 h 4 v -40 v 40 h 4 v -40 v 40 h 4 v -40 v 40 h 4 v -40 v 40 h 4 v -40 v 40 h 4 v -40 v 40 h 4 v -40 v 40 h 4 v -40 v 40z' } }), _svg('path', { classList: ['cage', 'floor'], attributeList: { d: 'M 0,55 l 20,-10 h 40 l -20,10 z' } }), _svg('path', { classList: ['cage'], attributeList: { d: 'M 0,15 l 20,-10 v 40 l -20,10 z l 4,-2 v 40 v -40 l 4,-2 v 40 v -40 l 4,-2 v 40 v -40 l 4,-2 v 40 v -40 z' } }), _svg('path', { classList: ['box'], attributeList: { d: 'M 25,44 h 15 v 10 h -15 z' } }), _svg('path', { classList: ['box'], attributeList: { d: 'M 25,44 l 5,-5 h 15 l -5,5 z' } }), _svg('path', { classList: ['box'], attributeList: { d: 'M 40,44 l 5,-5 v 10 l -5,5 z' } }), _svg('path', { classList: ['tape'], attributeList: { d: 'M 31,44 h 3 v 10 h -3 z' } }), _svg('path', { classList: ['tape'], attributeList: { d: 'M 31,44 l 5,-5 h 3 l -5,5 z' } }), _svg('path', { classList: ['label'], attributeList: { d: 'M 29,43 l 3,-3 h 5 l -3,3 z' } }), _svg('path', { classList: ['cage'], attributeList: { d: 'M 40,15 l 20,-10 v 40 l -20,10 z l 4,-2 v 40 v -40 l 4,-2 v 40 v -40 l 4,-2 v 40 v -40 l 4,-2 v 40 v -40 z' } }), ); break; case 'van': svg.setAttribute('viewBox', '-30 -30 60 60'); svg._( _svg('circle', { classList: ['van'], attributeList: { r: '6', cx: '-17.5', cy: '15' } }), _svg('circle', { classList: ['wheel'], attributeList: { r: '3', cx: '-17.5', cy: '15' } }), _svg('path', { classList: ['wheelnut'], attributeList: { d: 'M -17.5,15 l-0.5,-0.5 l 0.5,0.5 l 0.5,-0.5 l -0.5,0.5 l 0.5,0.5 l -0.5,-0.5 l -0.5,0.5 l 0.5,-0.5 z' } }), _svg('circle', { classList: ['van'], attributeList: { r: '6', cx: '17.5', cy: '15' } }), _svg('circle', { classList: ['wheel'], attributeList: { r: '3', cx: '17.5', cy: '15' } }), _svg('path', { classList: ['wheelnut'], attributeList: { d: 'M 17.5,15 l-0.5,-0.5 l 0.5,0.5 l 0.5,-0.5 l -0.5,0.5 l 0.5,0.5 l -0.5,-0.5 l -0.5,0.5 l 0.5,-0.5 z' } }), _svg('path', { classList: ['van'], attributeList: { d: 'M -27.5,15 v -15 l 15,-15 h 40 v 30 h -4 q 0,-6 -6,-6 q -6,0 -6,6 h -23 q 0,-6 -6,-6 q -6,0 -6,6 z' } }), _svg('path', { classList: ['window'], attributeList: { d: 'M -25,0 l 12.5,-12.5 v 12.5 z' } }), _svg('path', { classList: ['smile'], attributeList: { d: 'M -10,-7 q 15,10 30,2 q -15,12 -30,-2 m 28,0 q 7,-3 4,4 q 2,-6 -4,-4' } }), ); break; case 'in_trailer': svg._( _svg('path', { classList: ['cab'], attributeList: { d: 'M 60,45 v -10 l -15,-15 h -3 v 18 h -10 v 7 h 1 q 0,-3 3,-3 q 3,0 3,3 h 1 q 0,-3 3,-3 q 3,0 3,3 h 7 q 0,-3 3,-3 q 3,0 3,3 z' } }), _svg('path', { classList: ['trailer'], attributeList: { d: 'M 30.5,45 v -8.5 h 10 v -20.5 h -40 v 29 h 1 q 0,-3 3,-3 q 3,0 3,3 h 1 q 0,-3 3,-3 q 3,0 3,3 h 7 q 0,-3 3,-3 q 3,0 3,3 z' } }), _svg('path', { classList: ['window'], attributeList: { d: 'M 57.5,35 l -12.5,-12.5 v 12.5 z' } }), _svg('path', { classList: ['tsmile'], attributeList: { d: 'M 3,25 q 15,10 30,2 q -15,12 -30,-2 m 28,0 q 7,-3 4,4 q 2,-6 -4,-4' } }), _svg('circle', { classList: ['wheel'], attributeList: { r: '2', cx: '56', cy: '45.5' } }), _svg('circle', { classList: ['wheel'], attributeList: { r: '2', cx: '43', cy: '45.5' } }), _svg('circle', { classList: ['wheel'], attributeList: { r: '2', cx: '36', cy: '45.5' } }), _svg('circle', { classList: ['wheel'], attributeList: { r: '2', cx: '24.5', cy: '45.5' } }), _svg('circle', { classList: ['wheel'], attributeList: { r: '2', cx: '11.5', cy: '45.5' } }), _svg('circle', { classList: ['wheel'], attributeList: { r: '2', cx: '4.5', cy: '45.5' } }), ); break; case 'trailer': svg._( _svg('path', { classList: ['cab'], attributeList: { d: 'M 0,45 v -10 l 15,-15 h 3 v 18 h 10 v 7 h -1 q 0,-3 -3,-3 q -3,0 -3,3 h -1 q 0,-3 -3,-3 q -3,0 -3,3 h -7 q 0,-3 -3,-3 q -3,0 -3,3 z' } }), _svg('path', { classList: ['trailer'], attributeList: { d: 'M 29.5,45 v -8.5 h -10 v -20.5 h 40 v 29 h -1 q 0,-3 -3,-3 q -3,0 -3,3 h -1 q 0,-3 -3,-3 q -3,0 -3,3 h -7 q 0,-3 -3,-3 q -3,0 -3,3 z' } }), _svg('path', { classList: ['window'], attributeList: { d: 'M 2.5,35 l 12.5,-12.5 v 12.5 z' } }), _svg('path', { classList: ['tsmile'], attributeList: { d: 'M 23,25 q 15,10 30,2 q -15,12 -30,-2 m 28,0 q 7,-3 4,4 q 2,-6 -4,-4' } }), _svg('circle', { classList: ['wheel'], attributeList: { r: '2', cx: '4', cy: '45.5' } }), _svg('circle', { classList: ['wheel'], attributeList: { r: '2', cx: '17', cy: '45.5' } }), _svg('circle', { classList: ['wheel'], attributeList: { r: '2', cx: '24', cy: '45.5' } }), _svg('circle', { classList: ['wheel'], attributeList: { r: '2', cx: '35.5', cy: '45.5' } }), _svg('circle', { classList: ['wheel'], attributeList: { r: '2', cx: '48.5', cy: '45.5' } }), _svg('circle', { classList: ['wheel'], attributeList: { r: '2', cx: '55.5', cy: '45.5' } }), ); break; case 'avery': svg._( _svg('g', { attributeList: { transform: 'rotate(-30 30 30)' } })._( _svg('path', { classList: ['print'], attributeList: { d: 'M 20,12 l 24,-6 q 10,25 0,25 v 20 h 5 v 10 h -20 v -10 h 10 v -20 l -16,-4 q -4,-6 -4,-10 z' } }), _svg('path', { classList: ['deco'], attributeList: { d: 'M 28,15 l 12,-3 q 0,6 -6,6 h -6 z' } }), _svg('path', { classList: ['clip'], attributeList: { d: 'M 21,17 l 6,-2 v 3 h -6 z' } }), ), _svg('path', { classList: ['box'], attributeList: { d: 'M 5,44 h 15 v 10 h -15 z' } }), _svg('path', { classList: ['box'], attributeList: { d: 'M 5,44 l 5,-5 h 15 l -5,5 z' } }), _svg('path', { classList: ['box'], attributeList: { d: 'M 20,44 l 5,-5 v 10 l -5,5 z' } }), _svg('path', { classList: ['tape'], attributeList: { d: 'M 11,44 h 3 v 10 h -3 z' } }), _svg('path', { classList: ['tape'], attributeList: { d: 'M 11,44 l 5,-5 h 3 l -5,5 z' } }), _svg('path', { classList: ['label'], attributeList: { d: 'M 9,43 l 3,-3 h 5 l -3,3 z' } }), ); break; default: break; } return svg; } /** @type {(method: string | undefined | null, node: HTMLElement) => void} */ function colourResult(method, node) { if (!method) return; const m = S(method); m.contains('AGEVER') && node.classList.add('AVD'); m.contains('OUT') && node.classList.add('SWA'); m.contains('LOCKER') && node.classList.add('LOCK'); m.contains('SAME') && node.classList.add('SAME'); } /** @type {(node: HTMLElement | ParentNode | null, count?: number) => ParentNode?} */ const parentNode = (node, count = 1) => node && count ? (--count ? parentNode(node.parentNode, count) : node.parentNode) : node; /** @type {(node: HTMLElement, parents?: number) => void} */ function miniBadge(node, parents = 1) { if (['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'Total', '...', '-'].includes(node?.innerText) || node?.classList.contains('badge') || !node?.innerText) return; node?.classList.add('badge'); const oldInnerText = node.innerText.split('@')[0]; parentNode(node, parents)?.append(_('a', { href: `https://fclm-portal.amazon.com/employee/ppaTimeDetails?employeeId=${oldInnerText}`, target: '_blank', classList: ['minibadge'] })._(_('img', { src: `https://internal-cdn.amazon.com/badgephotos.amazon.com/?login=${oldInnerText}`, loading: 'lazy', classList: ['minibadge'] }))); } /** @type {(url: ExtendedString) => Extended | undefined} */ const _buttonImg = (url) => { if (url.contains('royalmail')) return _('img', { src: 'https://www.royalmail.com/themes/custom/rmlcwr/favicon.ico' }); if (url.contains('maps.google.com')) return _('img', { src: 'https://www.google.com/images/branding/product/ico/maps15_bnuw3a_32dp.ico' }); if (url.contains('bing.com')) return _('img', { src: 'https://www.bing.com/sa/simg/favicon-2x.ico' }); if (url.contains('openstreetmap')) return _('img', { src: 'https://www.openstreetmap.org/assets/favicon-194x194-79d3fb0152c735866e64b1d7535d504483cd13c2fad0131a6142bd9629d30de2.png' }); if (url.contains('duckduckgo')) return _('img', { src: 'https://duckduckgo.com/favicon.ico' }); if (url.contains('gamtools')) return _('img', { src: 'https://m.media-amazon.com/images/G/01/ate/gam/tools/favicon.png' }); if (url.contains('eagleeye.amazon.dev')) return _('img', { src: 'https://eagleeye.amazon.dev/favicon.ico' }); if (url.contains('eagleeye')) return _('img', { src: 'data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAYAAACQjC21AAAACXBIWXMAAAsSAAALEgHS3X78AAADRElEQVQ4jYXTT2gcVRwH8O9v/tiNO5NkdhqNDVm3Zktg4qZqiKK4hcJGkBpYXBExIRjIRS8lnoRqIYcYySGXeiiIR9lK6CU5mIQcTIuwQQSFENvaCEm2lWRhszvzZgMh+35edpekTtffaXiP3+d9md97hIBi5ogQ4iMAKWa+CMAmIh/AAwB3ANwyTfPPoF56AtJ8378qpbwOoDWooVZVIroF4HPTNPcDQWY2hBC3mfmdJtDpNESPiOiKYRh/nAKZWRNC/MTMqZMNBwcHWF9fx+7uLjzPQ0dHB3p7ezE4OAgiqqMFXdffDIVCWw1QCPGFlHKmDm1ubmJ2dhaLi4uQUsJxHDiOA8uyUC6Xsb+/j+HhYYyPj4OIQER3DcO4TERVxfO856SU12pJcePbG0gmk1hYWMDIyAhyuRyWl5eRTqdx6Puw83kMDAzAdV2Mjo4im82iVColhRAfoJbuquu67LouT09Ps33W5mg0yisrK1wqldh1Xd7Y2OC1tTX+4eZNXotG+axtc39/P4+NjbFlWRyPx3lpaWkVAEgIsSilfO/erz9j8quvIZkwNzeHvr6+wEHk83nout74x0dHR2hpacHMzMzh/Px8hyalTMjjI7y6/hl+fKOIh5e/g+M4gVihUEAmk0E+n0cikUB3dzd830elUkFra2uL7/txDUD7/b+28Is/DKf9H7z+9ruNCZ4sZsbU1BT29vagqipSqRQmJiZgmiYKhQKy2SxUVW3TiKhcLpfbnnmhD1tKAm9p2lPv3dDASyjci+DDT68hk8k01js7OzE5OQlVVV2NmTfOhM5Eu7q6YNv2UzEASF+M4OXHOmLp9H/2iOhQ1/WHiqIoqxfiF9DT04Nnw+Gm4N/tl7Aafh+qqgZt54hIKACy4XC4EovF0HXuXFMwdv482jpfBDMHJfweqL0Uz/OuM/NUM4yZQUTwPA+hUKhxdWpYzjCMJBEdKwCwvb39DYC7zcD65A3DgHZ6cEVd1z8houNGQgAoFottmqYtALjUDH7ikD1FUa6Ew+Hf6mtK/SMSiZR3dnaGVFX9kpkr/2NJIrqtKMprJ7FTCU+WEOJ5AB8DGGLmV4jIYuZDAPeZ+U61Ws1alvV7UO+/+k9aMjlySqQAAAAASUVORK5CYII=' }); if (url.contains('hero')) return _('img', { src: 'https://hero.eu.picking.aft.a2z.com/favicon.ico' }); if (url.contains('sim.amazon.com')) return _('img', { src: 'https://sim.amazon.com/images/sim-favicon-new.ico' }); if (url.contains('ordnancesurvey.co.uk')) return _('img', { src: 'https://osmaps.ordnancesurvey.co.uk/bundles/app/css/favicon.ico' }); if (url.contains('explore.osmaps.com')) return _('img', { src: 'https://explore.osmaps.com/images/logo/osmaps-logo-triangle.svg' }); }; /** @type {(url: string, buttonText: string, order: number, windowProps?: {id?: string} & WindowProps) => void} */ function addButton(url, buttonText, order, { id, name, ...windowProps } = {}) { id ??= `${name ?? buttonText}_button`.replace(/[^a-zA-Z0-9\-_]/gm, ''); promises.topBar.then((improveBoxes) => improveBoxes.buttons._(($(`button#${id}`, { style: { order: `${order}` } }) ?? _('button', { id, style: { order: `${order}` } })).on('click', () => buttonclick(url, { name, ...windowProps })).__(_buttonImg(S(url)), buttonText))); } /** @type {() => void} */ function specialButtons() { const qrButton = ($(`button#QR`) ?? _('button', { id: 'QR', style: { order: '-1' } })).__(s('qrCode')), podButton = ($(`button#POD`) ?? _('button', { id: 'POD', style: { order: '-1' } })).__(s('viewPOD')); qrButton.onclick = showQR; podButton.onclick = getPODData; promises.topBar.then((improveBoxes) => improveBoxes.buttons._(qrButton, podButton)); } function showQR() { const contentSection = _('section'), dialog = _('dialog', { classList: ['QR'] })._(_('button', { classList: ['close'] })._('X').on('click', () => { dialog.close(); contentSection.remove(); dialog.remove(); }), contentSection); document.body.append(dialog); queueMicrotask(() => { dialog.showModal(); new QRCode(contentSection, page.trackingId); }); } /** @type {(url: string, windowProps?: WindowProps) => Extended} */ function miniButton(url, windowProps) { const img = _buttonImg(S(url)); if (!img) { throw 'Unable to generate minibut img for url'; } img.classList.add('minibut'); return img.on('click', () => buttonclick(url, windowProps)); } function addrbuts(packageData) { debuglog('addrbuts()'); if (packageData.customerInfo.customerAddress) { if (/^[A-Z]{1,2}[0-9]{1,2}[A-Z]{0,1} ?[0-9][A-Z]{2}$/i.test(packageData.pcd.trim().toUpperCase()) || S(packageData.customerInfo.customerAddress).contains('United Kingdom')) { addButton(`https://www.royalmail.com/find-a-postcode#${packageData.customerInfo.customerAddress}`, s('RoyalMail'), 3, { name: 'RMpostcode' }); } addAddrButs(s('Address'), packageData.customerInfo.customerAddress.replace(/\//g, '-').replace(/&/gi, 'and').replace('#', ''), 3); } if (/Amazon.*Locker/i.test(packageData.customerInfo.customerName)) { addButton(`https://locker${page.region == 'na' ? '' : `-${page.region}`}.amazon.com/search?searchType=kioskPostalCode¶m=${packageData.pcd}`, s('LockerStatus'), 2); addButton(`https://locker${page.region == 'na' ? '' : `-${page.region}`}.amazon.com/search?searchType=externalReferenceID¶m=${page.trackingId}`, s('LockerReserve'), 2); addAddrButs(s('Locker'), `${packageData.customerInfo.customerName} ${packageData.pcd}`, 5); } if (/Amazon.*Counter/i.test(packageData.customerInfo.customerName)) { addAddrButs(s('Counter'), `${packageData.customerInfo.customerName.replace(/.* - /i, '')} ${packageData.customerInfo.customerAddress.replace(/\//g, '-')}`, 5); } } /** @type {(buttonText: string, mapSearchString: string, order: number) => void} */ function addAddrButs(buttonText, mapSearchString, order) { const id = `${buttonText}_button`.replace(/[^a-zA-Z0-9\-_]/gm, ''); promises.topBar?.then((improveBoxes) => { improveBoxes.buttons._(($(`div.button_group#${id}`) ?? _('div', { id, style: { order: `${order}` }, classList: ['button_group'] })).__( buttonText, miniButton(`http://maps.google.com/maps?t=h&q=loc:${mapSearchString}`), miniButton(`https://bing.com/maps?style=a&where1=${mapSearchString}`), miniButton(`https://www.openstreetmap.org/search?query=${mapSearchString}`), miniButton(`https://duckduckgo.com/?iaxm=maps&q=${mapSearchString}`), )); }); } /** @type {(url: string, windowProps?: WindowProps) => void} */ function buttonclick(url, { w = 1200, h = 800, name = '' } = {}) { window.open(encodeURI(url).replace(/'/g, '%27'), name, `width=${w}, height=${h}, noopener, noreferrer`); } /** @type {(lat: string|number, lon: string|number) => Extended} */ function distanceNode(lat, lon) { debuglog('distanceNode()'); const distSpan = _('span', { classList: ['dist'] })._('…'); promises.geo?.then((geoData) => { if (!geoData.validLatLon) { return distSpan.remove(); } debuglog(`${lat} - ${lon} - ${geoData.latitude} - ${geoData.longitude}`); const clat_1 = (90.0 - Number(lat)) * Math.PI / 180.0, clon_1 = (Number(lon)) * Math.PI / 180.0, clat_2 = (90.0 - Number(geoData.latitude)) * Math.PI / 180.0, clon_2 = Number(geoData.longitude) * Math.PI / 180.0, d = Math.acos(Math.sin(clat_1) * Math.sin(clat_2) * Math.cos(clon_1 - clon_2) + Math.cos(clat_1) * Math.cos(clat_2)); if (d >= 0.5 / 6370) { distSpan.classList.add('longDistance'); } distSpan._( `${s('calcText').replace('{{ft#}}', formatUnit({ value: (d * 3960 * 5280), unit: 'foot' })).replace('{{m#}}', formatUnit({ value: (d * 6370 * 1000), unit: 'meter' }))})\u2002`, miniButton(`http://maps.google.com/maps?t=h&saddr=${lat}+${lon}&daddr=${geoData.latitude}+${geoData.longitude}`), miniButton(`https://www.openstreetmap.org/directions?engine=fossgis_osrm_foot&route=${lat},${lon};${geoData.latitude},${geoData.longitude}`), miniButton(`https://duckduckgo.com/?iaxm=directions&q=${lat}+${lon}&end=what:${lat}%20${lon}&transport=walk&start=what:${geoData.latitude}%20${geoData.longitude}`) ); }, () => distSpan.remove()); return distSpan; } /** @type {(text?: string) => void} */ function copyText(text) { text && navigator.clipboard.writeText(text).then(() => notify("Copied to clipboard", text)).catch(e => { notify('Copy Failed', e); console.warn(e); }); } function closeNotification() { notification?.close(); } /** @type {(title: string, content: string, closeDelay?:number) => void} */ function notify(title, content, closeDelay = 3) { if (Notification.permission !== "denied" && Notification.permission !== "granted") { Notification.requestPermission(); } if (Notification.permission !== "granted") { alert(`${title}\n\n${content}`); return; } closeNotification(); notification = new Notification(title, { body: content, silent: true }); delay(closeDelay).then(closeNotification); } function historyFormatMenu() { const localOption = { colours: 'OnRoad', ...JSON.parse(localStorage.getItem('SCC_Search_CONFIG') ?? '{}') }, onChange = (newValue) => { const tabs = $$("[role=tablist] label"); localOption.colours = newValue; localStorage.setItem('SCC_Search_CONFIG', JSON.stringify(localOption)); tabs[0].do('click'); tabs[3].do('click'); }; return { colourValue: localOption.colours, menuElement: _('div', { id: 'SCC_Search_CONFIG' })._( _('strong')._(s('formatTable')), [{ label: s('onRoadOption'), value: 'OnRoad' }, { label: s('inStationOption'), value: 'InStation' }].map(({ label, value }) => _('label')._(label, _('input', { type: 'radio', name: 'colours', value, checked: value == localOption.colours }).on('change', () => onChange(value)))) ) }; } //#endregion //#region: CSS function addCSS() { wait$('head').then(head => head._(_('meta', { name: 'theme-color', content: '#ffffff' }))); _css(` /* All Pages */ :root { color-scheme: light; --redBG: #FFAAAA; --yellowBG: #FFFFAA; --greenBG: #AAFFAA; --blueBG: #AAFFFF; --matchBG: white; --greenTableBG: #96FF96; --yellowTableBG: #FFFF96; --redTableBG: #FF9696; --blueTableBG: #9696FF; --cyanTableBG: #96FFFF; --greenText: forestgreen; --orangeText: darkorange; --redText: firebrick; --smile: #FF9900; --squidInk: #232F3E; --primeBlue: #0096D6; } :root[data-improve-scc-css-dark-mode="dark"] { color-scheme: dark; --redBG: #640000; --yellowBG: #646400; --greenBG: #006400; --blueBG: #00004B; --matchBG: #232F3E; --greenTableBG: #003200; --yellowTableBG: #323200; --redTableBG: #320000; --blueTableBG: #000032; --cyanTableBG: #006464; --greenText: #00FF00; --orangeText: #FFFF00; --redText: #FF0000; & :is(.fp-navigation-container, .fp-navigation-container .fp-nav-menu, .fp-page-template, .css-avryxx, .css-m7c1h1, .css-1ekky2x, #verdiv, #changelog ul, #changelog li, .css-sdn4iy:hover) { background-color: var(--squidInk)!important; } } *, *:before, *:after { box-sizing: border-box; font-family: "Amazon Ember", Sans-serif; margin: 0; padding: 0; border-collapse: collapse; vertical-align: middle; } ::-webkit-scrollbar, ::-webkit-scrollbar-track, ::-webkit-scrollbar-corner, ::-webkit-scrollbar-thumb { width: 1rem; height: 1rem; border: 0.25rem solid transparent; } ::-webkit-scrollbar, ::-webkit-scrollbar-corner { background: inherit; } ::-webkit-scrollbar-track { box-shadow: inset 0 0 0 0.0625rem var(--primeBlue); border-radius: 1rem; } ::-webkit-scrollbar-thumb { box-shadow: inset 0 0 0 1rem var(--primeBlue); border-radius: 1rem; } @supports not selector(::-webkit-scrollbar) { * { scrollbar-color: var(--primeBlue) transparent; } } dialog { max-height: 60vh; max-height: 60svh; padding-block-start: 3rem; & #debugModalButtons { position: absolute; inset-block-start: 1rem; inset-inline-end: 1rem; font-size: 200%; & > button { padding: 0.25rem; margin-inline: 0.25rem; } } } :root[data-improve-scc-css-noframe] { zoom: 0.9; &:not([data-improve-scc-show-top-menu]) { display: flex; flex-flow: column nowrap; height: 100%; overflow: auto; & :is(header.fp-header, div.fp-navigation-container) { display: none; } & .is-it-down-stripe { flex: 0 0 0; z-index: unset; position: unset; overflow: unset; } & body { flex: 1 1 100%; overflow: auto; margin: 0; padding: 0; height: unset; min-height: unset; & > div { display: flex; flex-flow: column nowrap; height: 100%; overflow: auto; } & .boson-meridian-frame-dimension { position: unset; top: unset; bottom: unset; flex: 1 1 100%; } } } & #scc_alert { padding: 0; :root[data-improve-scc-css-hide-alerts] &, & .boson-display-none { display: none!important; } } & #dkingamzNav { color: canvastext; text-align: center; border-top: 1px solid #BBC0C1; & li { list-style: none; & button { background: transparent; border: none; } } } & #main_row { position: relative; } & #taskContainer { background: var(--matchBG); border-block-end: 1px solid #C0C0C0; } & #verdiv { position: absolute; top: -1px; right: -0.125rem; color: canvastext; background: var(--matchBG); padding: 0.5rem; border-radius: 0 0 0 1em; border: 1px solid #C0C0C0; font-size: 1.2rem; &.hidden { transform: translate(100%) translate(-2rem); &::before { content: '<\u2003'; } } } & :is(#dkingamzNav, #verdiv) a { color: inherit; text-decoration: underline; & strong { padding: 0.25em; } } } :root[data-improve-scc-css-iframe] { margin-block-start: 0.5rem; & img.minibadge { border: 0.125rem ridge silver; border-radius: 0.5rem; &:not(.pkmn) { max-height: 80px; max-width: 60px; } } & :has( > a.minibadge) { display: inline-flex; flex-flow: column-reverse nowrap; align-items: center; align-content: center; padding: 0.375rem; & a { padding: 0!important; margin: 0!important; } } & #exportLogs { position: fixed; inset-block-start: 3rem; inset-inline-end: 2rem; background: canvas; padding: 0.5rem; font-size: 200%; } } :root:is([data-improve-scc-css-search-page],[data-improve-scc-css-details-page]) { & #root#root { & .AVD { &, & th, & td { background: var(--redBG); } } & .LOCK { &, & th, & td { background: var(--yellowBG); } } & .SAME { &, & th, & td { background: var(--greenBG); } } & .SWA { &, & th, & td { background: var(--blueBG); } } } } :root[data-improve-scc-css-search-page] { & :is(tr, th, td) { background-color: inherit; border-block-end: 1px outset; } & tr[data-row-number]::before { content: attr(data-row-number); display: table-cell; color: canvastext; padding: 8px; border-block-end: 1px outset; } & tr[data-vrid]::after { content: attr(data-vrid); display: table-cell; color: canvastext; padding: 8px; border-block-end: 1px outset; } & tr[data-exchange-id] td:last-child::after { content: attr(data-exchange-id); display: table-cell; color: canvastext; padding: 8px; border-block-end: 1px outset; } & .css-vps56m { margin-block-end: 0!important; padding: 0; } } :root[data-improve-scc-css-details-page] { /*main box below root*/ & .css-xx5nu9 { padding: 2px!important; /*main rows below main box*/ & > :is(div,ul) { margin: 2px!important; padding: 0 2px!important; } } &[data-improve-scc-xhr] :is(.css-rx4572, .css-rx4572 + .css-14fuupd) { display: none!important; } & #SCC_Search_CONFIG { display: flex; gap: 0.5rem; & label { display: inline-flex; gap: 0.5rem; } } & #improveRoot { margin-block-start: -1px; & > div { border-block-end: 2px groove; border-radius: 0; } & #improveHead { font-family: "Amazon Ember", "Amazon Ember Arabic", Arial, sans-serif; color: canvastext; display: grid; grid-template-columns: max-content min-content max-content 1fr; column-rule: 2px solid currentcolor; column-rule-outset: 0; gap: 4px; align-items: center; border-radius: 1em 1em 0 0; & h1 { font-weight: 600; font-size: 36px; line-height: 48px; margin: 0; } & > div { display: flex; flex-flow: column nowrap; &:not(#customerColumn) * { text-align: center; } &:first-of-type > * { padding-inline-start: 0; } &:last-of-type > * { padding-inline-end: 0; } } & div { & > * { padding: 0 0.25em; } &.spaced { display:flex; flex-flow: row nowrap; justify-content: space-around; & > * { margin: 0 0.5em; &:first-of-type { margin-left: 0; } &:last-of-type { margin-right: 0; } } } &.simple-flex { display:flex } } & #oid { &.vret { background: var(--yellowTableBG); } &.covid { background: var(--redTableBG); } } & #flags { justify-content: space-evenly; align-self: stretch; padding-inline: 0.25rem; & > strong { margin: 0; font-size: 1.2rem; } } & #customerColumn { flex-grow: 1; flex-shrink: 1; & > div > strong { padding: 0; } & #custNotes { padding-left: 3em!important; & > div { text-indent: -1.5em; } } } } & #podContainer { padding:0.125rem; &:not(:has(>*)) { display:none; } & section { min-height: 2rem; display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); grid-auto-rows: max-content; & .pod-item { display:grid; grid-template-columns: 1fr; text-align: center; & .pod-img { max-width: 100%; margin-inline: auto; } & :has(> .minibut) { padding-block: 0.6rem; } } } } & #transport { &, & > div { display: flex; flex-flow: row wrap; justify-content: space-around; } & > div { flex: 1 1 auto; border-radius: 0; &:not(:first-child) { border-inline-start: 1px groove currentcolor; } } } & #gamrow { text-align: center; } & #buttons { display: flex; flex-flow: row wrap; align-content: space-around; justify-content: space-around; padding-block: 0.375rem; & > :is(button, div) { appearance: none; display: flex; flex-flow: row nowrap; align-items: center; justify-content: center; font-family: "Amazon Ember"; font-size: 1.1rem; line-height: 1.1rem; background: #077398; color: white; margin: 0.375rem; padding: 0.125rem 0.5rem; border: none; border-radius: 0.25rem; &, & img { box-shadow: 0 0 0.25rem 0 #077398; } } & button { margin-inline-start: 0.5rem; cursor: pointer; &:hover { &, & img { box-shadow: inset 0 0 0.25rem 0 canvas, 0 0 0.5rem 0 canvastext; } } & img { margin-inline-start: -1rem; margin-inline-end: 0.25rem; } } } & .errMsg { color: var(--redText); font-size: small; } & :is(.AVD, .LOCK, .SAME, .SWA) { padding-left: 12px; border-radius: 1em 1em 0 0; } } & :is(#buttons button img, .minibut) { height: 2.2rem; padding: 0.25rem; background: white; border-radius: 100%; overflow: hidden; cursor: pointer; margin-block: -1.5rem; } & .minibut{ margin-inline: 0.125rem; margin-block: -0.6rem; vertical-align: middle; &:hover { box-shadow: inset 0 0 0.25rem 0 canvas, 0 0 0.5rem 0 canvastext; } &:first-of-type { margin-inline-start: 0.75rem; } &:last-of-type { margin-inline-end: -0.25rem; } } & table[data-improve-scc=true] { & button { border-radius: 0.375rem; margin-inline: 0.125rem; padding-inline: 0.25rem; padding-block: 0.125rem; &.copyButton { display: inline-block; } } & :is(thead, tfoot) th { text-align: start; padding: 0; &:not(:has( > *)) { border: none; } & > * { margin: 0.5rem; } } & td:first-child { white-space: nowrap; } & :is(.newRow, .newRow td, .newRow th) { border: 2px inset; border-block-end: none; } & tr.newRow { & td > * { margin-inline-end: 0.75rem; } & td > .photoImg { display: block; width: 100%; max-width: calc(120vw - 1rem); max-height: calc(120vh - 1rem); object-fit: contain; margin-block-start: 0.75rem; &.hide { display: none; } } } & tr.newRow + tr { border: 2px inset; border-top: none; &, & td, & th { border-block-end: 2px outset; } & :is(td:first-of-type, th:first-of-type) { border-left: 2px inset; } & :is(td:last-of-type, th:last-of-type) { border-right: 2px inset; } } & .newDay.newRow:not(.newRow + tr) { &, & td, & th { border-top: 3px solid currentcolor; } } & :is(.delSuc, .delSuc td, .delSuc th) { background: var(--greenTableBG)!important; } & :is(.delFail, .delFail td, .delFail th) { background: var(--yellowTableBG)!important; } & :is(.endFail, .endFail td, .endFail th) { background: var(--redTableBG)!important; } & :is(.rts, .rts td, .rts th) { background: var(--blueTableBG)!important; } & :is(.oor, .oor td, .oor th) { background: var(--cyanTableBG)!important; } & .goodTime { color: var(--greenText)!important; } & .poorTime { color: var(--orangeText)!important; } & :is(.badTime, .longDistance) { color: var(--redText)!important; } & svg.bag { background: silver; border-radius: 0.75rem; max-height: 100%; position: absolute; inset-block: 0; inset-inline-end: 0; margin-block: auto; max-width: 3rem; &.BLK .colour{ fill: black; } &.GRN .colour{ fill: green; } &.NVY .colour{ fill: blue; } &.YLO .colour{ fill: yellow; } &.ORG .colour{ fill: orange; } } & .die { display: none; } } & [role=tablist] label { line-height: 1rem; flex: 1 1 auto; & > div:last-child { margin-block: 0; } & > span > div { padding-block: 0.125rem; padding-inline: 1rem; } } & :is(#flags > strong, .goodTime, .poorTime, .badTime, .longDistance) { background: canvas; border-radius: 0.5rem; padding: 0.0625em 0.25rem; margin-block: 0.125rem; } & div > a.minibadge { position: absolute; display: none; right: 8px; top: -32px; z-index: 10; } & div:hover > .minibadge { display: initial; } & :is(b,strong) > .minibadge { display: none; position: relative; background: white; border: 3px ridge silver; border-radius: 8px; margin: -3em 0; height: 7em; z-index: 10; } & :is(b,strong):hover > .minibadge { display: block; } } :root[data-improve-scc-css-receive-page] { & .fmcdone { text-decoration: underline; } } :root[data-improve-scc-css-outbound-page] { font-size: 0.8rem; & * { font-size: inherit!important; line-height: inherit!important; } & div:has( table) { overflow-x: unset!important; } & th { padding-inline-end: 0.25rem; } & :is(th, td) { padding-inline-start: 0.25rem; padding-block: 0.25rem; } & #root div.highlighted-warning { color: black; text-align: center; } } :root[data-improve-scc-css-badges-page] { & :is(tr, th, td) { border-block-end: 2px solid silver; } & :is(span, a).badge { display: flex; align-content: center; justify-content: center; align-items: center; justify-items: center; flex-flow: column-reverse nowrap; } } dialog { inset: 50vh 50vw; inset: 50dvh 50dvw; transform: translate(-50%, -50%); background: canvas; color: canvastext; border: 2px ridge #0096D6; border-radius: 1em; padding: 3rem; width: max-content; &.QR { color-scheme: light; } & button.close { position: absolute; inset: 0.5rem 0.5rem auto auto; margin: 0; } } div.button-align:has(> button.close) { width: 100%; height: 0; overflow: visible; display: flex; flex-flow: row-reverse nowrap; margin: 0.125rem; } button.close { cursor: pointer; background: firebrick; color: white; border: 0.125rem ridge red; border-radius: 1rem; padding: 0; width: 2em; height: 2em; z-index: 3; &:is(:hover, :focus, :active) { box-shadow: inset 0 0 0.125rem 0.125rem red; background: firebrick; color: white; } } ::backdrop { backdrop-filter: blur(5px) brightness(50%); } @-moz-document url-prefix() { ::backdrop { background: #00000088; } } `); } //#endregion //#region: non-SCC pages | start SCC (() => { debuglog(`multiple check - ${window.ImproveSCC}`); if (window.ImproveSCC) return; window.ImproveSCC = true; if (hrefContains('midway-auth')) { if (window.name == 'midwayAuth') { debuglog('midwayAuthPage'); wait$('#auth-success-view').then(success => { new MutationObserver(() => { if (success?.style?.display == 'block') { window.close(); } }).observe(success, { characterData: false, attributes: true, childList: false, subtree: false }); }); } return; } if (hrefContains('siw-eu-dub.dub.') || hrefContains('siw-na-iad.iad')) { debuglog('GCRSsearchPage'); const tId = window.location.hash.slice(1); debuglog(tId); return tId && wait$('[ng-model="vm.queryItems"]', { customProps: { input: tId } }).then(input => { debuglog(input); input.do('input'); wait$('[ng-click="vm.query()"]:not([disabled])').then(button => button.do('click')); }); } if (hrefContains('royalmail')) { debuglog('RMpostcodePage'); const addr = decodeURI(window.location.hash.slice(1)); debuglog(addr); return addr && wait$('#edit-rml-postcode-finder-postal-code').then(input => { debuglog(input); input.focus(); input.value = addr; input.do('input'); }); } if (GM.info.scriptHandler == 'Greasemonkey') { alert('Improve SCC Search\n\nThis script will not run in Greasemonkey due to a limitation with how the extension handles iframes.\nPlease install with Tampermonkey.'); window.open('https://www.tampermonkey.net'); return; } addCSS(); startup(); })(); //#endregion