<body>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Editable JSON Table with Search</title>
<style>
html, body {
height: 100%;
margin: 5px;
background: #f4f4f4;
font-family: Arial, sans-serif;
text-align: center;
-webkit-tap-highlight-color: transparent;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
.page-wrapper {
min-height: 100%;
display: flex;
flex-direction: column;
}
.content {
flex: 1;
}
h2 {
text-align: center;
}
.container {
width: 100%;
max-width: 1200px;
margin: auto;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.buttons {
display: flex;
gap: 10px;
margin-left: 50px;
margin-bottom: 20px;
}
button, label {
padding: 8px 15px;
background-color: #007700;
color: white;
cursor: pointer;
border: none;
border-radius: 5px;
}
input[type="file"] {
display: none;
}
.search-container {
text-align: center;
margin-bottom: 10px;
}
.search-container input {
width: 40%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 5px;
text-align: center;
}
.table-container {
width: 100%;
max-height: 350px;
overflow-y: auto;
border: 1px solid #ddd;
background: white;
}
table {
width: 100%;
border-collapse: collapse;
background: white;
}
thead {
position: sticky;
top: 0;
background-color: #005000;
color: white;
z-index: 2;
}
th, td {
border: 1px solid #ddd;
padding: 10px;
text-align: left;
}
td[contenteditable="true"] {
background-color: #e8f5e9;
}
.footer {
background: #000;
color: #fff;
text-align: center;
font-size: 10px;
bottom:0;
left: 0;
position: fixed;
width: 100vw;
}
.footer b {
font-size: 12px;
color: #009500;
margin-top: 10px;
}
.contact {
background: #f4f4f4;
font-family: 'Righteous', cursive;
}
.contact-inner {
display: flex;
justify-content: space-between;
align-items: center;
width: calc(100% - 20px);
margin: 0 auto;
padding: 50px 10px;
margin-bottom: 20px;
}
.contact-logo {
width: 100px;
height: auto;
margin-top: -1px;
}
.contact-link {
color: #009500;
text-decoration: none;
font-weight: bold;
}
.contact-link i {
font-size: 20px;
}
</style>
<div class="page-wrapper">
<div class="content">
<!-- xxxxxxxxxxxxxxxxxxxxxxxxxxx -->
<header style="position: fixed; top: 0; left: 0; width: 100vw; height: 50px; background-color: #000; display: flex; justify-content: center; align-items: center; z-index: 1000;">
<a href="https://nearbys.online">
<img src="https://cdn.shopify.com/s/files/1/0664/3751/3414/files/nearbys-logo.webp?v=1741177270" alt="nearbys Logo" style="width: 150px;">
</a>
</header>
<div class="container" style="margin-top: 50px;">
<div class="header">
<h2>Customers</h2>
</div>
<div class="buttons">
<button onclick="downloadJSON()">Download JSON</button>
<label for="fileInput">Upload JSON</label>
<input type="file" id="fileInput" accept=".json" onchange="uploadJSON()">
</div>
<!-- Search Input -->
<div class="search-container">
<input type="text" id="searchInput" placeholder="Search by any field..." onkeyup="filterTable()">
</div>
<div class="table-container">
<table id="dataTable">
<thead>
<tr id="tableHead"></tr>
</thead>
<tbody id="tableBody"></tbody>
</table>
</div>
</div>
<script>
let jsonData = [];
document.addEventListener("DOMContentLoaded", function () {
fetch("https://vendors-data.replit.app/data")
.then(response => response.json())
.then(data => {
if (!Array.isArray(data) || data.length === 0) {
console.error("Invalid or empty JSON data.");
return;
}
jsonData = data;
createTable(jsonData);
})
.catch(error => console.error("Error fetching data:", error));
});
function createTable(data) {
const tableHead = document.getElementById("tableHead");
const tableBody = document.getElementById("tableBody");
tableHead.innerHTML = "";
tableBody.innerHTML = "";
const headers = Object.keys(data[0]);
headers.forEach(header => {
const th = document.createElement("th");
th.textContent = header;
tableHead.appendChild(th);
});
data.forEach((row, rowIndex) => {
const tr = document.createElement("tr");
headers.forEach(header => {
const td = document.createElement("td");
td.textContent = row[header] || "N/A";
td.setAttribute("contenteditable", "true");
td.addEventListener("input", function () {
jsonData[rowIndex][header] = this.textContent;
});
tr.appendChild(td);
});
tableBody.appendChild(tr);
});
}
function downloadJSON() {
const blob = new Blob([JSON.stringify(jsonData, null, 4)], { type: "application/json" });
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = "modified_data.json";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
function uploadJSON() {
const fileInput = document.getElementById("fileInput");
if (!fileInput.files.length) {
alert("Please select a JSON file to upload.");
return;
}
const file = fileInput.files[0];
const formData = new FormData();
formData.append("file", file); // Match the field name expected by Multer
fetch("https://vendors-data.replit.app/upload", { // Ensure this matches your Glitch server URL
method: "POST",
body: formData // Send as multipart/form-data
})
.then(response => response.json())
.then(data => {
alert(data.message);
location.reload();
})
.catch(error => console.error("Upload error:", error));
}
function filterTable() {
const searchInput = document.getElementById("searchInput").value.toLowerCase();
const rows = document.querySelectorAll("#tableBody tr");
rows.forEach(row => {
const cells = row.getElementsByTagName("td");
let found = false;
for (let cell of cells) {
if (cell.textContent.toLowerCase().includes(searchInput)) {
found = true;
break;
}
}
row.style.display = found ? "" : "none";
});
}
</script>
<!-- xxxxxxxxxxxxxxxxxxxxxxxx -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<link href="https://fonts.googleapis.com/css2?family=Righteous&display=swap" rel="stylesheet">
<!-- xxxxxxxxxxxxxxxxxxxxxxxx -->
</div>
<div class="contact">
<div class="contact-inner">
<a href="https://nearbys.online" target="_blank">
<img src="https://cdn.shopify.com/s/files/1/0947/2340/8240/files/1000084881.webp?v=1743588303" alt="nearbys Logo" class="contact-logo">
</a>
<!-- Email Link with Icon -->
<a href="mailto:admin@nearbys.online" class="contact-link">
<i class="fas fa-envelope"></i> email
</a>
<!-- WhatsApp with Icon -->
<a href="https://wa.me/971509880960" class="contact-link">
<i class="fab fa-whatsapp"></i> whatsApp
</a>
</div>
</div>
</div>
<!-- xxxxxxxxxxxxxxxxxxxxxxxx -->
<footer class="footer">
<div style="padding: 10px; font-family: 'Righteous', cursive; font-style:italic;">
<b>nearby<span style="color:#A0D6B4;">s</span></b> ⓒ 2025 <br>
All rights reserved</div>
</footer>
</body>