Project1 / index.html
tayy786's picture
Update index.html
9b94997 verified
Raw History Blame Contribute Delete
20.1 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Super Store Debug Dashboard</title>
<script src="https://cdn.jsdelivr.net/npm/papaparse@5.4.3/papaparse.min.js"></script>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: Arial, sans-serif;
background: #f1f5f9;
color: #0f172a;
}
.container {
max-width: 1400px;
margin: auto;
padding: 25px;
}
header {
background: #0f172a;
color: white;
padding: 30px;
border-radius: 15px;
margin-bottom: 20px;
}
header h1 {
margin: 0 0 10px;
}
header p {
margin: 0;
color: #cbd5e1;
}
.card {
background: white;
padding: 22px;
border-radius: 12px;
margin-bottom: 20px;
box-shadow: 0 3px 12px rgba(0,0,0,0.08);
}
button {
padding: 12px 20px;
margin-top: 10px;
border: none;
border-radius: 8px;
background: #2563eb;
color: white;
cursor: pointer;
font-size: 15px;
}
button:hover {
background: #1d4ed8;
}
button.secondary {
background: #475569;
}
.success {
background: #dcfce7;
color: #166534;
padding: 15px;
border-radius: 8px;
}
.error {
background: #fee2e2;
color: #991b1b;
padding: 15px;
border-radius: 8px;
}
.warning {
background: #fef3c7;
color: #92400e;
padding: 15px;
border-radius: 8px;
}
.info {
background: #dbeafe;
color: #1e40af;
padding: 15px;
border-radius: 8px;
}
pre {
background: #0f172a;
color: #e2e8f0;
padding: 15px;
border-radius: 8px;
overflow-x: auto;
white-space: pre-wrap;
}
.columns {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.column {
background: #e0f2fe;
color: #075985;
padding: 8px 12px;
border-radius: 20px;
font-size: 13px;
}
.missing {
background: #fee2e2;
color: #991b1b;
}
.question {
border-left: 5px solid #2563eb;
background: #f8fafc;
padding: 15px;
margin-bottom: 12px;
border-radius: 6px;
}
.question.ok {
border-left-color: #16a34a;
}
.question.fail {
border-left-color: #dc2626;
}
.question h3 {
margin-top: 0;
}
.answer {
font-weight: bold;
color: #2563eb;
}
table {
border-collapse: collapse;
width: 100%;
overflow-x: auto;
}
th,
td {
padding: 10px;
border: 1px solid #cbd5e1;
text-align: left;
white-space: nowrap;
}
th {
background: #e2e8f0;
}
.table-wrapper {
overflow-x: auto;
}
.hidden {
display: none;
}
.kpi-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 15px;
}
.kpi {
background: #eff6ff;
padding: 18px;
border-radius: 10px;
}
.kpi small {
color: #475569;
}
.kpi strong {
display: block;
font-size: 25px;
margin-top: 8px;
color: #1d4ed8;
}
@media(max-width:800px) {
.kpi-grid {
grid-template-columns: repeat(2,1fr);
}
}
@media(max-width:500px) {
.kpi-grid {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>πŸ› Super Store Debug Dashboard</h1>
<p>
This version shows exactly what happens when your CSV is uploaded.
</p>
</header>
<!-- UPLOAD -->
<div class="card">
<h2>1️⃣ Upload CSV</h2>
<input
type="file"
id="csvFile"
accept=".csv"
>
<br>
<button onclick="debugCSV()">
πŸ” Analyze CSV
</button>
<button
class="secondary"
onclick="clearDebug()"
>
Clear
</button>
</div>
<!-- STATUS -->
<div class="card">
<h2>2️⃣ System Status</h2>
<div id="status">
Waiting for CSV...
</div>
</div>
<!-- COLUMNS -->
<div class="card">
<h2>3️⃣ Detected CSV Columns</h2>
<div id="columns">
No CSV loaded.
</div>
</div>
<!-- REQUIRED COLUMNS -->
<div class="card">
<h2>4️⃣ Required Columns Check</h2>
<div id="requiredCheck">
Not checked yet.
</div>
</div>
<!-- DATASET INFO -->
<div class="card">
<h2>5️⃣ Dataset Information</h2>
<div class="kpi-grid">
<div class="kpi">
<small>Total Rows</small>
<strong id="rowCount">0</strong>
</div>
<div class="kpi">
<small>Total Columns</small>
<strong id="columnCount">0</strong>
</div>
<div class="kpi">
<small>Valid Quantity</small>
<strong id="validQuantity">0</strong>
</div>
<div class="kpi">
<small>Valid Price</small>
<strong id="validPrice">0</strong>
</div>
</div>
</div>
<!-- CALCULATION TEST -->
<div class="card">
<h2>6️⃣ Sales Calculation Test</h2>
<p>
The dashboard calculates:
</p>
<pre>
Sales = quantiy Γ— prce
</pre>
<div id="calculationTest">
Waiting for data...
</div>
</div>
<!-- RAW DATA -->
<div class="card">
<h2>7️⃣ First 5 Rows of Your CSV</h2>
<div
class="table-wrapper"
id="rawData"
>
No data loaded.
</div>
</div>
<!-- QUESTIONS -->
<div class="card">
<h2>8️⃣ Ten Questions Debug</h2>
<div id="questions">
No questions processed yet.
</div>
</div>
<!-- ERRORS -->
<div class="card">
<h2>9️⃣ Errors & Warnings</h2>
<div id="errors">
No errors detected.
</div>
</div>
<!-- JAVASCRIPT LOG -->
<div class="card">
<h2>πŸ”Ÿ JavaScript Debug Log</h2>
<pre id="debugLog">
Waiting...
</pre>
</div>
</div>
<script>
/* =====================================================
CONFIGURATION
===================================================== */
const REQUIRED_COLUMNS = [
"transaction_id",
"customer_id",
"customer_name",
"customer_age",
"gender",
"product_id",
"product_name",
"product_category",
"quantiy",
"prce",
"payment_mode",
"purchase_date",
"time_of_purchase",
"status"
];
let debugMessages = [];
let errorMessages = [];
/* =====================================================
LOGGING
===================================================== */
function log(message) {
const time =
new Date().toLocaleTimeString();
debugMessages.push(
"[" + time + "] " + message
);
document.getElementById(
"debugLog"
).textContent =
debugMessages.join("\n");
console.log(message);
}
function addError(message) {
errorMessages.push(message);
renderErrors();
console.error(message);
}
function renderErrors() {
const box =
document.getElementById("errors");
if (errorMessages.length === 0) {
box.innerHTML =
'<div class="success">βœ… No errors detected.</div>';
return;
}
box.innerHTML =
errorMessages
.map(
e =>
`<div class="error">❌ ${escapeHTML(e)}</div>`
)
.join("");
}
/* =====================================================
ESCAPE HTML
===================================================== */
function escapeHTML(value) {
return String(value)
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
/* =====================================================
CLEAR
===================================================== */
function clearDebug() {
location.reload();
}
/* =====================================================
START CSV ANALYSIS
===================================================== */
function debugCSV() {
debugMessages = [];
errorMessages = [];
renderErrors();
const file =
document.getElementById(
"csvFile"
).files[0];
if (!file) {
addError(
"No CSV file selected."
);
document.getElementById(
"status"
).innerHTML =
'<div class="error">❌ Please select a CSV file.</div>';
return;
}
log(
"Selected file: " +
file.name
);
log(
"File size: " +
file.size +
" bytes"
);
document.getElementById(
"status"
).innerHTML =
'<div class="info">⏳ Reading CSV...</div>';
Papa.parse(
file,
{
header: true,
skipEmptyLines: true,
dynamicTyping: false,
complete: function(results) {
log(
"Papa Parse completed."
);
log(
"Rows returned: " +
results.data.length
);
if (
results.errors &&
results.errors.length > 0
) {
results.errors.forEach(
error => {
addError(
"CSV Parser: " +
JSON.stringify(error)
);
}
);
}
try {
processData(
results.data,
results.meta
);
}
catch(error) {
addError(
"MAIN ERROR: " +
error.message
);
document.getElementById(
"status"
).innerHTML =
`<div class="error">
❌ Application error:<br>
${escapeHTML(error.message)}
</div>`;
console.error(error);
}
},
error: function(error) {
addError(
"Papa Parse error: " +
JSON.stringify(error)
);
}
}
);
}
/* =====================================================
CLEAN COLUMN NAME
===================================================== */
function cleanColumnName(name) {
return String(name)
.replace(/^\uFEFF/, "")
.trim()
.toLowerCase();
}
/* =====================================================
PROCESS DATA
===================================================== */
function processData(
data,
meta
) {
log(
"Starting data processing..."
);
if (!data || data.length === 0) {
throw new Error(
"CSV contains zero data rows."
);
}
/* ---------------------------------------------
ORIGINAL COLUMNS
--------------------------------------------- */
const originalColumns =
meta.fields || Object.keys(data[0]);
log(
"Original columns detected: " +
JSON.stringify(originalColumns)
);
/* ---------------------------------------------
NORMALIZE COLUMN NAMES
--------------------------------------------- */
const normalizedMap = {};
originalColumns.forEach(
original => {
const clean =
cleanColumnName(
original
);
normalizedMap[clean] =
original;
}
);
const columns =
Object.keys(normalizedMap);
log(
"Normalized columns: " +
JSON.stringify(columns)
);
showColumns(columns);
/* ---------------------------------------------
REQUIRED COLUMN CHECK
--------------------------------------------- */
const missing =
REQUIRED_COLUMNS.filter(
required =>
!columns.includes(required)
);
if (missing.length > 0) {
log(
"Missing columns detected: " +
missing.join(", ")
);
showRequiredCheck(
missing
);
throw new Error(
"Required columns are missing: " +
missing.join(", ")
);
}
showRequiredCheck([]);
log(
"All required columns found."
);
/* ---------------------------------------------
RENAME DATA
--------------------------------------------- */
const cleanData =
data.map(
originalRow => {
const row = {};
Object.keys(
normalizedMap
).forEach(
cleanName => {
const originalName =
normalizedMap[
cleanName
];
row[cleanName] =
originalRow[
originalName
];
}
);
return row;
}
);
log(
"Data normalization complete."
);
/* ---------------------------------------------
ROW COUNT
--------------------------------------------- */
document.getElementById(
"rowCount"
).innerText =
cleanData.length.toLocaleString();
document.getElementById(
"columnCount"
).innerText =
columns.length.toLocaleString();
/* ---------------------------------------------
NUMERIC TEST
--------------------------------------------- */
let validQuantity = 0;
let validPrice = 0;
cleanData.forEach(
row => {
const quantity =
parseNumber(
row.quantiy
);
const price =
parseNumber(
row.prce
);
if (
!isNaN(quantity) &&
quantity !== 0
) {
validQuantity++;
}
if (
!isNaN(price) &&
price !== 0
) {
validPrice++;
}
row.quantityValue =
quantity;
row.priceValue =
price;
row.salesAmount =
quantity * price;
}
);
document.getElementById(
"validQuantity"
).innerText =
validQuantity.toLocaleString();
document.getElementById(
"validPrice"
).innerText =
validPrice.toLocaleString();
log(
"Valid quantity values: " +
validQuantity
);
log(
"Valid price values: " +
validPrice
);
/* ---------------------------------------------
CALCULATION TEST
--------------------------------------------- */
calculationTest(
cleanData
);
/* ---------------------------------------------
RAW DATA
--------------------------------------------- */
showRawData(
cleanData
);
/* ---------------------------------------------
QUESTIONS
--------------------------------------------- */
answerQuestions(
cleanData
);
document.getElementById(
"status"
).innerHTML =
`<div class="success">
βœ… CSV successfully processed.<br>
${cleanData.length.toLocaleString()}
rows detected.
</div>`;
log(
"Processing completed successfully."
);
}
/* =====================================================
PARSE NUMBER
===================================================== */
function parseNumber(value) {
if (
value === undefined ||
value === null ||
String(value).trim() === ""
) {
return NaN;
}
const cleaned =
String(value)
.replace(/[$,\s]/g, "")
.trim();
return Number(
cleaned
);
}
/* =====================================================
SHOW COLUMNS
===================================================== */
function showColumns(
columns
) {
const container =
document.getElementById(
"columns"
);
container.innerHTML =
columns
.map(
column =>
`<span class="column">
${escapeHTML(column)}
</span>`
)
.join("");
}
/* =====================================================
REQUIRED COLUMN CHECK
===================================================== */
function showRequiredCheck(
missing
) {
const box =
document.getElementById(
"requiredCheck"
);
if (
missing.length === 0
) {
box.innerHTML =
`<div class="success">
βœ… All ${REQUIRED_COLUMNS.length}
required columns are present.
</div>`;
return;
}
box.innerHTML =
`<div class="error">
❌ Missing columns:
<br><br>
<strong>
${missing.join(", ")}
</strong>
</div>`;
}
/* =====================================================
CALCULATION TEST
===================================================== */
function calculationTest(
data
) {
const box =
document.getElementById(
"calculationTest"
);
if (
data.length === 0
) {
box.innerHTML =
'<div class="error">No rows.</div>';
return;
}
const first =
data[0];
const quantity =
first.quantityValue;
const price =
first.priceValue;
const sales =
first.salesAmount;
log(
"First quantity = " +
quantity
);
log(
"First price = " +
price
);
log(
"First calculated sales = " +
sales
);
if (
isNaN(quantity) ||
isNaN(price)
) {
box.innerHTML =
`<div class="error">
❌ Numeric conversion failed.
<br><br>
Raw quantity:
<strong>
${escapeHTML(first.quantiy)}
</strong>
<br>
Raw price:
<strong>
${escapeHTML(first.prce)}
</strong>
</div>`;
addError(
"quantiy or prce could not be converted into numbers."
);
return;
}
box.innerHTML =
`<div class="success">
βœ… Calculation works.
<br><br>
Quantity:
<strong>${quantity}</strong>
Γ—
Price:
<strong>${price}</strong>
=
Sales:
<strong>${sales.toFixed(2)}</strong>
</div>`;
}
/* =====================================================
RAW DATA TABLE
===================================================== */
function showRawData(
data
) {
const box =
document.getElementById(
"rawData"
);
const columns = [
"transaction_id",
"customer_id",
"customer_name",
"product_name",
"product_category",
"quantiy",
"prce",
"payment_mode",
"purchase_date",
"status"
];
let html =
"<table><thead><tr>";
columns.forEach(
column => {
html +=
`<th>${column}</th>`;
}
);
html +=
"</tr></thead><tbody>";
data.slice(0,5).forEach(
row => {
html += "<tr>";
columns.forEach(
column => {
html +=
`<td>
${escapeHTML(
row[column] ?? ""
)}
</td>`;
}
);
html += "</tr>";
}
);
html +=
"</tbody></table>";
box.innerHTML =
html;
}
/* =====================================================
GROUP SALES
===================================================== */
function groupSales(
data,
column
) {
const result = {};
data.forEach(
row => {
let key =
ro