Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name Amazon Vine: Order Status → Vine Reviews
- // @namespace https://www.reddit.com/r/VineHelper/comments/1mz5jr6/comment/nagt886/
- // @version 1.0.0
- // @description Capture delivery status from order history and display it in Vine Reviews table.
- // @author u/Ball_Catcher
- // @license MIT
- // @match https://www.amazon.com/your-orders*
- // @match https://www.amazon.com/*/order-history*
- // @match https://www.amazon.com/vine/vine-reviews*
- // @grant GM_getValue
- // @grant GM_setValue
- // @run-at document-idle
- // ==/UserScript==
- (function () {
- "use strict";
- // ---------- Storage helpers (GM_* wrappers per-ASIN) ----------
- async function saveAsinData(asin, data) {
- if (!asin) return;
- const key = `asin:${asin}`;
- await GM_setValue(key, data);
- }
- async function getAsinData(asin) {
- if (!asin) return null;
- const key = `asin:${asin}`;
- return (await GM_getValue(key)) || null;
- }
- // ---------- Page detection ----------
- function isOrderHistory() {
- const p = location.pathname;
- return /\/your-orders(?:\/|$)/.test(p) || /\/order-history(?:\/|$)/.test(p);
- }
- function isVineReviews() {
- return /\/vine\/vine-reviews(?:\/|$)/.test(location.pathname);
- }
- // ---------- Core features (converted from your module code) ----------
- async function identifyReceivedOrders() {
- if (!isOrderHistory()) return;
- const orderCards = document.querySelectorAll(".order-card__list");
- if (!orderCards.length) return;
- orderCards.forEach(async (card) => {
- const deliveryEl = card.querySelector(".delivery-box__primary-text");
- const deliveryStatus = deliveryEl ? deliveryEl.innerText.trim() : null;
- // Find review link
- const reviewAnchor = card.querySelector(
- 'a[href*="/review/review-your-purchases?asins="]'
- );
- if (!reviewAnchor) return;
- const href = reviewAnchor.getAttribute("href") || "";
- const asinMatch = href.match(/asins=([^&]+)/);
- if (!asinMatch) return;
- const productAsin = asinMatch[1];
- // Find tracking link
- const trackAnchor = card.querySelector(
- 'a[href*="/gp/your-account/ship-track"]'
- );
- const trackPackageLink = trackAnchor
- ? trackAnchor.getAttribute("href")
- : null;
- const data = {
- deliveryStatus,
- trackPackageLink,
- productAsin,
- };
- await saveAsinData(productAsin, data);
- console.debug(
- `[VineHelper] Saved order-history data for ASIN ${productAsin}`,
- data
- );
- });
- }
- async function insertOrderDeliveryStatus() {
- if (!isVineReviews()) return;
- const reviewsTable = document.querySelector(".vvp-reviews-table");
- if (!reviewsTable) return;
- // --- Insert header column ---
- const reviewHeading = reviewsTable.querySelector(
- "#vvp-reviews-table--review-content-heading"
- );
- const existingDeliveryHeading = reviewsTable.querySelector(
- ".vvp-reviews-table--delivery-status-heading"
- );
- if (reviewHeading && !existingDeliveryHeading) {
- const th = document.createElement("th");
- th.className = "vvp-reviews-table--delivery-status-heading";
- th.textContent = "Delivery status";
- const actionsHeading = reviewsTable.querySelector(
- "th.vvp-reviews-table--actions-col"
- );
- if (actionsHeading) {
- actionsHeading.insertAdjacentElement("beforebegin", th);
- } else {
- reviewHeading.insertAdjacentElement("afterend", th); // fallback
- }
- }
- // --- Insert row data ---
- const rows = reviewsTable.querySelectorAll(".vvp-reviews-table--row");
- rows.forEach(async (row) => {
- // Avoid duplicating cells on re-runs
- if (row.querySelector(".vvp-reviews-table--delivery-status-col")) return;
- let asin = null;
- // Try to get ASIN from product detail link
- const detailLink = row.querySelector(
- 'td.vvp-reviews-table--text-col #vvp-reviews-product-detail-page-link'
- );
- if (detailLink) {
- const href = detailLink.getAttribute("href") || "";
- const asinMatch = href.match(/\/dp\/([^/?]+)/);
- if (asinMatch) asin = asinMatch[1];
- }
- // Fallback: check innerText of 2nd <td>
- if (!asin) {
- const tds = row.querySelectorAll("td");
- if (tds.length >= 2) {
- const text = tds[1].innerText.trim();
- const asinMatch = text.match(/\b[A-Z0-9]{10}\b/); // typical ASIN format
- if (asinMatch) asin = asinMatch[0];
- }
- }
- const insertCell = (contentCb) => {
- const td = document.createElement("td");
- td.className = "vvp-reviews-table--delivery-status-col";
- contentCb(td);
- const actionsCol = row.querySelector("td.vvp-reviews-table--actions-col");
- if (actionsCol && actionsCol.parentNode) {
- actionsCol.insertAdjacentElement("beforebegin", td);
- }
- };
- // If no ASIN at all, just insert Status Unknown immediately
- if (!asin) {
- insertCell((td) => {
- td.textContent = "Status Unknown";
- td.style.fontStyle = "italic";
- td.style.color = "#777";
- });
- return;
- }
- // Lookup ASIN in storage
- const stored = await getAsinData(asin);
- let deliveryStatus = "Status Unknown";
- let trackPackageLink = null;
- if (stored) {
- if (stored.deliveryStatus) deliveryStatus = stored.deliveryStatus;
- if (stored.trackPackageLink) {
- // normalize relative to full URL
- trackPackageLink = new URL(stored.trackPackageLink, location.origin).href;
- }
- }
- insertCell((td) => {
- if (deliveryStatus.includes("Delivered")) {
- td.textContent = deliveryStatus;
- td.style.fontWeight = "bold";
- td.style.color = "#00796b";
- } else if (deliveryStatus === "Status Unknown") {
- td.textContent = deliveryStatus;
- td.style.fontStyle = "italic";
- td.style.color = "#777";
- } else {
- if (trackPackageLink) {
- const a = document.createElement("a");
- a.href = trackPackageLink;
- a.target = "_blank";
- a.rel = "noopener noreferrer";
- a.textContent = deliveryStatus;
- td.appendChild(a);
- } else {
- td.textContent = deliveryStatus; // fallback if no link available
- }
- }
- });
- });
- }
- // ---------- Observers to handle dynamic loads ----------
- const moOpts = { childList: true, subtree: true };
- function observeForOrders() {
- if (!isOrderHistory()) return;
- // Initial pass
- identifyReceivedOrders();
- // Re-check as cards load/expand
- const root = document.body;
- const mo = new MutationObserver(() => {
- // Throttle lightly with requestAnimationFrame
- window.requestAnimationFrame(identifyReceivedOrders);
- });
- mo.observe(root, moOpts);
- }
- function observeForVineReviews() {
- if (!isVineReviews()) return;
- // Initial pass
- insertOrderDeliveryStatus();
- // Re-check when table updates due to filters/pagination
- const root = document.querySelector(".vvp-reviews-table") || document.body;
- const mo = new MutationObserver(() => {
- window.requestAnimationFrame(insertOrderDeliveryStatus);
- });
- mo.observe(root, moOpts);
- }
- // ---------- Bootstrap ----------
- if (isOrderHistory()) observeForOrders();
- if (isVineReviews()) observeForVineReviews();
- })();
Advertisement
Add Comment
Please, Sign In to add comment