// ==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@)
// @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
// ==/UserScript==
//#region Utilities/Types
/// <reference path="./GM.d.ts" />
/// <reference path="./simple-dom.d.ts" />
/// <reference path="./Improve-SCC.d.ts" />
const { _, _svg, $, $$, wait$, delay, _css, O, dict, lock } = simpleDOM;
const
/** @type {<A extends unknown[]>(...bindArgs: A) => <R extends unknown>(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<string, Intl.DateTimeFormat>} */ 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<XHRResponse>} */
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<XHRResponse>} */
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 {<T>({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')._(
)).on('click', () => verdiv.classList.toggle('hidden'));
mainRow._(verdiv);
new MutationObserver(() => {
}).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' })).__(
_('li')._(_('button', { classList: ['css-11g0wa3'] })._(_('div', { classList: ['css-1u8dqdz'] })._(_('span', { classList: ['css-1bkd0di'] })._('Check For Updates'))).on('click', () => updateCheck().then(updateAvailable))),
updateAvailableLi,
_('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());
})),
)
);
});
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: `<html><head><meta name="color-scheme" content="light dark"><style>:root{background:canvas}</style></head><body>${Date.now()}<br/>SCC: ${globalOrigin}<br/>UA: ${navigator.userAgent}<br/>Default Language: ${navigator.language}<br/>All Languages: ${JSON.stringify(navigator.languages)}</body></html>`,
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();
});
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<String,Extended<HTMLTableRowElement>>} */ 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<HTMLDivElement>} */
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)));
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('</')?.[0]);
}
}, debuglog);
// serviceAreaId && cortexButtons._(_('button')._(s('cortexItinerary')).on('click', () => 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];
}
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<PackageData>} */
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); };
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<SiteMap>} */
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<GeoData>} */
function getGeoData() {
debuglog('getGeoData()');
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'),
));
}
/** @type {(packageData:PackageData) => Promise<GAMData>} */
function getGAMData(packageData) {
debuglog('getGAMData()');
return Promise.reject('GAM requests disabled');
const countryCode = packageData.shipInfo.shipMethod.split('_')[1];
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(/\<script.*\<\/script\>/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);
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]) {
// 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()');
// const oblt_row = _('html', { innerHTML: html.replace(/\<script.*\<\/script\>/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);
// response.json().EventList.filter((event) => event.eventType == 'COMPLETE_PACKAGE').forEach((event) => {
// if (!response.text.contains('boxRecommendation=')) return;
// improveBoxes.fc.__(_('strong')._('FC Box Recommendation: '), response.text.split('boxRecommendation=')[1].split(',')[0]);
// });
// });
// });
// }
/** @type {() => Promise<HistDataRow[]>} */
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<HTMLElement>, timestamp: ExtendedDate) => void} */
function routeVisButton(routeId, node, timestamp) {
debuglog('routeVisButton()', routeId, node, timestamp);
node._(
);
}
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<string, string>} */ 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…');
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<SVGSVGElement>} */
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];
}
/** @type {(url: ExtendedString) => Extended<HTMLImageElement> | undefined} */
const _buttonImg = (url) => {
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=' });
};
/** @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<HTMLImageElement>} */
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) {
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,
));
});
}
/** @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<HTMLSpanElement>} */
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`,
);
}, () => 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.');
return;
}
addCSS();
startup();
})();
//#endregion