inital commit

This commit is contained in:
2026-03-16 23:13:14 +01:00
commit bf36266fa1
5 changed files with 1332 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
node_modules/

1088
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

15
package.json Normal file
View File

@@ -0,0 +1,15 @@
{
"dependencies": {
"express": "latest",
"ikea-availability-checker": "latest"
},
"name": "IkeaAvailabilityTools",
"private": true,
"version": "0.0.0",
"type": "module",
"description": "Tools for checking availability at IKEA stores",
"main": "server.js",
"scripts": {
"start": "node ./server.js"
}
}

89
public/index.html Normal file
View File

@@ -0,0 +1,89 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>IKEA Stock Checker</title>
<style>
html {
background: #000000ab;
color: white;
}
td {
padding: 1%;
}
body { font-family: Arial; padding: 20px; }
input { padding: 8px; margin: 5px; }
button { padding: 10px; }
#result { margin-top: 20px; }
</style>
</head>
<body>
<h1>IKEA Tools</h1>
<table>
<tr>
<td><h2>Store stock checker</h2></td>
<td><h2>Store finder</h2></td>
<td><h2>Country stock checker</h2></td>
</tr>
<tr>
<td>
<label>Product ID:</label>
<input id="product" placeholder="e.g. 30457915"><br>
<label>Store ID:</label>
<input id="store" placeholder="e.g. 088 (Amsterdam)"><br>
<button onclick="checkStock()">Check Stock</button>
</td>
<td>
<label>Country code:</label>
<input id="countryCode" placeholder="e.g. nl"><br>
<button onclick="GetStores()">Get stores</button>
</td>
<td>
<label>Product ID:</label>
<input id="product2" placeholder="e.g. 30457915"><br>
<label>Country code:</label>
<input id="countryCode2" placeholder="e.g. nl"><br>
<button onclick="checkCountryStock()">Check Stock</button>
</td>
</tr>
</table>
<div id="result"></div>
<script>
async function checkStock() {
const product = document.getElementById("product").value;
const store = document.getElementById("store").value;
const res = await fetch(`/api/stock?product=${product}&store=${store}`);
const data = await res.json();
document.getElementById("result").innerHTML =
`<pre>${JSON.stringify(data, null, 2)}</pre>`;
}
async function GetStores() {
const countryCode = document.getElementById("countryCode").value;
const res = await fetch(`/api/stores?countryCode=${countryCode}}`);
const data = await res.json();
document.getElementById("result").innerHTML =
`<pre>${JSON.stringify(data, null, 2)}</pre>`;
}
async function checkCountryStock() {
const product = document.getElementById("product2").value;
const countryCode = document.getElementById("countryCode2").value;
const res = await fetch(`/api/countrystock?countryCode=${countryCode}&product=${product}`);
const data = await res.json();
document.getElementById("result").innerHTML =
`<pre>${JSON.stringify(data, null, 2)}</pre>`;
}
</script>
</body>
</html>

139
server.js Normal file
View File

@@ -0,0 +1,139 @@
const express = require("express");
const ikea = require("ikea-availability-checker");
const app = express();
const PORT = 3000;
app.use(express.static("public"));
app.get("/api/stock", async (req, res) => {
const { store, product } = req.query;
if (!product || !store) {
return res.status(400).json({ error: "Missing product or store parameter" });
}
try {
const result = await ikea.availability(store, product);
const Filterdresult = ({
productId: result.productId || null,
stock: result.stock,
probability: result.probability,
store: result.store.name,
buCode: result.store.buCode,
country: result.store.country,
});
res.json(Filterdresult);
} catch (err) {
res.status(500).json({
error: "Failed to fetch stock",
details: err.message
});
}
});
app.get("/api/countrystock", async (req, res) => {
const { countryCode, product } = req.query;
if (!product || !countryCode) {
return res.status(400).json({ error: "Missing product or countryCode parameter" });
}
try {
const stores = ikea.stores.findByCountryCode(countryCode);
const result = await ikea.availabilities(stores, [product]);
const Filterdresult = result.map(item => ({
productId: item.productId || null,
stock: item.stock,
probability: item.probability,
store: item.store.name,
buCode: item.store.buCode,
country: item.store.country,
}));
res.json(Filterdresult);
} catch (err) {
res.status(500).json({
error: "Failed to fetch stock",
details: err.message
});
}
});
app.get("/api/stores", async (req, res) => {
const { countryCode } = req.query;
if (!countryCode) {
return res.status(400).json({ error: "Missing product or store parameter" });
}
try {
const result = await ikea.stores.findByCountryCode(countryCode);
const Filterdresult = result.map(item => ({
buCode: item.buCode || null,
name: item.name,
country: item.country
}));
res.json(Filterdresult);
} catch (err) {
res.status(500).json({
error: "Failed to fetch stock",
details: err.message
});
}
});
//For ChangeDetection.io instance
app.get("/api/change", async (req, res) => {
const { product, store } = req.query;
if (!product || !store) {
return res.status(400).send("Missing product or store");
}
try {
const result = await ikea.availability(store, product);
const quantity = result.stock ?? 0;
let inStock;
if( quantity > 0 ) {
inStock = "InStock" ;
} else{
inStock = "OutOfStock" ;
}
res.send(`
<style>
html {
background: #000000ab;
color: white;
}
</style>
<h1>${product}</h1>
<p>Status: ${inStock ? "In Stock" : "Out of Stock"}</p>
<!-- JSON-LD structured data for restock detection -->
<script type="application/ld+json">
{
"@context": "https://schema.org/",
"@type": "Product",
"name": "${product}",
"offers": {
"@type": "Offer",
"priceCurrency": "EUR",
"availability": "https://schema.org/${inStock}"
}
}
</script>
`);
} catch (err) {
res.type("text").send("error");
}
});
app.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}`);
});