Recently Viewed Products Tracker

Silently records viewed products on the product page and saves them to local storage so the Recently Viewed Display block can show them elsewhere in the app.

<div class="recently-viewed-tracker" id="recentlyViewedTracker" hidden="">
</div>
.recently-viewed-tracker {
    display: none;
}
const RV_KEY = "recentlyViewedProducts";
const RV_LIMIT = 10;
const RV_TTL = 24 * 60 * 60 * 1000; // refresh/expire entries after 1 day
function getCurrentProduct() {
    // Always re-read live SDK state instead of caching.
    return Superfans.variables.product || null;
}
function isFresh(entry) {
    if (!entry?.viewedAt) {
        return false;
    }
    return Date.now() - entry.viewedAt < RV_TTL;
}
async function getRecentlyViewedList() {
    const raw = await Superfans.actions.getLocalStorage(RV_KEY);
    let list = [];
    try {
        list = raw ? JSON.parse(raw) : [];
    } catch (error) {
        list = [];
    }
    // Drop anything older than a day so stale data refreshes automatically.
    return Array.isArray(list) ? list.filter(isFresh) : [];
}
async function setRecentlyViewedList(products) {
    await Superfans.actions.setLocalStorage(RV_KEY, JSON.stringify(products));
}
async function saveCurrentProductToRecentlyViewed() {
    const product = getCurrentProduct();
    // Product not hydrated yet; onVariantChanged will retry.
    if (!product?.id) {
        return;
    }
    // Store the full product variable plus a timestamp for the 1-day refresh logic.
    const entry = {
        ...product,
        viewedAt: Date.now()
    };
    const existingProducts = await getRecentlyViewedList();
    const nextProducts = [
        entry,
        ...existingProducts.filter(item => String(item.id) !== String(product.id))
    ].slice(0, RV_LIMIT);
    await setRecentlyViewedList(nextProducts);
}
// Re-fire once product/variant data becomes available (covers null product on initial load).
Superfans.listeners.onVariantChanged(() => {
    saveCurrentProductToRecentlyViewed();
});
saveCurrentProductToRecentlyViewed();