← back to Handbag Authentication
public/js/price-tracker.js
292 lines
// Retail Price Tracking Data (manually curated from official brand price increases)
const retailPriceHistory = {
'Hermes': {
'Birkin 30': {
2020: 9850,
2021: 10300,
2022: 10800,
2023: 11200,
2024: 11200
},
'Kelly 28': {
2020: 9400,
2021: 9850,
2022: 10300,
2023: 10600,
2024: 10600
},
'Constance 18': {
2020: 7500,
2021: 7950,
2022: 8300,
2023: 8500,
2024: 8500
}
},
'Chanel': {
'Classic Flap Medium': {
2020: 6800,
2021: 7400,
2022: 8800,
2023: 9800,
2024: 10200
},
'Boy Bag Medium': {
2020: 4900,
2021: 5400,
2022: 6400,
2023: 7000,
2024: 7400
},
'Chanel 19 Medium': {
2020: 5600,
2021: 6200,
2022: 7200,
2023: 7600,
2024: 7900
}
},
'Louis Vuitton': {
'Neverfull MM': {
2020: 1500,
2021: 1630,
2022: 1760,
2023: 1900,
2024: 2030
},
'Speedy 30': {
2020: 1140,
2021: 1240,
2022: 1350,
2023: 1760,
2024: 1900
},
'Pochette Metis': {
2020: 2050,
2021: 2230,
2022: 2420,
2023: 2630,
2024: 2840
}
},
'Gucci': {
'Marmont Medium': {
2020: 2490,
2021: 2590,
2022: 2790,
2023: 2890,
2024: 2980
},
'Dionysus Medium': {
2020: 2790,
2021: 2890,
2022: 3050,
2023: 3150,
2024: 3200
}
},
'Prada': {
'Galleria Medium': {
2020: 2950,
2021: 3150,
2022: 3450,
2023: 3650,
2024: 3750
},
'Re-Edition 2005': {
2020: 890,
2021: 995,
2022: 1150,
2023: 1250,
2024: 1350
}
}
};
let currentBrand = 'Hermes';
let priceChart = null;
// Initialize
document.addEventListener('DOMContentLoaded', () => {
setupBrandTabs();
renderBrand('Hermes');
});
function setupBrandTabs() {
document.querySelectorAll('.sort-tab').forEach(tab => {
tab.addEventListener('click', () => {
document.querySelectorAll('.sort-tab').forEach(t => t.classList.remove('active'));
tab.classList.add('active');
currentBrand = tab.getAttribute('data-brand');
renderBrand(currentBrand);
});
});
}
function renderBrand(brand) {
const data = retailPriceHistory[brand];
if (!data) return;
renderSummary(brand, data);
renderChart(brand, data);
renderTable(brand, data);
renderInsights(brand, data);
}
function renderSummary(brand, data) {
const summaryEl = document.getElementById('summary-content');
let html = '';
for (const [model, prices] of Object.entries(data)) {
const years = Object.keys(prices).sort();
const firstYear = years[0];
const lastYear = years[years.length - 1];
const firstPrice = prices[firstYear];
const lastPrice = prices[lastYear];
const increase = lastPrice - firstPrice;
const increasePercent = ((increase / firstPrice) * 100).toFixed(1);
html += `
<div style="background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); padding: 1.5rem; border-radius: 10px;">
<h3 style="margin-top: 0; font-size: 1.1rem;">${brand} ${model}</h3>
<div style="font-size: 2rem; font-weight: 700; color: #667eea; margin: 0.5rem 0;">
+${increasePercent}%
</div>
<div style="font-size: 0.9rem; color: #7f8c8d;">
$${firstPrice.toLocaleString()} (${firstYear}) → $${lastPrice.toLocaleString()} (${lastYear})
</div>
<div style="font-size: 0.85rem; margin-top: 0.5rem; font-weight: 600; color: #27ae60;">
+$${increase.toLocaleString()} increase
</div>
</div>
`;
}
summaryEl.innerHTML = html;
}
function renderChart(brand, data) {
const ctx = document.getElementById('priceChart').getContext('2d');
const datasets = [];
const colors = ['#667eea', '#764ba2', '#f093fb', '#f5576c', '#fa709a', '#fee140'];
let i = 0;
for (const [model, prices] of Object.entries(data)) {
datasets.push({
label: `${brand} ${model}`,
data: Object.values(prices),
borderColor: colors[i % colors.length],
backgroundColor: colors[i % colors.length] + '20',
tension: 0.3,
fill: true
});
i++;
}
const years = Object.keys(Object.values(data)[0]);
if (priceChart) {
priceChart.destroy();
}
priceChart = new Chart(ctx, {
type: 'line',
data: {
labels: years,
datasets: datasets
},
options: {
responsive: true,
maintainAspectRatio: true,
plugins: {
title: {
display: true,
text: `${brand} Retail Price Growth (2020-2024)`,
font: { size: 16, weight: 'bold' }
},
legend: {
display: true,
position: 'top'
}
},
scales: {
y: {
beginAtZero: false,
ticks: {
callback: function(value) {
return '$' + value.toLocaleString();
}
}
}
}
}
});
}
function renderTable(brand, data) {
const tbody = document.getElementById('model-table-body');
let html = '';
for (const [model, prices] of Object.entries(data)) {
const years = Object.keys(prices).sort();
const firstPrice = prices[years[0]];
const lastPrice = prices[years[years.length - 1]];
const totalIncrease = lastPrice - firstPrice;
const totalIncreasePercent = ((totalIncrease / firstPrice) * 100).toFixed(1);
const annualGrowth = (totalIncreasePercent / (years.length - 1)).toFixed(1);
html += `
<tr>
<td style="font-weight: 700;">${brand} ${model}</td>
${years.map(year => `<td>$${prices[year].toLocaleString()}</td>`).join('')}
<td style="color: #27ae60; font-weight: 700;">+${totalIncreasePercent}%</td>
<td style="color: #667eea; font-weight: 700;">${annualGrowth}%/yr</td>
</tr>
`;
}
tbody.innerHTML = html;
}
function renderInsights(brand, data) {
const insightsEl = document.getElementById('insights');
// Calculate average annual growth
let totalGrowth = 0;
let modelCount = 0;
for (const [model, prices] of Object.entries(data)) {
const years = Object.keys(prices).sort();
const firstPrice = prices[years[0]];
const lastPrice = prices[years[years.length - 1]];
const growthPercent = ((lastPrice - firstPrice) / firstPrice) * 100;
const annualGrowth = growthPercent / (years.length - 1);
totalGrowth += annualGrowth;
modelCount++;
}
const avgAnnualGrowth = (totalGrowth / modelCount).toFixed(1);
// Find best performer
let bestModel = '';
let bestGrowth = 0;
for (const [model, prices] of Object.entries(data)) {
const years = Object.keys(prices).sort();
const firstPrice = prices[years[0]];
const lastPrice = prices[years[years.length - 1]];
const growthPercent = ((lastPrice - firstPrice) / firstPrice) * 100;
if (growthPercent > bestGrowth) {
bestGrowth = growthPercent;
bestModel = model;
}
}
insightsEl.innerHTML = `
<p><strong>✅ Average Annual Growth:</strong> ${brand} bags increase an average of <strong>${avgAnnualGrowth}% per year</strong> at retail.</p>
<p><strong>🏆 Best Performer:</strong> The ${bestModel} has appreciated <strong>+${bestGrowth.toFixed(1)}%</strong> since 2020.</p>
<p><strong>💎 Investment Strategy:</strong> Buying ${brand} bags from Japan at 20-40% below US retail means you're getting bags at 2018-2019 prices, with built-in appreciation.</p>
<p><strong>📈 Arbitrage Edge:</strong> Even if you buy today and resell in 2 years, retail price increases alone could cover your profit margin!</p>
`;
}