8 Commits

Author SHA1 Message Date
18c78e37a4 In progress: offline fuel record creation 2025-01-26 17:21:30 +01:00
ccbb0eac64 Added: Stats in dashboard
All checks were successful
Build and Deploy Zola Website / build_and_deploy (push) Successful in 12s
2025-01-05 21:24:55 +01:00
21c2f4598b Added: Create new refuel record
All checks were successful
Build and Deploy Zola Website / build_and_deploy (push) Successful in 13s
2025-01-05 19:05:30 +01:00
860a20d946 Added: Fuel record create - not complete yet
All checks were successful
Build and Deploy Zola Website / build_and_deploy (push) Successful in 12s
2025-01-03 17:10:08 +01:00
c5955010cb Edited: vehicle list styled
All checks were successful
Build and Deploy Zola Website / build_and_deploy (push) Successful in 13s
2025-01-03 16:16:15 +01:00
fc163431f8 Added: Gitea Workflow
All checks were successful
Build and Deploy Zola Website / build_and_deploy (push) Successful in 12s
2025-01-03 00:45:54 +01:00
15029970d6 Fix: wrong action url in vehicle create 2025-01-03 00:18:29 +01:00
e13edeccfc Edited: vehicle create route renamed from vehicle add 2025-01-02 02:02:14 +01:00
21 changed files with 601 additions and 76 deletions

View File

@@ -0,0 +1,36 @@
name: Build and Deploy Zola Website
on:
push:
branches:
- master
env:
HOST: ${{ secrets.SERVER_IP }}
SSH_USERNAME: ${{ secrets.USERNAME }}
SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_KEY }}
DEST_FOLDER: "/srv/www/cz/filiprojek/fuelstats"
jobs:
build_and_deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Deploy
run: |
apt update -y && apt-get install -y --no-install-recommends rsync
eval "$(ssh-agent -s)"
ssh-add - <<< "${SSH_PRIVATE_KEY}"
mkdir -p ~/.ssh/
ssh-keyscan -H ${HOST} >> ~/.ssh/known_hosts
rsync -r --delete-after ./* "${SSH_USERNAME}@${HOST}:${{ env.DEST_FOLDER }}"
- name: Copy environment.php
run: |
eval "$(ssh-agent -s)"
ssh-add - <<< "${SSH_PRIVATE_KEY}"
mkdir -p ~/.ssh/
ssh-keyscan -H ${HOST} >> ~/.ssh/known_hosts
ssh ${SSH_USERNAME}@${HOST} "cp /var/websrvenv/environment.php /srv/www/cz/filiprojek/fuelstats/config/environment.php"

17
TODO.md
View File

@@ -6,13 +6,10 @@
- [ ] edit user data - change password, mail...
## Core of the app
- [ ] header and navbar
- [ ] dashboard
- [x] css
- [ ] its just plain
- [ ] graphs
- [x] Habits list
- [ ] css
- [ ] Habits create
- [ ] validate cron input
- [ ] Habits track
- [ ] intro tutorial when no car exist or just dont show anything
- [ ] change/set default car
- [ ] specific car view - charts, fuel records
- [ ] remove/edit fuel record
- [ ] IndexDB
- [ ]

View File

@@ -4,9 +4,35 @@ class DashboardController extends Controller {
$vehicle = new Vehicle();
$vehicles = $vehicle->getVehiclesByUser($_SESSION['user']['id']);
$default_car = $vehicle->getDefaultVehicle($_SESSION['user']['id']);
$refuel = new Refuel();
$data = [
"date" => [],
"price" => [],
];
$raw_data = $refuel->latest_data($default_car['id'], 5);
foreach($raw_data as $one) {
array_push($data['date'], date('d. m.', strtotime($one['created_at'])));
array_push($data['price'], $one['price_per_liter']);
}
$latest_record = [
'name',
'liters',
'price_per_liter',
'total_price',
'created_at'
];
$latest_record = $refuel->latest_one($_SESSION['user']['id'])[0];
$this->view('dashboard/index', [
'title' => 'Dashboard',
'vehicles' => $vehicles,
'date_price_data' => $data,
'default_car' => $default_car,
'latest_record' => $latest_record,
]);
}

View File

@@ -0,0 +1,85 @@
<?php
class RefuelController extends Controller {
public function create() {
if($_SERVER['REQUEST_METHOD'] === 'GET'){
$vehicle = new Vehicle();
$vehicles = $vehicle->getVehiclesByUser($_SESSION['user']['id']);
$this->view('refuel/create', [
'title' => "New refuel record",
'vehicles' => $vehicles,
]);
return;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$vehicle_id = $_POST['vehicle'] ?? '';
$fuel_type = $_POST['fuel_type'] ?? '';
$liters = $_POST['liters'] ?? '';
$price_per_liter = $_POST['price_per_liter'] ?? '';
$total_price = $_POST['total_price'] ?? '';
$note = $_POST['note'] ?? '';
$validator = new Validator();
$validator->required('vehicle', $vehicle_id);
$validator->required('fuel_type', $fuel_type);
$validator->required('liters', $liters);
$validator->required('price_per_liter', $price_per_liter);
$validator->required('total_price', $total_price);
$validator->number('liters', $liters);
$validator->number('price_per_liter', $price_per_liter);
$validator->number('total_price', $total_price);
if (round($liters * $price_per_liter, 2) != $total_price) {
$validator->setErrors(["total_price" => "Price calculation is wrong"]);
}
if($note == "") $note = NULL;
if (!$validator->passes()) {
$vehicle = new Vehicle();
$vehicles = $vehicle->getVehiclesByUser($_SESSION['user']['id']);
$this->view('refuel/create', [
'error' => 'Please correct the errors below.',
'validationErrors' => $validator->errors() ?: [],
'vehicles' => $vehicles,
'title' => 'New refuel record',
]);
return;
}
$record = new Refuel();
$result = $record->create([
'user_id' => $_SESSION['user']['id'],
'vehicle_id' => $vehicle_id,
'fuel_type' => $fuel_type,
'note' => $note,
'liters' => $liters,
'price_per_liter' => $price_per_liter,
'total_price' => $total_price,
]);
if ($result === true) {
$this->redirect('/');
} else {
$vehicle = new Vehicle();
$vehicles = $vehicle->getVehiclesByUser($_SESSION['user']['id']);
$this->view('refuel/create', [
'title' => 'New refuel record',
'error' => $result,
'validationErrors' => [],
'vehicles' => $vehicles,
]);
}
return;
}
}
public function edit() {
// Edit refuel record (to be implemented later)
}
public function delete() {
// Delete refuel record (to be implemented later)
}
}

View File

@@ -22,7 +22,7 @@ class VehicleController extends Controller {
if($note == "") $note = NULL;
if (!$validator->passes()) {
$this->view('vehicle/create', [
$this->view('vehicles/create', [
'error' => 'Please correct the errors below.',
'validationErrors' => $validator->errors() ?: [],
]);

92
app/models/Refuel.php Normal file
View File

@@ -0,0 +1,92 @@
<?php
class Refuel {
private $db;
public function __construct() {
$this->db = Database::getInstance()->getConnection();
}
public function create($data) {
try{
$stmt = $this->db->prepare("
INSERT INTO refueling_records (user_id, vehicle_id, fuel_type, note, liters, price_per_liter, total_price, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, NOW())
");
$stmt->bind_param(
"iissddd",
$data['user_id'],
$data['vehicle_id'],
$data['fuel_type'],
$data['note'],
$data['liters'],
$data['price_per_liter'],
$data['total_price'],
);
if ($stmt->execute()) {
return true;
} else {
return "Error: " . $stmt->error;
}
} catch(mysqli_sql_exception $e) {
return $e->getMessage();
}
}
public function latest_data($vehicle_id, $record_count) {
try {
$stmt = $this->db->prepare("
SELECT `liters`, `price_per_liter`, `total_price`, `created_at`
FROM `refueling_records`
WHERE `vehicle_id` = ?
ORDER BY created_at DESC
LIMIT ?;
");
$stmt->bind_param("ii", $vehicle_id, $record_count);
if ($stmt->execute()) {
$result = $stmt->get_result();
$data = $result->fetch_all(MYSQLI_ASSOC);
$stmt->close();
return array_reverse($data);
} else {
return "Error: " . $stmt->error;
}
} catch (mysqli_sql_exception $e) {
return $e->getMessage();
}
}
public function latest_one($user_id, $record_count = 1) {
try {
$stmt = $this->db->prepare("
SELECT
`r`.`vehicle_id`,
`v`.`name` AS `vehicle_name`,
`r`.`liters`,
`r`.`price_per_liter`,
`r`.`total_price`,
`r`.`created_at`
FROM `refueling_records` AS `r`
JOIN `vehicles` AS `v` ON `r`.`vehicle_id` = `v`.`id`
WHERE `r`.`user_id` = ?
ORDER BY `r`.`created_at` DESC
LIMIT ?;
");
$stmt->bind_param("ii", $user_id, $record_count);
if ($stmt->execute()) {
$result = $stmt->get_result();
$data = $result->fetch_all(MYSQLI_ASSOC);
$stmt->close();
return array_reverse($data);
} else {
return "Error: " . $stmt->error;
}
} catch (mysqli_sql_exception $e) {
return $e->getMessage();
}
}
}

View File

@@ -33,9 +33,9 @@ class Vehicle {
}
}
public function getVehiclesByUser($userId) {
public function getVehiclesByUser($user_id) {
$stmt = $this->db->prepare("SELECT id, name, registration_plate, fuel_type, note, created_at FROM vehicles WHERE user_id = ?");
$stmt->bind_param("i", $userId);
$stmt->bind_param("i", $user_id);
$stmt->execute();
$result = $stmt->get_result();
@@ -46,4 +46,18 @@ class Vehicle {
return $vehicles;
}
public function getDefaultVehicle($user_id) {
$stmt = $this->db->prepare("
SELECT id, name, registration_plate, fuel_type, note, is_default
FROM vehicles
WHERE user_id = ? AND is_default = TRUE
LIMIT 1
");
$stmt->bind_param("i", $user_id);
$stmt->execute();
$result = $stmt->get_result();
return $result->fetch_assoc();
}
}

View File

@@ -3,45 +3,62 @@
<section class="dashboard">
<h1>Welcome, <?= htmlspecialchars($_SESSION['user']['username']) ?>!</h1>
<div>
<a href="/refuel/add" class="btn-green">Add new refuel record!</a>
<a href="/refuel/create" class="btn-green">Add new refuel record!</a>
<a href="/vehicles" class="btn-primary">List all vehicles</a>
<button class="btn-primary" id="btn-offline-add">Add new refuel record OFFLINE</button>
</div>
<div class="card-wrapper">
<section class="card upcoming">
<h2>Upcoming</h2>
<div class="habit">
<b>Habit Title</b>
<p>Frequency</p>
<p>Reward points</p>
<section class="card latest">
<h2>Latest fuel record</h2>
<hr>
<div>
<b>Car:</b>
<p><?= $data['latest_record']['vehicle_name'] ?></p>
<b>Liters:</b>
<p><?= $data['latest_record']['liters'] ?> liters</p>
<b>Price per liter:</b>
<p><?= $data['latest_record']['price_per_liter'] ?>,-/liter</p>
<b>Total price:</b>
<p><?= $data['latest_record']['total_price'] ?>,-</p>
</div>
</section>
<section class="card recent">
<h2>Recent</h2>
<div class="habit">
<b>Habit Title</b>
<p>Frequency</p>
<p>Reward points</p>
</div>
</section>
<section class="card missed">
<h2>Missed</h2>
<div class="habit">
<b>Habit Title</b>
<p>Frequency</p>
<p>Reward points</p>
</div>
<section class="card">
<h2>Default car</h2>
<hr>
<b>Car</b>
<p><?= $data['default_car']['name'] ?></p>
<b>Registration plate</b>
<p><?= $data['default_car']['registration_plate'] ?></p>
<b>Fuel type</b>
<p><?= $data['default_car']['fuel_type'] ?></p>
<b>Note</b>
<p><?= $data['default_car']['note'] ?></p>
</section>
<section class="card history-graph">
<h2>Graph of History</h2>
</section>
<section class="card streak">
<h2>Streak</h2>
<p>You're current streak is 123 days</p>
<p>Good job!</p>
<h2>Chart of Gas price</h2>
<hr>
<p><?= $data['default_car']['name'] . " | " . $data['default_car']['registration_plate']?></p>
<canvas id="chart-gas-price"></canvas>
</section>
</div>
</section>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
const ctx = document.getElementById('chart-gas-price');
const data = <?= json_encode($data['date_price_data']); ?>;
new Chart(ctx, {
type: 'line',
data: {
labels: [...data['date']],
datasets: [{
label: 'Gas price history',
data: data['price'],
borderWidth: 1,
}]
},
});
</script>
<script defer src="/js/offline-records.js"></script>

View File

@@ -6,7 +6,7 @@
<meta name="author" content="Filip Rojek | http://filiprojek.cz">
<meta name="email" content="webmaster(@)fofrweb.com">
<meta name="copyright" content="(c) filiprojek.cz">
<title>Fuel Stats | <?= $data['title'] ?></title>
<title>Fuel Stats<?= isset($data['title']) ? " | " . $data['title'] : "" ?></title>
<link rel="stylesheet" href="/css/main.css">
<link rel="stylesheet" href="/css/global.css">
<link rel="stylesheet" href="/css/vars.css">
@@ -17,7 +17,7 @@
<header>
<div id="hd-left">
<a href="/"><img src="/img/logo.jpg" alt="home"></a>
<label><?= $data['title'] ?></label>
<label><?= isset($data['title']) ? $data['title'] : "" ?></label>
</div>
<div id="hd-right">
<?php if (!isset($_SESSION['user'])): ?>

View File

@@ -6,7 +6,7 @@
<meta name="author" content="Filip Rojek | http://filiprojek.cz">
<meta name="email" content="webmaster(@)fofrweb.com">
<meta name="copyright" content="(c) filiprojek.cz">
<title>Fuel Stats | <?= $data['title'] ?></title>
<title>Fuel Stats<?= isset($data['title']) ? " | " . $data['title'] : "" ?></title>
<link rel="stylesheet" href="/css/main.css">
<link rel="stylesheet" href="/css/global.css">
<link rel="stylesheet" href="/css/vars.css">

119
app/views/refuel/create.php Normal file
View File

@@ -0,0 +1,119 @@
<link rel="stylesheet" href="/css/form.css">
<link rel="stylesheet" href="/css/vehicle_create.css">
<section class="form">
<h1 class="header-form"><?= $this->get('title') ?></h1>
<?php if ($this->get('error')): ?>
<div class="error" style="color: red; margin-bottom: 1rem;">
<?= htmlspecialchars($this->get('error')) ?>
</div>
<?php endif; ?>
<form method="POST" action="/refuel/create">
<label for="vehicle">Vehicle</label>
<select name="vehicle" id="vehicle">
<?php foreach ($this->get('vehicles') as $vehicle): ?>
<option value="<?= $vehicle['id'] ?>"><?= $vehicle['name'] . " | " . $vehicle['registration_plate'] ?></option>
<?php endforeach; ?>
</select>
<?php if (isset($this->get('validationErrors')['vehicle'])): ?>
<small class="error"><?= $this->get('validationErrors')['vehicle'] ?></small>
<?php endif; ?>
<label for="fuel_type">Fuel type</label>
<select name="fuel_type" id="fuel_type">
<option value="Diesel">Diesel</option>
<option value="Gasoline 95">Gasoline 95</option>
<option value="Gasoline 98">Gasoline 98</option>
<option value="Premium Diesel">Premium Diesel</option>
<option value="Premium Gasoline 95">Premium Gasoline 95</option>
<option value="Premium Gasoline 98">Premium Gasoline 98</option>
<option value="Other">Other</option>
</select>
<?php if (isset($this->get('validationErrors')['fuel_type'])): ?>
<small class="error"><?= $this->get('validationErrors')['fuel_type'] ?></small>
<?php endif; ?>
<label for="liters">Liters</label>
<input type="number" name="liters" id="liters" min="0" step=".01" value="<?= htmlspecialchars($_POST['liters'] ?? '0.0') ?>">
<?php if (isset($this->get('validationErrors')['liters'])): ?>
<small class="error"><?= $this->get('validationErrors')['liters'] ?></small>
<?php endif; ?>
<label for="price_per_liter">Price per liter</label>
<input type="number" name="price_per_liter" id="price_per_liter" min="0" step=".01" value="<?= htmlspecialchars($_POST['price_per_liter'] ?? '0.0') ?>">
<?php if (isset($this->get('validationErrors')['price_per_liter'])): ?>
<small class="error"><?= $this->get('validationErrors')['price_per_liter'] ?></small>
<?php endif; ?>
<label for="total_price">Total price</label>
<input type="number" name="total_price" id="total_price" min="0" step=".01" value="<?= htmlspecialchars($_POST['total_price'] ?? '0.0') ?>">
<?php if (isset($this->get('validationErrors')['total_price'])): ?>
<small class="error"><?= $this->get('validationErrors')['total_price'] ?></small>
<?php endif; ?>
<label for="note">Note</label>
<input type="text" name="note" id="note" value="<?= htmlspecialchars($_POST['note'] ?? '') ?>">
<?php if (isset($this->get('validationErrors')['note'])): ?>
<small class="error"><?= $this->get('validationErrors')['note'] ?></small>
<?php endif; ?>
<input type="submit" value="Create fuel record">
</form>
</section>
<script>
const inp_lit = document.querySelector("input#liters")
const inp_ppl = document.querySelector("input#price_per_liter")
const inp_tot = document.querySelector("input#total_price")
const rnd = (num) => Math.round((num + Number.EPSILON) * 100) / 100
function calculate(){
let liters = Number(inp_lit.value)
let price_per_liter = Number(inp_ppl.value)
let total_price = Number(inp_tot.value)
if(price_per_liter > 0 && liters > 0) {
total_price = rnd(liters * price_per_liter)
}
if(price_per_liter > 0 && total_price > 0) {
liters = rnd(total_price / price_per_liter)
}
if(liters > 0 && total_price > 0) {
price_per_liter = rnd(total_price / liters)
}
inp_lit.value = liters
inp_ppl.value = price_per_liter
inp_tot.value = total_price
}
[inp_lit, inp_ppl, inp_tot].forEach(inp => {
inp.addEventListener("change", () => {
calculate()
})
})
const vehicles = <?= json_encode($data['vehicles']); ?>;
const fuel_sel = document.querySelector("#fuel_type")
const vehic_sel = document.querySelector("#vehicle")
function selectFuel() {
const veh_id = vehic_sel.value
vehicles.forEach(el => {
if(el.id == veh_id) {
fuel_sel.value = el.fuel_type
return
}
})
}
selectFuel()
vehic_sel.addEventListener("change", () => {
selectFuel()
})
</script>

View File

@@ -9,7 +9,7 @@
</div>
<?php endif; ?>
<form method="POST" action="/vehicles/add">
<form method="POST" action="/vehicles/create">
<label for="name">Vehicle name</label>
<input type="text" name="name" id="name" required value="<?= htmlspecialchars($_POST['name'] ?? '') ?>">

View File

@@ -1,19 +1,24 @@
<link rel="stylesheet" href="/css/vehicles.css">
<section class="vehicles">
<?php if (empty($this->get('vehicles'))): ?>
<p>No vehicles yet. <a href="/vehicles/add">Add your first vehicle</a>.</p>
<p>No vehicles yet. <a href="/vehicles/create">Add your first vehicle</a>.</p>
<?php else: ?>
<div class="btn-wrapper">
<a href="/vehicles/create" class="btn-green">Add new vehicle!</a>
</div>
<div class="vehicle-wrapper">
<?php foreach ($this->get('vehicles') as $vehicle): ?>
<div class="vehicle bordered">
<b><?= htmlspecialchars($vehicle['name']) ?></b>
<a href="/vehicles/edit?id=<?= $vehicle['id'] ?>">Edit</a> |
<a href="/vehicles/delete?id=<?= $vehicle['id'] ?>" onclick="return confirm('Are you sure you want to delete this habit?')">Delete</a>
<p><?= htmlspecialchars($vehicle['registration_plate']) ?></p>
<p><?= htmlspecialchars($vehicle['fuel_type']) ?></p>
<p><?= htmlspecialchars($vehicle['note'] ?? "") ?></p>
<div class="actions">
<a href="/vehicles/edit?id=<?= $vehicle['id'] ?>">Edit</a>
<a href="/vehicles/delete?id=<?= $vehicle['id'] ?>" onclick="return confirm('Are you sure you want to delete this habit?')">Delete</a>
</div>
</div>
<?php endforeach; ?>
</div>
<br>
<a href="/vehicles/create" class="btn-green">Add new vehicle!</a>
<?php endif; ?>
</section>

View File

@@ -79,6 +79,7 @@ class Database {
registration_plate VARCHAR(50) NOT NULL UNIQUE,
fuel_type ENUM('Diesel', 'Gasoline 95', 'Gasoline 98', 'Premium Diesel', 'Premium Gasoline 95', 'Premium Gasoline 98', 'Other') NOT NULL,
note VARCHAR(150) NULL,
is_default BOOLEAN DEFAULT FALSE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB;
@@ -91,13 +92,16 @@ class Database {
$refuelingTableQuery = "
CREATE TABLE IF NOT EXISTS refueling_records (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
vehicle_id INT NOT NULL,
fuel_type ENUM('Diesel', 'Gasoline 95', 'Gasoline 98', 'Premium Diesel', 'Premium Gasoline 95', 'Premium Gasoline 98', 'Other') NOT NULL,
liters DECIMAL(10, 2) NOT NULL,
price_per_liter DECIMAL(10, 2) NOT NULL,
total_price DECIMAL(10, 2) NOT NULL,
note VARCHAR(150) NULL,
liters DOUBLE(10, 2) NOT NULL,
price_per_liter DOUBLE(10, 2) NOT NULL,
total_price DOUBLE(10, 2) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (vehicle_id) REFERENCES vehicles(id) ON DELETE CASCADE
FOREIGN KEY (vehicle_id) REFERENCES vehicles(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB;
";

View File

@@ -12,6 +12,15 @@ class Validator {
}
}
/**
* Check if a field contains numbers
*/
public function number($field, $value, $message = null) {
if(!is_numeric($value)) {
$this->errors[$field] = $message ?? "$field must be an number";
}
}
/**
* Check if a field meets minimum length
*/
@@ -46,6 +55,10 @@ class Validator {
return $this->errors;
}
public function setErrors($errors) {
$this->errors = $errors;
}
/**
* Check if validation passed
*/

View File

@@ -16,6 +16,6 @@
background-color: var(--clr-secondary);
border-radius: var(--border-radious);
border: var(--borderWidth-thin) solid var(--clr-border);
min-width: 17rem;
width: 18rem;
padding: 1rem;
}

View File

@@ -27,6 +27,7 @@ h1 {
cursor: pointer;
border-radius: var(--border-radious);
border: var(--borderWidth-thin) solid var(--clr-border);
color: white;
}
.btn-secondary {

View File

@@ -1,15 +0,0 @@
.habits-wrapper {
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: center;
}
.habits .bordered {
border-radius: var(--border-radious);
border: var(--borderWidth-thin) solid var(--clr-border);
width: 17rem;
padding: 1rem;
margin-top: 1rem;
text-align: center;
}

29
public/css/vehicles.css Normal file
View File

@@ -0,0 +1,29 @@
.vehicle-wrapper {
align-items: center;
display: flex;
flex-wrap: wrap;
gap: 1rem;
justify-content: center;
}
.vehicle {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: var(--clr-secondary);
border-radius: var(--border-radious);
border: var(--borderWidth-thin) solid var(--clr-border);
width: 17rem;
padding: 1rem;
margin-top: 1rem;
text-align: center;
min-height: 8rem;
}
.btn-wrapper {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 1rem;
}

View File

@@ -21,7 +21,7 @@ require_once '../core/middlewares/RequireAuth.php';
require_once models . 'User.php';
require_once models . 'Vehicle.php';
#require_once models . 'Refueling.php';
require_once models . 'Refuel.php';
// Initialize router
$router = new Router();
@@ -41,12 +41,16 @@ $router->group('/auth', [], function ($router) {
// dashboard route
$router->add('/dashboard', 'DashboardController@index', ['RequireAuth']);
// habits routes
// vehicle routes
$router->group('/vehicles', ['RequireAuth'], function ($router) {
$router->add('', 'VehicleController@index');
$router->add('/add', 'VehicleController@create');
$router->add('/create', 'VehicleController@create');
$router->add('/edit/{id}', 'VehicleController@edit');
$router->add('/delete/{id}', 'VehicleController@delete');
});
$router->group('/refuel', ['RequireAuth'], function ($router) {
$router->add('/create', 'RefuelController@create');
});
$router->dispatch();

View File

@@ -0,0 +1,98 @@
async function checkOnline() {
if (!navigator.onLine) {
console.log("Offline (no network connection)");
return false;
}
try {
const response = await fetch(
"https://www.google.com/favicon.ico?" + new Date().getTime(),
{
mode: "no-cors",
},
);
return true;
} catch (error) {
console.log("Connected to network but no internet access");
return false;
}
}
setInterval(async () => {
const isOnline = await checkOnline();
if (!isOnline) {
console.log("OFFLINE!!!");
}
}, 5000);
const offbtn = document.querySelector("#btn-offline-add");
offbtn.addEventListener("click", (e) => {
e.preventDefault();
document.querySelector("section.dashboard").style.display = "none";
const offline = document.createElement("div");
offline.classList.add("offline");
offline.innerHTML = `
<b>You're Offline</b>
<p>You can create an fuel record locally on your device and sync it later</p>
<section class="form">
<h1 class="header-form"><?= $this->get('title') ?></h1>
<!-- <?php if ($this->get('error')): ?> -->
<!-- <div class="error" style="color: red; margin-bottom: 1rem;"> -->
<!-- <?= htmlspecialchars($this->get('error')) ?> -->
<!-- </div> -->
<!-- <?php endif; ?> -->
<form method="POST" action="/refuel/create">
<label for="vehicle">Vehicle</label>
<select name="vehicle" id="vehicle">
<!-- <?php foreach ($this->get('vehicles') as $vehicle): ?> -->
<!-- <option value="<?= $vehicle['id'] ?>"><?= $vehicle['name'] . " | " . $vehicle['registration_plate'] ?></option> -->
<!-- <?php endforeach; ?> -->
</select>
<!-- <?php if (isset($this->get('validationErrors')['vehicle'])): ?> -->
<!-- <small class="error"><?= $this->get('validationErrors')['vehicle'] ?></small> -->
<!-- <?php endif; ?> -->
<label for="fuel_type">Fuel type</label>
<select name="fuel_type" id="fuel_type">
<option value="Diesel">Diesel</option>
<option value="Gasoline 95">Gasoline 95</option>
<option value="Gasoline 98">Gasoline 98</option>
<option value="Premium Diesel">Premium Diesel</option>
<option value="Premium Gasoline 95">Premium Gasoline 95</option>
<option value="Premium Gasoline 98">Premium Gasoline 98</option>
<option value="Other">Other</option>
</select>
<!-- <?php if (isset($this->get('validationErrors')['fuel_type'])): ?> -->
<!-- <small class="error"><?= $this->get('validationErrors')['fuel_type'] ?></small> -->
<!-- <?php endif; ?> -->
<label for="liters">Liters</label>
<input type="number" name="liters" id="liters" min="0" step=".01" value="<?= htmlspecialchars($_POST['liters'] ?? '0.0') ?>">
<!-- <?php if (isset($this->get('validationErrors')['liters'])): ?> -->
<!-- <small class="error"><?= $this->get('validationErrors')['liters'] ?></small> -->
<!-- <?php endif; ?> -->
<label for="price_per_liter">Price per liter</label>
<input type="number" name="price_per_liter" id="price_per_liter" min="0" step=".01" value="<?= htmlspecialchars($_POST['price_per_liter'] ?? '0.0') ?>">
<!-- <?php if (isset($this->get('validationErrors')['price_per_liter'])): ?> -->
<!-- <small class="error"><?= $this->get('validationErrors')['price_per_liter'] ?></small> -->
<!-- <?php endif; ?> -->
<label for="total_price">Total price</label>
<input type="number" name="total_price" id="total_price" min="0" step=".01" value="<?= htmlspecialchars($_POST['total_price'] ?? '0.0') ?>">
<!-- <?php if (isset($this->get('validationErrors')['total_price'])): ?> -->
<!-- <small class="error"><?= $this->get('validationErrors')['total_price'] ?></small> -->
<!-- <?php endif; ?> -->
<label for="note">Note</label>
<input type="text" name="note" id="note" value="<?= htmlspecialchars($_POST['note'] ?? '') ?>">
<!-- <?php if (isset($this->get('validationErrors')['note'])): ?> -->
<!-- <small class="error"><?= $this->get('validationErrors')['note'] ?></small> -->
<!-- <?php endif; ?> -->
<input type="submit" value="Create fuel record">
</form>
</section>
`;
document.querySelector("main").appendChild(offline);
});