From 053662c2e88893fdb5e07d359cda0159965c0cd9 Mon Sep 17 00:00:00 2001 From: Hickmeister <35031453+Hickmeister@users.noreply.github.com> Date: Wed, 15 Jan 2025 17:50:57 +0000 Subject: [PATCH] Update Filament Dryer --- public/filamentDryer.php | 510 +++++++++++++--------- public/viewFilament.php | 226 +++++----- src/filamentTracker/getFilamentPrices.php | 47 +- 3 files changed, 454 insertions(+), 329 deletions(-) diff --git a/public/filamentDryer.php b/public/filamentDryer.php index 013c8cf..151fc99 100644 --- a/public/filamentDryer.php +++ b/public/filamentDryer.php @@ -46,132 +46,177 @@ checkUserRole(['admin']);
- -
-
-
-
-
-
-
-

Dryer Status

-
STATUS
-
-
-
-
-
-
-
-
-
-
-

Heater Status

-
STATUS
-
-
-
-
-
-
-
-
-
-
-

Fan Status

-
STATUS
-
-
-
-
-
-
-
- -
-
- -
-
-
-
-

Temp:

-
--°C
-
-
-
-
-
- -
-
-
-
-

Humidity:

-
--%
-
-
-
-
-
-
-
- -
-
-
-
Filament Dryer Control
-
-
-
-
- - -
+ -
- - -
+ +
+
- + + + + + +
+
+ +
+
+
+
+
+

Dryer Status

+
STATUS
+
+
+
+
+
+
+
+
+
+
+

Heater Status

+
STATUS
+
+
+
+
+
+
+
+
+
+
+

Fan Status

+
STATUS
+
+
+
+
+
+
+ +
+ +
+
+ +
+
+
+
+

Temp:

+
--°C
+
+
+
+
+
+ +
+
+
+
+

Humidity:

+
--%
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
Dryer Control
+
+ +
+
+
+
+
+
+

Loadig..

+
+
+
+
+
+
+
+ + + @@ -213,10 +258,13 @@ checkUserRole(['admin']); $(".data-attributes span").peity("donut") - + + diff --git a/public/viewFilament.php b/public/viewFilament.php index 38be033..1bf38fd 100644 --- a/public/viewFilament.php +++ b/public/viewFilament.php @@ -137,135 +137,147 @@ document.addEventListener("DOMContentLoaded", function () { } fetch('../src/filamentTracker/getFilamentPrices.php') - .then(response => response.json()) - .then(data => { - if (data.status === 'success') { - container.innerHTML = ''; // Clear Skeleton + .then(response => response.json()) + .then(data => { + if (data.status === 'success') { + container.innerHTML = ''; // Clear Skeleton - Object.keys(data.data).forEach(filament => { - const filamentData = data.data[filament]; - const prices = filamentData.prices.map(entry => parseFloat(entry.price)); - const timestamps = filamentData.prices.map(entry => entry.recordedAt); - const latestPrice = prices[prices.length - 1] || 0; + Object.keys(data.data).forEach(filament => { + const filamentData = data.data[filament]; + const prices = filamentData.prices.map(entry => parseFloat(entry.price)); + const timestamps = filamentData.prices.map(entry => entry.recordedAt); + let latestPrice = prices[prices.length - 1] || 0; - // Find the last distinct price (where the price actually changed) - let lastDistinctPrice = latestPrice; - for (let i = prices.length - 2; i >= 0; i--) { - if (prices[i] !== latestPrice) { - lastDistinctPrice = prices[i]; - break; + // Adjust price for voucher + const currentDiscount = filamentData.currentDiscount || {}; + const voucher = currentDiscount.voucher || {}; + if (voucher.value > 0) { + if (voucher.type === 'percentage') { + latestPrice -= (latestPrice * voucher.value) / 100; // Apply percentage voucher + } else if (voucher.type === 'fixed') { + latestPrice -= voucher.value; // Subtract fixed voucher value + } } - } - const priceDifference = latestPrice - lastDistinctPrice; + // Ensure price doesn't go below zero + latestPrice = Math.max(latestPrice, 0); - // Price Change Indicator - let priceChangeIndicator; - if (priceDifference > 0) { - priceChangeIndicator = ` - +£${priceDifference.toFixed(2)}`; - } else if (priceDifference < 0) { - priceChangeIndicator = ` - -£${Math.abs(priceDifference).toFixed(2)}`; - } else { - priceChangeIndicator = ` - £0.00`; - } + // Find the last distinct price (where the price actually changed) + let lastDistinctPrice = latestPrice; + for (let i = prices.length - 2; i >= 0; i--) { + if (prices[i] !== latestPrice) { + lastDistinctPrice = prices[i]; + break; + } + } - const amazonUrl = filamentData.amazonUrl || '#'; + const priceDifference = latestPrice - lastDistinctPrice; - // Extract discount details - const currentDiscount = filamentData.currentDiscount || {}; - const voucher = currentDiscount.voucher || {}; - const discount = currentDiscount.discount || {}; + // Price Change Indicator + let priceChangeIndicator; + if (priceDifference > 0) { + priceChangeIndicator = ` + +£${priceDifference.toFixed(2)}`; + } else if (priceDifference < 0) { + priceChangeIndicator = ` + -£${Math.abs(priceDifference).toFixed(2)}`; + } else { + priceChangeIndicator = ` + £0.00`; + } - let discountText = ''; - if (voucher.value > 0) { - discountText = voucher.type === 'percentage' - ? `-${voucher.value}% Voucher` - : `-£${voucher.value} Voucher`; - } else if (discount.value > 0) { - discountText = discount.type === 'percentage' - ? `-${discount.value}%` - : `-£${discount.value}`; - } + const amazonUrl = filamentData.amazonUrl || '#'; - const chartId = `chart-${filament.replace(/\s+/g, '-')}`; - const chartColor = getRandomColor(); + // Extract discount details + const discount = currentDiscount.discount || {}; + let discountText = ''; + if (voucher.value > 0) { + discountText = voucher.type === 'percentage' + ? `-${voucher.value}% Voucher` + : `-£${voucher.value} Voucher`; + } else if (discount.value > 0) { + discountText = discount.type === 'percentage' + ? `-${discount.value}%` + : `-£${discount.value}`; + } - // Create Card HTML - const cardHTML = ` -
-
-
-
- ${filament} -
- £${latestPrice} ${priceChangeIndicator} -
-
-
- ${ - discountText - ? ` - ${discountText} - ` - : '' - } + const chartId = `chart-${filament.replace(/\s+/g, '-')}`; + const chartColor = getRandomColor(); + + // Create Card HTML + const cardHTML = ` +
+
+
+
+ ${filament} +
+ £${latestPrice.toFixed(2)} ${priceChangeIndicator} +
+
+
+ ${ + discountText + ? ` + ${discountText} + ` + : '' + } +
+
-
-
- `; + `; - container.insertAdjacentHTML('beforeend', cardHTML); + container.insertAdjacentHTML('beforeend', cardHTML); - // Chart Rendering - const chartOptions = { - series: [{ name: "Price", data: prices }], - chart: { - type: "area", - height: 110, - toolbar: { show: false }, - zoom: { enabled: false }, - sparkline: { enabled: true }, - }, - markers: { size: 0 }, - dataLabels: { enabled: false }, - stroke: { show: true, width: 2.4, curve: "smooth" }, - colors: [chartColor], - xaxis: { categories: timestamps, labels: { show: false } }, - fill: { opacity: 1 }, - tooltip: { - theme: "dark", - y: { - formatter: function (value, { dataPointIndex }) { - const date = new Date(timestamps[dataPointIndex]); - return `£${value} - ${date.toLocaleDateString()}`; + // Chart Rendering + const chartOptions = { + series: [{ name: "Price", data: prices }], + chart: { + type: "area", + height: 110, + toolbar: { show: false }, + zoom: { enabled: false }, + sparkline: { enabled: true }, + }, + markers: { size: 0 }, + dataLabels: { enabled: false }, + stroke: { show: true, width: 2.4, curve: "smooth" }, + colors: [chartColor], + xaxis: { categories: timestamps, labels: { show: false } }, + fill: { opacity: 1 }, + tooltip: { + theme: "dark", + y: { + formatter: function (value, { dataPointIndex }) { + const date = new Date(timestamps[dataPointIndex]); + return `£${value} - ${date.toLocaleDateString()}`; + }, }, }, - }, - }; + }; - const chartElement = document.getElementById(chartId); - if (chartElement) { - const chart = new ApexCharts(chartElement, chartOptions); - chart.render(); - } - }); - } else { - container.innerHTML = '

No filament data available.

'; - } - }) - .catch(error => { - console.error("Error fetching filament data:", error); - }); + const chartElement = document.getElementById(chartId); + if (chartElement) { + const chart = new ApexCharts(chartElement, chartOptions); + chart.render(); + } + }); + } else { + container.innerHTML = '

No filament data available.

'; + } + }) + .catch(error => { + console.error("Error fetching filament data:", error); + }); -showSkeletonLoader(); + showSkeletonLoader(); }); + \ No newline at end of file diff --git a/src/filamentTracker/getFilamentPrices.php b/src/filamentTracker/getFilamentPrices.php index 424f236..b14f9e6 100644 --- a/src/filamentTracker/getFilamentPrices.php +++ b/src/filamentTracker/getFilamentPrices.php @@ -9,35 +9,42 @@ include '../src/session_check.php'; header('Content-Type: application/json'); try { - // Fetch all filament prices with the latest discount - $stmt = $pdo->query(" - SELECT ft.filamentName, + // Query 1: Fetch filament details and price history + $stmt1 = $pdo->query(" + SELECT ft.id AS filamentId, + ft.filamentName, ft.brand, ft.material, ft.color, ft.amazonUrl, fp.price, - fp.currentDiscount, fp.recordedAt FROM filamentTracker ft JOIN filamentPriceHistory fp ON ft.id = fp.filamentId - JOIN ( - SELECT filamentId, recordedAt - FROM ( - SELECT filamentId, recordedAt, - ROW_NUMBER() OVER (PARTITION BY filamentId ORDER BY recordedAt DESC) as rn - FROM filamentPriceHistory - ) ranked - WHERE rn <= 380 - ) filtered ON fp.filamentId = filtered.filamentId AND fp.recordedAt = filtered.recordedAt - ORDER BY ft.filamentName, fp.recordedAt ASC + ORDER BY ft.filamentName ASC, fp.recordedAt ASC; "); + $filaments = $stmt1->fetchAll(PDO::FETCH_ASSOC); - $filaments = $stmt->fetchAll(PDO::FETCH_ASSOC); + // Query 2: Fetch the latest discount for each filament + $stmt2 = $pdo->query(" + SELECT filamentId, + JSON_OBJECT( + 'discount', JSON_OBJECT('value', MAX(JSON_EXTRACT(currentDiscount, '$.discount.value')), 'type', 'percentage'), + 'voucher', JSON_OBJECT('value', MAX(JSON_EXTRACT(currentDiscount, '$.voucher.value')), 'type', MAX(JSON_UNQUOTE(JSON_EXTRACT(currentDiscount, '$.voucher.type')))) + ) AS currentDiscount + FROM filamentPriceHistory + GROUP BY filamentId; + "); + $discounts = $stmt2->fetchAll(PDO::FETCH_ASSOC); + // Create a mapping of filamentId to discounts + $discountMap = []; + foreach ($discounts as $discount) { + $discountMap[$discount['filamentId']] = json_decode($discount['currentDiscount'], true); + } + + // Format data for response $result = []; - - // Format data for charts (grouped by filament) foreach ($filaments as $filament) { $name = $filament['filamentName']; @@ -48,15 +55,15 @@ try { 'color' => $filament['color'], 'amazonUrl' => $filament['amazonUrl'], 'prices' => [], - 'currentDiscount' => $filament['currentDiscount'] ? json_decode($filament['currentDiscount'], true) : [ + 'currentDiscount' => $discountMap[$filament['filamentId']] ?? [ 'discount' => ['value' => 0, 'type' => 'none'], 'voucher' => ['value' => 0, 'type' => 'none'] - ] // Decode JSON format and provide fallback + ] ]; } $result[$name]['prices'][] = [ - 'price' => $filament['price'], + 'price' => (float)$filament['price'], 'recordedAt' => $filament['recordedAt'] ]; }