Migrate HickLab3D dashboard and add production auto deployment
Deploy HickLab3D Dashboard / Deploy to production (push) Failing after 19s
Deploy HickLab3D Dashboard / Deploy to production (push) Failing after 19s
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
<IfModule mod_rewrite.c>
|
||||
<IfModule mod_negotiation.c>
|
||||
Options -MultiViews -Indexes
|
||||
</IfModule>
|
||||
|
||||
RewriteEngine On
|
||||
|
||||
# Handle Authorization Header
|
||||
RewriteCond %{HTTP:Authorization} .
|
||||
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||
|
||||
# Handle X-XSRF-Token Header
|
||||
RewriteCond %{HTTP:x-xsrf-token} .
|
||||
RewriteRule .* - [E=HTTP_X_XSRF_TOKEN:%{HTTP:X-XSRF-Token}]
|
||||
|
||||
# Redirect Trailing Slashes If Not A Folder...
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_URI} (.+)/$
|
||||
RewriteRule ^ %1 [L,R=301]
|
||||
|
||||
# Send Requests To Front Controller...
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ index.php [L]
|
||||
</IfModule>
|
||||
@@ -1,196 +0,0 @@
|
||||
<?php include '../src/session_check.php';
|
||||
checkUserRole(['admin']);
|
||||
?>
|
||||
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
<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 -->
|
||||
|
||||
<!--breadcrumb-->
|
||||
<div class="page-breadcrumb d-none d-sm-flex align-items-center mb-3">
|
||||
<div class="breadcrumb-title pe-3">Filament Settings</div>
|
||||
<div class="ps-3">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb mb-0 p-0">
|
||||
<li class="breadcrumb-item"><a href="index.php"><i class="bx bx-home-alt"></i></a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Add Filament</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
<!--end breadcrumb-->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-8 mx-auto">
|
||||
<div class="card">
|
||||
<div class="card-header px-4 py-3">
|
||||
<h5 class="mb-0">Add New Filament to Track</h5>
|
||||
</div>
|
||||
<div class="card-body p-4">
|
||||
<!-- Alert Banner (Hidden Initially) -->
|
||||
<div id="alertBanner" class="alert d-none" role="alert"></div>
|
||||
|
||||
<form id="filamentForm">
|
||||
<div class="row mb-3">
|
||||
<label for="productName" class="col-sm-3 col-form-label">Filament Name</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="productName" name="productName" placeholder="Brand / Type of Filament" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label for="productUrl" class="col-sm-3 col-form-label">Amazon URL</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="url" class="form-control" id="productUrl" name="productUrl" placeholder="https://www.amazon.co.uk/example" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<label class="col-sm-3 col-form-label"></label>
|
||||
<div class="col-sm-9">
|
||||
<div class="d-md-flex d-grid align-items-center gap-3">
|
||||
<button type="submit" class="btn btn-primary px-4">Track Filament</button>
|
||||
<button type="reset" class="btn btn-light px-4">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- jQuery & AJAX Script -->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#filamentForm').on('submit', function(event) {
|
||||
event.preventDefault(); // Prevent traditional form submission
|
||||
|
||||
// Collect form data
|
||||
let formData = $(this).serialize();
|
||||
|
||||
// AJAX request to submit form
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '../src/filamentTracker/addFilament.php',
|
||||
data: formData,
|
||||
dataType: 'json',
|
||||
success: function(response) {
|
||||
let banner = $('#alertBanner');
|
||||
if (response.status === 'success') {
|
||||
banner.removeClass('d-none alert-danger')
|
||||
.addClass('alert-success')
|
||||
.text(response.message);
|
||||
} else {
|
||||
banner.removeClass('d-none alert-success')
|
||||
.addClass('alert-danger')
|
||||
.text(response.message);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$('#alertBanner').removeClass('d-none alert-success')
|
||||
.addClass('alert-danger')
|
||||
.text('An error occurred while adding the filament.');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!--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>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 820">
|
||||
<title>HickLab3D</title>
|
||||
<rect width="1000" height="820" rx="180" fill="#e3f504"/>
|
||||
<g fill="#111111">
|
||||
<path d="M90 650 L90 240 L260 135 L260 290 L195 330 L195 425 L365 320 L365 155 L505 70 L505 520 L370 603 L370 450 L200 555 L200 715 Z"/>
|
||||
<path d="M545 90 L680 10 L680 420 L910 560 L775 645 L545 505 Z"/>
|
||||
<path d="M365 603 L505 520 L680 625 L545 710 Z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 451 B |
@@ -1,618 +0,0 @@
|
||||
<?php include '../src/session_check.php';
|
||||
checkUserRole(['admin']);
|
||||
?>
|
||||
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
<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 -->
|
||||
|
||||
<!-- Start Drying Modal -->
|
||||
<div class="modal fade" id="startDryingModal" tabindex="-1" aria-labelledby="startDryingModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="startDryingModalLabel">Start Drying</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="dryerControlForm">
|
||||
<div class="mb-3">
|
||||
<label for="filamentPreset" class="form-label">Filament Preset</label>
|
||||
<select class="form-select" id="filamentPreset" name="filamentPreset" required>
|
||||
<option value="">Select Filament Type</option>
|
||||
<option value="PLA" data-temp="50">PLA</option>
|
||||
<option value="ABS" data-temp="70">ABS</option>
|
||||
<option value="PETG" data-temp="65">PETG</option>
|
||||
<option value="Nylon" data-temp="80">Nylon</option>
|
||||
<option value="TPU" data-temp="45">TPU</option>
|
||||
<option value="Custom" data-temp="">Custom</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="dryingTime" class="form-label">Drying Time (Hours)</label>
|
||||
<input type="number" class="form-control" id="dryingTime" name="dryingTime" min="1" max="24" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="temperature" class="form-label">Drying Temperature (°C)</label>
|
||||
<input type="number" class="form-control" id="temperature" name="temperature" min="30" max="100" required>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between">
|
||||
<button type="submit" class="btn btn-success">Start Drying</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stop Drying Modal -->
|
||||
<div class="modal fade" id="stopDryingModal" tabindex="-1" aria-labelledby="stopDryingModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="stopDryingModalLabel">Stop Drying</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Are you sure you want to stop the drying process?</p>
|
||||
<div class="d-flex justify-content-between">
|
||||
<button type="button" class="btn btn-danger" id="confirmStopDrying">Yes, Stop Drying</button>
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Page Content -->
|
||||
<div class="container mt-4">
|
||||
<div class="row">
|
||||
<!-- Dryer Status Cards -->
|
||||
<div class="col-lg-4">
|
||||
<div class="card bg-danger radius-10 overflow-hidden">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center">
|
||||
<div>
|
||||
<p class="mb-0">Dryer Status</p>
|
||||
<h5 class="mb-0">STATUS</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card bg-danger radius-10 overflow-hidden" id="heaterRelayStatus">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center">
|
||||
<div>
|
||||
<p class="mb-0">Heater Status</p>
|
||||
<h5 class="mb-0">STATUS</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card bg-danger radius-10 overflow-hidden" id="fanRelayStatus">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center">
|
||||
<div>
|
||||
<p class="mb-0">Fan Status</p>
|
||||
<h5 class="mb-0">STATUS</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Left Column - Charts -->
|
||||
<div class="col-lg-7">
|
||||
<div class="row">
|
||||
<!-- Temperature Chart -->
|
||||
<div class="col-lg-12 mb-0">
|
||||
<div class="card radius-10 overflow-hidden">
|
||||
<div class="card-body d-flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<p class="mb-0 filament-name">Temp:</p>
|
||||
<h5 class="mb-0" id="temperatureValue">--°C</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tempChart"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Humidity Chart -->
|
||||
<div class="col-lg-12 mb-0">
|
||||
<div class="card radius-10 overflow-hidden">
|
||||
<div class="card-body d-flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<p class="mb-0 filament-name">Humidity:</p>
|
||||
<h5 class="mb-0" id="humidityValue">--%</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div id="humidityChart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Column - Dryer Control Card with Dropdown and Chart -->
|
||||
<div class="col-lg-5">
|
||||
<div class="card rounded-4 mb-0">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start justify-content-between mb-0">
|
||||
<div class="">
|
||||
<h6 class="mb-0">Dryer Control</h6>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<a href="javascript:;" class="dropdown-toggle-nocaret more-options dropdown-toggle" data-bs-toggle="dropdown">
|
||||
<i class='bx bx-dots-vertical-rounded'></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="javascript:;" data-bs-toggle="modal" data-bs-target="#startDryingModal">Start Drying</a></li>
|
||||
<li><a class="dropdown-item" href="javascript:;" data-bs-toggle="modal" data-bs-target="#stopDryingModal">Stop Drying</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-container2">
|
||||
<div id="chartProgress"></div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="">
|
||||
<h4 id="dryingTimeDisplay" class="mb-1">Loadig..</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- End Page Content -->
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!--end page 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 ESP32_IP = 'https://filamentdry.hickmeister.uk'; // Replace with your ESP32 IP
|
||||
let tempChart, humidityChart;
|
||||
let progressChart; // Declare a variable for the chart instance
|
||||
const startDryingModal = new bootstrap.Modal(document.getElementById('startDryingModal'));
|
||||
const stopDryingModal = new bootstrap.Modal(document.getElementById('stopDryingModal'));
|
||||
|
||||
// Fetch ESP32 Status Data
|
||||
function fetchDryerStatus() {
|
||||
fetch(`${ESP32_IP}/status`)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
if (data.dryerOn !== undefined) {
|
||||
updateTemperatureCard(data);
|
||||
updateHumidityCard(data);
|
||||
updateStatusCards(data);
|
||||
updateChartProgress(data); // Update chart for drying progress
|
||||
} else {
|
||||
console.error("Dryer offline or no data available");
|
||||
showOfflineStatus();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Failed to fetch dryer status:", error);
|
||||
showOfflineStatus();
|
||||
});
|
||||
}
|
||||
|
||||
// Control Dryer
|
||||
function controlDryer(dryerOn, targetTemperature, dryingTimeInMinutes) {
|
||||
const formData = new URLSearchParams();
|
||||
formData.append("dryerOn", dryerOn);
|
||||
formData.append("targetTemperature", targetTemperature);
|
||||
formData.append("dryingTime", dryingTimeInMinutes);
|
||||
|
||||
fetch(`${ESP32_IP}/control`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: formData.toString(),
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
console.log('Dryer control updated:', data);
|
||||
fetchDryerStatus(); // Refresh status after control update
|
||||
if (dryerOn) {
|
||||
startDryingModal.hide();
|
||||
} else {
|
||||
stopDryingModal.hide();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Failed to update dryer control:', error);
|
||||
alert('Failed to update dryer control. Check your connection.');
|
||||
});
|
||||
}
|
||||
|
||||
// Handle Form Submission for Starting Drying
|
||||
const dryerControlForm = document.getElementById("dryerControlForm");
|
||||
dryerControlForm.addEventListener("submit", function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
// Collect form data
|
||||
const formData = new FormData(dryerControlForm);
|
||||
const dryerOn = true; // Always true when starting the dryer
|
||||
const dryingTimeInHours = parseFloat(formData.get("dryingTime"));
|
||||
const targetTemperature = parseFloat(formData.get("temperature"));
|
||||
|
||||
// Validate Input
|
||||
if (isNaN(dryingTimeInHours) || isNaN(targetTemperature)) {
|
||||
alert("Please complete all required fields.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert drying time to minutes
|
||||
const dryingTimeInMinutes = Math.round(dryingTimeInHours * 60);
|
||||
|
||||
// Control Dryer
|
||||
controlDryer(dryerOn, targetTemperature, dryingTimeInMinutes);
|
||||
});
|
||||
|
||||
// Handle Stop Dryer
|
||||
document.getElementById("stopDryingModal").addEventListener("click", function () {
|
||||
stopDryingModal.show();
|
||||
});
|
||||
|
||||
document.getElementById("confirmStopDrying").addEventListener("click", function() {
|
||||
controlDryer(false, 0, 0); // Turn off the dryer
|
||||
});
|
||||
|
||||
// Auto-Fill Temperature Input Based on Filament Preset
|
||||
const filamentPresetSelect = document.getElementById("filamentPreset");
|
||||
const temperatureInput = document.getElementById("temperature");
|
||||
|
||||
filamentPresetSelect.addEventListener("change", function () {
|
||||
const selectedOption = filamentPresetSelect.options[filamentPresetSelect.selectedIndex];
|
||||
const presetTemperature = selectedOption.getAttribute("data-temp");
|
||||
|
||||
if (presetTemperature) {
|
||||
temperatureInput.value = presetTemperature; // Auto-fill temperature input
|
||||
} else {
|
||||
temperatureInput.value = ""; // Clear the temperature input for "Custom"
|
||||
}
|
||||
});
|
||||
|
||||
// Update chart progress
|
||||
function updateChartProgress(data) {
|
||||
const chartProgressElement = document.getElementById("chartProgress");
|
||||
|
||||
const dryingTime = data.dryingTime || 0; // Total drying time in minutes
|
||||
const remainingTime = data.remainingTime || 0; // Remaining time in minutes
|
||||
|
||||
// Convert remaining time and total drying time to h:mm format
|
||||
const remainingTimeFormatted = convertToHoursAndMinutes(remainingTime);
|
||||
const dryingTimeFormatted = convertToHoursAndMinutes(dryingTime);
|
||||
|
||||
const progressPercent = dryingTime > 0 ? ((dryingTime - remainingTime) / dryingTime) * 100 : 0; // Calculate the percentage of drying progress
|
||||
|
||||
// Initialize the chart if it doesn't exist yet
|
||||
if (!progressChart) {
|
||||
const options = {
|
||||
series: [progressPercent],
|
||||
chart: {
|
||||
height: 385,
|
||||
type: 'radialBar',
|
||||
toolbar: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
plotOptions: {
|
||||
radialBar: {
|
||||
hollow: {
|
||||
margin: 0,
|
||||
size: '80%',
|
||||
background: 'transparent',
|
||||
},
|
||||
track: {
|
||||
background: 'rgba(0, 0, 0, 0.1)',
|
||||
strokeWidth: '67%',
|
||||
},
|
||||
dataLabels: {
|
||||
show: true,
|
||||
name: {
|
||||
offsetY: -10,
|
||||
show: false,
|
||||
},
|
||||
value: {
|
||||
offsetY: 10,
|
||||
color: 'rgba(13, 160, 8, 0.82)',
|
||||
fontSize: '20px',
|
||||
show: true,
|
||||
formatter: function () {
|
||||
return remainingTimeFormatted; // Display remaining time in the center
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
fill: {
|
||||
type: 'gradient',
|
||||
gradient: {
|
||||
shade: 'dark',
|
||||
type: 'horizontal',
|
||||
shadeIntensity: 02,
|
||||
gradientToColors: ['#44FF00'],
|
||||
opacityFrom: 1,
|
||||
opacityTo: 1,
|
||||
stops: [0, 100]
|
||||
}
|
||||
},
|
||||
colors: ["#289600"],
|
||||
stroke: {
|
||||
lineCap: 'round'
|
||||
},
|
||||
labels: ['Drying Progress'],
|
||||
};
|
||||
|
||||
progressChart = new ApexCharts(chartProgressElement, options);
|
||||
progressChart.render();
|
||||
} else {
|
||||
progressChart.updateSeries([progressPercent]);
|
||||
|
||||
// Dynamically update the remaining time in the center
|
||||
progressChart.updateOptions({
|
||||
plotOptions: {
|
||||
radialBar: {
|
||||
dataLabels: {
|
||||
value: {
|
||||
formatter: function () {
|
||||
return remainingTimeFormatted; // Dynamically update the remaining time
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Display drying time below the chart
|
||||
const timeSetElement = document.getElementById('dryingTimeDisplay');
|
||||
if (timeSetElement) {
|
||||
timeSetElement.innerText = `Time Set: ${dryingTimeFormatted}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert minutes to hours and minutes (e.g., 90 minutes -> 1h 30m)
|
||||
function convertToHoursAndMinutes(minutes) {
|
||||
const hours = Math.floor(minutes / 60);
|
||||
const mins = minutes % 60;
|
||||
return `${hours}h ${mins}m`;
|
||||
}
|
||||
|
||||
// Update Temperature Card and Chart
|
||||
function updateTemperatureCard(data) {
|
||||
const temperature = data.temperature.toFixed(1); // Limit temperature to 1 decimal place
|
||||
const tempHistory = data.tempHistory.map(temp => parseFloat(temp.toFixed(1))); // Limit history data
|
||||
const timestamps = Array.from({ length: tempHistory.length }, (_, i) => `${i + 1}`);
|
||||
|
||||
document.getElementById('temperatureValue').innerText = `${temperature}°C`;
|
||||
|
||||
const options = {
|
||||
series: [{ name: "Temperature", data: tempHistory }],
|
||||
chart: {
|
||||
type: 'area',
|
||||
color: '#1df00a',
|
||||
height: 150,
|
||||
toolbar: { show: false },
|
||||
sparkline: { enabled: true },
|
||||
id: 'tempChart',
|
||||
},
|
||||
stroke: { curve: 'smooth' },
|
||||
xaxis: { categories: timestamps, labels: { show: false } },
|
||||
tooltip: {
|
||||
theme: 'dark',
|
||||
x: { show: false },
|
||||
y: { formatter: value => `${value.toFixed(1)}°C` },
|
||||
},
|
||||
};
|
||||
|
||||
if (!tempChart) {
|
||||
tempChart = new ApexCharts(document.querySelector("#tempChart"), options);
|
||||
tempChart.render();
|
||||
} else {
|
||||
tempChart.updateSeries([{ data: tempHistory }]);
|
||||
}
|
||||
}
|
||||
|
||||
// Update Humidity Card and Chart
|
||||
function updateHumidityCard(data) {
|
||||
const humidity = data.humidity.toFixed(1);
|
||||
const humidityHistory = data.humidityHistory || [];
|
||||
const timestamps = Array.from({ length: humidityHistory.length }, (_, i) => `${i + 1}`);
|
||||
|
||||
document.getElementById('humidityValue').innerText = `${humidity}%`;
|
||||
|
||||
const options = {
|
||||
series: [{ name: "Humidity", data: humidityHistory }],
|
||||
chart: {
|
||||
type: 'area',
|
||||
height: 150,
|
||||
toolbar: { show: false },
|
||||
sparkline: { enabled: true },
|
||||
id: 'humidityChart',
|
||||
},
|
||||
stroke: { curve: 'smooth' },
|
||||
xaxis: { categories: timestamps, labels: { show: false } },
|
||||
tooltip: {
|
||||
theme: 'dark',
|
||||
x: { show: false },
|
||||
y: { formatter: value => `${value.toFixed(1)}%` },
|
||||
},
|
||||
};
|
||||
|
||||
if (!humidityChart) {
|
||||
humidityChart = new ApexCharts(document.querySelector("#humidityChart"), options);
|
||||
humidityChart.render();
|
||||
} else {
|
||||
humidityChart.updateSeries([{ data: humidityHistory }]);
|
||||
}
|
||||
}
|
||||
|
||||
// Update Status Cards (Dryer, Heater, Fan)
|
||||
function updateStatusCards(data) {
|
||||
const dryerStatusCard = document.querySelector('.card:nth-child(1)');
|
||||
const heaterStatusCard = document.getElementById('heaterRelayStatus');
|
||||
const fanStatusCard = document.getElementById('fanRelayStatus');
|
||||
|
||||
const dryerState = data.dryerOn ? "On" : "Off";
|
||||
const fanRelayState = data.fanRelayState ? "On" : "Off";
|
||||
const heaterRelayState = data.heaterRelayState ? "On" : "Off";
|
||||
|
||||
if (dryerStatusCard) {
|
||||
dryerStatusCard.classList.toggle("bg-success", dryerState === "On");
|
||||
dryerStatusCard.classList.toggle("bg-danger", dryerState === "Off");
|
||||
dryerStatusCard.querySelector("h5").innerText = dryerState;
|
||||
}
|
||||
|
||||
if (heaterStatusCard) {
|
||||
heaterStatusCard.classList.toggle("bg-success", heaterRelayState === "On");
|
||||
heaterStatusCard.classList.toggle("bg-danger", heaterRelayState === "Off");
|
||||
heaterStatusCard.querySelector("h5").innerText = heaterRelayState;
|
||||
}
|
||||
|
||||
if (fanStatusCard) {
|
||||
fanStatusCard.classList.toggle("bg-success", fanRelayState === "On");
|
||||
fanStatusCard.classList.toggle("bg-danger", fanRelayState === "Off");
|
||||
fanStatusCard.querySelector("h5").innerText = fanRelayState;
|
||||
}
|
||||
}
|
||||
|
||||
// Show Offline Status
|
||||
function showOfflineStatus() {
|
||||
const dryerStatusCard = document.querySelector('.card:nth-child(1)');
|
||||
const heaterStatusCard = document.getElementById('heaterRelayStatus');
|
||||
const fanStatusCard = document.getElementById('fanRelayStatus');
|
||||
|
||||
if (dryerStatusCard) {
|
||||
dryerStatusCard.classList.remove("bg-success");
|
||||
dryerStatusCard.classList.add("bg-danger");
|
||||
dryerStatusCard.querySelector("h5").innerText = "Offline";
|
||||
}
|
||||
|
||||
if (heaterStatusCard) {
|
||||
heaterStatusCard.classList.remove("bg-success");
|
||||
heaterStatusCard.classList.add("bg-danger");
|
||||
heaterStatusCard.querySelector("h5").innerText = "Offline";
|
||||
}
|
||||
|
||||
if (fanStatusCard) {
|
||||
fanStatusCard.classList.remove("bg-success");
|
||||
fanStatusCard.classList.add("bg-danger");
|
||||
fanStatusCard.querySelector("h5").innerText = "Offline";
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch data every 10 seconds
|
||||
fetchDryerStatus();
|
||||
setInterval(fetchDryerStatus, 10000);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 703 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 405 KiB |
@@ -0,0 +1,12 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 820">
|
||||
<title>HL3D HL Touchmark</title>
|
||||
<desc>Single-colour simplified HL monogram for 3D-print embossing, debossing and touchmarking.</desc>
|
||||
<g fill="#111111">
|
||||
<!-- H: heavy angular form -->
|
||||
<path d="M90 650 L90 240 L260 135 L260 290 L195 330 L195 425 L365 320 L365 155 L505 70 L505 520 L370 603 L370 450 L200 555 L200 715 Z"/>
|
||||
<!-- L: interlocking lower-right form -->
|
||||
<path d="M545 90 L680 10 L680 420 L910 560 L775 645 L545 505 Z"/>
|
||||
<!-- lower bridge / foot to echo the dimensional mark while remaining a simple solid touchmark -->
|
||||
<path d="M365 603 L505 520 L680 625 L545 710 Z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 687 B |
+14
-227
@@ -1,233 +1,20 @@
|
||||
<?php include '../src/session_check.php'; ?>
|
||||
<?php
|
||||
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
<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>
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
<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">
|
||||
|
||||
<div class="">
|
||||
<div class="">
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-12 col-xl-4">
|
||||
<div class="card rounded-4 mb-0">
|
||||
<div class="card-body">
|
||||
<div class="hstack align-items-center gap-3">
|
||||
<div class="mb-1 widgets-icons bg-light-success text-success rounded-3 d-flex align-items-center justify-content-center">
|
||||
<i class='bx bx-printer'></i>
|
||||
</div>
|
||||
<hr class="vr">
|
||||
<div class="">
|
||||
<h4 class="mb-0 d-flex align-items-center gap-2">$84,256 <span class="dash-lable d-flex align-items-center gap-1 rounded mb-0 bg-light-danger text-danger bg-opacity-10"><i class='bx bx-up-arrow-alt' ></i>8.6%</span></h4>
|
||||
<p class="mb-0">Total Income</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="chart1"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-xl-2">
|
||||
<div class="card rounded-4 mb-0">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start justify-content-between mb-0">
|
||||
<div class="">
|
||||
<h6 class="mb-0">Active Users</h6>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<a href="javascript:;" class="dropdown-toggle-nocaret more-options dropdown-toggle"
|
||||
data-bs-toggle="dropdown">
|
||||
<i class='bx bx-dots-vertical-rounded'></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="javascript:;">Action</a></li>
|
||||
<li><a class="dropdown-item" href="javascript:;">Another action</a></li>
|
||||
<li><a class="dropdown-item" href="javascript:;">Something else here</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-container2">
|
||||
<div id="chart2"></div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="">
|
||||
<h4 class="mb-1">42.5K</h4>
|
||||
</div>
|
||||
<p class="mb-0"><span class="text-success">+37.5K</span> from last month</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-xl-4">
|
||||
<div class="card rounded-4 mb-0">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start justify-content-between mb-3">
|
||||
<div class="">
|
||||
<h6 class="mb-0">Sales & Views</h6>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<a href="javascript:;" class="dropdown-toggle-nocaret more-options dropdown-toggle"
|
||||
data-bs-toggle="dropdown">
|
||||
<i class='bx bx-dots-vertical-rounded'></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="javascript:;">Action</a></li>
|
||||
<li><a class="dropdown-item" href="javascript:;">Another action</a></li>
|
||||
<li><a class="dropdown-item" href="javascript:;">Something else here</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="chart3"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-xl-2">
|
||||
<div class="card rounded-4 mb-0 overflow-hidden mb-0">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start justify-content-between mb-1">
|
||||
<div class="">
|
||||
<h4 class="mb-0">87.4K</h4>
|
||||
<p class="mb-0">Total Clicks</p>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<a href="javascript:;" class="dropdown-toggle-nocaret more-options dropdown-toggle"
|
||||
data-bs-toggle="dropdown">
|
||||
<i class='bx bx-dots-vertical-rounded'></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="javascript:;">Action</a></li>
|
||||
<li><a class="dropdown-item" href="javascript:;">Another action</a></li>
|
||||
<li><a class="dropdown-item" href="javascript:;">Something else here</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<div id="chart4"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-xl-4">
|
||||
<div class="card border-0 rounded-4 shadow-none mb-0 bg-transparent mb-0">
|
||||
<div class="card-body p-0">
|
||||
<div class="d-flex flex-column gap-4">
|
||||
<div class="card rounded-4 mb-0">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center">
|
||||
<div>
|
||||
<p class="mb-0 text-secondary">Total Accounts</p>
|
||||
<h4 class="my-1">58.4K</h4>
|
||||
<p class="mb-0 font-13 text-success">+14% Since last Month</p>
|
||||
</div>
|
||||
<div class="widgets-icons bg-light-danger text-danger ms-auto"><i class='bx bxs-group'></i></div>
|
||||
</div>
|
||||
<div id="chart8"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card rounded-4">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center">
|
||||
<div>
|
||||
<p class="mb-0 text-secondary">Bounce Rate</p>
|
||||
<h4 class="my-1">36.7%</h4>
|
||||
<p class="mb-0 font-13 text-success">+17% Since last Month</p>
|
||||
</div>
|
||||
<div class="widgets-icons bg-light-primary text-primary ms-auto"><i class='bx bx-bar-chart-alt-2'></i></div>
|
||||
</div>
|
||||
<div id="chart9"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!--end page content -->
|
||||
</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-->
|
||||
define('LARAVEL_START', microtime(true));
|
||||
|
||||
// Determine if the application is in maintenance mode...
|
||||
if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
|
||||
require $maintenance;
|
||||
}
|
||||
|
||||
<!-- 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 -->
|
||||
// Register the Composer autoloader...
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
<!-- 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>
|
||||
// Bootstrap Laravel and handle the request...
|
||||
/** @var Application $app */
|
||||
$app = require_once __DIR__.'/../bootstrap/app.php';
|
||||
|
||||
<script src="../assets/js/index.js"></script>
|
||||
<script src="../assets/plugins/peity/jquery.peity.min.js"></script>
|
||||
<script>
|
||||
$(".data-attributes span").peity("donut")
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
$app->handleRequest(Request::capture());
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" href="../assets/images/favicon-32x32.png" type="image/png">
|
||||
<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">
|
||||
<link href="../assets/css/pace.min.css" rel="stylesheet">
|
||||
<script src="../assets/js/pace.min.js"></script>
|
||||
<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">
|
||||
<!-- 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">
|
||||
<link href="../assets/css/icons.css" rel="stylesheet">
|
||||
<title>TOD - Admin Dashboard</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<div class="section-authentication-cover">
|
||||
<div class="row g-0">
|
||||
<div class="col-12 col-xl-7 col-xxl-8 auth-cover-left d-none d-xl-flex align-items-center justify-content-center">
|
||||
<div class="card shadow-none bg-transparent rounded-0">
|
||||
<div class="card-body">
|
||||
<img src="../assets/images/login-images/login-cover.svg" class="img-fluid" width="650" alt=""/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-xl-5 col-xxl-4 auth-cover-right align-items-center justify-content-center">
|
||||
<div class="card rounded-0 m-3 shadow-none bg-transparent">
|
||||
<div class="card-body p-sm-5">
|
||||
<div class="text-center mb-4">
|
||||
<img src="../assets/images/logo-icon.png" width="60" alt="">
|
||||
<h5>TechOdyssey Designs Dashboard</h5>
|
||||
<p>Please log in to your account</p>
|
||||
</div>
|
||||
<form id="loginForm" class="row g-3">
|
||||
<div class="col-12">
|
||||
<label for="inputEmailAddress" class="form-label">Username</label>
|
||||
<input type="input" class="form-control" name="username" id="inputEmailAddress" required>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label for="inputChoosePassword" class="form-label">Password</label>
|
||||
<div class="input-group" id="show_hide_password">
|
||||
<input type="password" class="form-control" name="password" id="inputChoosePassword" required>
|
||||
<a href="javascript:;" class="input-group-text bg-transparent"><i class="bx bx-hide"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 d-grid">
|
||||
<button type="submit" class="btn btn-primary">Sign in</button>
|
||||
</div>
|
||||
<div class="col-12 text-danger text-center mt-2" id="loginMessage"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="../assets/js/bootstrap.bundle.min.js"></script>
|
||||
<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>
|
||||
$(document).ready(function () {
|
||||
$('#loginForm').on('submit', function (e) {
|
||||
e.preventDefault();
|
||||
const formData = $(this).serialize();
|
||||
|
||||
$.ajax({
|
||||
url: '../src/login.php',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
success: function (response) {
|
||||
if (response.trim() === 'success') {
|
||||
window.location.href = 'index.php';
|
||||
} else {
|
||||
$('#loginMessage').text(response);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<script src="../assets/js/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,7 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
session_unset();
|
||||
session_destroy();
|
||||
header("Location: login.php");
|
||||
exit();
|
||||
?>
|
||||
@@ -1,211 +0,0 @@
|
||||
<?php include '../src/session_check.php'; ?>
|
||||
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
<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 -->
|
||||
|
||||
<!--breadcrumb-->
|
||||
<div class="page-breadcrumb d-none d-sm-flex align-items-center mb-3">
|
||||
<div class="breadcrumb-title pe-3">User Settings</div>
|
||||
<div class="ps-3">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb mb-0 p-0">
|
||||
<li class="breadcrumb-item"><a href="index.php"><i class="bx bx-home-alt"></i></a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Add Printer</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
<!--end breadcrumb-->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-8 mx-auto">
|
||||
<div class="card">
|
||||
<div class="card-header px-4 py-3">
|
||||
<h5 class="mb-0">Add New Printer</h5>
|
||||
</div>
|
||||
<div class="card-body p-4">
|
||||
<!-- Alert Banner (Hidden Initially) -->
|
||||
<div id="alertBanner" class="alert d-none" role="alert"></div>
|
||||
|
||||
<form id="printerForm">
|
||||
<div class="row mb-3">
|
||||
<label for="printerName" class="col-sm-3 col-form-label">Printer Name</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="printerName" name="printerName" placeholder="Bambu X1 or P1P" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label for="printerIp" class="col-sm-3 col-form-label">Printer IP</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="printerIp" name="printerIp" placeholder="e.g., 192.168.1.100" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label for="serialNumber" class="col-sm-3 col-form-label">Serial Number</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="serialNumber" name="serialNumber" placeholder="e.g., X1SN123456" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label for="accessCode" class="col-sm-3 col-form-label">Printer Access Code</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="password" class="form-control" id="accessCode" name="accessCode" placeholder="Enter Printer Access Code" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<label class="col-sm-3 col-form-label"></label>
|
||||
<div class="col-sm-9">
|
||||
<div class="d-md-flex d-grid align-items-center gap-3">
|
||||
<button type="submit" class="btn btn-primary px-4">Add Printer</button>
|
||||
<button type="reset" class="btn btn-light px-4">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- jQuery & AJAX Script -->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#printerForm').on('submit', function(event) {
|
||||
event.preventDefault(); // Prevent traditional form submission
|
||||
|
||||
// Collect form data
|
||||
let formData = $(this).serialize();
|
||||
|
||||
// AJAX request to submit form
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '../src/printers/addPrinter.php',
|
||||
data: formData,
|
||||
dataType: 'json',
|
||||
success: function(response) {
|
||||
let banner = $('#alertBanner');
|
||||
if (response.status === 'success') {
|
||||
banner.removeClass('d-none alert-danger')
|
||||
.addClass('alert-success')
|
||||
.text(response.message);
|
||||
} else {
|
||||
banner.removeClass('d-none alert-success')
|
||||
.addClass('alert-danger')
|
||||
.text(response.message);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$('#alertBanner').removeClass('d-none alert-success')
|
||||
.addClass('alert-danger')
|
||||
.text('An error occurred while adding the printer.');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<!--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>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow:
|
||||
@@ -1,265 +0,0 @@
|
||||
<?php include '../src/session_check.php'; ?>
|
||||
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
<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">
|
||||
|
||||
<div class="">
|
||||
<div class="">
|
||||
|
||||
<!--start page content -->
|
||||
<div class="row g-4">
|
||||
<!-- Account Information Card -->
|
||||
<div class="col-12 col-xl-6">
|
||||
<div class="card rounded-4 mb-0 shadow-sm">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<div class="widgets-icons bg-light-success text-success rounded-circle d-flex align-items-center justify-content-center p-3">
|
||||
<i class='bx bxs-user fs-3'></i>
|
||||
</div>
|
||||
<div id="accountInfo" class="ms-3">
|
||||
<h5 class="mb-0 fw-bold">Loading...</h5>
|
||||
<p class="text-muted mb-0">Account Information</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Prepay Balance Card -->
|
||||
<div class="col-12 col-xl-6">
|
||||
<div class="card rounded-4 mb-0 shadow-sm">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<div class="widgets-icons bg-light-info text-info rounded-circle d-flex align-items-center justify-content-center p-3">
|
||||
<i class='bx bx-wallet fs-3'></i>
|
||||
</div>
|
||||
<div id="prepayBalance" class="ms-3">
|
||||
<h5 class="mb-0 fw-bold">Loading...</h5>
|
||||
<p class="text-muted mb-0">Prepay Balance</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Orders Table -->
|
||||
<div class="col-12 col-xl-12">
|
||||
<div class="card rounded-4 mb-0 shadow-sm">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title fw-bold mb-3">Orders</h5>
|
||||
<div id="ordersDetail" class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>Order ID</th>
|
||||
<th>Courier</th>
|
||||
<th>Service</th>
|
||||
<th>Tracking Status</th>
|
||||
<th>Estimated Delivery</th>
|
||||
<th>Recipient</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="6" class="text-center text-muted">Loading orders...</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--end page content -->
|
||||
|
||||
|
||||
|
||||
</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-->
|
||||
</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).ready(function () {
|
||||
// Fetch account information via AJAX
|
||||
function fetchAccountInfo() {
|
||||
$.ajax({
|
||||
url: '../src/shipping/get_account_info.php',
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
success: function (response) {
|
||||
if (response.success) {
|
||||
const data = response.data;
|
||||
let html = `
|
||||
<h5 class="mb-0 fw-bold">${data.Forename || 'N/A'} ${data.Surname || ''}</h5>
|
||||
<p class="text-muted mb-0">Email: ${data.Email || 'N/A'}</p>
|
||||
<p class="text-muted mb-0">Member Since: ${data.MemberSince || 'N/A'}</p>
|
||||
`;
|
||||
$('#accountInfo').html(html);
|
||||
} else {
|
||||
$('#accountInfo').html('<p class="text-danger">Error fetching account information.</p>');
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
$('#accountInfo').html('<p class="text-danger">Error loading account information.</p>');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Fetch prepay balance via AJAX
|
||||
function fetchPrepayBalance() {
|
||||
$.ajax({
|
||||
url: '../src/shipping/get_prepay_balance.php',
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
success: function (response) {
|
||||
if (response.success) {
|
||||
const data = response.data;
|
||||
const balance = data.Balance || 0;
|
||||
$('#prepayBalance').html(`
|
||||
<h5 class="mb-0 fw-bold">£ ${balance}</h5>
|
||||
<p class="text-muted mb-0">Prepay Balance</p>
|
||||
`);
|
||||
} else {
|
||||
$('#prepayBalance').html('<p class="text-danger">Error fetching balance.</p>');
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
$('#prepayBalance').html('<p class="text-danger">Error loading balance.</p>');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Fetch order details via AJAX
|
||||
function fetchOrdersDetail() {
|
||||
$.ajax({
|
||||
url: '../src/shipping/get_orders_detail.php',
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
success: function (response) {
|
||||
if (response.success) {
|
||||
const orders = response.data.Orders || [];
|
||||
let html = '';
|
||||
|
||||
if (orders.length === 0) {
|
||||
html = '<tr><td colspan="6" class="text-center text-muted">No orders found.</td></tr>';
|
||||
} else {
|
||||
orders.forEach(order => {
|
||||
const trackingStatus = order.Tracking?.Delivered ?
|
||||
'<span class="badge bg-success">Delivered</span>' :
|
||||
'<span class="badge bg-warning text-dark">In Transit</span>';
|
||||
html += `
|
||||
<tr>
|
||||
<td>${order.OrderLineId}</td>
|
||||
<td>${order.Courier}</td>
|
||||
<td>${order.Service}</td>
|
||||
<td>${trackingStatus}</td>
|
||||
<td>${order.EstimatedDeliveryDate ? new Date(order.EstimatedDeliveryDate).toLocaleString() : 'N/A'}</td>
|
||||
<td>${order.DeliveryAddress?.ContactName || 'N/A'}</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
}
|
||||
|
||||
$('#ordersDetail tbody').html(html);
|
||||
} else {
|
||||
$('#ordersDetail tbody').html('<tr><td colspan="6" class="text-center text-danger">Error fetching orders.</td></tr>');
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
$('#ordersDetail tbody').html('<tr><td colspan="6" class="text-center text-danger">Error loading orders.</td></tr>');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Trigger all fetches on page load
|
||||
fetchAccountInfo();
|
||||
fetchPrepayBalance();
|
||||
fetchOrdersDetail();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,319 +0,0 @@
|
||||
<?php include '../src/session_check.php';
|
||||
checkUserRole(['admin']);
|
||||
?>
|
||||
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
<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 mt-4">
|
||||
<h2 class="text-center mb-4">User Management</h2>
|
||||
|
||||
<div class="d-flex justify-content-between mb-3">
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#createUserModal">
|
||||
<i class="fas fa-user-plus"></i> Create New User
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover table-bordered align-middle">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Username</th>
|
||||
<th>Email</th>
|
||||
<th>Role</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="userTableBody">
|
||||
<!-- Rows dynamically populated -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Create User Modal -->
|
||||
<div class="modal fade" id="createUserModal" tabindex="-1" aria-labelledby="createUserModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="createUserModalLabel">Create New User</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="createUserForm">
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">Username</label>
|
||||
<input type="text" class="form-control" id="username" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Email</label>
|
||||
<input type="email" class="form-control" id="email" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="role" class="form-label">Role</label>
|
||||
<select id="role" class="form-select" required>
|
||||
<option value="">Select Role</option>
|
||||
<option value="admin">Admin</option>
|
||||
<option value="user">User</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<input type="password" class="form-control" id="password" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100">Create User</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reset Password Modal -->
|
||||
<div class="modal fade" id="resetPasswordModal" tabindex="-1" aria-labelledby="resetPasswordModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="resetPasswordModalLabel">Reset Password</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="resetPasswordForm">
|
||||
<p>Enter a new password for <span id="resetUserName"></span>:</p>
|
||||
<div class="mb-3">
|
||||
<label for="newPassword" class="form-label">New Password</label>
|
||||
<input type="password" class="form-control" id="newPassword" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-warning w-100">Reset Password</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</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).ready(function () {
|
||||
const apiUrl = '../src/userMananagementService.php';
|
||||
|
||||
// Load users on page load
|
||||
fetchUsers();
|
||||
|
||||
// Create new user form submission
|
||||
$('#createUserForm').submit(function (e) {
|
||||
e.preventDefault();
|
||||
const username = $('#username').val();
|
||||
const email = $('#email').val();
|
||||
const role = $('#role').val();
|
||||
const password = $('#password').val();
|
||||
|
||||
$.ajax({
|
||||
url: apiUrl,
|
||||
method: 'POST',
|
||||
dataType: 'json',
|
||||
data: JSON.stringify({ username, email, role, password }),
|
||||
contentType: 'application/json',
|
||||
success: function () {
|
||||
alert('User created successfully!');
|
||||
fetchUsers();
|
||||
$('#createUserModal').modal('hide');
|
||||
$('#createUserForm')[0].reset();
|
||||
},
|
||||
error: function (xhr) {
|
||||
alert('Error creating user: ' + xhr.responseText);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Reset password form submission
|
||||
$('#resetPasswordForm').submit(function (e) {
|
||||
e.preventDefault();
|
||||
const userId = $('#resetPasswordModal').data('userId');
|
||||
const password = $('#newPassword').val();
|
||||
|
||||
$.ajax({
|
||||
url: `${apiUrl}?reset-password=${userId}`,
|
||||
method: 'POST',
|
||||
dataType: 'json',
|
||||
data: JSON.stringify({ password }),
|
||||
contentType: 'application/json',
|
||||
success: function () {
|
||||
alert('Password reset successfully!');
|
||||
$('#resetPasswordModal').modal('hide');
|
||||
$('#resetPasswordForm')[0].reset();
|
||||
},
|
||||
error: function (xhr) {
|
||||
alert('Error resetting password: ' + xhr.responseText);
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Fetch users from the backend
|
||||
function fetchUsers() {
|
||||
const apiUrl = '../src/userMananagementService.php';
|
||||
|
||||
$.ajax({
|
||||
url: apiUrl,
|
||||
method: 'GET',
|
||||
dataType: 'json',
|
||||
success: function (users) {
|
||||
const tableBody = $('#userTableBody');
|
||||
tableBody.empty();
|
||||
|
||||
users.forEach(function (user) {
|
||||
const row = `
|
||||
<tr>
|
||||
<td>${user.id}</td>
|
||||
<td>${user.username}</td>
|
||||
<td>${user.email}</td>
|
||||
<td>${user.role}</td>
|
||||
<td>
|
||||
<button class="btn btn-warning btn-sm" onclick="openResetPasswordModal(${user.id}, '${user.username}')">
|
||||
<i class="fas fa-key"></i> Reset Password
|
||||
</button>
|
||||
<button class="btn btn-danger btn-sm" onclick="deleteUser(${user.id})">
|
||||
<i class="fas fa-trash"></i> Delete
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
tableBody.append(row);
|
||||
});
|
||||
},
|
||||
error: function (xhr) {
|
||||
alert('Error fetching users: ' + xhr.responseText);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Open the reset password modal
|
||||
function openResetPasswordModal(userId, username) {
|
||||
$('#resetPasswordModal').data('userId', userId);
|
||||
$('#resetUserName').text(username);
|
||||
$('#resetPasswordModal').modal('show');
|
||||
}
|
||||
|
||||
// Delete user
|
||||
function deleteUser(userId) {
|
||||
const apiUrl = '../src/userMananagementService.php';
|
||||
|
||||
if (confirm('Are you sure you want to delete this user?')) {
|
||||
$.ajax({
|
||||
url: `${apiUrl}?delete-user=${userId}`,
|
||||
method: 'POST',
|
||||
success: function () {
|
||||
alert('User deleted successfully!');
|
||||
fetchUsers();
|
||||
},
|
||||
error: function (xhr) {
|
||||
alert('Error deleting user: ' + xhr.responseText);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,283 +0,0 @@
|
||||
<?php include '../src/session_check.php'; ?>
|
||||
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
<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-->
|
||||
</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>
|
||||
`;
|
||||
}
|
||||
|
||||
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 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;
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure price doesn't go below zero
|
||||
latestPrice = Math.max(latestPrice, 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;
|
||||
}
|
||||
}
|
||||
|
||||
const priceDifference = latestPrice - lastDistinctPrice;
|
||||
|
||||
// Price Change Indicator
|
||||
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 = filamentData.amazonUrl || '#';
|
||||
|
||||
// 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}`;
|
||||
}
|
||||
|
||||
const chartId = `chart-${filament.replace(/\s+/g, '-')}`;
|
||||
const chartColor = getRandomColor();
|
||||
|
||||
// Create Card HTML
|
||||
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.toFixed(2)} ${priceChangeIndicator}
|
||||
</h5>
|
||||
</div>
|
||||
<div>
|
||||
${
|
||||
discountText
|
||||
? `<span class="text-success fw-bold" style="font-size: 1rem;">
|
||||
${discountText}
|
||||
</span>`
|
||||
: ''
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div id="${chartId}"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
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()}`;
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const chartElement = document.getElementById(chartId);
|
||||
if (chartElement) {
|
||||
const chart = new ApexCharts(chartElement, chartOptions);
|
||||
chart.render();
|
||||
}
|
||||
});
|
||||
} 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>
|
||||
@@ -1,249 +0,0 @@
|
||||
<?php include '../src/session_check.php'; ?>
|
||||
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
<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 -->
|
||||
|
||||
|
||||
<!-- Breadcrumb -->
|
||||
<div class="page-breadcrumb d-none d-sm-flex align-items-center mb-3">
|
||||
<div class="breadcrumb-title pe-3">Printer Dashboard</div>
|
||||
<div class="ps-3">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb mb-0 p-0">
|
||||
<li class="breadcrumb-item"><a href="index.php"><i class="bx bx-home-alt"></i></a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Your Printers</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="ms-auto">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
Refresh Interval: <span id="selectedIntervalText">60s</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end" id="intervalDropdown">
|
||||
<li><a class="dropdown-item set-interval" data-interval="5000" href="#">5 seconds</a></li>
|
||||
<li><a class="dropdown-item set-interval" data-interval="10000" href="#">10 seconds</a></li>
|
||||
<li><a class="dropdown-item set-interval" data-interval="30000" href="#">30 seconds</a></li>
|
||||
<li><a class="dropdown-item set-interval" data-interval="60000" href="#">60 seconds</a></li>
|
||||
<li><a class="dropdown-item set-interval" data-interval="off" href="#">Off</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- End Breadcrumb -->
|
||||
|
||||
<div class="container">
|
||||
<div class="main-body">
|
||||
<div id="alertContainer" class="container mt-3">
|
||||
<!-- Alerts will be dynamically inserted here -->
|
||||
</div>
|
||||
<div class="row" id="printerContainer">
|
||||
<!-- Printer cards will be dynamically inserted here -->
|
||||
</div>
|
||||
</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-->
|
||||
</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).ready(function() {
|
||||
let refreshInterval = 60000; // Default interval of 10s
|
||||
let intervalHandler;
|
||||
|
||||
// Load printers asynchronously
|
||||
async function loadPrinters() {
|
||||
try {
|
||||
const response = await $.ajax({
|
||||
url: '../src/printers/getPrinters.php',
|
||||
method: 'GET',
|
||||
dataType: 'json',
|
||||
cache: false
|
||||
});
|
||||
|
||||
let container = $('#printerContainer');
|
||||
|
||||
if (response.status === 'success' && response.data.length > 0) {
|
||||
response.data.forEach(function(printer) {
|
||||
let existingCard = container.find(`.printer-card[data-serial="${printer.serialNumber}"]`);
|
||||
|
||||
let trayHTML = '';
|
||||
printer.trays.forEach(tray => {
|
||||
let trayColor = `#${tray.color.slice(0, 6)}`;
|
||||
trayHTML += `
|
||||
<div class="tray-slot text-center">
|
||||
<div class="tray-circle" style="background-color: ${trayColor}; width: 40px; height: 40px; border-radius: 50%;"></div>
|
||||
<p>Slot ${parseInt(tray.id) + 1}</p>
|
||||
</div>`;
|
||||
});
|
||||
|
||||
let printerCard = `
|
||||
<div class="col-lg-4 printer-card" data-serial="${printer.serialNumber}">
|
||||
<div class="card mb-4">
|
||||
<div class="card-body text-center">
|
||||
<img src="../assets/images/printer-icon.png" alt="Printer" class="rounded-circle p-1" width="110">
|
||||
<div class="mt-3">
|
||||
<h4>${printer.printerName}</h4>
|
||||
<p class="text-secondary mb-1">Current Job: <span>${printer.jobName}</span></p>
|
||||
<p class="text-muted font-size-sm">
|
||||
Bed Temp: <span>${printer.bedTemp}°C</span> |
|
||||
Nozzle Temp: <span>${printer.nozzleTemp}°C</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="d-flex justify-content-center gap-4 mt-3">
|
||||
${trayHTML}
|
||||
</div>
|
||||
<div class="mt-4 w-100">
|
||||
<label for="humidityBar${printer.serialNumber}" class="form-label">AMS Humidity</label>
|
||||
<div class="progress" style="height: 20px;">
|
||||
<div id="humidityBar${printer.serialNumber}" class="progress-bar" role="progressbar"
|
||||
style="width: ${printer.humidity * 20}%;"
|
||||
aria-valuemin="1"
|
||||
aria-valuemax="5">
|
||||
${printer.humidity}/5
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
if (existingCard.length) {
|
||||
existingCard.replaceWith(printerCard);
|
||||
} else {
|
||||
container.append(printerCard);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('Failed to load printers:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Polling function
|
||||
function startPolling(interval) {
|
||||
clearInterval(intervalHandler);
|
||||
if (interval !== 'off') {
|
||||
intervalHandler = setInterval(loadPrinters, interval);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle refresh dropdown
|
||||
$('.set-interval').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
let selectedInterval = $(this).data('interval');
|
||||
|
||||
if (selectedInterval === 'off') {
|
||||
clearInterval(intervalHandler);
|
||||
console.log("Auto-refresh turned off.");
|
||||
} else {
|
||||
refreshInterval = parseInt(selectedInterval);
|
||||
startPolling(refreshInterval);
|
||||
console.log(`Refresh interval set to ${refreshInterval / 1000} seconds.`);
|
||||
}
|
||||
$('#selectedIntervalText').text(selectedInterval === 'off' ? 'Off' : `${selectedInterval / 1000}s`);
|
||||
});
|
||||
|
||||
loadPrinters();
|
||||
startPolling(refreshInterval); // Start polling immediately
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user