I cba with this commit message tbh
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
checkUserRole(['admin']);
|
||||
?>
|
||||
|
||||
<html lang="en" data-bs-theme="light">
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
checkUserRole(['admin']);
|
||||
?>
|
||||
|
||||
<html lang="en" data-bs-theme="light">
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php include '../src/session_check.php'; ?>
|
||||
|
||||
<html lang="en" data-bs-theme="light">
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!doctype html>
|
||||
<html lang="en" data-bs-theme="light">
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
@@ -14,7 +14,10 @@
|
||||
<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>
|
||||
@@ -40,7 +43,7 @@
|
||||
</div>
|
||||
<form id="loginForm" class="row g-3">
|
||||
<div class="col-12">
|
||||
<label for="inputEmailAddress" class="form-label">Email</label>
|
||||
<label for="inputEmailAddress" class="form-label">Username</label>
|
||||
<input type="input" class="form-control" name="username" id="inputEmailAddress" required>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php include '../src/session_check.php'; ?>
|
||||
|
||||
<html lang="en" data-bs-theme="light">
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
|
||||
265
public/shipping.php
Normal file
265
public/shipping.php
Normal file
@@ -0,0 +1,265 @@
|
||||
<?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>
|
||||
319
public/userManagement.php
Normal file
319
public/userManagement.php
Normal file
@@ -0,0 +1,319 @@
|
||||
<?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,6 +1,6 @@
|
||||
<?php include '../src/session_check.php'; ?>
|
||||
|
||||
<html lang="en" data-bs-theme="light">
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
@@ -139,16 +139,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
`;
|
||||
}
|
||||
|
||||
// Debounce function to reduce DOM updates
|
||||
function debounceRender(func, delay) {
|
||||
let inDebounce;
|
||||
return function() {
|
||||
const context = this, args = arguments;
|
||||
clearTimeout(inDebounce);
|
||||
inDebounce = setTimeout(() => func.apply(context, args), delay);
|
||||
};
|
||||
}
|
||||
|
||||
fetch('../src/filamentTracker/getFilamentPrices.php')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
@@ -159,36 +149,56 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
const prices = data.data[filament].prices.map(entry => entry.price);
|
||||
const timestamps = data.data[filament].prices.map(entry => entry.recordedAt);
|
||||
const latestPrice = prices[prices.length - 1] || 0;
|
||||
const previousPrice = prices[prices.length - 2] || latestPrice;
|
||||
const priceDifference = latestPrice - previousPrice;
|
||||
|
||||
|
||||
// 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>`;
|
||||
<i class="bx bx-down-arrow-alt"></i> -£${Math.abs(priceDifference).toFixed(2)}</span>`;
|
||||
} else {
|
||||
priceChangeIndicator = `<span class="text-muted ms-4">
|
||||
<i class="bx bx-minus"></i> £0.00</span>`;
|
||||
}
|
||||
|
||||
const amazonUrl = data.data[filament].amazonUrl || '#';
|
||||
const discount = data.data[filament].currentDiscount || 0; // Get discount percentage
|
||||
const chartId = `chart-${filament.replace(/\s+/g, '-')}`;
|
||||
const chartColor = getRandomColor();
|
||||
|
||||
// Create Card HTML with cart button
|
||||
// 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>
|
||||
<a href="${amazonUrl}" target="_blank" class="mb-0 filament-name">${filament}</a>
|
||||
<h5 class="mb-0">
|
||||
£${latestPrice} ${priceChangeIndicator}
|
||||
</h5>
|
||||
</div>
|
||||
<div>
|
||||
${
|
||||
discount > 0
|
||||
? `<span class="text-success fw-bold" style="font-size: 1rem;">
|
||||
-${discount}%
|
||||
</span>`
|
||||
: ''
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div id="${chartId}"></div>
|
||||
</div>
|
||||
@@ -197,84 +207,38 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
container.insertAdjacentHTML('beforeend', cardHTML);
|
||||
|
||||
// Observer to Wait for DOM Insertion
|
||||
const observer = new MutationObserver(debounceRender(() => {
|
||||
const chartElement = document.getElementById(chartId);
|
||||
if (chartElement) {
|
||||
const chartOptions = {
|
||||
series: [{
|
||||
name: "Price",
|
||||
data: prices
|
||||
}],
|
||||
chart: {
|
||||
type: "area",
|
||||
height: 110,
|
||||
toolbar: {
|
||||
show: false
|
||||
},
|
||||
zoom: {
|
||||
enabled: false
|
||||
},
|
||||
dropShadow: {
|
||||
enabled: true,
|
||||
top: 3,
|
||||
left: 14,
|
||||
blur: 4,
|
||||
opacity: 0.12,
|
||||
color: chartColor
|
||||
},
|
||||
sparkline: {
|
||||
enabled: true
|
||||
}
|
||||
// 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()}`;
|
||||
},
|
||||
markers: {
|
||||
size: 0,
|
||||
colors: [chartColor],
|
||||
strokeColors: "#fff",
|
||||
strokeWidth: 2,
|
||||
hover: {
|
||||
size: 7
|
||||
}
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false
|
||||
},
|
||||
stroke: {
|
||||
show: true,
|
||||
width: 2.4,
|
||||
curve: "smooth"
|
||||
},
|
||||
colors: [chartColor],
|
||||
xaxis: {
|
||||
categories: timestamps,
|
||||
labels: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
fill: {
|
||||
opacity: 1
|
||||
},
|
||||
tooltip: {
|
||||
theme: "dark",
|
||||
x: {
|
||||
show: false
|
||||
},
|
||||
y: {
|
||||
formatter: function (value, { dataPointIndex }) {
|
||||
const date = new Date(timestamps[dataPointIndex]);
|
||||
return `£${value} - ${date.toLocaleDateString()}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const chart = new ApexCharts(chartElement, chartOptions);
|
||||
chart.render();
|
||||
observer.disconnect();
|
||||
}
|
||||
}, 300));
|
||||
|
||||
observer.observe(container, { childList: true, subtree: true });
|
||||
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>';
|
||||
@@ -288,6 +252,9 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php include '../src/session_check.php'; ?>
|
||||
|
||||
<html lang="en" data-bs-theme="light">
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
|
||||
Reference in New Issue
Block a user