erm did a small amount

output database to view
added basic filters
improve bootstrap theming and positioning
added pagination
This commit is contained in:
boris
2024-11-28 23:40:06 +00:00
parent 5c24228c20
commit 4005328979
36 changed files with 6746 additions and 8223 deletions

2
.~lock.Assessment Brief Form 2024-25.docx# Executable file → Normal file
View File

@@ -1 +1 @@
,boris,boris-ThinkPad-T480,07.11.2024 12:14,file:///home/boris/.config/libreoffice/4;
,boris,boris-ThinkPad-T480,28.11.2024 18:42,file:///home/boris/.config/libreoffice/4;

View File

@@ -1 +0,0 @@
,boris,boris-ThinkPad-T480,08.11.2024 12:14,file:///home/boris/.config/libreoffice/4;

View File

@@ -6,7 +6,7 @@
}
#menu {
border-top: solid 6px #000;
background-color: #fff
background-color: #fff;
color: #fff;
height: 400px;
}

View File

@@ -24,6 +24,8 @@ class Database {
private function __construct() {
try {
$this->_dbHandle = new PDO("sqlite:Databases/ecobuddy.sqlite");
$this->_dbHandle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->_dbHandle->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}
catch (PDOException $e) {
echo $e->getMessage();

View File

@@ -1,11 +1,12 @@
<?php
class FacilityData {
protected $_id, $_title, $_category, $_description, $_houseNumber, $_streetName, $_county, $_town, $_postcode, $_lng, $_lat;
protected $_id, $_title, $_category, $_status, $_description, $_houseNumber, $_streetName, $_county, $_town, $_postcode, $_lng, $_lat, $_contributor;
public function __construct($dbRow) {
$this->_id = $dbRow['_id'];
$this->_id = $dbRow['id'];
$this->_title = $dbRow['title'];
$this->_category = $dbRow['category'];
$this->_status = $dbRow['status'];
$this->_description = $dbRow['description'];
$this->_houseNumber = $dbRow['houseNumber'];
$this->_streetName = $dbRow['streetName'];
@@ -14,6 +15,7 @@ class FacilityData {
$this->_postcode = $dbRow['postcode'];
$this->_lng = $dbRow['lng'];
$this->_lat = $dbRow['lat'];
$this->_contributor = $dbRow['contributor'];
}
public function getId() {
@@ -25,6 +27,10 @@ class FacilityData {
public function getCategory() {
return $this->_category;
}
public function getStatus() {
return $this->_status;
}
public function getDescription() {
return $this->_description;
}
@@ -49,4 +55,7 @@ class FacilityData {
public function getLat() {
return $this->_lat;
}
public function getContributor() {
return $this->_contributor;
}
}

View File

@@ -10,21 +10,132 @@ class FacilityDataSet {
$this->_dbHandle = $this->_dbInstance->getDbConnection();
}
public function fetchAll(): array
/**
* @param $filterArray
* @param $rowCount
* @param $offset
* @return array
* Function to allow fetching of facility data. Data objects are created and held in an array
* Count of rows for pagination returned alongside data objects.
*/
public function fetchAll($filterArray, $rowCount, $offset): array
{
$sqlQuery = 'SELECT * FROM ecoFacilities;';
/**
* COUNT(DISTINCT ecoFacilities.id) required due to multiple status comments possible.
*/
$sqlCount = "SELECT COUNT(DISTINCT ecoFacilities.id) AS total FROM ecoFacilities";
$statement = $this->_dbHandle->prepare($sqlQuery); // prepare a PDO statement
$statement->execute(); // execute the PDO statemen
/**
* DISTINCT used again for prior reasoning, although data is handled properly regardless later.
* GROUP_CONCAT is used to handle multiple status comments under one facility. Without this, DISTINCT
* drops the additional comment.
*/
$sqlData = "SELECT DISTINCT ecoFacilities.id,
title,
GROUP_CONCAT(ecoFacilityStatus.statusComment, ', ') AS status,
ecoCategories.name AS category,
description,
houseNumber,
streetName,
county,
town,
postcode,
lng,
lat,
ecoUser.username AS contributor
FROM ecoFacilities";
/**
* ? Parameters used here over named parameters so logic can be modular, more
* columns can be added in the future
*/
$sqlWhere = "
LEFT JOIN ecoCategories ON ecoCategories.id = ecoFacilities.category
LEFT JOIN ecoUser ON ecoUser.id = ecoFacilities.contributor
LEFT JOIN ecoFacilityStatus ON ecoFacilityStatus.facilityid = ecoFacilities.id
WHERE (ecoFacilityStatus.statusComment LIKE ? OR ? IS NULL)
AND ecoFacilities.title LIKE ?
AND ecoCategories.name LIKE ?
AND ecoFacilities.description LIKE ?
AND ecoFacilities.streetName LIKE ?
AND ecoFacilities.county LIKE ?
AND ecoFacilities.town LIKE ?
AND ecoFacilities.postcode LIKE ?
AND ecoUser.username LIKE ?
";
/**
* GROUP BY required to ensure status comments are displayed under the same ID
* Named parameters used here for prior reasoning, columns can be added above without
* effecting the bindIndex.
*/
$sqlLimits = "
GROUP BY ecoFacilities.id
LIMIT :limit OFFSET :offset;";
$sqlLimits = "
GROUP BY ecoFacilities.id
;";
// Concatenate query snippets for data and row count
$dataQuery = $sqlData . $sqlWhere . $sqlLimits;
$countQuery = $sqlCount . $sqlWhere . ";";
// Prepare, bind and execute data query
$stmt = $this->populateFields($dataQuery, $rowCount, $offset, $filterArray);
$stmt->execute();
// Create data objects
$dataSet = [];
// loop through and read the results of the query and cast
// them into a matching object
while ($row = $statement->fetch()) {
while ($row = $stmt->fetch()) {
$dataSet[] = new FacilityData($row);
}
return $dataSet;
// Prepare, bind then execute count query
$stmt = $this->populateFields($countQuery, null, null, $filterArray);
$stmt->execute();
$totalCount = $stmt->fetch()['total'];
return [
'dataset' => $dataSet,
'count' => $totalCount
];
}
/**
* @param $sqlQuery
* @param $rowCount
* @param $offset
* @param $filterArray
* @return false|PDOStatement
* Function for fetchAll() to de-dupe code. Performs binding on PDO statements to facilitate
* filtering of facilities. Returns a bound PDO statement.
*/
private function populateFields($sqlQuery, $rowCount, $offset, $filterArray)
{
$stmt = $this->_dbHandle->prepare($sqlQuery);
// Ensures only one value is returned per column name
$stmt->setFetchMode(\PDO::FETCH_ASSOC);
// Initialize index for binding
$bindIndex = 1;
// Bind statusComment filter, required due to comments not being so.
$statusComment = !empty($filterArray[0]) ? "%" . $filterArray[0] . "%" : null;
$stmt->bindValue($bindIndex++, $statusComment ?? "%", \PDO::PARAM_STR); // First ?
$stmt->bindValue($bindIndex++, $statusComment, $statusComment === null ? \PDO::PARAM_NULL : \PDO::PARAM_STR); // Second ?
// Bind other filters
for ($i = 1; $i <= 8; $i++) { // Assuming 8 other filters
$value = !empty($filterArray[$i]) ? "%" . $filterArray[$i] . "%" : "%";
$stmt->bindValue($bindIndex++, $value, \PDO::PARAM_STR);
}
// Bind LIMIT and OFFSET
if (!$rowCount == null || !$offset == null) {
$stmt->bindValue(':limit', $rowCount, \PDO::PARAM_INT); // LIMIT ?
$stmt->bindValue(':offset', $offset, \PDO::PARAM_INT); // OFFSET ?
}
return $stmt;
}
}

View File

@@ -1 +1,84 @@
<?php
require_once('FacilityDataSet.php');
class Paginator {
protected $_pages, $_totalPages, $_rowLimit, $_offset, $_pageMatrix, $_rowCount;
public function __construct($rowLimit, $offset, $dataset) {
$this->_rowLimit = $rowLimit;
$this->_offset = $offset;
$this->_totalPages = $this->calculateTotalPages($dataset['count']);
$this->_rowCount = $dataset['count'];
$this->_pages = $dataset['dataset'];
$this->_pageMatrix = $this->Paginate();
}
private function calculateTotalPages(int $count): int {
return $count > 0 ? ceil($count / $this->_rowLimit) : 0;
}
public function Paginate(): array {
$pageMatrix = [];
for ($i = 0; $i < $this->_totalPages; $i++) {
$page = [];
$start = $i * $this->_rowLimit;
$end = min($start + $this->_rowLimit, $this->_rowCount); // Ensure within bounds
for ($j = $start; $j < $end; $j++) {
$page[] = $this->_pages[$j];
}
$pageMatrix[$i] = $page;
}
return $pageMatrix;
}
function getPageFromUri(): int {
// Retrieve 'page' parameter and default to 0 if missing or invalid
return filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT, [
'options' => ['default' => 0, 'min_range' => 0] // Default to 0 if invalid or missing
]);
}
public function setPageUri(int $page): void
{
$uri = $_SERVER['REQUEST_URI'];
$uriComp = parse_url($uri);
$params = [];
// Parse existing query parameters
if (isset($uriComp['query'])) {
parse_str($uriComp['query'], $params);
}
// Avoid unnecessary redirection if the page is already correct
if (isset($params['page']) && (int)$params['page'] === $page) {
return; // Do nothing if already on the correct page
}
// Update the 'page' parameter
$params['page'] = $page;
// Rebuild the query string
$newUri = http_build_query($params);
// Redirect to the updated URI
$path = $uriComp['path'] ?? '/'; // Use the current path or root
header("Location: $path?$newUri");
exit;
}
public function getPage(int $pageNumber): array {
if ($pageNumber < 0 || $pageNumber >= $this->_totalPages) {
return []; // Return an empty array if the page number is invalid
}
return $this->_pageMatrix[$pageNumber];
}
public function countPageResults(int $pageNumber): int {
if ($pageNumber < 0 || $pageNumber >= $this->_totalPages) {
return 0; // Return 0 if the page number is invalid
}
return count($this->_pageMatrix[$pageNumber]);
}
}

View File

@@ -2,7 +2,7 @@
require_once('UserDataSet.php');
class User {
protected $_username, $_loggedIn, $_userId;
protected $_username, $_loggedIn, $_userId, $_accessLevel;
public function getUsername() {
return $this->_username;
@@ -16,11 +16,13 @@ class User {
$this->_username = "None";
$this->_loggedIn = false;
$this->_userId = "0";
$this->_accessLevel = null;
if(isset($_SESSION['login'])) {
$this->_username = $_SESSION['login'];
$this->_userId = $_SESSION['uid'];
$this->_loggedIn = true;
$this->_accessLevel = $_SESSION['accessLevel'];
}
}
@@ -35,13 +37,22 @@ class User {
$this->_loggedIn = true;
}
}
private function setAccessLevel($level) {
$this->_accessLevel = $level;
$_SESSION['accessLevel'] = $level;
}
public function getAccessLevel() {
return $this->_accessLevel;
}
public function Authenticate($username, $password): bool
{
$users = new UserDataSet();
$userDataSet = $users->checkUserCredentials($username, $password);
$accessLevel = $users->checkAccessLevel($username);
if(count($userDataSet) > 0) {
$_SESSION['login'] = $username;
$_SESSION['uid'] = $userDataSet[0]->getId();
$this->setAccessLevel($accessLevel);
$this->_loggedIn = true;
$this->_username = $username;
$this->_userId = $userDataSet[0]->getId();

View File

@@ -3,11 +3,10 @@ class UserData {
protected $_id, $_username, $_name, $_password, $_usertype;
public function __construct($dbRow) {
$this->_id = $dbRow['_id'];
$this->_id = $dbRow['id'];
$this->_username = $dbRow['username'];
$this->_name = $dbRow['name'];
$this->_password = $dbRow['password'];
$this->_usertype = $dbRow['usertype'];
$this->_usertype = $dbRow['userType'];
}
public function getId() {
@@ -18,8 +17,4 @@ class UserData {
return $this->_username;
}
public function getName() {
return $this->_name;
}
}

View File

@@ -9,7 +9,15 @@ class UserDataSet {
$this->_dbInstance = Database::getInstance();
$this->_dbHandle = $this->_dbInstance->getDbConnection();
}
public function checkAccessLevel($username) {
$sqlQuery = "SELECT ecoUser.userType FROM ecoUser
LEFT JOIN ecoUsertypes ON ecoUser.userType = ecoUsertypes.userType
WHERE ecoUser.username = ?";
$statement = $this->_dbHandle->prepare($sqlQuery);
$statement->bindValue(1, $username);
$statement->execute();
return $statement->fetch(PDO::FETCH_ASSOC)['userType'];
}
public function fetchAll(): array
{
$sqlQuery = 'SELECT * FROM ecoUser;';

View File

@@ -1,32 +1,63 @@
<?php require('template/header.phtml') ?>
<div class="col-auto">
<?php require('template/pagination.phtml') ?>
</div>
<div class="row">
<div class="col-5">
<p><?php echo $view->dbMessage; ?></p>
</div>
<div class="col-7">
<div class="col-auto">
<p>Current script <?php echo $_SERVER["PHP_SELF"]; ?></p>
</div>
</div>
<div class="row">
<table class="table table-bordered">
<thead> <tr> <th>Facility ID</th> <th>Title</th> <th>Category</th> <th>Description</th> <th>Address</th> <th>Postcode</th> <th>Lat/Long</th> <th>Contributor</th> </tr>
</thead>
<tbody>
<?php foreach ($view->facilityDataSet as $facilityData) {
echo '<tr> <td>' . $facilityData->getId() .
'</td> <td>' . $facilityData->getTitle() .
'</td> <td>' . $facilityData->getCategory() .
'</td> <td>' . $facilityData->getDescription() .
'</td> <td>' . $facilityData->getHouseNumber() . " " . $facilityData->getStreetName() . " " . $facilityData->getCounty() . " " . $facilityData->getTown() .
'</td> <td>' . $facilityData->getPostcode() .
'</td> <td>' . $facilityData->getLatitude() . " " . $facilityData->getLongitude() .
'</td> <td>' . $facilityData->getContributor() .
'</td> </td> </tr>';
} ?>
</tbody>
</table>
<div class="container-fluid p-3">
<table class="table table-bordered">
<thead>
<tr>
<th>Facility ID</th>
<th>Title</th>
<th>Category</th>
<th>Status</th>
<th>Description</th>
<th>Address</th>
<th>Postcode</th>
<th>Lat/Long</th>
<th>Contributor</th>
<?php if($view->user->getAccessLevel() == 1): ?>
<th>Actions</th>
<?php endif; ?>
</tr>
</thead>
<tbody>
<?php foreach ($view->pageData as $facilityData): ?>
<tr>
<td><?= htmlspecialchars($facilityData->getId() ?? 'N/A') ?></td>
<td><?= htmlspecialchars($facilityData->getTitle() ?? 'N/A') ?></td>
<td><?= htmlspecialchars($facilityData->getCategory() ?? 'N/A') ?></td>
<td><?= htmlspecialchars($facilityData->getStatus() ?? 'N/A') ?></td>
<td><?= htmlspecialchars($facilityData->getDescription() ?? 'N/A') ?></td>
<td><?= htmlspecialchars(trim(($facilityData->getHouseNumber() ?? '') . ' ' .
($facilityData->getStreetName() ?? '') . ' ' .
($facilityData->getCounty() ?? '') . ' ' .
($facilityData->getTown() ?? ''))) ?></td>
<td><?= htmlspecialchars($facilityData->getPostcode() ?? 'N/A') ?></td>
<td><?= htmlspecialchars(($facilityData->getLat() ?? 'N/A') . ', ' .
($facilityData->getLng() ?? 'N/A')) ?></td>
<td><?= htmlspecialchars($facilityData->getContributor() ?? 'N/A') ?></td>
<?php if($view->user->getAccessLevel() == 1): ?>
<td class="btn-group">
<?php require("template/updateModal.phtml") ?>
<?php require("template/deleteModal.phtml") ?>
</td>
<?php endif; ?>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php require('template/footer.phtml') ?>

View File

@@ -0,0 +1,19 @@
<button type="button" class="col btn bg-danger btn-outline-danger text-light" data-bs-toggle="modal" data-bs-target="#deleteModal">
<span class="bi bi-trash-fill">
</button>
<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="deleteModalLabel">Delete Facility Record</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form method="post" action="<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>">
<button type="submit" class="btn bg-danger btn-outline-danger text-light" name="deleteButton">Yes</button>
<button type="button" class="btn btn-outline primary btn-primary" data-bs-dismiss="modal">No</button>
</form>
</div>
</div>
</div>
</div>

View File

@@ -1,16 +1,17 @@
</div>
<div class="row">
<div id="footer" class="col-xs-12">
<p>George Wilkinson @2024</p>
<p>Powered by Bootstrap</p>
<p class="m-0">George Wilkinson @2024</p>
<p class="m-0">Powered by Bootstrap</p>
</div>
</div>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<!-- script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script -->
<script src="/js/bootstrap.min.js"></script>
</body>
</html>

View File

@@ -13,6 +13,8 @@
<!-- Bootstrap theme -->
<link href="/css/bootstrap-theme.css" rel="stylesheet">
<link href="/css/my-style.css" rel="stylesheet">
<!-- Bootstrap Icons -->
<link href="/css/bootstrap-icons.css" rel="stylesheet">
<title>Ecobuddy - <?php echo $view->pageTitle; ?></title>
</head>
@@ -31,37 +33,60 @@
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link disabled" aria-disabled="true">Disabled</a>
</li>
</ul>
<form class="d-flex" role="search">
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn bg-light btn-outline-light text-dark" type="submit">Search</button>
<form class="row g-2 me-2 align-content-center align-content-center align-items-center" role="search" action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST">
<div class="col-md">
<div class="form-floating input-group">
<select name="filter" class="form-select" id="filter">
<option selected></option>
<option value="1">Title</option>
<option value="2">Category</option>
<option value="0">Status</option>
<option value="3">Description</option>
<option value="4">Street Name</option>
<option value="5">County</option>
<option value="6">Town</option>
<option value="7">Postcode</option>
<option value="8">Contributor</option>
</select>
<span class="input-group-text bi bi-filter-circle bg-success-subtle border-0 rounded-end" id="filter"></span>
<label for="filter">Column Filter</label>
</div>
</div>
<div class="col-md">
<div class="form-floating input-group">
<input class="form-control" id="search" type="search" name="applyFilters" aria-label="Search">
<span class="input-group-text bg-primary-subtle border-0 rounded-end" id="search">
<button class="btn bg-light bg-primary-subtle" type="submit"><span class="bi bi-search"></span></button>
</span>
<label for="search">Search</label>
</div>
</div>
</form>
<div class="row g-2 align-content-center align-content-center align-items-center">
<div class="col-sm" id="loginStatus">
<?php
<?php
if ($view->loginError) {
require_once('Views/template/loginError.phtml');
}
if(!$user->isLoggedIn()) {
require_once('Views/template/loginModal.phtml');
}
if($user->isLoggedIn()) {
require_once('Views/template/logoutButton.phtml');
}
?>
if ($view->loginError) {
require_once('Views/template/loginError.phtml');
}
if(!$view->user->isLoggedIn()) {
require_once('Views/template/loginModal.phtml');
}
if($view->user->isLoggedIn()) {
require_once('Views/template/logoutButton.phtml');
}
?>
</div>
</div>
</div>
</div>
</nav>
<body role="document">
<div class="container-lg">
<div id="content" >
<div class="container-fluid">
<?php /*require_once("sidebar.phtml");*/?>
<div class="col" id="content">

View File

@@ -1,4 +1,4 @@
<button type="button" class="btn bg-primary btn-outline-primary text-light m-1 ms-2" data-bs-toggle="modal" data-bs-target="#loginModal">
<button type="button" class="btn bg-primary btn-outline-primary text-light m-auto" data-bs-toggle="modal" data-bs-target="#loginModal">
Login
</button>
<div class="modal fade" id="loginModal" tabindex="-1" aria-labelledby="loginModalLabel" aria-hidden="true">
@@ -22,7 +22,7 @@
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-warning" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-warning btn-outline-warning text-light" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>

View File

@@ -1,4 +1,4 @@
<?php echo "<p class='nav-link m-2' style='color: black;'>" . $user->getUsername() . " is logged in.</p>"?>
<form class="form-inline my-2 my-lg-0" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?> ">
<input class="btn bg-danger btn-outline-danger text-light" type="submit" name="logoutButton" value="Logout">
<form class="form-floating" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?> ">
<?php echo "<p class='text-center bg-light border-0 rounded' style='color: black;'>" . $user->getUsername() . "<span class='bi bi-person-fill'></span></p>"?>
<button class="btn bg-danger btn-outline-danger text-light m-auto" type="submit" name="logoutButton">Logout</button>
</form>

View File

@@ -0,0 +1,25 @@
<form class="form-floating">
<div class="row mb-2">
<div class="col-2 me-auto ms-auto g-2 btn-group">
<button class="btn btn-outline-primary"><span class="bi bi-chevron-double-left"</button>
<button class="btn btn-outline-primary"><span class="bi bi-chevron-left"</button>
<button class="btn btn-outline-primary" disabled>...</button>
<button class="btn btn-outline-primary">1</button>
<button class="btn btn-outline-primary">2</button>
<button class="btn btn-outline-primary">3</button>
<button class="btn btn-outline-primary"><span class="bi bi-chevron-right"</button>
<button class="btn btn-outline-primary"><span class="bi bi-chevron-double-right"</button>
</div>
</div>
<div class="row">
<div class="col-1 me-auto ms-auto form-floating">
<select id="pagedown" class="form-select">
<option value="current" selected>1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
<label for="pagedown">Page</label>
</div>
</div>
</form>

View File

@@ -0,0 +1,34 @@
<div class="col-2" id="sidebar">
<div class="row mt-1 m-0 p-3 border rounded" id="loginStatus">
<?php
if ($view->loginError) {
require_once('Views/template/loginError.phtml');
}
if(!$user->isLoggedIn()) {
require_once('Views/template/loginModal.phtml');
}
if($user->isLoggedIn()) {
require_once('Views/template/logoutButton.phtml');
}
?>
</div>
<div class="row mt-1 m-4 p-3 border rounded" id="filters">
<h4 class="mb-4 text-center">Filter Options</h4>
<form class="form-inline my-2 my-lg-0" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?> ">
<!--<input class="btn bg-primary btn-outline-primary text-light" type="submit" name="addFilter" value="+">-->
<input name="0" class="form-control rounded mb-2" placeholder="Title">
<input name="1" class="form-control rounded mb-2" placeholder="Category">
<input name="2" class="form-control rounded mb-2" placeholder="Description">
<input name="3" class="form-control rounded mb-2" placeholder="Status">
<input name="4" class="form-control rounded mb-2" placeholder="Street Name">
<input name="5" class="form-control rounded mb-2" placeholder="County">
<input name="6" class="form-control rounded mb-2" placeholder="Town">
<input name="7" class="form-control rounded mb-2" placeholder="Postcode">
<input name="8" class="form-control rounded mb-2" placeholder="Contributor">
<button name="applyFilters" class="form-control rounded mb-2 mt-3 btn bg-primary border-primary">Update</button>
<button name="clearFilters" class="form-control rounded mb-2 btn bg-danger border-danger">Clear</button>
</form>
</div>
</div>

View File

@@ -0,0 +1,32 @@
<button type="button" class="col btn bg-primary btn-outline-primary text-light" data-bs-toggle="modal" data-bs-target="#updateModal">
<span class="bi bi-pen-fill"></span>
</button>
<div class="modal fade" id="updateModal" tabindex="-1" aria-labelledby="updateModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="updateModalLabel">Update Facility</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form method="post" action="<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>">
<form class="form-inline" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?> ">
<input name="titlUpdate" class="form-control rounded mb-2" placeholder="Title">
<input name="cateUpdate" class="form-control rounded mb-2" placeholder="Category">
<input name="descUpdate" class="form-control rounded mb-2" placeholder="Description">
<input name="statUpdate" class="form-control rounded mb-2" placeholder="Status">
<input name="strtUpdate" class="form-control rounded mb-2" placeholder="Street Name">
<input name="cntyUpdate" class="form-control rounded mb-2" placeholder="County">
<input name="townUpdate" class="form-control rounded mb-2" placeholder="Town">
<input name="postUpdate" class="form-control rounded mb-2" placeholder="Postcode">
<input name="contUpdate" class="form-control rounded mb-2" placeholder="Contributor">
</form>
<button type="submit" class="btn bg-primary btn-outline-primary text-light" name="updateButton">Update</button>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-warning" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>

View File

@@ -1,347 +0,0 @@
/*!
* Bootstrap v3.1.1 (http://getbootstrap.com)
* Copyright 2011-2014 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
.btn-default,
.btn-primary,
.btn-success,
.btn-info,
.btn-warning,
.btn-danger {
text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
}
.btn-default:active,
.btn-primary:active,
.btn-success:active,
.btn-info:active,
.btn-warning:active,
.btn-danger:active,
.btn-default.active,
.btn-primary.active,
.btn-success.active,
.btn-info.active,
.btn-warning.active,
.btn-danger.active {
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
}
.btn:active,
.btn.active {
background-image: none;
}
.btn-default {
text-shadow: 0 1px 0 #fff;
background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #dbdbdb;
border-color: #ccc;
}
.btn-default:hover,
.btn-default:focus {
background-color: #e0e0e0;
background-position: 0 -15px;
}
.btn-default:active,
.btn-default.active {
background-color: #e0e0e0;
border-color: #dbdbdb;
}
.btn-primary {
background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #2b669a;
}
.btn-primary:hover,
.btn-primary:focus {
background-color: #2d6ca2;
background-position: 0 -15px;
}
.btn-primary:active,
.btn-primary.active {
background-color: #2d6ca2;
border-color: #2b669a;
}
.btn-success {
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #3e8f3e;
}
.btn-success:hover,
.btn-success:focus {
background-color: #419641;
background-position: 0 -15px;
}
.btn-success:active,
.btn-success.active {
background-color: #419641;
border-color: #3e8f3e;
}
.btn-info {
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #28a4c9;
}
.btn-info:hover,
.btn-info:focus {
background-color: #2aabd2;
background-position: 0 -15px;
}
.btn-info:active,
.btn-info.active {
background-color: #2aabd2;
border-color: #28a4c9;
}
.btn-warning {
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #e38d13;
}
.btn-warning:hover,
.btn-warning:focus {
background-color: #eb9316;
background-position: 0 -15px;
}
.btn-warning:active,
.btn-warning.active {
background-color: #eb9316;
border-color: #e38d13;
}
.btn-danger {
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #b92c28;
}
.btn-danger:hover,
.btn-danger:focus {
background-color: #c12e2a;
background-position: 0 -15px;
}
.btn-danger:active,
.btn-danger.active {
background-color: #c12e2a;
border-color: #b92c28;
}
.thumbnail,
.img-thumbnail {
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
}
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
background-color: #e8e8e8;
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
background-repeat: repeat-x;
}
.dropdown-menu > .active > a,
.dropdown-menu > .active > a:hover,
.dropdown-menu > .active > a:focus {
background-color: #357ebd;
background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
background-repeat: repeat-x;
}
.navbar-default {
background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
}
.navbar-default .navbar-nav > .active > a {
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);
background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);
background-repeat: repeat-x;
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
}
.navbar-brand,
.navbar-nav > li > a {
text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
}
.navbar-inverse {
background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
}
.navbar-inverse .navbar-nav > .active > a {
background-image: -webkit-linear-gradient(top, #222 0%, #282828 100%);
background-image: linear-gradient(to bottom, #222 0%, #282828 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);
background-repeat: repeat-x;
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
}
.navbar-inverse .navbar-brand,
.navbar-inverse .navbar-nav > li > a {
text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
}
.navbar-static-top,
.navbar-fixed-top,
.navbar-fixed-bottom {
border-radius: 0;
}
.alert {
text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
}
.alert-success {
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
background-repeat: repeat-x;
border-color: #b2dba1;
}
.alert-info {
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
background-repeat: repeat-x;
border-color: #9acfea;
}
.alert-warning {
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
background-repeat: repeat-x;
border-color: #f5e79e;
}
.alert-danger {
background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
background-repeat: repeat-x;
border-color: #dca7a7;
}
.progress {
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar {
background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);
background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-success {
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-info {
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-warning {
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-danger {
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
background-repeat: repeat-x;
}
.list-group {
border-radius: 4px;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
}
.list-group-item.active,
.list-group-item.active:hover,
.list-group-item.active:focus {
text-shadow: 0 -1px 0 #3071a9;
background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);
background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);
background-repeat: repeat-x;
border-color: #3278b3;
}
.panel {
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
}
.panel-default > .panel-heading {
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
background-repeat: repeat-x;
}
.panel-primary > .panel-heading {
background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
background-repeat: repeat-x;
}
.panel-success > .panel-heading {
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
background-repeat: repeat-x;
}
.panel-info > .panel-heading {
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
background-repeat: repeat-x;
}
.panel-warning > .panel-heading {
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
background-repeat: repeat-x;
}
.panel-danger > .panel-heading {
background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
background-repeat: repeat-x;
}
.well {
background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
background-repeat: repeat-x;
border-color: #dcdcdc;
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
}
/*# sourceMappingURL=bootstrap-theme.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,38 +0,0 @@
#title {
margin-top: 12px;
background-color: #fff;
color: #000;
}
#menu {
border-top: solid 6px #000;
background-color: #fff;
color: #fff;
height: 400px;
}
#menu a {
background-color: #f00;
color: #fff;
text-decoration: none;
display: block;
}
#menu a:hover {
background-color: #f00;
color: #ddd;
text-decoration:underline;
display: block;
}
#content {
background-color: #fff;
border-top: solid 6px #f00;
}
#footer {
margin-top: 20px;
text-align: center;
background-color: #000;
color: #fff;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

2078
css/bootstrap-icons.css vendored Normal file

File diff suppressed because it is too large Load Diff

2052
css/bootstrap-icons.json Normal file

File diff suppressed because it is too large Load Diff

5
css/bootstrap-icons.min.css vendored Normal file

File diff suppressed because one or more lines are too long

2090
css/bootstrap-icons.scss vendored Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@@ -1,5 +1,6 @@
nav {
nav, #loginStatus, #filters {
background-color: #3cc471;
color: #111
}
#title {
margin-top: 12px;

View File

@@ -1,24 +1,79 @@
<?php
// load required classes
require_once('Models/UserDataSet.php');
require_once('Models/FacilityDataSet.php');
require_once("logincontroller.php");
// make a view class
$view = new stdClass();
$view->pageTitle = 'Home';
// include the view
require_once('Views/index.phtml');
// create a new student dataset object that we can generate data from
$facilityDataSet = new FacilityDataSet();
$view->facilityDataSet = $facilityDataSet->fetchAll();
$filterArray = [
'titlFilter' => "",
'cateFilter' => "",
'descFilter' => "",
'statFilter' => "",
'strtFilter' => "",
'cntyFilter' => "",
'townFilter' => "",
'postFilter' => "",
'contFilter' => ""
];
$filterArray = [
0 => "",
1 => "",
2 => "",
3 => "",
4 => "",
5 => "",
6 => "",
7 => "",
8 => ""
];
$values = [
"Title" => 0,
"Category" => 1,
"Description" => 2,
"Status" => 3,
"Street" => 4,
"County" => 5,
"Town" => 6,
"Postcode" => 7,
"Contributor" => 8,
];
$rowLimit = 7; //$_POST['rowCount'];
$offset = 0; //$_POST['offset'];
if (isset($_POST['applyFilters'])) {
//$filterNumeric = array_values($filterArray);
$filterArray[(int)$_POST['filter']] = $_POST['applyFilters'];
//$filterArray = array_combine(array_keys($filterArray), $filterNumeric);
}
if (isset($_POST['applyAdvFilters'])) {
array_push($filterArray, $_POST['titlFilter'], $_POST['cateFilter'],
$description = $_POST['descFilter'], $status = $_POST['statFilter'],
$street = $_POST['strtFilter'], $county = $_POST['cntyFilter'],
$town = $_POST['townFilter'], $postcode = $_POST['postFilter'],
$contributor = $_POST['contFilter']);
var_dump($filterArray);
}
//$view->facilityDataSet = $facilityDataSet->fetchAll($filterArray, $rowLimit, $offset);
require_once('Models/Paginator.php');
$view->paginator = new Paginator($rowLimit, $offset, $facilityDataSet->fetchAll($filterArray, null, null));
$view->pageNumber = $view->paginator->getPageFromUri();
$view->paginator->setPageUri($view->pageNumber);
$view->pageData = $view->paginator->getPage($view->pageNumber);
$view->user = new User();
// send a results count to the view to show how many results were retrieved
if (count($view->facilityDataSet) == 0)
if ($view->paginator->countPageResults($view->pageNumber) == 0)
{
$view->dbMessage = "No results";
}
else
{
$view->dbMessage = count($view->facilityDataSet) . " result(s)";
$view->dbMessage = $view->paginator->countPageResults($view->pageNumber) . " result(s)";
}
require_once('Views/index.phtml');