mirror of
https://github.com/grocy/grocy.git
synced 2025-04-29 01:32:38 +00:00
Added habit tracking
This commit is contained in:
parent
ebe92335a6
commit
1241261ca4
@ -88,7 +88,7 @@ class GrocyDbMigrator
|
|||||||
CREATE VIEW stock_current
|
CREATE VIEW stock_current
|
||||||
AS
|
AS
|
||||||
SELECT product_id, SUM(amount) AS amount, MIN(best_before_date) AS best_before_date
|
SELECT product_id, SUM(amount) AS amount, MIN(best_before_date) AS best_before_date
|
||||||
from stock
|
FROM stock
|
||||||
GROUP BY product_id
|
GROUP BY product_id
|
||||||
ORDER BY MIN(best_before_date) ASC;"
|
ORDER BY MIN(best_before_date) ASC;"
|
||||||
);
|
);
|
||||||
@ -102,6 +102,35 @@ class GrocyDbMigrator
|
|||||||
row_created_timestamp DATETIME DEFAULT (datetime('now', 'localtime'))
|
row_created_timestamp DATETIME DEFAULT (datetime('now', 'localtime'))
|
||||||
)"
|
)"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
self::ExecuteMigrationWhenNeeded($pdo, 10, "
|
||||||
|
CREATE TABLE habits (
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||||
|
name TEXT NOT NULL UNIQUE,
|
||||||
|
description TEXT,
|
||||||
|
period_type TEXT NOT NULL,
|
||||||
|
period_days INTEGER,
|
||||||
|
row_created_timestamp DATETIME DEFAULT (datetime('now', 'localtime'))
|
||||||
|
)"
|
||||||
|
);
|
||||||
|
|
||||||
|
self::ExecuteMigrationWhenNeeded($pdo, 11, "
|
||||||
|
CREATE TABLE habits_log (
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||||
|
habit_id INTEGER NOT NULL,
|
||||||
|
tracked_time DATETIME,
|
||||||
|
row_created_timestamp DATETIME DEFAULT (datetime('now', 'localtime'))
|
||||||
|
)"
|
||||||
|
);
|
||||||
|
|
||||||
|
self::ExecuteMigrationWhenNeeded($pdo, 12, "
|
||||||
|
CREATE VIEW habits_current
|
||||||
|
AS
|
||||||
|
SELECT habit_id, MAX(tracked_time) AS last_tracked_time
|
||||||
|
FROM habits_log
|
||||||
|
GROUP BY habit_id
|
||||||
|
ORDER BY MAX(tracked_time) DESC;"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function ExecuteMigrationWhenNeeded(PDO $pdo, int $migrationId, string $sql)
|
private static function ExecuteMigrationWhenNeeded(PDO $pdo, int $migrationId, string $sql)
|
||||||
|
@ -35,6 +35,9 @@ class GrocyDemoDataGenerator
|
|||||||
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Radieschen', 4, 6, 6, 1); --14
|
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Radieschen', 4, 6, 6, 1); --14
|
||||||
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Tomate', 4, 1, 1, 1); --15
|
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Tomate', 4, 1, 1, 1); --15
|
||||||
|
|
||||||
|
INSERT INTO habits (name, period_type, period_days) VALUES ('Changed towels in the bathroom', 'manually', 5); --1
|
||||||
|
INSERT INTO habits (name, period_type, period_days) VALUES ('Cleaned the kitchen floor', 'dynamic-regular', 7); --2
|
||||||
|
|
||||||
INSERT INTO migrations (migration) VALUES (-1);
|
INSERT INTO migrations (migration) VALUES (-1);
|
||||||
";
|
";
|
||||||
|
|
||||||
@ -54,6 +57,12 @@ class GrocyDemoDataGenerator
|
|||||||
GrocyLogicStock::AddProduct(14, 5, date('Y-m-d', strtotime('+2 days')), GrocyLogicStock::TRANSACTION_TYPE_PURCHASE);
|
GrocyLogicStock::AddProduct(14, 5, date('Y-m-d', strtotime('+2 days')), GrocyLogicStock::TRANSACTION_TYPE_PURCHASE);
|
||||||
GrocyLogicStock::AddProduct(15, 5, date('Y-m-d', strtotime('-2 days')), GrocyLogicStock::TRANSACTION_TYPE_PURCHASE);
|
GrocyLogicStock::AddProduct(15, 5, date('Y-m-d', strtotime('-2 days')), GrocyLogicStock::TRANSACTION_TYPE_PURCHASE);
|
||||||
GrocyLogicStock::AddMissingProductsToShoppingList();
|
GrocyLogicStock::AddMissingProductsToShoppingList();
|
||||||
|
|
||||||
|
GrocyLogicHabits::TrackHabit(1, date('Y-m-d H:i:s', strtotime('-5 days')));
|
||||||
|
GrocyLogicHabits::TrackHabit(1, date('Y-m-d H:i:s', strtotime('-10 days')));
|
||||||
|
GrocyLogicHabits::TrackHabit(1, date('Y-m-d H:i:s', strtotime('-15 days')));
|
||||||
|
GrocyLogicHabits::TrackHabit(2, date('Y-m-d H:i:s', strtotime('-10 days')));
|
||||||
|
GrocyLogicHabits::TrackHabit(2, date('Y-m-d H:i:s', strtotime('-20 days')));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
59
GrocyLogicHabits.php
Normal file
59
GrocyLogicHabits.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class GrocyLogicHabits
|
||||||
|
{
|
||||||
|
const HABIT_TYPE_MANUALLY = 'manually';
|
||||||
|
const HABIT_TYPE_DYNAMIC_REGULAR = 'dynamic-regular';
|
||||||
|
|
||||||
|
public static function GetCurrentHabits()
|
||||||
|
{
|
||||||
|
$sql = 'SELECT * from habits_current';
|
||||||
|
return Grocy::ExecuteDbQuery(Grocy::GetDbConnectionRaw(), $sql)->fetchAll(PDO::FETCH_OBJ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function GetNextHabitTime(int $habitId)
|
||||||
|
{
|
||||||
|
$db = Grocy::GetDbConnection();
|
||||||
|
|
||||||
|
$habit = $db->habits($habitId);
|
||||||
|
$habitLastLogRow = Grocy::ExecuteDbQuery(Grocy::GetDbConnectionRaw(), "SELECT * from habits_current WHERE habit_id = $habitId LIMIT 1")->fetch(PDO::FETCH_OBJ);
|
||||||
|
|
||||||
|
switch ($habit->period_type)
|
||||||
|
{
|
||||||
|
case self::HABIT_TYPE_MANUALLY:
|
||||||
|
return date('Y-m-d H:i:s');
|
||||||
|
case self::HABIT_TYPE_DYNAMIC_REGULAR:
|
||||||
|
return date('Y-m-d H:i:s', strtotime('+' . $habit->period_days . ' day', strtotime($habitLastLogRow->last_tracked_time)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function GetHabitDetails(int $habitId)
|
||||||
|
{
|
||||||
|
$db = Grocy::GetDbConnection();
|
||||||
|
|
||||||
|
$habit = $db->habits($habitId);
|
||||||
|
$habitTrackedCount = $db->habits_log()->where('habit_id', $habitId)->count();
|
||||||
|
$habitLastTrackedTime = $db->habits_log()->where('habit_id', $habitId)->max('tracked_time');
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'habit' => $habit,
|
||||||
|
'last_tracked' => $habitLastTrackedTime,
|
||||||
|
'tracked_count' => $habitTrackedCount
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function TrackHabit(int $habitId, string $trackedTime)
|
||||||
|
{
|
||||||
|
$db = Grocy::GetDbConnection();
|
||||||
|
|
||||||
|
$logRow = $db->habits_log()->createRow(array(
|
||||||
|
'habit_id' => $habitId,
|
||||||
|
'tracked_time' => $trackedTime
|
||||||
|
));
|
||||||
|
$logRow->save();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -57,4 +57,10 @@ class GrocyPhpHelper
|
|||||||
|
|
||||||
return $sum;
|
return $sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function GetClassConstants($className)
|
||||||
|
{
|
||||||
|
$r = new ReflectionClass($className);
|
||||||
|
return $r->getConstants();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
"datatables.net-responsive-bs": "2.1.1",
|
"datatables.net-responsive-bs": "2.1.1",
|
||||||
"jquery-timeago": "1.5.4",
|
"jquery-timeago": "1.5.4",
|
||||||
"toastr": "2.1.3",
|
"toastr": "2.1.3",
|
||||||
"tagmanager": "3.0.2"
|
"tagmanager": "3.0.2",
|
||||||
|
"eonasdan-bootstrap-datetimepicker": "4.17.47"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,14 +24,18 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="config-dist.php" />
|
<Compile Include="config-dist.php" />
|
||||||
<Compile Include="Grocy.php" />
|
<Compile Include="Grocy.php" />
|
||||||
|
<Compile Include="GrocyLogicHabits.php" />
|
||||||
<Compile Include="GrocyLogicStock.php" />
|
<Compile Include="GrocyLogicStock.php" />
|
||||||
<Compile Include="GrocyDemoDataGenerator.php" />
|
<Compile Include="GrocyDemoDataGenerator.php" />
|
||||||
<Compile Include="GrocyPhpHelper.php" />
|
<Compile Include="GrocyPhpHelper.php" />
|
||||||
<Compile Include="GrocyDbMigrator.php" />
|
<Compile Include="GrocyDbMigrator.php" />
|
||||||
<Compile Include="index.php" />
|
<Compile Include="index.php" />
|
||||||
|
<Compile Include="views\habittracking.php" />
|
||||||
<Compile Include="views\consume.php" />
|
<Compile Include="views\consume.php" />
|
||||||
<Compile Include="views\login.php" />
|
<Compile Include="views\login.php" />
|
||||||
<Compile Include="views\inventory.php" />
|
<Compile Include="views\inventory.php" />
|
||||||
|
<Compile Include="views\habits.php" />
|
||||||
|
<Compile Include="views\habitform.php" />
|
||||||
<Compile Include="views\shoppinglistform.php" />
|
<Compile Include="views\shoppinglistform.php" />
|
||||||
<Compile Include="views\shoppinglist.php" />
|
<Compile Include="views\shoppinglist.php" />
|
||||||
<Compile Include="views\purchase.php" />
|
<Compile Include="views\purchase.php" />
|
||||||
@ -41,7 +45,8 @@
|
|||||||
<Compile Include="views\locations.php" />
|
<Compile Include="views\locations.php" />
|
||||||
<Compile Include="views\quantityunits.php" />
|
<Compile Include="views\quantityunits.php" />
|
||||||
<Compile Include="views\products.php" />
|
<Compile Include="views\products.php" />
|
||||||
<Compile Include="views\dashboard.php" />
|
<Compile Include="views\habitsoverview.php" />
|
||||||
|
<Compile Include="views\stockoverview.php" />
|
||||||
<Compile Include="views\layout.php" />
|
<Compile Include="views\layout.php" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -58,10 +63,14 @@
|
|||||||
<Content Include="robots.txt" />
|
<Content Include="robots.txt" />
|
||||||
<Content Include="style.css" />
|
<Content Include="style.css" />
|
||||||
<Content Include="version.txt" />
|
<Content Include="version.txt" />
|
||||||
|
<Content Include="views\habittracking.js" />
|
||||||
<Content Include="views\consume.js" />
|
<Content Include="views\consume.js" />
|
||||||
<Content Include="views\dashboard.js" />
|
<Content Include="views\habitsoverview.js" />
|
||||||
|
<Content Include="views\stockoverview.js" />
|
||||||
<Content Include="views\inventory.js" />
|
<Content Include="views\inventory.js" />
|
||||||
<Content Include="views\login.js" />
|
<Content Include="views\login.js" />
|
||||||
|
<Content Include="views\habits.js" />
|
||||||
|
<Content Include="views\habitform.js" />
|
||||||
<Content Include="views\shoppinglistform.js" />
|
<Content Include="views\shoppinglistform.js" />
|
||||||
<Content Include="views\shoppinglist.js" />
|
<Content Include="views\shoppinglist.js" />
|
||||||
<Content Include="views\purchase.js" />
|
<Content Include="views\purchase.js" />
|
||||||
|
78
index.php
78
index.php
@ -10,6 +10,7 @@ require_once __DIR__ . '/Grocy.php';
|
|||||||
require_once __DIR__ . '/GrocyDbMigrator.php';
|
require_once __DIR__ . '/GrocyDbMigrator.php';
|
||||||
require_once __DIR__ . '/GrocyDemoDataGenerator.php';
|
require_once __DIR__ . '/GrocyDemoDataGenerator.php';
|
||||||
require_once __DIR__ . '/GrocyLogicStock.php';
|
require_once __DIR__ . '/GrocyLogicStock.php';
|
||||||
|
require_once __DIR__ . '/GrocyLogicHabits.php';
|
||||||
require_once __DIR__ . '/GrocyPhpHelper.php';
|
require_once __DIR__ . '/GrocyPhpHelper.php';
|
||||||
|
|
||||||
$app = new \Slim\App(new \Slim\Container([
|
$app = new \Slim\App(new \Slim\Container([
|
||||||
@ -86,9 +87,14 @@ $app->get('/', function(Request $request, Response $response) use($db)
|
|||||||
{
|
{
|
||||||
$db = Grocy::GetDbConnection(true); //For database schema migration
|
$db = Grocy::GetDbConnection(true); //For database schema migration
|
||||||
|
|
||||||
|
return $response->withRedirect('/stockoverview');
|
||||||
|
});
|
||||||
|
|
||||||
|
$app->get('/stockoverview', function(Request $request, Response $response) use($db)
|
||||||
|
{
|
||||||
return $this->renderer->render($response, '/layout.php', [
|
return $this->renderer->render($response, '/layout.php', [
|
||||||
'title' => 'Dashboard',
|
'title' => 'Stock overview',
|
||||||
'contentPage' => 'dashboard.php',
|
'contentPage' => 'stockoverview.php',
|
||||||
'products' => $db->products(),
|
'products' => $db->products(),
|
||||||
'quantityunits' => $db->quantity_units(),
|
'quantityunits' => $db->quantity_units(),
|
||||||
'currentStock' => GrocyLogicStock::GetCurrentStock(),
|
'currentStock' => GrocyLogicStock::GetCurrentStock(),
|
||||||
@ -96,6 +102,16 @@ $app->get('/', function(Request $request, Response $response) use($db)
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$app->get('/habitsoverview', function(Request $request, Response $response) use($db)
|
||||||
|
{
|
||||||
|
return $this->renderer->render($response, '/layout.php', [
|
||||||
|
'title' => 'Habits overview',
|
||||||
|
'contentPage' => 'habitsoverview.php',
|
||||||
|
'habits' => $db->habits(),
|
||||||
|
'currentHabits' => GrocyLogicHabits::GetCurrentHabits(),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
$app->get('/purchase', function(Request $request, Response $response) use($db)
|
$app->get('/purchase', function(Request $request, Response $response) use($db)
|
||||||
{
|
{
|
||||||
return $this->renderer->render($response, '/layout.php', [
|
return $this->renderer->render($response, '/layout.php', [
|
||||||
@ -135,6 +151,15 @@ $app->get('/shoppinglist', function(Request $request, Response $response) use($d
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$app->get('/habittracking', function(Request $request, Response $response) use($db)
|
||||||
|
{
|
||||||
|
return $this->renderer->render($response, '/layout.php', [
|
||||||
|
'title' => 'Habit tracking',
|
||||||
|
'contentPage' => 'habittracking.php',
|
||||||
|
'habits' => $db->habits()
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
$app->get('/products', function(Request $request, Response $response) use($db)
|
$app->get('/products', function(Request $request, Response $response) use($db)
|
||||||
{
|
{
|
||||||
return $this->renderer->render($response, '/layout.php', [
|
return $this->renderer->render($response, '/layout.php', [
|
||||||
@ -164,6 +189,16 @@ $app->get('/quantityunits', function(Request $request, Response $response) use($
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$app->get('/habits', function(Request $request, Response $response) use($db)
|
||||||
|
{
|
||||||
|
return $this->renderer->render($response, '/layout.php', [
|
||||||
|
'title' => 'Habits',
|
||||||
|
'contentPage' => 'habits.php',
|
||||||
|
'habits' => $db->habits()
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
$app->get('/product/{productId}', function(Request $request, Response $response, $args) use($db)
|
$app->get('/product/{productId}', function(Request $request, Response $response, $args) use($db)
|
||||||
{
|
{
|
||||||
if ($args['productId'] == 'new')
|
if ($args['productId'] == 'new')
|
||||||
@ -231,6 +266,29 @@ $app->get('/quantityunit/{quantityunitId}', function(Request $request, Response
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$app->get('/habit/{habitId}', function(Request $request, Response $response, $args) use($db)
|
||||||
|
{
|
||||||
|
if ($args['habitId'] == 'new')
|
||||||
|
{
|
||||||
|
return $this->renderer->render($response, '/layout.php', [
|
||||||
|
'title' => 'Create habit',
|
||||||
|
'contentPage' => 'habitform.php',
|
||||||
|
'periodTypes' => GrocyPhpHelper::GetClassConstants('GrocyLogicHabits'),
|
||||||
|
'mode' => 'create'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return $this->renderer->render($response, '/layout.php', [
|
||||||
|
'title' => 'Edit habit',
|
||||||
|
'contentPage' => 'habitform.php',
|
||||||
|
'habit' => $db->habits($args['habitId']),
|
||||||
|
'periodTypes' => GrocyPhpHelper::GetClassConstants('GrocyLogicHabits'),
|
||||||
|
'mode' => 'edit'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$app->get('/shoppinglistitem/{itemId}', function(Request $request, Response $response, $args) use($db)
|
$app->get('/shoppinglistitem/{itemId}', function(Request $request, Response $response, $args) use($db)
|
||||||
{
|
{
|
||||||
if ($args['itemId'] == 'new')
|
if ($args['itemId'] == 'new')
|
||||||
@ -350,6 +408,22 @@ $app->group('/api', function() use($db)
|
|||||||
GrocyLogicStock::AddMissingProductsToShoppingList();
|
GrocyLogicStock::AddMissingProductsToShoppingList();
|
||||||
echo json_encode(array('success' => true));
|
echo json_encode(array('success' => true));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$this->get('/habits/track-habit/{habitId}', function(Request $request, Response $response, $args)
|
||||||
|
{
|
||||||
|
$trackedTime = date('Y-m-d H:i:s');
|
||||||
|
if (isset($request->getQueryParams()['tracked_time']) && !empty($request->getQueryParams()['tracked_time']))
|
||||||
|
{
|
||||||
|
$trackedTime = $request->getQueryParams()['tracked_time'];
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode(array('success' => GrocyLogicHabits::TrackHabit($args['habitId'], $trackedTime)));
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->get('/habits/get-habit-details/{habitId}', function(Request $request, Response $response, $args)
|
||||||
|
{
|
||||||
|
echo json_encode(GrocyLogicHabits::GetHabitDetails($args['habitId']));
|
||||||
|
});
|
||||||
})->add(function($request, $response, $next)
|
})->add(function($request, $response, $next)
|
||||||
{
|
{
|
||||||
$response = $next($request, $response);
|
$response = $next($request, $response);
|
||||||
|
54
views/habitform.js
Normal file
54
views/habitform.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
$('#save-habit-button').on('click', function(e)
|
||||||
|
{
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (Grocy.EditMode === 'create')
|
||||||
|
{
|
||||||
|
Grocy.PostJson('/api/add-object/habits', $('#habit-form').serializeJSON(),
|
||||||
|
function(result)
|
||||||
|
{
|
||||||
|
window.location.href = '/habits';
|
||||||
|
},
|
||||||
|
function(xhr)
|
||||||
|
{
|
||||||
|
console.error(xhr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Grocy.PostJson('/api/edit-object/habits/' + Grocy.EditObjectId, $('#habit-form').serializeJSON(),
|
||||||
|
function(result)
|
||||||
|
{
|
||||||
|
window.location.href = '/habits';
|
||||||
|
},
|
||||||
|
function(xhr)
|
||||||
|
{
|
||||||
|
console.error(xhr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$(function()
|
||||||
|
{
|
||||||
|
$('#name').focus();
|
||||||
|
$('#habit-form').validator();
|
||||||
|
$('#habit-form').validator('validate');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.input-group-habit-period-type').on('change', function(e)
|
||||||
|
{
|
||||||
|
var periodType = $('#period_type').val();
|
||||||
|
var periodDays = $('#period_days').val();
|
||||||
|
|
||||||
|
if (periodType === 'dynamic-regular')
|
||||||
|
{
|
||||||
|
$('#habit-period-type-info').text('This means it is estimated that a new "execution" of this habit is tracked ' + periodDays.toString() + ' days after the last was tracked.');
|
||||||
|
$('#habit-period-type-info').show();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$('#habit-period-type-info').hide();
|
||||||
|
}
|
||||||
|
});
|
46
views/habitform.php
Normal file
46
views/habitform.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main">
|
||||||
|
|
||||||
|
<h1 class="page-header"><?php echo $title; ?></h1>
|
||||||
|
|
||||||
|
<script>Grocy.EditMode = '<?php echo $mode; ?>';</script>
|
||||||
|
|
||||||
|
<?php if ($mode == 'edit') : ?>
|
||||||
|
<script>Grocy.EditObjectId = <?php echo $habit->id; ?>;</script>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form id="habit-form">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name">Name</label>
|
||||||
|
<input type="text" class="form-control" required id="name" name="name" value="<?php if ($mode == 'edit') echo $habit->name; ?>" />
|
||||||
|
<div class="help-block with-errors"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="description">Description</label>
|
||||||
|
<textarea class="form-control" rows="2" id="description" name="description"><?php if ($mode == 'edit') echo $habit->description; ?></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="period_type">Location</label>
|
||||||
|
<select required class="form-control input-group-habit-period-type" id="period_type" name="period_type">
|
||||||
|
<?php foreach ($periodTypes as $periodType) : ?>
|
||||||
|
<option <?php if ($mode == 'edit' && $periodType == $habit->period_type) echo 'selected="selected"'; ?> value="<?php echo $periodType; ?>"><?php echo $periodType; ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<div class="help-block with-errors"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="period_days">Period days</label>
|
||||||
|
<input type="number" class="form-control input-group-habit-period-type" id="period_days" name="period_days" value="<?php if ($mode == 'edit') echo $habit->period_days; ?>" />
|
||||||
|
<div class="help-block with-errors"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p id="habit-period-type-info" class="help-block text-muted"></p>
|
||||||
|
|
||||||
|
<button id="save-habit-button" type="submit" class="btn btn-default">Save</button>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
43
views/habits.js
Normal file
43
views/habits.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
$(document).on('click', '.habit-delete-button', function(e)
|
||||||
|
{
|
||||||
|
bootbox.confirm({
|
||||||
|
message: 'Delete habit <strong>' + $(e.target).attr('data-habit-name') + '</strong>?',
|
||||||
|
buttons: {
|
||||||
|
confirm: {
|
||||||
|
label: 'Yes',
|
||||||
|
className: 'btn-success'
|
||||||
|
},
|
||||||
|
cancel: {
|
||||||
|
label: 'No',
|
||||||
|
className: 'btn-danger'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
callback: function(result)
|
||||||
|
{
|
||||||
|
if (result === true)
|
||||||
|
{
|
||||||
|
Grocy.FetchJson('/api/delete-object/habits/' + $(e.target).attr('data-habit-id'),
|
||||||
|
function(result)
|
||||||
|
{
|
||||||
|
window.location.href = '/habits';
|
||||||
|
},
|
||||||
|
function(xhr)
|
||||||
|
{
|
||||||
|
console.error(xhr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$(function()
|
||||||
|
{
|
||||||
|
$('#habits-table').DataTable({
|
||||||
|
'pageLength': 50,
|
||||||
|
'order': [[1, 'asc']],
|
||||||
|
'columnDefs': [
|
||||||
|
{ 'orderable': false, 'targets': 0 }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
});
|
50
views/habits.php
Normal file
50
views/habits.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
|
||||||
|
|
||||||
|
<h1 class="page-header">
|
||||||
|
Habits
|
||||||
|
<a class="btn btn-default" href="/habit/new" role="button">
|
||||||
|
<i class="fa fa-plus"></i> Add
|
||||||
|
</a>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table id="habits-table" class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>#</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Period type</th>
|
||||||
|
<th>Period days</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($habits as $habit) : ?>
|
||||||
|
<tr>
|
||||||
|
<td class="fit-content">
|
||||||
|
<a class="btn btn-info" href="/habit/<?php echo $habit->id; ?>" role="button">
|
||||||
|
<i class="fa fa-pencil"></i>
|
||||||
|
</a>
|
||||||
|
<a class="btn btn-danger habit-delete-button" href="#" role="button" data-habit-id="<?php echo $habit->id; ?>" data-habit-name="<?php echo $habit->name; ?>">
|
||||||
|
<i class="fa fa-trash"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<?php echo $habit->name; ?>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<?php echo $habit->period_type; ?>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<?php echo $habit->period_days; ?>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<?php echo $habit->description; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
7
views/habitsoverview.js
Normal file
7
views/habitsoverview.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
$(function()
|
||||||
|
{
|
||||||
|
$('#habits-overview-table').DataTable({
|
||||||
|
'pageLength': 50,
|
||||||
|
'order': [[1, 'desc']]
|
||||||
|
});
|
||||||
|
});
|
38
views/habitsoverview.php
Normal file
38
views/habitsoverview.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
|
||||||
|
|
||||||
|
<h1 class="page-header">Habits overview</h1>
|
||||||
|
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table id="habits-overview-table" class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Habit</th>
|
||||||
|
<th>Next estimated tracking</th>
|
||||||
|
<th>Last tracked</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($currentHabits as $curentHabitEntry) : ?>
|
||||||
|
<tr class="<?php if (GrocyPhpHelper::FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->period_type === GrocyLogicHabits::HABIT_TYPE_DYNAMIC_REGULAR && GrocyLogicHabits::GetNextHabitTime($curentHabitEntry->habit_id) < date('Y-m-d H:i:s')) echo 'error-bg'; ?>">
|
||||||
|
<td>
|
||||||
|
<?php echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->name; ?>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<?php if (GrocyPhpHelper::FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->period_type === GrocyLogicHabits::HABIT_TYPE_DYNAMIC_REGULAR): ?>
|
||||||
|
<?php echo GrocyLogicHabits::GetNextHabitTime($curentHabitEntry->habit_id); ?>
|
||||||
|
<time class="timeago timeago-contextual" datetime="<?php echo GrocyLogicHabits::GetNextHabitTime($curentHabitEntry->habit_id); ?>"></time>
|
||||||
|
<?php else: ?>
|
||||||
|
Whenever you want...
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<?php echo $curentHabitEntry->last_tracked_time; ?>
|
||||||
|
<time class="timeago timeago-contextual" datetime="<?php echo $curentHabitEntry->last_tracked_time; ?>"></time>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
165
views/habittracking.js
Normal file
165
views/habittracking.js
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
$('#save-habittracking-button').on('click', function(e)
|
||||||
|
{
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var jsonForm = $('#habittracking-form').serializeJSON();
|
||||||
|
|
||||||
|
Grocy.FetchJson('/api/habits/get-habit-details/' + jsonForm.habit_id,
|
||||||
|
function (habitDetails)
|
||||||
|
{
|
||||||
|
Grocy.FetchJson('/api/habits/track-habit/' + jsonForm.habit_id + '?tracked_time=' + $('#tracked_time').val(),
|
||||||
|
function(result)
|
||||||
|
{
|
||||||
|
toastr.success('Tracked execution of habit ' + habitDetails.habit.name + ' on ' + $('#tracked_time').val());
|
||||||
|
|
||||||
|
$('#habit_id').val('');
|
||||||
|
$('#habit_id_text_input').focus();
|
||||||
|
$('#habit_id_text_input').val('');
|
||||||
|
$('#tracked_time').val(moment().format('YYYY-MM-DD HH:mm:ss'));
|
||||||
|
$('#tracked_time').trigger('change');
|
||||||
|
$('#habit_id_text_input').trigger('change');
|
||||||
|
$('#habittracking-form').validator('validate');
|
||||||
|
},
|
||||||
|
function(xhr)
|
||||||
|
{
|
||||||
|
console.error(xhr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
function(xhr)
|
||||||
|
{
|
||||||
|
console.error(xhr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#habit_id').on('change', function(e)
|
||||||
|
{
|
||||||
|
var habitId = $(e.target).val();
|
||||||
|
|
||||||
|
if (habitId)
|
||||||
|
{
|
||||||
|
Grocy.FetchJson('/api/habits/get-habit-details/' + habitId,
|
||||||
|
function(habitDetails)
|
||||||
|
{
|
||||||
|
$('#selected-habit-name').text(habitDetails.habit.name);
|
||||||
|
$('#selected-habit-last-tracked').text((habitDetails.last_tracked || 'never'));
|
||||||
|
$('#selected-habit-last-tracked-timeago').text($.timeago(habitDetails.last_tracked || ''));
|
||||||
|
$('#selected-habit-tracked-count').text((habitDetails.tracked_count || '0'));
|
||||||
|
|
||||||
|
Grocy.EmptyElementWhenMatches('#selected-habit-last-tracked-timeago', 'NaN years ago');
|
||||||
|
},
|
||||||
|
function(xhr)
|
||||||
|
{
|
||||||
|
console.error(xhr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$(function()
|
||||||
|
{
|
||||||
|
$('.datetimepicker').datetimepicker(
|
||||||
|
{
|
||||||
|
format: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
showTodayButton: true,
|
||||||
|
calendarWeeks: true,
|
||||||
|
maxDate: moment()
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#tracked_time').val(moment().format('YYYY-MM-DD HH:mm:ss'));
|
||||||
|
$('#tracked_time').trigger('change');
|
||||||
|
|
||||||
|
$('#tracked_time').on('focus', function(e)
|
||||||
|
{
|
||||||
|
if ($('#habit_id_text_input').val().length === 0)
|
||||||
|
{
|
||||||
|
$('#habit_id_text_input').focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.combobox').combobox({
|
||||||
|
appendId: '_text_input'
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#habit_id').val('');
|
||||||
|
$('#habit_id_text_input').focus();
|
||||||
|
$('#habit_id_text_input').val('');
|
||||||
|
$('#habit_id_text_input').trigger('change');
|
||||||
|
|
||||||
|
$('#habittracking-form').validator();
|
||||||
|
$('#habittracking-form').validator('validate');
|
||||||
|
|
||||||
|
$('#habittracking-form input').keydown(function(event)
|
||||||
|
{
|
||||||
|
if (event.keyCode === 13) //Enter
|
||||||
|
{
|
||||||
|
if ($('#habittracking-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
|
||||||
|
{
|
||||||
|
event.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#tracked_time').on('change', function(e)
|
||||||
|
{
|
||||||
|
var value = $('#tracked_time').val();
|
||||||
|
var now = new Date();
|
||||||
|
var centuryStart = Number.parseInt(now.getFullYear().toString().substring(0, 2) + '00');
|
||||||
|
var centuryEnd = Number.parseInt(now.getFullYear().toString().substring(0, 2) + '99');
|
||||||
|
|
||||||
|
if (value === 'x' || value === 'X') {
|
||||||
|
value = '29991231';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.length === 4 && !(Number.parseInt(value) > centuryStart && Number.parseInt(value) < centuryEnd))
|
||||||
|
{
|
||||||
|
value = (new Date()).getFullYear().toString() + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.length === 8 && $.isNumeric(value))
|
||||||
|
{
|
||||||
|
value = value.replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3');
|
||||||
|
$('#tracked_time').val(value);
|
||||||
|
$('#habittracking-form').validator('validate');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#tracked_time').on('keypress', function(e)
|
||||||
|
{
|
||||||
|
var element = $(e.target);
|
||||||
|
var value = element.val();
|
||||||
|
var dateObj = moment(element.val(), 'YYYY-MM-DD', true);
|
||||||
|
|
||||||
|
$('.datepicker').datepicker('hide');
|
||||||
|
|
||||||
|
//If input is empty and any arrow key is pressed, set date to today
|
||||||
|
if (value.length === 0 && (e.keyCode === 38 || e.keyCode === 40 || e.keyCode === 37 || e.keyCode === 39))
|
||||||
|
{
|
||||||
|
dateObj = moment(new Date(), 'YYYY-MM-DD', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dateObj.isValid())
|
||||||
|
{
|
||||||
|
if (e.keyCode === 38) //Up
|
||||||
|
{
|
||||||
|
element.val(dateObj.add(-1, 'days').format('YYYY-MM-DD'));
|
||||||
|
}
|
||||||
|
else if (e.keyCode === 40) //Down
|
||||||
|
{
|
||||||
|
element.val(dateObj.add(1, 'days').format('YYYY-MM-DD'));
|
||||||
|
}
|
||||||
|
else if (e.keyCode === 37) //Left
|
||||||
|
{
|
||||||
|
element.val(dateObj.add(-1, 'weeks').format('YYYY-MM-DD'));
|
||||||
|
}
|
||||||
|
else if (e.keyCode === 39) //Right
|
||||||
|
{
|
||||||
|
element.val(dateObj.add(1, 'weeks').format('YYYY-MM-DD'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#habittracking-form').validator('validate');
|
||||||
|
});
|
42
views/habittracking.php
Normal file
42
views/habittracking.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2 main">
|
||||||
|
|
||||||
|
<h1 class="page-header">Habit tracking</h1>
|
||||||
|
|
||||||
|
<form id="habittracking-form">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="habit_id">Habit</label>
|
||||||
|
<select class="form-control combobox" id="habit_id" name="habit_id" required>
|
||||||
|
<option value=""></option>
|
||||||
|
<?php foreach ($habits as $habit) : ?>
|
||||||
|
<option value="<?php echo $habit->id; ?>"><?php echo $habit->name; ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<div id="product-error" class="help-block with-errors"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="tracked_time">Tracked time</label>
|
||||||
|
<div class="input-group date datetimepicker">
|
||||||
|
<input type="text" class="form-control" id="tracked_time" name="tracked_time" required >
|
||||||
|
<span class="input-group-addon">
|
||||||
|
<span class="fa fa-calendar"></span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="help-block with-errors"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button id="save-habittracking-button" type="submit" class="btn btn-default">OK</button>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-6 col-md-5 col-lg-3 main well">
|
||||||
|
<h3>Habit overview <strong><span id="selected-habit-name"></span></strong></h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<strong>Tracked count:</strong> <span id="selected-habit-tracked-count"></span><br />
|
||||||
|
<strong>Last tracked:</strong> <span id="selected-habit-last-tracked"></span> <time id="selected-habit-last-tracked-timeago" class="timeago timeago-contextual"></time><br />
|
||||||
|
</p>
|
||||||
|
</div>
|
@ -20,6 +20,7 @@
|
|||||||
<link href="/bower_components/datatables.net-responsive-bs/css/responsive.bootstrap.min.css?v=<?php echo Grocy::GetInstalledVersion(); ?>" rel="stylesheet" />
|
<link href="/bower_components/datatables.net-responsive-bs/css/responsive.bootstrap.min.css?v=<?php echo Grocy::GetInstalledVersion(); ?>" rel="stylesheet" />
|
||||||
<link href="/bower_components/toastr/toastr.min.css?v=<?php echo Grocy::GetInstalledVersion(); ?>" rel="stylesheet" />
|
<link href="/bower_components/toastr/toastr.min.css?v=<?php echo Grocy::GetInstalledVersion(); ?>" rel="stylesheet" />
|
||||||
<link href="/bower_components/tagmanager/tagmanager.css?v=<?php echo Grocy::GetInstalledVersion(); ?>" rel="stylesheet" />
|
<link href="/bower_components/tagmanager/tagmanager.css?v=<?php echo Grocy::GetInstalledVersion(); ?>" rel="stylesheet" />
|
||||||
|
<link href="/bower_components/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css?v=<?php echo Grocy::GetInstalledVersion(); ?>" rel="stylesheet" />
|
||||||
<link href="/style.css?v=<?php echo Grocy::GetInstalledVersion(); ?>" rel="stylesheet" />
|
<link href="/style.css?v=<?php echo Grocy::GetInstalledVersion(); ?>" rel="stylesheet" />
|
||||||
|
|
||||||
<script src="/bower_components/jquery/dist/jquery.min.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
|
<script src="/bower_components/jquery/dist/jquery.min.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
|
||||||
@ -49,9 +50,15 @@
|
|||||||
<div id="navbar-mobile" class="navbar-collapse collapse">
|
<div id="navbar-mobile" class="navbar-collapse collapse">
|
||||||
|
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
<li data-nav-for-page="dashboard.php">
|
<li data-nav-for-page="stockoverview.php">
|
||||||
<a class="discrete-link" href="/"><i class="fa fa-tachometer fa-fw"></i> Dashboard</a>
|
<a class="discrete-link" href="/stockoverview"><i class="fa fa-tachometer fa-fw"></i> Stock overview</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li data-nav-for-page="habitsoverview.php">
|
||||||
|
<a class="discrete-link" href="/habitsoverview"><i class="fa fa-tachometer fa-fw"></i> Habits overview</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="nav navbar-nav navbar-right">
|
||||||
<li data-nav-for-page="purchase.php">
|
<li data-nav-for-page="purchase.php">
|
||||||
<a class="discrete-link" href="/purchase"><i class="fa fa-shopping-cart fa-fw"></i> Purchase</a>
|
<a class="discrete-link" href="/purchase"><i class="fa fa-shopping-cart fa-fw"></i> Purchase</a>
|
||||||
</li>
|
</li>
|
||||||
@ -64,6 +71,9 @@
|
|||||||
<li data-nav-for-page="shoppinglist.php">
|
<li data-nav-for-page="shoppinglist.php">
|
||||||
<a class="discrete-link" href="/shoppinglist"><i class="fa fa-shopping-bag fa-fw"></i> Shopping list</a>
|
<a class="discrete-link" href="/shoppinglist"><i class="fa fa-shopping-bag fa-fw"></i> Shopping list</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li data-nav-for-page="habittracking.php">
|
||||||
|
<a class="discrete-link" href="/habittracking"><i class="fa fa-play fa-fw"></i> Habit tracking</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
@ -77,6 +87,9 @@
|
|||||||
<li data-nav-for-page="quantityunits.php">
|
<li data-nav-for-page="quantityunits.php">
|
||||||
<a class="discrete-link" href="/quantityunits"><i class="fa fa-balance-scale fa-fw"></i> Quantity units</a>
|
<a class="discrete-link" href="/quantityunits"><i class="fa fa-balance-scale fa-fw"></i> Quantity units</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li data-nav-for-page="habits.php">
|
||||||
|
<a class="discrete-link" href="/habits"><i class="fa fa-refresh fa-fw"></i> Habits</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
@ -95,9 +108,15 @@
|
|||||||
<div class="col-sm-3 col-md-2 sidebar">
|
<div class="col-sm-3 col-md-2 sidebar">
|
||||||
|
|
||||||
<ul class="nav nav-sidebar">
|
<ul class="nav nav-sidebar">
|
||||||
<li data-nav-for-page="dashboard.php">
|
<li data-nav-for-page="stockoverview.php">
|
||||||
<a class="discrete-link" href="/"><i class="fa fa-tachometer fa-fw"></i> Dashboard</a>
|
<a class="discrete-link" href="/stockoverview"><i class="fa fa-tachometer fa-fw"></i> Stock overview</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li data-nav-for-page="habitsoverview.php">
|
||||||
|
<a class="discrete-link" href="/habitsoverview"><i class="fa fa-tachometer fa-fw"></i> Habits overview</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="nav nav-sidebar">
|
||||||
<li data-nav-for-page="purchase.php">
|
<li data-nav-for-page="purchase.php">
|
||||||
<a class="discrete-link" href="/purchase"><i class="fa fa-shopping-cart fa-fw"></i> Purchase</a>
|
<a class="discrete-link" href="/purchase"><i class="fa fa-shopping-cart fa-fw"></i> Purchase</a>
|
||||||
</li>
|
</li>
|
||||||
@ -110,6 +129,9 @@
|
|||||||
<li data-nav-for-page="shoppinglist.php">
|
<li data-nav-for-page="shoppinglist.php">
|
||||||
<a class="discrete-link" href="/shoppinglist"><i class="fa fa-shopping-bag fa-fw"></i> Shopping list</a>
|
<a class="discrete-link" href="/shoppinglist"><i class="fa fa-shopping-bag fa-fw"></i> Shopping list</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li data-nav-for-page="habittracking.php">
|
||||||
|
<a class="discrete-link" href="/habittracking"><i class="fa fa-play fa-fw"></i> Habit tracking</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<ul class="nav nav-sidebar">
|
<ul class="nav nav-sidebar">
|
||||||
@ -123,6 +145,9 @@
|
|||||||
<li data-nav-for-page="quantityunits.php">
|
<li data-nav-for-page="quantityunits.php">
|
||||||
<a class="discrete-link" href="/quantityunits"><i class="fa fa-balance-scale fa-fw"></i> Quantity units</a>
|
<a class="discrete-link" href="/quantityunits"><i class="fa fa-balance-scale fa-fw"></i> Quantity units</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li data-nav-for-page="habits.php">
|
||||||
|
<a class="discrete-link" href="/habits"><i class="fa fa-refresh fa-fw"></i> Habits</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="nav-copyright nav nav-sidebar">
|
<div class="nav-copyright nav nav-sidebar">
|
||||||
@ -162,6 +187,7 @@
|
|||||||
<script src="/bower_components/jquery-timeago/jquery.timeago.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
|
<script src="/bower_components/jquery-timeago/jquery.timeago.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
|
||||||
<script src="/bower_components/toastr/toastr.min.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
|
<script src="/bower_components/toastr/toastr.min.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
|
||||||
<script src="/bower_components/tagmanager/tagmanager.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
|
<script src="/bower_components/tagmanager/tagmanager.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
|
||||||
|
<script src="/bower_components/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js?v=<?php echo Grocy::GetInstalledVersion(); ?>"></script>
|
||||||
|
|
||||||
<?php if (file_exists(__DIR__ . '/' . str_replace('.php', '.js', $contentPage))) : ?>
|
<?php if (file_exists(__DIR__ . '/' . str_replace('.php', '.js', $contentPage))) : ?>
|
||||||
<script src="/views/<?php echo str_replace('.php', '.js', $contentPage) . '?v=' . Grocy::GetInstalledVersion(); ?>"></script>
|
<script src="/views/<?php echo str_replace('.php', '.js', $contentPage) . '?v=' . Grocy::GetInstalledVersion(); ?>"></script>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
$(function()
|
$(function()
|
||||||
{
|
{
|
||||||
$('#current-stock-table').DataTable({
|
$('#stock-overview-table').DataTable({
|
||||||
'pageLength': 50,
|
'pageLength': 50,
|
||||||
'order': [[2, 'asc']]
|
'order': [[2, 'asc']]
|
||||||
});
|
});
|
@ -1,8 +1,6 @@
|
|||||||
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
|
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
|
||||||
|
|
||||||
<h1 class="page-header">Dashboard</h1>
|
<h1 class="page-header">Stock overview <span class="text-muded small"><strong><?php echo count($currentStock) ?></strong> products with <strong><?php echo GrocyPhpHelper::SumArrayValue($currentStock, 'amount'); ?></strong> units in stock</span></h1>
|
||||||
|
|
||||||
<h3>Stock overview <span class="text-muded small"><strong><?php echo count($currentStock) ?></strong> products with <strong><?php echo GrocyPhpHelper::SumArrayValue($currentStock, 'amount'); ?></strong> units in stock</span></h3>
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -15,7 +13,7 @@
|
|||||||
<div class="discrete-content-separator-2x"></div>
|
<div class="discrete-content-separator-2x"></div>
|
||||||
|
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table id="current-stock-table" class="table table-striped">
|
<table id="stock-overview-table" class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Product</th>
|
<th>Product</th>
|
Loading…
x
Reference in New Issue
Block a user