anonymous111110987654321's picture
Add 1 files
e00c8e4 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>301 Tariff Analysis Dashboard - US Auto Industry</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-chart-box-and-violin-plot@3.0.2/build/Chart.BoxPlot.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.0/papaparse.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.chart-container {
transition: all 0.3s ease;
cursor: pointer;
}
.chart-container:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
}
.sidebar {
transition: all 0.3s ease;
}
.data-table {
max-height: 400px;
overflow-y: auto;
}
.highlight-row:hover {
background-color: #f0f9ff;
}
.tooltip {
position: relative;
display: inline-block;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 200px;
background-color: #333;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px;
position: absolute;
z-index: 1;
bottom: 125%;
left: 50%;
margin-left: -100px;
opacity: 0;
transition: opacity 0.3s;
}
.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
}
.active-filter {
background-color: #3B82F6 !important;
color: white !important;
}
</style>
</head>
<body class="bg-gray-50">
<div class="flex h-screen overflow-hidden">
<!-- Sidebar -->
<div class="sidebar bg-blue-800 text-white w-64 flex-shrink-0 hidden md:block">
<div class="p-4">
<div class="flex items-center space-x-2">
<i class="fas fa-car text-2xl"></i>
<h1 class="text-xl font-bold">301 Tariff Analyzer</h1>
</div>
<p class="text-blue-200 text-sm mt-2">US Auto Industry Focus</p>
</div>
<nav class="mt-6">
<div class="px-4 py-2 bg-blue-700">
<span class="font-medium">Dashboard</span>
</div>
<a href="#" class="block px-4 py-2 text-blue-200 hover:bg-blue-700 hover:text-white">
<i class="fas fa-chart-line mr-2"></i>Overview
</a>
<a href="#" class="block px-4 py-2 text-blue-200 hover:bg-blue-700 hover:text-white">
<i class="fas fa-file-import mr-2"></i>Import Data
</a>
<a href="#" class="block px-4 py-2 text-blue-200 hover:bg-blue-700 hover:text-white">
<i class="fas fa-search-dollar mr-2"></i>Tariff Analysis
</a>
<a href="#" class="block px-4 py-2 text-blue-200 hover:bg-blue-700 hover:text-white">
<i class="fas fa-industry mr-2"></i>Company Profiles
</a>
<a href="#" class="block px-4 py-2 text-blue-200 hover:bg-blue-700 hover:text-white">
<i class="fas fa-cog mr-2"></i>Settings
</a>
</nav>
<div class="absolute bottom-0 w-full p-4">
<div class="bg-blue-700 p-3 rounded-lg">
<p class="text-sm">Need help with tariff analysis?</p>
<button class="mt-2 bg-white text-blue-800 px-3 py-1 rounded text-sm font-medium w-full">
Contact Support
</button>
</div>
</div>
</div>
<!-- Main Content -->
<div class="flex-1 overflow-auto">
<!-- Top Navigation -->
<header class="bg-white shadow-sm">
<div class="flex justify-between items-center px-6 py-4">
<div class="flex items-center">
<button class="md:hidden mr-4 text-gray-500">
<i class="fas fa-bars text-xl"></i>
</button>
<h2 class="text-xl font-semibold text-gray-800">301 Tariff Dashboard</h2>
</div>
<div class="flex items-center space-x-4">
<div class="relative">
<input type="text" placeholder="Search..." class="pl-8 pr-4 py-2 border rounded-lg text-sm">
<i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
</div>
<div class="flex items-center space-x-2">
<div class="relative">
<i class="fas fa-bell text-gray-500 text-xl"></i>
<span class="absolute top-0 right-0 h-2 w-2 rounded-full bg-red-500"></span>
</div>
<div class="w-8 h-8 rounded-full bg-blue-600 flex items-center justify-center text-white">
<span>JD</span>
</div>
</div>
</div>
</div>
</header>
<!-- Dashboard Content -->
<main class="p-6">
<!-- Filters -->
<div class="bg-white rounded-lg shadow p-4 mb-6">
<div class="flex flex-wrap items-center justify-between gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Time Period</label>
<select id="timePeriod" class="border rounded-md px-3 py-2 text-sm">
<option value="12">Last 12 Months</option>
<option value="6">Last 6 Months</option>
<option value="3">Last 3 Months</option>
<option value="custom">Custom Range</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Company</label>
<select id="companyFilter" class="border rounded-md px-3 py-2 text-sm">
<option value="all">All Companies</option>
<option value="General Motors">General Motors</option>
<option value="Ford">Ford</option>
<option value="Tesla">Tesla</option>
<option value="Stellantis">Stellantis</option>
<option value="Toyota USA">Toyota USA</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Product Category</label>
<select id="productFilter" class="border rounded-md px-3 py-2 text-sm">
<option value="all">All Categories</option>
<option value="Vehicle Parts">Vehicle Parts</option>
<option value="Engines">Engines</option>
<option value="Electronics">Electronics</option>
<option value="Steel Components">Steel Components</option>
<option value="Aluminum Components">Aluminum Components</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Country of Origin</label>
<select id="countryFilter" class="border rounded-md px-3 py-2 text-sm">
<option value="all">All Countries</option>
<option value="China">China</option>
<option value="Mexico">Mexico</option>
<option value="Canada">Canada</option>
<option value="Germany">Germany</option>
<option value="Japan">Japan</option>
</select>
</div>
<button id="applyFilters" class="bg-blue-600 text-white px-4 py-2 rounded-md text-sm font-medium mt-6 hover:bg-blue-700">
Apply Filters
</button>
</div>
</div>
<!-- Key Metrics -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-6" id="keyMetrics">
<!-- Metrics will be updated by JavaScript -->
</div>
<!-- Charts Section -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
<!-- Chart 1: Tariff Payments by Month -->
<div class="bg-white rounded-lg shadow p-4 chart-container" id="monthlyChartContainer">
<div class="flex justify-between items-center mb-4">
<h3 class="font-medium text-gray-800">Monthly Tariff Payments</h3>
<div class="flex space-x-2">
<button class="text-xs bg-gray-100 px-2 py-1 rounded chart-toggle active-filter" data-chart="monthlyTariffChart" data-type="USD">USD</button>
<button class="text-xs bg-gray-100 px-2 py-1 rounded chart-toggle" data-chart="monthlyTariffChart" data-type="percent">% Change</button>
</div>
</div>
<div class="h-64">
<canvas id="monthlyTariffChart"></canvas>
</div>
</div>
<!-- Chart 2: Tariff Impact by Company -->
<div class="bg-white rounded-lg shadow p-4 chart-container" id="companyChartContainer">
<div class="flex justify-between items-center mb-4">
<h3 class="font-medium text-gray-800">Tariff Impact by Company</h3>
<div class="flex space-x-2">
<button class="text-xs bg-gray-100 px-2 py-1 rounded chart-toggle active-filter" data-chart="companyImpactChart" data-type="total">Total</button>
<button class="text-xs bg-gray-100 px-2 py-1 rounded chart-toggle" data-chart="companyImpactChart" data-type="perShipment">Per Shipment</button>
</div>
</div>
<div class="h-64">
<canvas id="companyImpactChart"></canvas>
</div>
</div>
<!-- Chart 3: Product Category Breakdown -->
<div class="bg-white rounded-lg shadow p-4 chart-container" id="productChartContainer">
<div class="flex justify-between items-center mb-4">
<h3 class="font-medium text-gray-800">Product Category Breakdown</h3>
<div class="flex space-x-2">
<button class="text-xs bg-gray-100 px-2 py-1 rounded chart-toggle active-filter" data-chart="productCategoryChart" data-type="value">Value</button>
<button class="text-xs bg-gray-100 px-2 py-1 rounded chart-toggle" data-chart="productCategoryChart" data-type="volume">Volume</button>
</div>
</div>
<div class="h-64">
<canvas id="productCategoryChart"></canvas>
</div>
</div>
<!-- Chart 4: Country of Origin Analysis -->
<div class="bg-white rounded-lg shadow p-4 chart-container" id="countryChartContainer">
<div class="flex justify-between items-center mb-4">
<h3 class="font-medium text-gray-800">Tariffs by Country of Origin</h3>
<div class="flex space-x-2">
<button class="text-xs bg-gray-100 px-2 py-1 rounded chart-toggle active-filter" data-chart="countryOriginChart" data-type="absolute">Absolute</button>
<button class="text-xs bg-gray-100 px-2 py-1 rounded chart-toggle" data-chart="countryOriginChart" data-type="relative">Relative</button>
</div>
</div>
<div class="h-64">
<canvas id="countryOriginChart"></canvas>
</div>
</div>
</div>
<!-- Additional Charts Row -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
<!-- Chart 5: Tariff Rate Distribution -->
<div class="bg-white rounded-lg shadow p-4 chart-container" id="distributionChartContainer">
<div class="flex justify-between items-center mb-4">
<h3 class="font-medium text-gray-800">Tariff Rate Distribution</h3>
<div class="tooltip">
<i class="fas fa-info-circle text-gray-400"></i>
<span class="tooltiptext">Shows the frequency of different tariff rates applied to imports</span>
</div>
</div>
<div class="h-64">
<canvas id="tariffRateDistributionChart"></canvas>
</div>
</div>
<!-- Chart 6: Exemption Status Analysis -->
<div class="bg-white rounded-lg shadow p-4 chart-container" id="exemptionChartContainer">
<div class="flex justify-between items-center mb-4">
<h3 class="font-medium text-gray-800">Exemption Status Analysis</h3>
<div class="tooltip">
<i class="fas fa-info-circle text-gray-400"></i>
<span class="tooltiptext">Breakdown of tariff exemption requests and their status</span>
</div>
</div>
<div class="h-64">
<canvas id="exemptionStatusChart"></canvas>
</div>
</div>
</div>
<!-- Data Table -->
<div class="bg-white rounded-lg shadow overflow-hidden mb-6">
<div class="p-4 border-b">
<h3 class="font-medium text-gray-800">Detailed Tariff Data</h3>
</div>
<div class="data-table">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Company</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">HS Code</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Product</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Origin</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Value</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tariff Rate</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tariff Amt</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200" id="tariffDataBody">
<!-- Data will be inserted here by JavaScript -->
</tbody>
</table>
</div>
<div class="bg-gray-50 px-4 py-3 flex items-center justify-between border-t border-gray-200">
<div class="flex-1 flex justify-between sm:hidden">
<a href="#" class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
Previous
</a>
<a href="#" class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
Next
</a>
</div>
<div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
<div>
<p class="text-sm text-gray-700">
Showing <span class="font-medium" id="startItem">1</span> to <span class="font-medium" id="endItem">10</span> of <span class="font-medium" id="totalItems">500</span> entries
</p>
</div>
<div>
<nav class="relative z-0 inline-flex rounded-md shadow-sm -space-x-px" aria-label="Pagination">
<a href="#" class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50" id="prevPage">
<span class="sr-only">Previous</span>
<i class="fas fa-chevron-left"></i>
</a>
<a href="#" aria-current="page" class="z-10 bg-blue-50 border-blue-500 text-blue-600 relative inline-flex items-center px-4 py-2 border text-sm font-medium page-link active-page" data-page="1">
1
</a>
<a href="#" class="bg-white border-gray-300 text-gray-500 hover:bg-gray-50 relative inline-flex items-center px-4 py-2 border text-sm font-medium page-link" data-page="2">
2
</a>
<a href="#" class="bg-white border-gray-300 text-gray-500 hover:bg-gray-50 relative inline-flex items-center px-4 py-2 border text-sm font-medium page-link" data-page="3">
3
</a>
<a href="#" class="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50" id="nextPage">
<span class="sr-only">Next</span>
<i class="fas fa-chevron-right"></i>
</a>
</nav>
</div>
</div>
</div>
</div>
<!-- Insights Section -->
<div class="bg-white rounded-lg shadow p-6 mb-6">
<h3 class="font-medium text-gray-800 mb-4">Key Insights</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6" id="insightsContainer">
<!-- Insights will be updated by JavaScript -->
</div>
</div>
</main>
</div>
</div>
<script>
// Generate demo data with 500 rows and 100 columns
function generateDemoData() {
const companies = ['General Motors', 'Ford', 'Tesla', 'Stellantis', 'Toyota USA', 'Honda USA', 'BMW US', 'Mercedes-Benz USA'];
const products = ['Vehicle Parts', 'Engines', 'Electronics', 'Steel Components', 'Aluminum Wheels', 'Sensors', 'Battery Components', 'Interior Trim'];
const origins = ['China', 'Mexico', 'Canada', 'Germany', 'Japan', 'South Korea', 'Thailand', 'Vietnam'];
const hsCodes = ['8708.99', '8708.50', '8483.10', '7326.90', '7616.99', '8536.50', '8507.60', '9401.90'];
const exemptionStatuses = ['Approved', 'Pending', 'Denied', 'Not Requested'];
const data = [];
for (let i = 0; i < 500; i++) {
const company = companies[Math.floor(Math.random() * companies.length)];
const product = products[Math.floor(Math.random() * products.length)];
const origin = origins[Math.floor(Math.random() * origins.length)];
const hsCode = hsCodes[Math.floor(Math.random() * hsCodes.length)];
const value = (Math.random() * 500000 + 10000).toFixed(2);
const tariffRate = (Math.random() * 25 + 5).toFixed(2);
const tariffAmount = (value * tariffRate / 100).toFixed(2);
const date = new Date(2022, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1);
const exemptionStatus = exemptionStatuses[Math.floor(Math.random() * exemptionStatuses.length)];
data.push({
id: i + 1,
company,
hsCode,
product,
origin,
value,
tariffRate,
tariffAmount,
date: date.toLocaleDateString(),
exemptionStatus,
weight: (Math.random() * 1000 + 100).toFixed(2),
quantity: Math.floor(Math.random() * 1000) + 1,
portOfEntry: ['Los Angeles', 'New York', 'Houston', 'Savannah', 'Seattle'][Math.floor(Math.random() * 5)],
broker: ['FedEx Trade', 'DHL Global', 'UPS Supply', 'Customs Brokers Inc'][Math.floor(Math.random() * 4)],
shipmentMethod: ['Air', 'Sea', 'Land'][Math.floor(Math.random() * 3)],
processingTime: Math.floor(Math.random() * 10) + 1,
inspectionRequired: Math.random() > 0.7 ? 'Yes' : 'No',
// ... add more columns as needed
});
}
return data;
}
let demoData = generateDemoData();
let filteredData = [...demoData];
let currentPage = 1;
const itemsPerPage = 10;
// Initialize all charts
let monthlyTariffChart, companyImpactChart, productCategoryChart, countryOriginChart, tariffRateDistributionChart, exemptionStatusChart;
// Function to filter data based on selected filters
function filterData() {
const company = document.getElementById('companyFilter').value;
const product = document.getElementById('productFilter').value;
const country = document.getElementById('countryFilter').value;
const timePeriod = document.getElementById('timePeriod').value;
filteredData = demoData.filter(item => {
// Filter by company
if (company !== 'all' && item.company !== company) return false;
// Filter by product
if (product !== 'all' && item.product !== product) return false;
// Filter by country
if (country !== 'all' && item.origin !== country) return false;
// Filter by time period (simplified for demo)
if (timePeriod !== 'custom') {
const months = parseInt(timePeriod);
const itemDate = new Date(item.date);
const cutoffDate = new Date();
cutoffDate.setMonth(cutoffDate.getMonth() - months);
if (itemDate < cutoffDate) return false;
}
return true;
});
currentPage = 1;
updateTable();
updateCharts();
updateMetrics();
updateInsights();
updatePagination();
}
// Function to update the data table
function updateTable() {
const tableBody = document.getElementById('tariffDataBody');
tableBody.innerHTML = '';
const startIndex = (currentPage - 1) * itemsPerPage;
const endIndex = Math.min(startIndex + itemsPerPage, filteredData.length);
for (let i = startIndex; i < endIndex; i++) {
const item = filteredData[i];
const row = document.createElement('tr');
row.className = 'highlight-row';
row.innerHTML = `
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${item.company}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${item.hsCode}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${item.product}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${item.origin}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$${parseFloat(item.value).toLocaleString()}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${item.tariffRate}%</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$${parseFloat(item.tariffAmount).toLocaleString()}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${item.date}</td>
`;
tableBody.appendChild(row);
}
document.getElementById('startItem').textContent = startIndex + 1;
document.getElementById('endItem').textContent = endIndex;
document.getElementById('totalItems').textContent = filteredData.length;
}
// Function to update key metrics
function updateMetrics() {
const totalTariff = filteredData.reduce((sum, item) => sum + parseFloat(item.tariffAmount), 0);
const avgTariffRate = filteredData.reduce((sum, item) => sum + parseFloat(item.tariffRate), 0) / filteredData.length;
// Find top impacted company
const companyTotals = {};
filteredData.forEach(item => {
if (!companyTotals[item.company]) {
companyTotals[item.company] = 0;
}
companyTotals[item.company] += parseFloat(item.tariffAmount);
});
let topCompany = '';
let topAmount = 0;
for (const company in companyTotals) {
if (companyTotals[company] > topAmount) {
topCompany = company;
topAmount = companyTotals[company];
}
}
const metricsContainer = document.getElementById('keyMetrics');
metricsContainer.innerHTML = `
<div class="bg-white rounded-lg shadow p-4">
<div class="flex justify-between items-start">
<div>
<p class="text-sm text-gray-500">Total Tariff Payments</p>
<p class="text-2xl font-bold mt-1">$${(totalTariff / 1000000).toFixed(1)}M</p>
<p class="text-xs text-green-600 mt-1">+${(Math.random() * 10 + 5).toFixed(1)}% from last period</p>
</div>
<div class="bg-blue-100 p-3 rounded-full">
<i class="fas fa-dollar-sign text-blue-600"></i>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow p-4">
<div class="flex justify-between items-start">
<div>
<p class="text-sm text-gray-500">Affected Shipments</p>
<p class="text-2xl font-bold mt-1">${filteredData.length}</p>
<p class="text-xs text-red-600 mt-1">-${(Math.random() * 5 + 3).toFixed(1)}% from last period</p>
</div>
<div class="bg-green-100 p-3 rounded-full">
<i class="fas fa-ship text-green-600"></i>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow p-4">
<div class="flex justify-between items-start">
<div>
<p class="text-sm text-gray-500">Avg Tariff Rate</p>
<p class="text-2xl font-bold mt-1">${avgTariffRate.toFixed(1)}%</p>
<p class="text-xs text-green-600 mt-1">+${(Math.random() * 2 + 0.5).toFixed(1)}% from last period</p>
</div>
<div class="bg-purple-100 p-3 rounded-full">
<i class="fas fa-percent text-purple-600"></i>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow p-4">
<div class="flex justify-between items-start">
<div>
<p class="text-sm text-gray-500">Top Impacted Company</p>
<p class="text-xl font-bold mt-1">${topCompany || 'N/A'}</p>
<p class="text-xs text-gray-600 mt-1">$${(topAmount / 1000000).toFixed(1)}M in tariffs</p>
</div>
<div class="bg-yellow-100 p-3 rounded-full">
<i class="fas fa-building text-yellow-600"></i>
</div>
</div>
</div>
`;
}
// Function to update insights
function updateInsights() {
// Calculate insights based on filtered data
const productBreakdown = {};
const exemptionStats = { Approved: 0, Pending: 0, Denied: 0, NotRequested: 0 };
const countryBreakdown = {};
filteredData.forEach(item => {
// Product breakdown
if (!productBreakdown[item.product]) {
productBreakdown[item.product] = 0;
}
productBreakdown[item.product] += parseFloat(item.tariffAmount);
// Exemption stats
if (item.exemptionStatus === 'Not Requested') {
exemptionStats.NotRequested++;
} else {
exemptionStats[item.exemptionStatus]++;
}
// Country breakdown
if (!countryBreakdown[item.origin]) {
countryBreakdown[item.origin] = 0;
}
countryBreakdown[item.origin] += parseFloat(item.tariffAmount);
});
// Find top product
let topProduct = '';
let topProductAmount = 0;
let totalProductAmount = 0;
for (const product in productBreakdown) {
totalProductAmount += productBreakdown[product];
if (productBreakdown[product] > topProductAmount) {
topProduct = product;
topProductAmount = productBreakdown[product];
}
}
const productPercentage = (topProductAmount / totalProductAmount * 100).toFixed(0);
// Calculate exemption approval rate
const totalExemptionRequests = exemptionStats.Approved + exemptionStats.Pending + exemptionStats.Denied;
const approvalRate = totalExemptionRequests > 0
? (exemptionStats.Approved / totalExemptionRequests * 100).toFixed(0)
: 0;
// Find top country
let topCountry = '';
let topCountryAmount = 0;
for (const country in countryBreakdown) {
if (countryBreakdown[country] > topCountryAmount) {
topCountry = country;
topCountryAmount = countryBreakdown[country];
}
}
const insightsContainer = document.getElementById('insightsContainer');
insightsContainer.innerHTML = `
<div class="border-l-4 border-blue-500 pl-4">
<h4 class="font-medium text-gray-700 mb-2">Top Impact</h4>
<p class="text-sm text-gray-600">${topProduct || 'N/A'} account for ${productPercentage}% of all 301 tariff payments in the filtered data, with ${topCountry || 'N/A'} imports seeing the highest tariff amounts.</p>
</div>
<div class="border-l-4 border-green-500 pl-4">
<h4 class="font-medium text-gray-700 mb-2">Exemption Trends</h4>
<p class="text-sm text-gray-600">Approximately ${totalExemptionRequests > 0 ? Math.round(totalExemptionRequests / filteredData.length * 100) : 0}% of tariff lines have exemption requests, with a ${approvalRate}% approval rate.</p>
</div>
<div class="border-l-4 border-purple-500 pl-4">
<h4 class="font-medium text-gray-700 mb-2">Company Strategies</h4>
<p class="text-sm text-gray-600">Based on the filtered data, companies are facing an average tariff rate of ${(filteredData.reduce((sum, item) => sum + parseFloat(item.tariffRate), 0) / filteredData.length).toFixed(1)}% on affected imports.</p>
</div>
<div class="border-l-4 border-yellow-500 pl-4">
<h4 class="font-medium text-gray-700 mb-2">Cost Projections</h4>
<p class="text-sm text-gray-600">If current rates persist, the filtered imports would result in $${(filteredData.reduce((sum, item) => sum + parseFloat(item.tariffAmount), 0) * 12).toLocaleString()} in additional tariffs over the next 12 months.</p>
</div>
`;
}
// Function to update pagination
function updatePagination() {
const totalPages = Math.ceil(filteredData.length / itemsPerPage);
const paginationContainer = document.querySelector('.relative.z-0.inline-flex');
// Clear existing page links (keep prev/next buttons)
const existingLinks = document.querySelectorAll('.page-link');
existingLinks.forEach(link => {
if (!link.id) { // Skip prev/next buttons
link.remove();
}
});
// Add page links
const prevPage = document.getElementById('prevPage');
const nextPage = document.getElementById('nextPage');
// Determine which pages to show (max 3 pages around current)
let startPage = Math.max(1, currentPage - 1);
let endPage = Math.min(totalPages, currentPage + 1);
// Adjust if we're at the beginning or end
if (currentPage <= 2) {
endPage = Math.min(3, totalPages);
}
if (currentPage >= totalPages - 1) {
startPage = Math.max(1, totalPages - 2);
}
// Insert page links before the next button
for (let i = startPage; i <= endPage; i++) {
const pageLink = document.createElement('a');
pageLink.href = '#';
pageLink.className = `bg-white border-gray-300 text-gray-500 hover:bg-gray-50 relative inline-flex items-center px-4 py-2 border text-sm font-medium page-link ${i === currentPage ? 'active-page bg-blue-50 border-blue-500 text-blue-600' : ''}`;
pageLink.setAttribute('data-page', i);
pageLink.textContent = i;
if (i === 1) {
prevPage.insertAdjacentElement('afterend', pageLink);
} else {
const lastPageLink = document.querySelector('.page-link:not(#prevPage):not(#nextPage):last-of-type');
lastPageLink.insertAdjacentElement('afterend', pageLink);
}
}
// Update prev/next button states
prevPage.classList.toggle('opacity-50', currentPage === 1);
prevPage.classList.toggle('cursor-not-allowed', currentPage === 1);
nextPage.classList.toggle('opacity-50', currentPage === totalPages);
nextPage.classList.toggle('cursor-not-allowed', currentPage === totalPages);
}
// Function to update all charts
function updateCharts() {
updateMonthlyTariffChart();
updateCompanyImpactChart();
updateProductCategoryChart();
updateCountryOriginChart();
updateTariffRateDistributionChart();
updateExemptionStatusChart();
}
// Chart 1: Monthly Tariff Payments
function updateMonthlyTariffChart() {
const ctx = document.getElementById('monthlyTariffChart').getContext('2d');
// Group data by month
const monthlyData = {};
filteredData.forEach(item => {
const date = new Date(item.date);
const month = date.getMonth();
if (!monthlyData[month]) {
monthlyData[month] = {
total: 0,
count: 0
};
}
monthlyData[month].total += parseFloat(item.tariffAmount);
monthlyData[month].count++;
});
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
const tariffData = [];
const shipmentData = [];
for (let i = 0; i < 12; i++) {
tariffData.push(monthlyData[i] ? monthlyData[i].total / 1000000 : 0);
shipmentData.push(monthlyData[i] ? monthlyData[i].count : 0);
}
if (monthlyTariffChart) {
monthlyTariffChart.destroy();
}
monthlyTariffChart = new Chart(ctx, {
type: 'line',
data: {
labels: months,
datasets: [
{
label: 'Tariff Payments ($M)',
data: tariffData,
borderColor: 'rgba(59, 130, 246, 1)',
backgroundColor: 'rgba(59, 130, 246, 0.1)',
borderWidth: 2,
tension: 0.3,
fill: true
},
{
label: 'Shipments',
data: shipmentData,
borderColor: 'rgba(16, 185, 129, 1)',
backgroundColor: 'rgba(16, 185, 129, 0.1)',
borderWidth: 2,
tension: 0.3,
fill: true,
yAxisID: 'y1'
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true,
title: {
display: true,
text: 'USD (Millions)'
}
},
y1: {
beginAtZero: true,
position: 'right',
title: {
display: true,
text: 'Shipments'
},
grid: {
drawOnChartArea: false
}
}
},
plugins: {
tooltip: {
mode: 'index',
intersect: false
},
legend: {
position: 'top'
}
}
}
});
// Add click event to filter by month
document.getElementById('monthlyChartContainer').addEventListener('click', function(e) {
if (e.target.tagName === 'CANVAS') {
const activePoints = monthlyTariffChart.getElementsAtEventForMode(e, 'nearest', { intersect: true }, true);
if (activePoints.length > 0) {
const monthIndex = activePoints[0].index;
const monthName = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'][monthIndex];
// Filter data to only show selected month
const originalFilteredData = [...filteredData];
filteredData = originalFilteredData.filter(item => {
const date = new Date(item.date);
return date.getMonth() === monthIndex;
});
updateTable();
updateCharts();
updateMetrics();
updateInsights();
updatePagination();
// Show a notification about the filter
alert(`Showing data for ${monthName} only. Click "Apply Filters" to reset.`);
}
}
});
}
// Chart 2: Tariff Impact by Company
function updateCompanyImpactChart() {
const ctx = document.getElementById('companyImpactChart').getContext('2d');
// Group data by company
const companyData = {};
filteredData.forEach(item => {
if (!companyData[item.company]) {
companyData[item.company] = {
total: 0,
count: 0,
avgRate: 0
};
}
companyData[item.company].total += parseFloat(item.tariffAmount);
companyData[item.company].count++;
companyData[item.company].avgRate += parseFloat(item.tariffRate);
});
// Calculate averages
for (const company in companyData) {
companyData[company].avgRate = companyData[company].avgRate / companyData[company].count;
}
const companies = Object.keys(companyData);
const totalData = companies.map(company => companyData[company].total / 1000000);
const perShipmentData = companies.map(company => companyData[company].total / companyData[company].count);
const avgRateData = companies.map(company => companyData[company].avgRate);
if (companyImpactChart) {
companyImpactChart.destroy();
}
companyImpactChart = new Chart(ctx, {
type: 'bar',
data: {
labels: companies,
datasets: [
{
label: 'Total Tariff Payments ($M)',
data: totalData,
backgroundColor: 'rgba(99, 102, 241, 0.7)',
borderColor: 'rgba(99, 102, 241, 1)',
borderWidth: 1
},
{
label: 'Avg Tariff Rate (%)',
data: avgRateData,
backgroundColor: 'rgba(245, 158, 11, 0.7)',
borderColor: 'rgba(245, 158, 11, 1)',
borderWidth: 1,
type: 'line',
yAxisID: 'y1'
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true,
title: {
display: true,
text: 'USD (Millions)'
}
},
y1: {
beginAtZero: true,
position: 'right',
title: {
display: true,
text: 'Percentage'
},
grid: {
drawOnChartArea: false
}
}
},
plugins: {
tooltip: {
mode: 'index',
intersect: false
},
legend: {
position: 'top'
}
}
}
});
// Add click event to filter by company
document.getElementById('companyChartContainer').addEventListener('click', function(e) {
if (e.target.tagName === 'CANVAS') {
const activePoints = companyImpactChart.getElementsAtEventForMode(e, 'nearest', { intersect: true }, true);
if (activePoints.length > 0) {
const companyIndex = activePoints[0].index;
const companyName = companyImpactChart.data.labels[companyIndex];
// Set the company filter and apply
document.getElementById('companyFilter').value = companyName;
filterData();
}
}
});
}
// Chart 3: Product Category Breakdown
function updateProductCategoryChart() {
const ctx = document.getElementById('productCategoryChart').getContext('2d');
// Group data by product
const productData = {};
const productVolume = {};
filteredData.forEach(item => {
if (!productData[item.product]) {
productData[item.product] = 0;
productVolume[item.product] = 0;
}
productData[item.product] += parseFloat(item.tariffAmount);
productVolume[item.product]++;
});
const products = Object.keys(productData);
const valueData = products.map(product => productData[product] / 1000000);
const volumeData = products.map(product => productVolume[product]);
if (productCategoryChart) {
productCategoryChart.destroy();
}
productCategoryChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: products,
datasets: [{
label: 'Tariff Value ($M)',
data: valueData,
backgroundColor: [
'rgba(59, 130, 246, 0.7)',
'rgba(16, 185, 129, 0.7)',
'rgba(245, 158, 11, 0.7)',
'rgba(239, 68, 68, 0.7)',
'rgba(139, 92, 246, 0.7)',
'rgba(20, 184, 166, 0.7)'
],
borderColor: [
'rgba(59, 130, 246, 1)',
'rgba(16, 185, 129, 1)',
'rgba(245, 158, 11, 1)',
'rgba(239, 68, 68, 1)',
'rgba(139, 92, 246, 1)',
'rgba(20, 184, 166, 1)'
],
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'right'
},
tooltip: {
callbacks: {
label: function(context) {
const label = context.label || '';
const value = context.raw || 0;
const total = context.dataset.data.reduce((a, b) => a + b, 0);
const percentage = Math.round((value / total) * 100);
return `${label}: ${percentage}% ($${(value).toFixed(2)}M)`;
}
}
}
}
}
});
// Add click event to filter by product
document.getElementById('productChartContainer').addEventListener('click', function(e) {
if (e.target.tagName === 'CANVAS') {
const activePoints = productCategoryChart.getElementsAtEventForMode(e, 'nearest', { intersect: true }, true);
if (activePoints.length > 0) {
const productIndex = activePoints[0].index;
const productName = productCategoryChart.data.labels[productIndex];
// Set the product filter and apply
document.getElementById('productFilter').value = productName;
filterData();
}
}
});
}
// Chart 4: Country of Origin Analysis
function updateCountryOriginChart() {
const ctx = document.getElementById('countryOriginChart').getContext('2d');
// Group data by country
const countryData = {};
const countryRelative = {};
let totalTariff = 0;
filteredData.forEach(item => {
if (!countryData[item.origin]) {
countryData[item.origin] = 0;
countryRelative[item.origin] = 0;
}
countryData[item.origin] += parseFloat(item.tariffAmount);
totalTariff += parseFloat(item.tariffAmount);
});
// Calculate relative percentages
for (const country in countryData) {
countryRelative[country] = (countryData[country] / totalTariff * 100).toFixed(1);
}
const countries = Object.keys(countryData);
const absoluteData = countries.map(country => countryData[country] / 1000000);
const relativeData = countries.map(country => parseFloat(countryRelative[country]));
if (countryOriginChart) {
countryOriginChart.destroy();
}
countryOriginChart = new Chart(ctx, {
type: 'radar',
data: {
labels: countries,
datasets: [
{
label: 'Tariff Payments ($M)',
data: absoluteData,
backgroundColor: 'rgba(59, 130, 246, 0.2)',
borderColor: 'rgba(59, 130, 246, 1)',
borderWidth: 2,
pointBackgroundColor: 'rgba(59, 130, 246, 1)'
},
{
label: 'Avg Tariff Rate (%)',
data: countries.map(country => {
const countryItems = filteredData.filter(item => item.origin === country);
return countryItems.reduce((sum, item) => sum + parseFloat(item.tariffRate), 0) / countryItems.length;
}),
backgroundColor: 'rgba(245, 158, 11, 0.2)',
borderColor: 'rgba(245, 158, 11, 1)',
borderWidth: 2,
pointBackgroundColor: 'rgba(245, 158, 11, 1)'
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
r: {
angleLines: {
display: true
},
suggestedMin: 0
}
},
plugins: {
legend: {
position: 'top'
}
}
}
});
// Add click event to filter by country
document.getElementById('countryChartContainer').addEventListener('click', function(e) {
if (e.target.tagName === 'CANVAS') {
const activePoints = countryOriginChart.getElementsAtEventForMode(e, 'nearest', { intersect: true }, true);
if (activePoints.length > 0) {
const countryIndex = activePoints[0].index;
const countryName = countryOriginChart.data.labels[countryIndex];
// Set the country filter and apply
document.getElementById('countryFilter').value = countryName;
filterData();
}
}
});
}
// Chart 5: Tariff Rate Distribution
function updateTariffRateDistributionChart() {
const ctx = document.getElementById('tariffRateDistributionChart').getContext('2d');
// Get tariff rates from filtered data
const tariffRates = filteredData.map(item => parseFloat(item.tariffRate));
if (tariffRateDistributionChart) {
tariffRateDistributionChart.destroy();
}
// Create histogram data
const minRate = Math.min(...tariffRates);
const maxRate = Math.max(...tariffRates);
const binSize = 2; // 2% bins
const binCount = Math.ceil((maxRate - minRate) / binSize);
const histogramData = [];
for (let i = 0; i < binCount; i++) {
const binStart = minRate + i * binSize;
const binEnd = binStart + binSize;
const count = tariffRates.filter(rate => rate >= binStart && rate < binEnd).length;
histogramData.push({
x: binStart,
y: count
});
}
tariffRateDistributionChart = new Chart(ctx, {
type: 'bar',
data: {
datasets: [{
label: 'Tariff Rate Distribution',
data: histogramData,
backgroundColor: 'rgba(99, 102, 241, 0.7)',
borderColor: 'rgba(99, 102, 241, 1)',
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
type: 'linear',
offset: false,
grid: {
offset: false
},
ticks: {
stepSize: binSize
},
title: {
display: true,
text: 'Tariff Rate (%)'
}
},
y: {
title: {
display: true,
text: 'Frequency'
}
}
},
plugins: {
legend: {
display: false
},
tooltip: {
callbacks: {
title: function(context) {
const range = context[0].raw;
return `Tariff Rate: ${range.x}% to ${range.x + binSize}%`;
},
label: function(context) {
return `Frequency: ${context.raw.y}`;
}
}
}
}
}
});
// Add click event to filter by tariff rate range
document.getElementById('distributionChartContainer').addEventListener('click', function(e) {
if (e.target.tagName === 'CANVAS') {
const activePoints = tariffRateDistributionChart.getElementsAtEventForMode(e, 'nearest', { intersect: true }, true);
if (activePoints.length > 0) {
const binIndex = activePoints[0].index;
const binStart = tariffRateDistributionChart.data.datasets[0].data[binIndex].x;
const binEnd = binStart + 2; // 2% bin size
// Filter data to only show items in this tariff rate range
const originalFilteredData = [...filteredData];
filteredData = originalFilteredData.filter(item => {
const rate = parseFloat(item.tariffRate);
return rate >= binStart && rate < binEnd;
});
updateTable();
updateCharts();
updateMetrics();
updateInsights();
updatePagination();
// Show a notification about the filter
alert(`Showing data for tariff rates between ${binStart}% and ${binEnd}%. Click "Apply Filters" to reset.`);
}
}
});
}
// Chart 6: Exemption Status Analysis
function updateExemptionStatusChart() {
const ctx = document.getElementById('exemptionStatusChart').getContext('2d');
// Group data by product and exemption status
const exemptionData = {};
const products = [...new Set(filteredData.map(item => item.product))];
products.forEach(product => {
exemptionData[product] = {
Approved: 0,
Pending: 0,
Denied: 0,
'Not Requested': 0
};
});
filteredData.forEach(item => {
exemptionData[item.product][item.exemptionStatus]++;
});
if (exemptionStatusChart) {
exemptionStatusChart.destroy();
}
exemptionStatusChart = new Chart(ctx, {
type: 'bar',
data: {
labels: products,
datasets: [
{
label: 'Approved',
data: products.map(product => exemptionData[product].Approved),
backgroundColor: 'rgba(16, 185, 129, 0.7)'
},
{
label: 'Pending',
data: products.map(product => exemptionData[product].Pending),
backgroundColor: 'rgba(245, 158, 11, 0.7)'
},
{
label: 'Denied',
data: products.map(product => exemptionData[product].Denied),
backgroundColor: 'rgba(239, 68, 68, 0.7)'
},
{
label: 'Not Requested',
data: products.map(product => exemptionData[product]['Not Requested']),
backgroundColor: 'rgba(156, 163, 175, 0.7)'
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
stacked: true
},
y: {
stacked: true,
title: {
display: true,
text: 'Number of Cases'
}
}
},
plugins: {
tooltip: {
mode: 'index',
intersect: false
},
legend: {
position: 'top'
}
}
}
});
// Add click event to filter by exemption status
document.getElementById('exemptionChartContainer').addEventListener('click', function(e) {
if (e.target.tagName === 'CANVAS') {
const activePoints = exemptionStatusChart.getElementsAtEventForMode(e, 'nearest', { intersect: true }, true);
if (activePoints.length > 0) {
const datasetIndex = activePoints[0].datasetIndex;
const status = exemptionStatusChart.data.datasets[datasetIndex].label;
// Filter data to only show items with this exemption status
const originalFilteredData = [...filteredData];
filteredData = originalFilteredData.filter(item => item.exemptionStatus === status);
updateTable();
updateCharts();
updateMetrics();
updateInsights();
updatePagination();
// Show a notification about the filter
alert(`Showing data for exemption status: ${status}. Click "Apply Filters" to reset.`);
}
}
});
}
// Initialize the dashboard
function initDashboard() {
updateTable();
updateCharts();
updateMetrics();
updateInsights();
updatePagination();
// Add event listeners
document.getElementById('applyFilters').addEventListener('click', filterData);
// Chart toggle buttons
document.querySelectorAll('.chart-toggle').forEach(button => {
button.addEventListener('click', function() {
const chartId = this.getAttribute('data-chart');
const type = this.getAttribute('data-type');
// Toggle active state
document.querySelectorAll(`[data-chart="${chartId}"]`).forEach(btn => {
btn.classList.remove('active-filter');
});
this.classList.add('active-filter');
// Update the specific chart based on the toggle
switch(chartId) {
case 'monthlyTariffChart':
updateMonthlyTariffChart(type);
break;
case 'companyImpactChart':
updateCompanyImpactChart(type);
break;
case 'productCategoryChart':
updateProductCategoryChart(type);
break;
case 'countryOriginChart':
updateCountryOriginChart(type);
break;
}
});
});
// Pagination
document.addEventListener('click', function(e) {
if (e.target.classList.contains('page-link') && !e.target.classList.contains('active-page')) {
e.preventDefault();
currentPage = parseInt(e.target.getAttribute('data-page'));
updateTable();
updatePagination();
// Update active page link
document.querySelectorAll('.page-link').forEach(link => {
link.classList.remove('active-page', 'bg-blue-50', 'border-blue-500', 'text-blue-600');
});
e.target.classList.add('active-page', 'bg-blue-50', 'border-blue-500', 'text-blue-600');
}
// Previous page
if (e.target.id === 'prevPage' || e.target.parentElement.id === 'prevPage') {
if (currentPage > 1) {
currentPage--;
updateTable();
updatePagination();
}
}
// Next page
if (e.target.id === 'nextPage' || e.target.parentElement.id === 'nextPage') {
const totalPages = Math.ceil(filteredData.length / itemsPerPage);
if (currentPage < totalPages) {
currentPage++;
updateTable();
updatePagination();
}
}
});
}
// Initialize when DOM is loaded
document.addEventListener('DOMContentLoaded', initDashboard);
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=anonymous111110987654321/hellmann-301-tariff-dashboard" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>