Compare commits
2 Commits
5a11305caf
...
8c9cb042ff
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c9cb042ff | ||
|
|
d96fa63298 |
293
public/viewFilament.php
Normal file
293
public/viewFilament.php
Normal file
@@ -0,0 +1,293 @@
|
|||||||
|
<?php include '../src/session_check.php'; ?>
|
||||||
|
|
||||||
|
<html lang="en" data-bs-theme="light">
|
||||||
|
<head>
|
||||||
|
<!-- Required meta tags -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<!--favicon-->
|
||||||
|
<link rel="icon" href="../assets/images/favicon-32x32.png" type="image/png">
|
||||||
|
<!--plugins-->
|
||||||
|
<link href="../assets/plugins/vectormap/jquery-jvectormap-2.0.2.css" rel="stylesheet">
|
||||||
|
<link href="../assets/plugins/simplebar/css/simplebar.css" rel="stylesheet">
|
||||||
|
<link href="../assets/plugins/perfect-scrollbar/css/perfect-scrollbar.css" rel="stylesheet">
|
||||||
|
<link href="../assets/plugins/metismenu/css/metisMenu.min.css" rel="stylesheet">
|
||||||
|
<!-- loader-->
|
||||||
|
<link href="../assets/css/pace.min.css" rel="stylesheet"/>
|
||||||
|
<script src="../assets/js/pace.min.js"></script>
|
||||||
|
<!-- Bootstrap CSS -->
|
||||||
|
<link href="../assets/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="../assets/css/bootstrap-extended.css" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500&display=swap" rel="stylesheet">
|
||||||
|
|
||||||
|
<link href="../assets/sass/app.css" rel="stylesheet">
|
||||||
|
<link href="../assets/css/icons.css" rel="stylesheet">
|
||||||
|
<link href='https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css' rel='stylesheet'>
|
||||||
|
<!-- Theme Style CSS -->
|
||||||
|
<link rel="stylesheet" href="../assets/sass/dark-theme.css">
|
||||||
|
<link rel="stylesheet" href="../assets/sass/semi-dark.css">
|
||||||
|
<link rel="stylesheet" href="../assets/sass/bordered-theme.css">
|
||||||
|
|
||||||
|
<title>TOD Dashboard</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<!--wrapper-->
|
||||||
|
<div class="wrapper">
|
||||||
|
<!--sidebar wrapper -->
|
||||||
|
<?php include '../src/nav.php'; ?>
|
||||||
|
<!--end sidebar wrapper -->
|
||||||
|
<!--start header -->
|
||||||
|
<?php include '../src/header.php'; ?>
|
||||||
|
<!--end header -->
|
||||||
|
|
||||||
|
<!--start page wrapper -->
|
||||||
|
<div class="page-wrapper">
|
||||||
|
<div class="page-content">
|
||||||
|
<!--start page content -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row" id="filamentCardContainer">
|
||||||
|
<!-- Cards will be inserted here dynamically -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--end page content -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--end page wrapper -->
|
||||||
|
|
||||||
|
<!--start overlay-->
|
||||||
|
<div class="overlay mobile-toggle-icon"></div>
|
||||||
|
<!--end overlay-->
|
||||||
|
<!--Start Back To Top Button-->
|
||||||
|
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
||||||
|
<!--End Back To Top Button-->
|
||||||
|
<footer class="page-footer">
|
||||||
|
<p class="mb-0">Copyright © 2024. All right reserved.</p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
<!--end wrapper-->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- search modal -->
|
||||||
|
<div class="modal" id="SearchModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-fullscreen-md-down">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header gap-2">
|
||||||
|
<div class="position-relative popup-search w-100">
|
||||||
|
<input class="form-control form-control-lg ps-5 border border-3 border-primary" type="search" placeholder="Search">
|
||||||
|
<span class="position-absolute top-50 search-show ms-3 translate-middle-y start-0 top-50 fs-4"><i class='bx bx-search'></i></span>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn-close d-md-none" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- end search modal -->
|
||||||
|
|
||||||
|
<!-- Bootstrap JS -->
|
||||||
|
<script src="../assets/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<!--plugins-->
|
||||||
|
<script src="../assets/js/jquery.min.js"></script>
|
||||||
|
<script src="../assets/plugins/simplebar/js/simplebar.min.js"></script>
|
||||||
|
<script src="../assets/plugins/metismenu/js/metisMenu.min.js"></script>
|
||||||
|
<script src="../assets/plugins/perfect-scrollbar/js/perfect-scrollbar.js"></script>
|
||||||
|
<script src="../assets/plugins/apexcharts-bundle/js/apexcharts.min.js"></script>
|
||||||
|
<!--app JS-->
|
||||||
|
<script src="../assets/js/app.js"></script>
|
||||||
|
|
||||||
|
<script src="../assets/js/index.js"></script>
|
||||||
|
<script src="../assets/plugins/peity/jquery.peity.min.js"></script>
|
||||||
|
<script>
|
||||||
|
$(".data-attributes span").peity("donut")
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
const container = document.getElementById('filamentCardContainer');
|
||||||
|
|
||||||
|
// Function to generate random colors
|
||||||
|
function getRandomColor() {
|
||||||
|
const letters = '0123456789ABCDEF';
|
||||||
|
let color = '#';
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
color += letters[Math.floor(Math.random() * 16)];
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skeleton Loader Template
|
||||||
|
function showSkeletonLoader() {
|
||||||
|
container.innerHTML = `
|
||||||
|
<div class="col-lg-4 mb-1">
|
||||||
|
<div class="card radius-10 overflow-hidden skeleton-loader" style="height: 200px;">
|
||||||
|
<div class="card-body d-flex align-items-center justify-content-between">
|
||||||
|
<div>
|
||||||
|
<div class="skeleton-text mb-2" style="width: 70px; height: 20px;"></div>
|
||||||
|
<div class="skeleton-text" style="width: 50px; height: 30px;"></div>
|
||||||
|
</div>
|
||||||
|
<div class="skeleton-button" style="width: 40px; height: 40px;"></div>
|
||||||
|
</div>
|
||||||
|
<div class="skeleton-chart" style="height: 120px;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debounce function to reduce DOM updates
|
||||||
|
function debounceRender(func, delay) {
|
||||||
|
let inDebounce;
|
||||||
|
return function() {
|
||||||
|
const context = this, args = arguments;
|
||||||
|
clearTimeout(inDebounce);
|
||||||
|
inDebounce = setTimeout(() => func.apply(context, args), delay);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch('../src/filamentTracker/getFilamentPrices.php')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
container.innerHTML = ''; // Clear Skeleton
|
||||||
|
|
||||||
|
Object.keys(data.data).forEach(filament => {
|
||||||
|
const prices = data.data[filament].prices.map(entry => entry.price);
|
||||||
|
const timestamps = data.data[filament].prices.map(entry => entry.recordedAt);
|
||||||
|
const latestPrice = prices[prices.length - 1] || 0;
|
||||||
|
const previousPrice = prices[prices.length - 2] || latestPrice;
|
||||||
|
const priceDifference = latestPrice - previousPrice;
|
||||||
|
|
||||||
|
let priceChangeIndicator;
|
||||||
|
if (priceDifference > 0) {
|
||||||
|
priceChangeIndicator = `<span class="text-danger ms-4">
|
||||||
|
<i class="bx bx-up-arrow-alt"></i> +£${priceDifference.toFixed(2)}</span>`;
|
||||||
|
} else if (priceDifference < 0) {
|
||||||
|
priceChangeIndicator = `<span class="text-success ms-4">
|
||||||
|
<i class="bx bx-down-arrow-alt"></i> £${Math.abs(priceDifference).toFixed(2)}</span>`;
|
||||||
|
} else {
|
||||||
|
priceChangeIndicator = `<span class="text-muted ms-4">
|
||||||
|
<i class="bx bx-minus"></i> £0.00</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const amazonUrl = data.data[filament].amazonUrl || '#';
|
||||||
|
const chartId = `chart-${filament.replace(/\s+/g, '-')}`;
|
||||||
|
const chartColor = getRandomColor();
|
||||||
|
|
||||||
|
// Create Card HTML with cart button
|
||||||
|
const cardHTML = `
|
||||||
|
<div class="col-lg-4 mb-1">
|
||||||
|
<div class="card radius-10 overflow-hidden">
|
||||||
|
<div class="card-body d-flex align-items-center justify-content-between">
|
||||||
|
<div>
|
||||||
|
<a href="${amazonUrl}" target="_blank" class="mb-0 filament-name">${filament}</a>
|
||||||
|
<h5 class="mb-0">
|
||||||
|
£${latestPrice} ${priceChangeIndicator}
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="${chartId}"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
container.insertAdjacentHTML('beforeend', cardHTML);
|
||||||
|
|
||||||
|
// Observer to Wait for DOM Insertion
|
||||||
|
const observer = new MutationObserver(debounceRender(() => {
|
||||||
|
const chartElement = document.getElementById(chartId);
|
||||||
|
if (chartElement) {
|
||||||
|
const chartOptions = {
|
||||||
|
series: [{
|
||||||
|
name: "Price",
|
||||||
|
data: prices
|
||||||
|
}],
|
||||||
|
chart: {
|
||||||
|
type: "area",
|
||||||
|
height: 110,
|
||||||
|
toolbar: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
zoom: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
dropShadow: {
|
||||||
|
enabled: true,
|
||||||
|
top: 3,
|
||||||
|
left: 14,
|
||||||
|
blur: 4,
|
||||||
|
opacity: 0.12,
|
||||||
|
color: chartColor
|
||||||
|
},
|
||||||
|
sparkline: {
|
||||||
|
enabled: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
markers: {
|
||||||
|
size: 0,
|
||||||
|
colors: [chartColor],
|
||||||
|
strokeColors: "#fff",
|
||||||
|
strokeWidth: 2,
|
||||||
|
hover: {
|
||||||
|
size: 7
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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",
|
||||||
|
x: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
formatter: function (value, { dataPointIndex }) {
|
||||||
|
const date = new Date(timestamps[dataPointIndex]);
|
||||||
|
return `£${value} - ${date.toLocaleDateString()}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const chart = new ApexCharts(chartElement, chartOptions);
|
||||||
|
chart.render();
|
||||||
|
observer.disconnect();
|
||||||
|
}
|
||||||
|
}, 300));
|
||||||
|
|
||||||
|
observer.observe(container, { childList: true, subtree: true });
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
container.innerHTML = '<p class="text-center">No filament data available.</p>';
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error("Error fetching filament data:", error);
|
||||||
|
});
|
||||||
|
|
||||||
|
showSkeletonLoader();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -4,11 +4,7 @@ require '../db.php';
|
|||||||
require_once '../envLoader.php';
|
require_once '../envLoader.php';
|
||||||
loadEnv(__DIR__ . '/../../.env');
|
loadEnv(__DIR__ . '/../../.env');
|
||||||
|
|
||||||
// Check if the user is logged in
|
include '../src/session_check.php';
|
||||||
if (!isset($_SESSION['userId'])) {
|
|
||||||
echo json_encode(['status' => 'error', 'message' => 'User not authenticated.']);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
use Goutte\Client;
|
use Goutte\Client;
|
||||||
|
|
||||||
|
|||||||
@@ -4,31 +4,32 @@ require '../db.php';
|
|||||||
require_once '../envLoader.php';
|
require_once '../envLoader.php';
|
||||||
loadEnv(__DIR__ . '/../../.env');
|
loadEnv(__DIR__ . '/../../.env');
|
||||||
|
|
||||||
// Check if the user is logged in
|
include '../src/session_check.php';
|
||||||
if (!isset($_SESSION['userId'])) {
|
|
||||||
echo json_encode(['status' => 'error', 'message' => 'User not authenticated.']);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
// Fetch all filament prices from the database
|
|
||||||
try {
|
try {
|
||||||
|
// Fetch all filament prices with a limit of 180 entries per filament using JOIN
|
||||||
$stmt = $pdo->query("
|
$stmt = $pdo->query("
|
||||||
SELECT
|
SELECT ft.filamentName,
|
||||||
ft.filamentName,
|
ft.brand,
|
||||||
ft.brand,
|
ft.material,
|
||||||
ft.material,
|
ft.color,
|
||||||
ft.color,
|
ft.amazonUrl,
|
||||||
fp.price,
|
fp.price,
|
||||||
fp.recordedAt
|
fp.recordedAt
|
||||||
FROM
|
FROM filamentTracker ft
|
||||||
filamentTracker ft
|
JOIN filamentPriceHistory fp ON ft.id = fp.filamentId
|
||||||
JOIN
|
JOIN (
|
||||||
filamentPriceHistory fp ON ft.id = fp.filamentId
|
SELECT filamentId, recordedAt
|
||||||
ORDER BY
|
FROM (
|
||||||
ft.filamentName,
|
SELECT filamentId, recordedAt,
|
||||||
fp.recordedAt ASC
|
ROW_NUMBER() OVER (PARTITION BY filamentId ORDER BY recordedAt DESC) as rn
|
||||||
|
FROM filamentPriceHistory
|
||||||
|
) ranked
|
||||||
|
WHERE rn <= 180
|
||||||
|
) filtered ON fp.filamentId = filtered.filamentId AND fp.recordedAt = filtered.recordedAt
|
||||||
|
ORDER BY ft.filamentName, fp.recordedAt ASC
|
||||||
");
|
");
|
||||||
|
|
||||||
$filaments = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$filaments = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
@@ -44,6 +45,7 @@ try {
|
|||||||
'brand' => $filament['brand'],
|
'brand' => $filament['brand'],
|
||||||
'material' => $filament['material'],
|
'material' => $filament['material'],
|
||||||
'color' => $filament['color'],
|
'color' => $filament['color'],
|
||||||
|
'amazonUrl' => $filament['amazonUrl'],
|
||||||
'prices' => []
|
'prices' => []
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,98 +0,0 @@
|
|||||||
<?php
|
|
||||||
ini_set('display_errors', 1);
|
|
||||||
ini_set('display_startup_errors', 1);
|
|
||||||
error_reporting(E_ALL);
|
|
||||||
|
|
||||||
require '../../vendor/autoload.php';
|
|
||||||
require '../db.php';
|
|
||||||
require_once '../envLoader.php';
|
|
||||||
loadEnv(__DIR__ . '/../../.env');
|
|
||||||
|
|
||||||
use Goutte\Client;
|
|
||||||
|
|
||||||
function scrapeFilamentPrice($productName, $productUrl) {
|
|
||||||
$client = new Client();
|
|
||||||
$crawler = $client->request('GET', $productUrl);
|
|
||||||
|
|
||||||
// Extract the current price
|
|
||||||
$price = $crawler->filter('span.a-price-whole')->first()->text();
|
|
||||||
$price = str_replace(',', '', $price); // Clean the price string
|
|
||||||
|
|
||||||
// Extract the original price (if available)
|
|
||||||
$originalPriceNode = $crawler->filter('span.a-price.a-text-price')->first();
|
|
||||||
$originalPrice = $originalPriceNode->count() ? str_replace(',', '', $originalPriceNode->text()) : null;
|
|
||||||
|
|
||||||
// Calculate the discount percentage
|
|
||||||
$discountPercentage = null;
|
|
||||||
if ($originalPrice) {
|
|
||||||
$discountPercentage = round(100 - (($price / $originalPrice) * 100), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
$currency = 'GBP';
|
|
||||||
|
|
||||||
return [
|
|
||||||
'productName' => $productName,
|
|
||||||
'productUrl' => $productUrl,
|
|
||||||
'price' => $price,
|
|
||||||
'originalPrice' => $originalPrice,
|
|
||||||
'discountPercentage' => $discountPercentage,
|
|
||||||
'currency' => $currency
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle Form Submission (Add New Filament to Track)
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
||||||
$productName = $_POST['productName'];
|
|
||||||
$productUrl = $_POST['productUrl'];
|
|
||||||
|
|
||||||
$result = scrapeFilamentPrice($productName, $productUrl);
|
|
||||||
|
|
||||||
try {
|
|
||||||
$stmt = $pdo->prepare("
|
|
||||||
INSERT INTO filamentPrices (productName, productUrl, price, originalPrice, discountPercentage, currency)
|
|
||||||
VALUES (:productName, :productUrl, :price, :originalPrice, :discountPercentage, :currency)
|
|
||||||
");
|
|
||||||
$stmt->execute([
|
|
||||||
':productName' => $result['productName'],
|
|
||||||
':productUrl' => $result['productUrl'],
|
|
||||||
':price' => $result['price'],
|
|
||||||
':originalPrice' => $result['originalPrice'],
|
|
||||||
':discountPercentage' => $result['discountPercentage'],
|
|
||||||
':currency' => $result['currency']
|
|
||||||
]);
|
|
||||||
|
|
||||||
echo json_encode(['status' => 'success', 'message' => 'Filament price recorded successfully!']);
|
|
||||||
} catch (PDOException $e) {
|
|
||||||
echo json_encode(['status' => 'error', 'message' => 'Failed to record price: ' . $e->getMessage()]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle Scheduled Scraping for Existing URLs (Cron Job)
|
|
||||||
if (isset($argv[1]) && $argv[1] === 'cron') {
|
|
||||||
try {
|
|
||||||
$stmt = $pdo->query("SELECT * FROM filamentPrices GROUP BY productUrl");
|
|
||||||
$filaments = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
foreach ($filaments as $filament) {
|
|
||||||
$result = scrapeFilamentPrice($filament['productName'], $filament['productUrl']);
|
|
||||||
|
|
||||||
$stmt = $pdo->prepare("
|
|
||||||
INSERT INTO filamentPrices (productName, productUrl, price, originalPrice, discountPercentage, currency)
|
|
||||||
VALUES (:productName, :productUrl, :price, :originalPrice, :discountPercentage, :currency)
|
|
||||||
");
|
|
||||||
$stmt->execute([
|
|
||||||
':productName' => $result['productName'],
|
|
||||||
':productUrl' => $result['productUrl'],
|
|
||||||
':price' => $result['price'],
|
|
||||||
':originalPrice' => $result['originalPrice'],
|
|
||||||
':discountPercentage' => $result['discountPercentage'],
|
|
||||||
':currency' => $result['currency']
|
|
||||||
]);
|
|
||||||
|
|
||||||
echo "Recorded: {$result['productName']} - £{$result['price']} (Discount: {$result['discountPercentage']}%)\n";
|
|
||||||
}
|
|
||||||
} catch (PDOException $e) {
|
|
||||||
echo "Failed to fetch filament data: " . $e->getMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
<ul class="dropdown-menu dropdown-menu-end">
|
<ul class="dropdown-menu dropdown-menu-end">
|
||||||
<li><a class="dropdown-item d-flex align-items-center" href="javascript:;"><i class="bx bx-user fs-5"></i><span>Profile</span></a>
|
<li><a class="dropdown-item d-flex align-items-center" href="javascript:;"><i class="bx bx-user fs-5"></i><span>Profile</span></a>
|
||||||
</li>
|
</li>
|
||||||
<li><a class="dropdown-item d-flex align-items-center" href="printerForm.php"><i class="bx bx-cog fs-5"></i><span>My Printers</span></a>
|
<li><a class="dropdown-item d-flex align-items-center" href="printerForm.php"><i class="bx bx-cog fs-5"></i><span>Add Printer</span></a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<div class="dropdown-divider mb-0"></div>
|
<div class="dropdown-divider mb-0"></div>
|
||||||
|
|||||||
101
src/nav.php
101
src/nav.php
@@ -1,40 +1,61 @@
|
|||||||
<!--sidebar wrapper -->
|
<!--sidebar wrapper -->
|
||||||
<div class="sidebar-wrapper" data-simplebar="true">
|
<div class="sidebar-wrapper" data-simplebar="true">
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<div>
|
<div>
|
||||||
<img src="../assets/images/logo-icon.png" class="logo-icon" alt="logo icon">
|
<img src="../assets/images/logo-icon.png" class="logo-icon" alt="logo icon">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4 class="logo-text">TechOdyssey</h4>
|
<h4 class="logo-text">TechOdyssey</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="mobile-toggle-icon ms-auto"><i class='bx bx-x'></i>
|
<div class="mobile-toggle-icon ms-auto"><i class='bx bx-x'></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--navigation-->
|
<!--navigation-->
|
||||||
<ul class="metismenu" id="menu">
|
<ul class="metismenu" id="menu">
|
||||||
<li>
|
|
||||||
<a href="javascript:;" class="has-arrow">
|
<li>
|
||||||
<div class="parent-icon"><i class='bx bx-home-alt'></i>
|
<a href="index.php">
|
||||||
</div>
|
<div class="parent-icon"><i class='bx bx-home-alt'></i>
|
||||||
<div class="menu-title">Dashboard</div>
|
</div>
|
||||||
</a>
|
<div class="menu-title">Dashboard</div>
|
||||||
<ul>
|
</a>
|
||||||
<li> <a href="index.html"><i class='bx bx-radio-circle'></i>Infographic</a>
|
</li>
|
||||||
</li>
|
|
||||||
<li> <a href="index2.html"><i class='bx bx-radio-circle'></i>eCommerce</a>
|
<li>
|
||||||
</li>
|
<a href="viewPrinters.php">
|
||||||
<li> <a href="index3.html"><i class='bx bx-radio-circle'></i>Analytics</a>
|
<div class="parent-icon"><i class='bx bx-code-alt'></i>
|
||||||
</li>
|
</div>
|
||||||
</ul>
|
<div class="menu-title">Printer Dashboard</div>
|
||||||
</li>
|
</a>
|
||||||
<li>
|
</li>
|
||||||
<a href="viewPrinters.php">
|
|
||||||
<div class="parent-icon"><i class='bx bx-code-alt'></i>
|
<!-- Filament Tracking Section -->
|
||||||
</div>
|
<li class="menu-label">Filament Tracker</li>
|
||||||
<div class="menu-title">Printer Dashboard</div>
|
<li>
|
||||||
</a>
|
<a href="viewFilament.php">
|
||||||
</li>
|
<div class="parent-icon"><i class='bx bx-layer'></i>
|
||||||
</ul>
|
</div>
|
||||||
<!--end navigation-->
|
<div class="menu-title">Filament Overview</div>
|
||||||
</div>
|
</a>
|
||||||
<!--end sidebar wrapper -->
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="addFilament.php">
|
||||||
|
<div class="parent-icon"><i class='bx bx-plus-circle'></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-title">Add Filament</div>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- Settings or Admin Section -->
|
||||||
|
<li class="menu-label">Settings</li>
|
||||||
|
<li>
|
||||||
|
<a href="settings.php">
|
||||||
|
<div class="parent-icon"><i class='bx bx-cog'></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-title">User Settings</div>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<!--end navigation-->
|
||||||
|
</div>
|
||||||
|
<!--end sidebar wrapper -->
|
||||||
|
|||||||
Reference in New Issue
Block a user