mirror of
https://github.com/grocy/grocy.git
synced 2025-04-29 17:45:39 +00:00
Renamed habits to chores as this is more what it is about
This commit is contained in:
parent
bd3c63218b
commit
4075067a10
@ -2,19 +2,19 @@
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use \Grocy\Services\HabitsService;
|
||||
use \Grocy\Services\ChoresService;
|
||||
|
||||
class HabitsApiController extends BaseApiController
|
||||
class ChoresApiController extends BaseApiController
|
||||
{
|
||||
public function __construct(\Slim\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
$this->HabitsService = new HabitsService();
|
||||
$this->ChoresService = new ChoresService();
|
||||
}
|
||||
|
||||
protected $HabitsService;
|
||||
protected $ChoresService;
|
||||
|
||||
public function TrackHabitExecution(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
|
||||
public function TrackChoreExecution(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
|
||||
{
|
||||
$trackedTime = date('Y-m-d H:i:s');
|
||||
if (isset($request->getQueryParams()['tracked_time']) && !empty($request->getQueryParams()['tracked_time']) && IsIsoDateTime($request->getQueryParams()['tracked_time']))
|
||||
@ -30,7 +30,7 @@ class HabitsApiController extends BaseApiController
|
||||
|
||||
try
|
||||
{
|
||||
$this->HabitsService->TrackHabit($args['habitId'], $trackedTime, $doneBy);
|
||||
$this->ChoresService->TrackChore($args['choreId'], $trackedTime, $doneBy);
|
||||
return $this->VoidApiActionResponse($response);
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
@ -39,11 +39,11 @@ class HabitsApiController extends BaseApiController
|
||||
}
|
||||
}
|
||||
|
||||
public function HabitDetails(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
|
||||
public function ChoreDetails(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
|
||||
{
|
||||
try
|
||||
{
|
||||
return $this->ApiResponse($this->HabitsService->GetHabitDetails($args['habitId']));
|
||||
return $this->ApiResponse($this->ChoresService->GetChoreDetails($args['choreId']));
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
{
|
||||
@ -53,6 +53,6 @@ class HabitsApiController extends BaseApiController
|
||||
|
||||
public function Current(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
|
||||
{
|
||||
return $this->ApiResponse($this->HabitsService->GetCurrent());
|
||||
return $this->ApiResponse($this->ChoresService->GetCurrent());
|
||||
}
|
||||
}
|
68
controllers/ChoresController.php
Normal file
68
controllers/ChoresController.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use \Grocy\Services\ChoresService;
|
||||
|
||||
class ChoresController extends BaseController
|
||||
{
|
||||
public function __construct(\Slim\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
$this->ChoresService = new ChoresService();
|
||||
}
|
||||
|
||||
protected $ChoresService;
|
||||
|
||||
public function Overview(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'choresoverview', [
|
||||
'chores' => $this->Database->chores()->orderBy('name'),
|
||||
'currentChores' => $this->ChoresService->GetCurrent(),
|
||||
'nextXDays' => 5
|
||||
]);
|
||||
}
|
||||
|
||||
public function TrackChoreExecution(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'choretracking', [
|
||||
'chores' => $this->Database->chores()->orderBy('name'),
|
||||
'users' => $this->Database->users()->orderBy('username')
|
||||
]);
|
||||
}
|
||||
|
||||
public function ChoresList(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'chores', [
|
||||
'chores' => $this->Database->chores()->orderBy('name')
|
||||
]);
|
||||
}
|
||||
|
||||
public function Analysis(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'choresanalysis', [
|
||||
'choresLog' => $this->Database->chores_log()->orderBy('tracked_time', 'DESC'),
|
||||
'chores' => $this->Database->chores()->orderBy('name'),
|
||||
'users' => $this->Database->users()->orderBy('username')
|
||||
]);
|
||||
}
|
||||
|
||||
public function ChoreEditForm(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
|
||||
{
|
||||
if ($args['choredId'] == 'new')
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'choreform', [
|
||||
'periodTypes' => GetClassConstants('\Grocy\Services\ChoresService'),
|
||||
'mode' => 'create'
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'choreform', [
|
||||
'chore' => $this->Database->chores($args['choreId']),
|
||||
'periodTypes' => GetClassConstants('\Grocy\Services\ChoresService'),
|
||||
'mode' => 'edit'
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use \Grocy\Services\HabitsService;
|
||||
|
||||
class HabitsController extends BaseController
|
||||
{
|
||||
public function __construct(\Slim\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
$this->HabitsService = new HabitsService();
|
||||
}
|
||||
|
||||
protected $HabitsService;
|
||||
|
||||
public function Overview(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'habitsoverview', [
|
||||
'habits' => $this->Database->habits()->orderBy('name'),
|
||||
'currentHabits' => $this->HabitsService->GetCurrent(),
|
||||
'nextXDays' => 5
|
||||
]);
|
||||
}
|
||||
|
||||
public function TrackHabitExecution(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'habittracking', [
|
||||
'habits' => $this->Database->habits()->orderBy('name'),
|
||||
'users' => $this->Database->users()->orderBy('username')
|
||||
]);
|
||||
}
|
||||
|
||||
public function HabitsList(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'habits', [
|
||||
'habits' => $this->Database->habits()->orderBy('name')
|
||||
]);
|
||||
}
|
||||
|
||||
public function Analysis(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'habitsanalysis', [
|
||||
'habitsLog' => $this->Database->habits_log()->orderBy('tracked_time', 'DESC'),
|
||||
'habits' => $this->Database->habits()->orderBy('name'),
|
||||
'users' => $this->Database->users()->orderBy('username')
|
||||
]);
|
||||
}
|
||||
|
||||
public function HabitEditForm(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
|
||||
{
|
||||
if ($args['habitId'] == 'new')
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'habitform', [
|
||||
'periodTypes' => GetClassConstants('\Grocy\Services\HabitsService'),
|
||||
'mode' => 'create'
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'habitform', [
|
||||
'habit' => $this->Database->habits($args['habitId']),
|
||||
'periodTypes' => GetClassConstants('\Grocy\Services\HabitsService'),
|
||||
'mode' => 'edit'
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
@ -54,7 +54,7 @@
|
||||
"$ref": "#/components/schemas/Product"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Habit"
|
||||
"$ref": "#/components/schemas/Chore"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Battery"
|
||||
@ -128,7 +128,7 @@
|
||||
"$ref": "#/components/schemas/Product"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Habit"
|
||||
"$ref": "#/components/schemas/Chore"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Battery"
|
||||
@ -191,7 +191,7 @@
|
||||
"$ref": "#/components/schemas/Product"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Habit"
|
||||
"$ref": "#/components/schemas/Chore"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Battery"
|
||||
@ -274,7 +274,7 @@
|
||||
"$ref": "#/components/schemas/Product"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Habit"
|
||||
"$ref": "#/components/schemas/Chore"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Battery"
|
||||
@ -1041,18 +1041,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/habits/track-habit-execution/{habitId}": {
|
||||
"/chores/track-chore-execution/{choreId}": {
|
||||
"get": {
|
||||
"description": "Tracks an execution of the given habit",
|
||||
"description": "Tracks an execution of the given chore",
|
||||
"tags": [
|
||||
"Habits"
|
||||
"Chores"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "habitId",
|
||||
"name": "choreId",
|
||||
"required": true,
|
||||
"description": "A valid habit id",
|
||||
"description": "A valid chore id",
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
@ -1061,7 +1061,7 @@
|
||||
"in": "query",
|
||||
"name": "tracked_time",
|
||||
"required": false,
|
||||
"description": "The time of when the habit was executed, when omitted, the current time is used",
|
||||
"description": "The time of when the chore was executed, when omitted, the current time is used",
|
||||
"schema": {
|
||||
"type": "date-time"
|
||||
}
|
||||
@ -1070,7 +1070,7 @@
|
||||
"in": "query",
|
||||
"name": "done_by",
|
||||
"required": false,
|
||||
"description": "A valid user id of who executed this habit, when omitted, the currently authenticated user will be used",
|
||||
"description": "A valid user id of who executed this chore, when omitted, the currently authenticated user will be used",
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
@ -1088,7 +1088,7 @@
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "A VoidApiActionResponse object (possible errors are: Not existing habit)",
|
||||
"description": "A VoidApiActionResponse object (possible errors are: Not existing chore)",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
@ -1100,18 +1100,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/habits/get-habit-details/{habitId}": {
|
||||
"/chores/get-chore-details/{choreId}": {
|
||||
"get": {
|
||||
"description": "Returns details of the given habit",
|
||||
"description": "Returns details of the given chore",
|
||||
"tags": [
|
||||
"Habits"
|
||||
"Chores"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "habitId",
|
||||
"name": "choreId",
|
||||
"required": true,
|
||||
"description": "A valid habit id",
|
||||
"description": "A valid chore id",
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
@ -1119,17 +1119,17 @@
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A HabitDetailsResponse object",
|
||||
"description": "A ChoreDetailsResponse object",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HabitDetailsResponse"
|
||||
"$ref": "#/components/schemas/ChoreDetailsResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "A VoidApiActionResponse object (possible errors are: Not existing habit)",
|
||||
"description": "A VoidApiActionResponse object (possible errors are: Not existing chore)",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
@ -1141,21 +1141,21 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/habits/get-current": {
|
||||
"/chores/get-current": {
|
||||
"get": {
|
||||
"description": "Returns all habits incl. the next estimated execution time per habit",
|
||||
"description": "Returns all chores incl. the next estimated execution time per chore",
|
||||
"tags": [
|
||||
"Habits"
|
||||
"Chores"
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "An array of CurrentHabitResponse objects",
|
||||
"description": "An array of CurrentChoreResponse objects",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/CurrentHabitResponse"
|
||||
"$ref": "#/components/schemas/CurrentChoreResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1286,7 +1286,7 @@
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"products",
|
||||
"habits",
|
||||
"chores",
|
||||
"batteries",
|
||||
"locations",
|
||||
"quantity_units",
|
||||
@ -1494,20 +1494,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"HabitDetailsResponse": {
|
||||
"ChoreDetailsResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"habit": {
|
||||
"$ref": "#/components/schemas/Habit"
|
||||
"chore": {
|
||||
"$ref": "#/components/schemas/Chore"
|
||||
},
|
||||
"last_tracked": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When this habit was last tracked"
|
||||
"description": "When this chore was last tracked"
|
||||
},
|
||||
"track_count": {
|
||||
"type": "integer",
|
||||
"description": "How often this habit was tracked so far"
|
||||
"description": "How often this chore was tracked so far"
|
||||
},
|
||||
"last_done_by": {
|
||||
"$ref": "#/components/schemas/UserDto"
|
||||
@ -1521,7 +1521,7 @@
|
||||
"BatteryDetailsResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"habit": {
|
||||
"chore": {
|
||||
"$ref": "#/components/schemas/Battery"
|
||||
},
|
||||
"last_charged": {
|
||||
@ -1709,7 +1709,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Habit": {
|
||||
"Chore": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
@ -1737,13 +1737,13 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"HabitLogEntry": {
|
||||
"ChoreLogEntry": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"habit_id": {
|
||||
"chore_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"tracked_time": {
|
||||
@ -1842,10 +1842,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"CurrentHabitResponse": {
|
||||
"CurrentChoreResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"habit_id": {
|
||||
"chore_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"last_tracked_time": {
|
||||
@ -1855,7 +1855,7 @@
|
||||
"next_estimated_execution_time": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "The next estimated execution time of this habit, 2999-12-31 23:59:59 when the given habit has a period_type of manually"
|
||||
"description": "The next estimated execution time of this chore, 2999-12-31 23:59:59 when the given chore has a period_type of manually"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -9,20 +9,20 @@ return array(
|
||||
'Amount' => 'Menge',
|
||||
'Next best before date' => 'Nächstes MHD',
|
||||
'Logout' => 'Abmelden',
|
||||
'Habits overview' => 'Gewohnheiten',
|
||||
'Chores overview' => 'Hausarbeiten',
|
||||
'Batteries overview' => 'Batterien',
|
||||
'Purchase' => 'Einkauf',
|
||||
'Consume' => 'Verbrauch',
|
||||
'Inventory' => 'Inventur',
|
||||
'Shopping list' => 'Einkaufszettel',
|
||||
'Habit tracking' => 'Gewohnheit-Ausführung',
|
||||
'Chore tracking' => 'Hausarbeiten-Ausführung',
|
||||
'Battery tracking' => 'Batterie-Ladzyklus',
|
||||
'Products' => 'Produkte',
|
||||
'Locations' => 'Standorte',
|
||||
'Quantity units' => 'Mengeneinheiten',
|
||||
'Habits' => 'Gewohnheiten',
|
||||
'Chores' => 'Hausarbeiten',
|
||||
'Batteries' => 'Batterien',
|
||||
'Habit' => 'Gewohnheit',
|
||||
'Chore' => 'Hausarbeit',
|
||||
'Next estimated tracking' => 'Nächste geplante Ausführung',
|
||||
'Last tracked' => 'Zuletzt ausgeführt',
|
||||
'Battery' => 'Batterie',
|
||||
@ -41,7 +41,7 @@ return array(
|
||||
'New amount' => 'Neue Menge',
|
||||
'Note' => 'Notiz',
|
||||
'Tracked time' => 'Ausführungszeit',
|
||||
'Habit overview' => 'Gewohnheit Übersicht',
|
||||
'Chore overview' => 'Hausarbeit Übersicht',
|
||||
'Tracked count' => 'Ausführungsanzahl',
|
||||
'Battery overview' => 'Batterie Übersicht',
|
||||
'Charge cycles count' => 'Ladezyklen',
|
||||
@ -68,11 +68,11 @@ return array(
|
||||
'Create quantity unit' => 'Mengeneinheit erstellen',
|
||||
'Period type' => 'Periodentyp',
|
||||
'Period days' => 'Tage/Periode',
|
||||
'Create habit' => 'Gewohnheit erstellen',
|
||||
'Create chore' => 'Hausarbeit erstellen',
|
||||
'Used in' => 'Benutzt in',
|
||||
'Create battery' => 'Batterie erstellen',
|
||||
'Edit battery' => 'Batterie bearbeiten',
|
||||
'Edit habit' => 'Gewohnheit bearbeiten',
|
||||
'Edit chore' => 'Hausarbeit bearbeiten',
|
||||
'Edit quantity unit' => 'Mengeneinheit bearbeiten',
|
||||
'Edit product' => 'Produkt bearbeiten',
|
||||
'Edit location' => 'Standort bearbeiten',
|
||||
@ -90,7 +90,7 @@ return array(
|
||||
'Are you sure to delete battery "#1"?' => 'Battery "#1" wirklich löschen?',
|
||||
'Yes' => 'Ja',
|
||||
'No' => 'Nein',
|
||||
'Are you sure to delete habit "#1"?' => 'Gewohnheit "#1" wirklich löschen?',
|
||||
'Are you sure to delete chore "#1"?' => 'Hausarbeit "#1" wirklich löschen?',
|
||||
'"#1" could not be resolved to a product, how do you want to proceed?' => '"#1" konnte nicht zu einem Produkt aufgelöst werden, wie möchtest du weiter machen?',
|
||||
'Create or assign product' => 'Produkt erstellen oder verknüpfen',
|
||||
'Cancel' => 'Abbrechen',
|
||||
@ -110,29 +110,29 @@ return array(
|
||||
'This product is not in stock' => 'Dieses Produkt ist nicht vorrätig',
|
||||
'This means #1 will be added to stock' => 'Das bedeutet #1 wird dem Bestand hinzugefügt',
|
||||
'This means #1 will be removed from stock' => 'Das bedeutet #1 wird aus dem Bestand entfernt',
|
||||
'This means it is estimated that a new execution of this habit is tracked #1 days after the last was tracked' => 'Das bedeutet, dass eine erneute Ausführung der Gewohnheit #1 Tage nach der letzten Ausführung geplant wird',
|
||||
'This means it is estimated that a new execution of this chore is tracked #1 days after the last was tracked' => 'Das bedeutet, dass eine erneute Ausführung der Hausarbeit #1 Tage nach der letzten Ausführung geplant wird',
|
||||
'Removed #1 #2 of #3 from stock' => '#1 #2 #3 aus dem Bestand entfernt',
|
||||
'About grocy' => 'Über grocy',
|
||||
'Close' => 'Schließen',
|
||||
'#1 batteries are due to be charged within the next #2 days' => '#1 Batterien müssen in den nächsten #2 Tagen geladen werden',
|
||||
'#1 batteries are overdue to be charged' => '#1 Batterien sind überfällig',
|
||||
'#1 habits are due to be done within the next #2 days' => '#1 Gewohnheiten stehen in den nächsten #2 Tagen an',
|
||||
'#1 habits are overdue to be done' => '#1 Gewohnheiten sind überfällig',
|
||||
'#1 chores are due to be done within the next #2 days' => '#1 Hausarbeiten stehen in den nächsten #2 Tagen an',
|
||||
'#1 chores are overdue to be done' => '#1 Hausarbeiten sind überfällig',
|
||||
'Released on' => 'Veröffentlicht am',
|
||||
'Consume #3 #1 of #2' => 'Verbrauche #3 #1 #2',
|
||||
'Added #1 #2 of #3 to stock' => '#1 #2 #3 dem Bestand hinzugefügt',
|
||||
'Stock amount of #1 is now #2 #3' => 'Es sind nun #2 #3 #1 im Bestand',
|
||||
'Tracked execution of habit #1 on #2' => 'Ausführung von #1 am #2 erfasst',
|
||||
'Tracked execution of chore #1 on #2' => 'Ausführung von #1 am #2 erfasst',
|
||||
'Tracked charge cycle of battery #1 on #2' => 'Ladezyklus für Batterie #1 am #2 erfasst',
|
||||
'Consume all #1 which are currently in stock' => 'Verbrauche den kompletten Bestand von #1',
|
||||
'All' => 'Alle',
|
||||
'Track charge cycle of battery #1' => 'Erfasse einen Ladezyklus für Batterie #1',
|
||||
'Track execution of habit #1' => 'Erfasse eine Ausführung von #1',
|
||||
'Track execution of chore #1' => 'Erfasse eine Ausführung von #1',
|
||||
'Filter by location' => 'Nach Standort filtern',
|
||||
'Search' => 'Suche',
|
||||
'Not logged in' => 'Nicht angemeldet',
|
||||
'You have to select a product' => 'Ein Produkt muss ausgewählt werden',
|
||||
'You have to select a habit' => 'Eine Gewohnheit muss ausgewählt werden',
|
||||
'You have to select a chore' => 'Eine Hausarbeit muss ausgewählt werden',
|
||||
'You have to select a battery' => 'Eine Batterie muss ausgewählt werden',
|
||||
'A name is required' => 'Ein Name ist erforderlich',
|
||||
'A location is required' => 'Ein Standort ist erforderlich',
|
||||
@ -183,8 +183,8 @@ return array(
|
||||
'Done by' => 'Ausgeführt von',
|
||||
'Last done by' => 'Zuletzt ausgeführt von',
|
||||
'Unknown' => 'Unbekannt',
|
||||
'Filter by habit' => 'Nach Gewohnheit filtern',
|
||||
'Habits analysis' => 'Gewohnheiten Analyse',
|
||||
'Filter by chore' => 'Nach Hausarbeit filtern',
|
||||
'Chores analysis' => 'Hausarbeiten Analyse',
|
||||
'0 means suggestions for the next charge cycle are disabled' => '0 bedeutet dass Vorschläge für den nächsten Ladezyklus deaktiviert sind',
|
||||
'Charge cycle interval (days)' => 'Ladezyklusintervall (Tage)',
|
||||
'Last price' => 'Letzter Preis',
|
||||
@ -198,8 +198,8 @@ return array(
|
||||
'#1 product is below defined min. stock amount' => '#1 Produkt ist unter Mindestbestand',
|
||||
'Unit' => 'Einheit',
|
||||
'Units' => 'Einheiten',
|
||||
'#1 habit is due to be done within the next #2 days' => '#1 Gewohnheit steht in den nächsten #2 Tagen an',
|
||||
'#1 habit is overdue to be done' => '#1 Gewohnheit ist überfällig',
|
||||
'#1 chore is due to be done within the next #2 days' => '#1 Hausarbeit steht in den nächsten #2 Tagen an',
|
||||
'#1 chore is overdue to be done' => '#1 Hausarbeit ist überfällig',
|
||||
'#1 battery is due to be charged within the next #2 days' => '#1 Batterie muss in den nächsten #2 Tagen geladen werden',
|
||||
'#1 battery is overdue to be charged' => '#1 Batterie ist überfällig',
|
||||
'#1 unit was automatically added and will apply in addition to the amount entered here' => '#1 Einheit wurde automatisch hinzugefügt und gilt zusätzlich der hier eingegebenen Menge',
|
||||
|
@ -9,20 +9,20 @@ return array(
|
||||
'Amount' => 'quantità',
|
||||
'Next best before date' => 'Prossima data di scadenza',
|
||||
'Logout' => 'Logout',
|
||||
'Habits overview' => 'Riepilogo delle abitudini',
|
||||
'Chores overview' => 'Riepilogo delle abitudini',
|
||||
'Batteries overview' => 'Riepilogo delle batterie',
|
||||
'Purchase' => 'Acquisti',
|
||||
'Consume' => 'Consumi',
|
||||
'Inventory' => 'Inventario',
|
||||
'Shopping list' => 'Lista della spesa',
|
||||
'Habit tracking' => 'Dati abitudini',
|
||||
'Chore tracking' => 'Dati abitudini',
|
||||
'Battery tracking' => 'Dati batterie',
|
||||
'Products' => 'Prodotti',
|
||||
'Locations' => 'Posizioni',
|
||||
'Quantity units' => 'Unità di misura',
|
||||
'Habits' => 'Abitudini',
|
||||
'Chores' => 'Abitudini',
|
||||
'Batteries' => 'Batterie',
|
||||
'Habit' => 'Abitudine',
|
||||
'Chore' => 'Abitudine',
|
||||
'Next estimated tracking' => 'Prossima esecuzione',
|
||||
'Last tracked' => 'Ultima esecuzione',
|
||||
'Battery' => 'Batterie',
|
||||
@ -41,7 +41,7 @@ return array(
|
||||
'New amount' => 'Nuova quantità',
|
||||
'Note' => 'Nota',
|
||||
'Tracked time' => 'Ora di esecuzione',
|
||||
'Habit overview' => 'Riepilogo dell\'abitudine',
|
||||
'Chore overview' => 'Riepilogo dell\'abitudine',
|
||||
'Tracked count' => 'Numero di esecuzioni',
|
||||
'Battery overview' => 'Riepilogo della batteria',
|
||||
'Charge cycles count' => 'Numero di ricariche',
|
||||
@ -68,11 +68,11 @@ return array(
|
||||
'Create quantity unit' => 'Aggiungi unità di misura',
|
||||
'Period type' => 'Tipo di ripetizione',
|
||||
'Period days' => 'Periodo in giorni',
|
||||
'Create habit' => 'Aggiungi abitudine',
|
||||
'Create chore' => 'Aggiungi abitudine',
|
||||
'Used in' => 'Usato in',
|
||||
'Create battery' => 'Aggiungi batteria',
|
||||
'Edit battery' => 'Modifica batteria',
|
||||
'Edit habit' => 'Modifica abitudine',
|
||||
'Edit chore' => 'Modifica abitudine',
|
||||
'Edit quantity unit' => 'Modifica unità di misura',
|
||||
'Edit product' => 'Modifica prodotto',
|
||||
'Edit location' => 'Modifica posizione',
|
||||
@ -90,7 +90,7 @@ return array(
|
||||
'Are you sure to delete battery "#1"?' => 'Sei sicuro di voler eliminare la batteria "#1"?',
|
||||
'Yes' => 'Si',
|
||||
'No' => 'No',
|
||||
'Are you sure to delete habit "#1"?' => 'Sei sicuro di voler eliminare l\'abitudine "#1"?',
|
||||
'Are you sure to delete chore "#1"?' => 'Sei sicuro di voler eliminare l\'abitudine "#1"?',
|
||||
'"#1" could not be resolved to a product, how do you want to proceed?' => '"#1" non è stato associato a nessun prodotto, vuoi procedere?',
|
||||
'Create or assign product' => 'Aggiungi o assegna prodotto',
|
||||
'Cancel' => 'Annulla',
|
||||
@ -110,29 +110,29 @@ return array(
|
||||
'This product is not in stock' => 'Questo prodotto non è in dispensa',
|
||||
'This means #1 will be added to stock' => '#1 sarà aggiunto alla dispensa',
|
||||
'This means #1 will be removed from stock' => '#1 sarà rimosso dalla dispensa',
|
||||
'This means it is estimated that a new execution of this habit is tracked #1 days after the last was tracked' => 'L\'esecuzione dell\'abitudine è #1 giorni dopo la precedente',
|
||||
'This means it is estimated that a new execution of this chore is tracked #1 days after the last was tracked' => 'L\'esecuzione dell\'abitudine è #1 giorni dopo la precedente',
|
||||
'Removed #1 #2 of #3 from stock' => '#1 #2 su #3 rimossi dalla dispensa',
|
||||
'About grocy' => 'Riguardo grocy',
|
||||
'Close' => 'Chiudi',
|
||||
'#1 batteries are due to be charged within the next #2 days' => '#1 batterie da ricaricare entro #2 giorni',
|
||||
'#1 batteries are overdue to be charged' => '#1 batterie devono essere ricaricate',
|
||||
'#1 habits are due to be done within the next #2 days' => '#1 abitudini da eseguire entro #2 giorni',
|
||||
'#1 habits are overdue to be done' => '#1 abitudini da eseguire',
|
||||
'#1 chores are due to be done within the next #2 days' => '#1 abitudini da eseguire entro #2 giorni',
|
||||
'#1 chores are overdue to be done' => '#1 abitudini da eseguire',
|
||||
'Released on' => 'Rilasciato il',
|
||||
'Consume #3 #1 of #2' => 'Consumati #3 #1 di #2',
|
||||
'Added #1 #2 of #3 to stock' => 'Aggiunti #1 #2 di #3',
|
||||
'Stock amount of #1 is now #2 #3' => 'La quantità in dispensa di #1 è ora #2 #3',
|
||||
'Tracked execution of habit #1 on #2' => 'Esecuzione dell\'abitudine #1 registrata il #2',
|
||||
'Tracked execution of chore #1 on #2' => 'Esecuzione dell\'abitudine #1 registrata il #2',
|
||||
'Tracked charge cycle of battery #1 on #2' => 'Ricarica della batteria #1 effettuata il #2',
|
||||
'Consume all #1 which are currently in stock' => 'Consuma tutto #1 in dispensa',
|
||||
'All' => 'Tutto',
|
||||
'Track charge cycle of battery #1' => 'Registra la ricarica della batteria #1',
|
||||
'Track execution of habit #1' => 'Registra l\'esecuzione dell\'abitudine #1',
|
||||
'Track execution of chore #1' => 'Registra l\'esecuzione dell\'abitudine #1',
|
||||
'Filter by location' => 'Filtra per posizione',
|
||||
'Search' => 'Cerca',
|
||||
'Not logged in' => 'Non autenticato',
|
||||
'You have to select a product' => 'Devi selezionare un prodotto',
|
||||
'You have to select a habit' => 'Devi selezionare un\'abitudine',
|
||||
'You have to select a chore' => 'Devi selezionare un\'abitudine',
|
||||
'You have to select a battery' => 'Devi selezionare una batteria',
|
||||
'A name is required' => 'Inserisci un nome',
|
||||
'A location is required' => 'Inserisci la posizione',
|
||||
|
@ -9,20 +9,20 @@ return array(
|
||||
'Amount' => 'Antall',
|
||||
'Next best before date' => 'Kommende best før dato',
|
||||
'Logout' => 'Logg ut',
|
||||
'Habits overview' => 'Oversikt Husoppgaver',
|
||||
'Chores overview' => 'Oversikt Husoppgaver',
|
||||
'Batteries overview' => 'Oversikt Batteri',
|
||||
'Purchase' => 'Innkjøp',
|
||||
'Consume' => 'Forbrukt',
|
||||
'Inventory' => 'Endre Husholdning',
|
||||
'Shopping list' => 'Handleliste',
|
||||
'Habit tracking' => 'Logge Husoppgaver',
|
||||
'Chore tracking' => 'Logge Husoppgaver',
|
||||
'Battery tracking' => 'Batteri Ladesyklus',
|
||||
'Products' => 'Produkter',
|
||||
'Locations' => 'Lokasjoner',
|
||||
'Quantity units' => 'Forpakning',
|
||||
'Habits' => 'Husoppgaver',
|
||||
'Chores' => 'Husoppgaver',
|
||||
'Batteries' => 'Batterier',
|
||||
'Habit' => 'Husoppgave',
|
||||
'Chore' => 'Husoppgave',
|
||||
'Next estimated tracking' => 'Neste handling',
|
||||
'Last tracked' => 'Sist logget',
|
||||
'Battery' => 'Batteri',
|
||||
@ -41,7 +41,7 @@ return array(
|
||||
'New amount' => 'Nytt antall',
|
||||
'Note' => 'Info',
|
||||
'Tracked time' => 'Tid utført/ ladet',
|
||||
'Habit overview' => 'Oversikt Husoppgave',
|
||||
'Chore overview' => 'Oversikt Husoppgave',
|
||||
'Tracked count' => 'Antall utførelser/ ladninger',
|
||||
'Battery overview' => 'Batteri Oversikt',
|
||||
'Charge cycles count' => 'Antall ladesykluser',
|
||||
@ -68,11 +68,11 @@ return array(
|
||||
'Create quantity unit' => 'Opprett forpakning',
|
||||
'Period type' => 'Gjentakelse',
|
||||
'Period days' => 'Antall dager for gjentakelse',
|
||||
'Create habit' => 'Opprett husoppgave',
|
||||
'Create chore' => 'Opprett husoppgave',
|
||||
'Used in' => 'Brukt',
|
||||
'Create battery' => 'Opprett batteri',
|
||||
'Edit battery' => 'Endre batteri',
|
||||
'Edit habit' => 'Endre husoppgave',
|
||||
'Edit chore' => 'Endre husoppgave',
|
||||
'Edit quantity unit' => 'Endre forpakning',
|
||||
'Edit product' => 'Endre produkt',
|
||||
'Edit location' => 'Endre lokasjon',
|
||||
@ -90,7 +90,7 @@ return array(
|
||||
'Are you sure to delete battery "#1"?' => 'Er du sikker du ønsker å slette Batteri "#1"?',
|
||||
'Yes' => 'Ja',
|
||||
'No' => 'Nei',
|
||||
'Are you sure to delete habit "#1"?' => 'Er du sikker på du ønsker å slette husoppgave "#1"?',
|
||||
'Are you sure to delete chore "#1"?' => 'Er du sikker på du ønsker å slette husoppgave "#1"?',
|
||||
'"#1" could not be resolved to a product, how do you want to proceed?' => '"#1" kunne ikke bli tildelt et produkt, hvordan ønsker du å fortsette?',
|
||||
'Create or assign product' => 'Opprett eller tildel til produkt',
|
||||
'Cancel' => 'Avbryt',
|
||||
@ -110,29 +110,29 @@ return array(
|
||||
'This product is not in stock' => 'Dette produktet er ikke i husholdningen',
|
||||
'This means #1 will be added to stock' => 'Dette betyr at #1 vil bli lagt til i husholdningen',
|
||||
'This means #1 will be removed from stock' => 'Dette betyr at #1 vil bli fjernet fra husholdningen',
|
||||
'This means it is estimated that a new execution of this habit is tracked #1 days after the last was tracked' => 'Dette betyr at det er estimert at den nye utførelsen av denne husoppgaven er logget #1 dag etter den sist var logget',
|
||||
'This means it is estimated that a new execution of this chore is tracked #1 days after the last was tracked' => 'Dette betyr at det er estimert at den nye utførelsen av denne husoppgaven er logget #1 dag etter den sist var logget',
|
||||
'Removed #1 #2 of #3 from stock' => 'Fjernet #1 #2 #3 fra husholdningen',
|
||||
'About grocy' => 'Om Grocy',
|
||||
'Close' => 'Lukk',
|
||||
'#1 batteries are due to be charged within the next #2 days' => '#1 Batteri må lades innen de #2 neste dagene',
|
||||
'#1 batteries are overdue to be charged' => '#1 Batteri har gått over fristen for å bli ladet opp',
|
||||
'#1 habits are due to be done within the next #2 days' => '#1 husoppgaver skal gjøres inne de #2 neste dagene',
|
||||
'#1 habits are overdue to be done' => '#1 husoppgaver har gått over fristen for utførelse',
|
||||
'#1 chores are due to be done within the next #2 days' => '#1 husoppgaver skal gjøres inne de #2 neste dagene',
|
||||
'#1 chores are overdue to be done' => '#1 husoppgaver har gått over fristen for utførelse',
|
||||
'Released on' => 'Utgitt',
|
||||
'Consume #3 #1 of #2' => 'Forbruk #3 #1 #2',
|
||||
'Added #1 #2 of #3 to stock' => '#1 #2 #3 lagt til i husholdningen',
|
||||
'Stock amount of #1 is now #2 #3' => 'Husholdning antall #1 er nå #2 #3',
|
||||
'Tracked execution of habit #1 on #2' => 'Utførte husoppgave "#1" den #2',
|
||||
'Tracked execution of chore #1 on #2' => 'Utførte husoppgave "#1" den #2',
|
||||
'Tracked charge cycle of battery #1 on #2' => 'Ladet #1 den #2',
|
||||
'Consume all #1 which are currently in stock' => 'Konsumér alle #1 som er i husholdningen',
|
||||
'All' => 'Alle',
|
||||
'Track charge cycle of battery #1' => '#1 ladet',
|
||||
'Track execution of habit #1' => 'Utfør husoppgave #1',
|
||||
'Track execution of chore #1' => 'Utfør husoppgave #1',
|
||||
'Filter by location' => 'Filtrér etter lokasjon',
|
||||
'Search' => 'Søk',
|
||||
'Not logged in' => 'Ikke logget inn',
|
||||
'You have to select a product' => 'Du må velge et produkt',
|
||||
'You have to select a habit' => 'Du må velge en husoppgaven',
|
||||
'You have to select a chore' => 'Du må velge en husoppgaven',
|
||||
'You have to select a battery' => 'Du må velge et batteri',
|
||||
'A name is required' => 'Vennligst fyll inn et navn',
|
||||
'A location is required' => 'En lokasjon kreves',
|
||||
@ -183,8 +183,8 @@ return array(
|
||||
'Done by' => 'Utført av',
|
||||
'Last done by' => 'Sist utført av',
|
||||
'Unknown' => 'Ukjent',
|
||||
'Filter by habit' => 'Filtrér husoppave',
|
||||
'Habits analysis' => 'Statistikk husoppgaver',
|
||||
'Filter by chore' => 'Filtrér husoppave',
|
||||
'Chores analysis' => 'Statistikk husoppgaver',
|
||||
'0 means suggestions for the next charge cycle are disabled' => '0 betyr neste ladesyklus er avslått',
|
||||
'Charge cycle interval (days)' => 'Ladesyklysintervall (Dager)',
|
||||
'Last price' => 'Siste pris',
|
||||
@ -198,8 +198,8 @@ return array(
|
||||
'#1 product is below defined min. stock amount' => '#1 Produkt er under minimums husholdningsnivå',
|
||||
'Unit' => 'Enhet',
|
||||
'Units' => 'Enheter',
|
||||
'#1 habit is due to be done within the next #2 days' => '#1 husoppgave skal gjøres inne de #2 neste dagene',
|
||||
'#1 habit is overdue to be done' => '#1 husoppgave har gått over fristen for utførelse',
|
||||
'#1 chore is due to be done within the next #2 days' => '#1 husoppgave skal gjøres inne de #2 neste dagene',
|
||||
'#1 chore is overdue to be done' => '#1 husoppgave har gått over fristen for utførelse',
|
||||
'#1 battery is due to be charged within the next #2 days' => '#1 Batteri må lades innen #2 dager',
|
||||
'#1 battery is overdue to be charged' => '#1 Batteri har gått over fristen for å lades',
|
||||
'#1 unit was automatically added and will apply in addition to the amount entered here' => '#1 enhet ble automatisk lagt til i tillegg til hva som blir skrevet inn her',
|
||||
|
@ -1,5 +1,5 @@
|
||||
ALTER TABLE habits_log
|
||||
ADD done_by_user_id;
|
||||
ADD done_by_user_id INTEGER;
|
||||
|
||||
DROP TABLE api_keys;
|
||||
|
||||
|
31
migrations/0035.sql
Normal file
31
migrations/0035.sql
Normal file
@ -0,0 +1,31 @@
|
||||
ALTER TABLE habits RENAME TO chores;
|
||||
|
||||
CREATE TABLE chores_log (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
chore_id INTEGER NOT NULL,
|
||||
tracked_time DATETIME,
|
||||
done_by_user_id INTEGER,
|
||||
row_created_timestamp DATETIME DEFAULT (datetime('now', 'localtime'))
|
||||
);
|
||||
|
||||
INSERT INTO chores_log
|
||||
(chore_id, tracked_time, done_by_user_id, row_created_timestamp)
|
||||
SELECT habit_id, tracked_time, done_by_user_id, row_created_timestamp
|
||||
FROM habits_log;
|
||||
|
||||
DROP TABLE habits_log;
|
||||
|
||||
DROP VIEW habits_current;
|
||||
CREATE VIEW chores_current
|
||||
AS
|
||||
SELECT
|
||||
h.id AS chore_id,
|
||||
MAX(l.tracked_time) AS last_tracked_time,
|
||||
CASE h.period_type
|
||||
WHEN 'manually' THEN '2999-12-31 23:59:59'
|
||||
WHEN 'dynamic-regular' THEN datetime(MAX(l.tracked_time), '+' || CAST(h.period_days AS TEXT) || ' day')
|
||||
END AS next_estimated_execution_time
|
||||
FROM chores h
|
||||
LEFT JOIN chores_log l
|
||||
ON h.id = l.chore_id
|
||||
GROUP BY h.id, h.period_days;
|
71
public/viewjs/choreform.js
Normal file
71
public/viewjs/choreform.js
Normal file
@ -0,0 +1,71 @@
|
||||
$('#save-chore-button').on('click', function(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
|
||||
if (Grocy.EditMode === 'create')
|
||||
{
|
||||
Grocy.Api.Post('add-object/chores', $('#chore-form').serializeJSON(),
|
||||
function(result)
|
||||
{
|
||||
window.location.href = U('/chores');
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
||||
}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
Grocy.Api.Post('edit-object/chores/' + Grocy.EditObjectId, $('#chore-form').serializeJSON(),
|
||||
function(result)
|
||||
{
|
||||
window.location.href = U('/chores');
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
$('#chore-form input').keyup(function(event)
|
||||
{
|
||||
Grocy.FrontendHelpers.ValidateForm('chore-form');
|
||||
});
|
||||
|
||||
$('#chore-form input').keydown(function(event)
|
||||
{
|
||||
if (event.keyCode === 13) //Enter
|
||||
{
|
||||
if (document.getElementById('chore-form').checkValidity() === false) //There is at least one validation error
|
||||
{
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#save-chore-button').click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#name').focus();
|
||||
Grocy.FrontendHelpers.ValidateForm('chore-form');
|
||||
|
||||
$('.input-group-chore-period-type').on('change', function(e)
|
||||
{
|
||||
var periodType = $('#period_type').val();
|
||||
var periodDays = $('#period_days').val();
|
||||
|
||||
if (periodType === 'dynamic-regular')
|
||||
{
|
||||
$('#chore-period-type-info').text(L('This means it is estimated that a new execution of this chore is tracked #1 days after the last was tracked', periodDays.toString()));
|
||||
$('#chore-period-type-info').removeClass('d-none');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#chore-period-type-info').addClass('d-none');
|
||||
}
|
||||
});
|
@ -1,4 +1,4 @@
|
||||
var habitsTable = $('#habits-table').DataTable({
|
||||
var choresTable = $('#chores-table').DataTable({
|
||||
'paginate': false,
|
||||
'order': [[1, 'asc']],
|
||||
'columnDefs': [
|
||||
@ -22,16 +22,16 @@ $("#search").on("keyup", function()
|
||||
value = "";
|
||||
}
|
||||
|
||||
habitsTable.search(value).draw();
|
||||
choresTable.search(value).draw();
|
||||
});
|
||||
|
||||
$(document).on('click', '.habit-delete-button', function (e)
|
||||
$(document).on('click', '.chore-delete-button', function (e)
|
||||
{
|
||||
var objectName = $(e.currentTarget).attr('data-habit-name');
|
||||
var objectId = $(e.currentTarget).attr('data-habit-id');
|
||||
var objectName = $(e.currentTarget).attr('data-chore-name');
|
||||
var objectId = $(e.currentTarget).attr('data-chore-id');
|
||||
|
||||
bootbox.confirm({
|
||||
message: L('Are you sure to delete habit "#1"?', objectName),
|
||||
message: L('Are you sure to delete chore "#1"?', objectName),
|
||||
buttons: {
|
||||
confirm: {
|
||||
label: L('Yes'),
|
||||
@ -46,10 +46,10 @@ $(document).on('click', '.habit-delete-button', function (e)
|
||||
{
|
||||
if (result === true)
|
||||
{
|
||||
Grocy.Api.Get('delete-object/habits/' + objectId,
|
||||
Grocy.Api.Get('delete-object/chores/' + objectId,
|
||||
function(result)
|
||||
{
|
||||
window.location.href = U('/habits');
|
||||
window.location.href = U('/chores');
|
||||
},
|
||||
function(xhr)
|
||||
{
|
@ -1,4 +1,4 @@
|
||||
var habitsAnalysisTable = $('#habits-analysis-table').DataTable({
|
||||
var choresAnalysisTable = $('#chores-analysis-table').DataTable({
|
||||
'paginate': false,
|
||||
'order': [[1, 'desc']],
|
||||
'language': JSON.parse(L('datatables_localization')),
|
||||
@ -11,16 +11,16 @@
|
||||
}
|
||||
});
|
||||
|
||||
$("#habit-filter").on("change", function()
|
||||
$("#chore-filter").on("change", function()
|
||||
{
|
||||
var value = $(this).val();
|
||||
var text = $("#habit-filter option:selected").text();
|
||||
var text = $("#chore-filter option:selected").text();
|
||||
if (value === "all")
|
||||
{
|
||||
text = "";
|
||||
}
|
||||
|
||||
habitsAnalysisTable.column(0).search(text).draw();
|
||||
choresAnalysisTable.column(0).search(text).draw();
|
||||
});
|
||||
|
||||
$("#search").on("keyup", function()
|
||||
@ -31,11 +31,11 @@ $("#search").on("keyup", function()
|
||||
value = "";
|
||||
}
|
||||
|
||||
habitsAnalysisTable.search(value).draw();
|
||||
choresAnalysisTable.search(value).draw();
|
||||
});
|
||||
|
||||
if (typeof GetUriParam("habit") !== "undefined")
|
||||
if (typeof GetUriParam("chore") !== "undefined")
|
||||
{
|
||||
$("#habit-filter").val(GetUriParam("habit"));
|
||||
$("#habit-filter").trigger("change");
|
||||
$("#chore-filter").val(GetUriParam("chore"));
|
||||
$("#chore-filter").trigger("change");
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
var habitsOverviewTable = $('#habits-overview-table').DataTable({
|
||||
var choresOverviewTable = $('#chores-overview-table').DataTable({
|
||||
'paginate': false,
|
||||
'order': [[2, 'desc']],
|
||||
'columnDefs': [
|
||||
@ -22,55 +22,55 @@ $("#search").on("keyup", function()
|
||||
value = "";
|
||||
}
|
||||
|
||||
habitsOverviewTable.search(value).draw();
|
||||
choresOverviewTable.search(value).draw();
|
||||
});
|
||||
|
||||
$(document).on('click', '.track-habit-button', function(e)
|
||||
$(document).on('click', '.track-chore-button', function(e)
|
||||
{
|
||||
var habitId = $(e.currentTarget).attr('data-habit-id');
|
||||
var habitName = $(e.currentTarget).attr('data-habit-name');
|
||||
var choreId = $(e.currentTarget).attr('data-chore-id');
|
||||
var choreName = $(e.currentTarget).attr('data-chore-name');
|
||||
var trackedTime = moment().format('YYYY-MM-DD HH:mm:ss');
|
||||
|
||||
Grocy.Api.Get('habits/track-habit-execution/' + habitId + '?tracked_time=' + trackedTime,
|
||||
Grocy.Api.Get('chores/track-chore-execution/' + choreId + '?tracked_time=' + trackedTime,
|
||||
function()
|
||||
{
|
||||
Grocy.Api.Get('habits/get-habit-details/' + habitId,
|
||||
Grocy.Api.Get('chores/get-chore-details/' + choreId,
|
||||
function(result)
|
||||
{
|
||||
var habitRow = $('#habit-' + habitId + '-row');
|
||||
var nextXDaysThreshold = moment().add($("#info-due-habits").data("next-x-days"), "days");
|
||||
var choreRow = $('#chore-' + choreId + '-row');
|
||||
var nextXDaysThreshold = moment().add($("#info-due-chores").data("next-x-days"), "days");
|
||||
var now = moment();
|
||||
var nextExecutionTime = moment(result.next_estimated_execution_time);
|
||||
|
||||
habitRow.removeClass("table-warning");
|
||||
habitRow.removeClass("table-danger");
|
||||
choreRow.removeClass("table-warning");
|
||||
choreRow.removeClass("table-danger");
|
||||
if (nextExecutionTime.isBefore(now))
|
||||
{
|
||||
habitRow.addClass("table-danger");
|
||||
choreRow.addClass("table-danger");
|
||||
}
|
||||
else if (nextExecutionTime.isBefore(nextXDaysThreshold))
|
||||
{
|
||||
habitRow.addClass("table-warning");
|
||||
choreRow.addClass("table-warning");
|
||||
}
|
||||
|
||||
$('#habit-' + habitId + '-last-tracked-time').parent().effect('highlight', { }, 500);
|
||||
$('#habit-' + habitId + '-last-tracked-time').fadeOut(500, function()
|
||||
$('#chore-' + choreId + '-last-tracked-time').parent().effect('highlight', { }, 500);
|
||||
$('#chore-' + choreId + '-last-tracked-time').fadeOut(500, function()
|
||||
{
|
||||
$(this).text(trackedTime).fadeIn(500);
|
||||
});
|
||||
$('#habit-' + habitId + '-last-tracked-time-timeago').attr('datetime', trackedTime);
|
||||
$('#chore-' + choreId + '-last-tracked-time-timeago').attr('datetime', trackedTime);
|
||||
|
||||
if (result.habit.period_type == "dynamic-regular")
|
||||
if (result.chore.period_type == "dynamic-regular")
|
||||
{
|
||||
$('#habit-' + habitId + '-next-execution-time').parent().effect('highlight', { }, 500);
|
||||
$('#habit-' + habitId + '-next-execution-time').fadeOut(500, function()
|
||||
$('#chore-' + choreId + '-next-execution-time').parent().effect('highlight', { }, 500);
|
||||
$('#chore-' + choreId + '-next-execution-time').fadeOut(500, function()
|
||||
{
|
||||
$(this).text(result.next_estimated_execution_time).fadeIn(500);
|
||||
});
|
||||
$('#habit-' + habitId + '-next-execution-time-timeago').attr('datetime', result.next_estimated_execution_time);
|
||||
$('#chore-' + choreId + '-next-execution-time-timeago').attr('datetime', result.next_estimated_execution_time);
|
||||
}
|
||||
|
||||
toastr.success(L('Tracked execution of habit #1 on #2', habitName, trackedTime));
|
||||
toastr.success(L('Tracked execution of chore #1 on #2', choreName, trackedTime));
|
||||
RefreshContextualTimeago();
|
||||
RefreshStatistics();
|
||||
},
|
||||
@ -89,8 +89,8 @@ $(document).on('click', '.track-habit-button', function(e)
|
||||
|
||||
function RefreshStatistics()
|
||||
{
|
||||
var nextXDays = $("#info-due-habits").data("next-x-days");
|
||||
Grocy.Api.Get('habits/get-current',
|
||||
var nextXDays = $("#info-due-chores").data("next-x-days");
|
||||
Grocy.Api.Get('chores/get-current',
|
||||
function(result)
|
||||
{
|
||||
var dueCount = 0;
|
||||
@ -109,8 +109,8 @@ function RefreshStatistics()
|
||||
}
|
||||
});
|
||||
|
||||
$("#info-due-habits").text(Pluralize(dueCount, L('#1 habit is due to be done within the next #2 days', dueCount, nextXDays), L('#1 habits are due to be done within the next #2 days', dueCount, nextXDays)));
|
||||
$("#info-overdue-habits").text(Pluralize(overdueCount, L('#1 habit is overdue to be done', overdueCount), L('#1 habits are overdue to be done', overdueCount)));
|
||||
$("#info-due-chores").text(Pluralize(dueCount, L('#1 chore is due to be done within the next #2 days', dueCount, nextXDays), L('#1 chores are due to be done within the next #2 days', dueCount, nextXDays)));
|
||||
$("#info-overdue-chores").text(Pluralize(overdueCount, L('#1 chore is overdue to be done', overdueCount), L('#1 chores are overdue to be done', overdueCount)));
|
||||
},
|
||||
function(xhr)
|
||||
{
|
82
public/viewjs/choretracking.js
Normal file
82
public/viewjs/choretracking.js
Normal file
@ -0,0 +1,82 @@
|
||||
$('#save-choretracking-button').on('click', function(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
|
||||
var jsonForm = $('#choretracking-form').serializeJSON();
|
||||
|
||||
Grocy.Api.Get('chores/get-chore-details/' + jsonForm.chore_id,
|
||||
function (choreDetails)
|
||||
{
|
||||
Grocy.Api.Get('chores/track-chore-execution/' + jsonForm.chore_id + '?tracked_time=' + Grocy.Components.DateTimePicker.GetValue() + "&done_by=" + Grocy.Components.UserPicker.GetValue(),
|
||||
function(result)
|
||||
{
|
||||
toastr.success(L('Tracked execution of chore #1 on #2', choreDetails.chore.name, Grocy.Components.DateTimePicker.GetValue()));
|
||||
|
||||
$('#chore_id').val('');
|
||||
$('#chore_id_text_input').focus();
|
||||
$('#chore_id_text_input').val('');
|
||||
Grocy.Components.DateTimePicker.SetValue(moment().format('YYYY-MM-DD HH:mm:ss'));
|
||||
$('#chore_id_text_input').trigger('change');
|
||||
Grocy.FrontendHelpers.ValidateForm('choretracking-form');
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
console.error(xhr);
|
||||
}
|
||||
);
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
console.error(xhr);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
$('#chore_id').on('change', function(e)
|
||||
{
|
||||
var input = $('#chore_id_text_input').val().toString();
|
||||
$('#chore_id_text_input').val(input);
|
||||
$('#chore_id').data('combobox').refresh();
|
||||
|
||||
var choreId = $(e.target).val();
|
||||
if (choreId)
|
||||
{
|
||||
Grocy.Components.ChoreCard.Refresh(choreId);
|
||||
Grocy.Components.DateTimePicker.GetInputElement().focus();
|
||||
Grocy.FrontendHelpers.ValidateForm('choretracking-form');
|
||||
}
|
||||
});
|
||||
|
||||
$('.combobox').combobox({
|
||||
appendId: '_text_input'
|
||||
});
|
||||
|
||||
$('#chore_id_text_input').focus();
|
||||
$('#chore_id_text_input').trigger('change');
|
||||
Grocy.FrontendHelpers.ValidateForm('choretracking-form');
|
||||
|
||||
$('#choretracking-form input').keyup(function (event)
|
||||
{
|
||||
Grocy.FrontendHelpers.ValidateForm('choretracking-form');
|
||||
});
|
||||
|
||||
$('#choretracking-form input').keydown(function(event)
|
||||
{
|
||||
if (event.keyCode === 13) //Enter
|
||||
{
|
||||
if (document.getElementById('choretracking-form').checkValidity() === false) //There is at least one validation error
|
||||
{
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#save-choretracking-button').click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Grocy.Components.DateTimePicker.GetInputElement().on('keypress', function(e)
|
||||
{
|
||||
Grocy.FrontendHelpers.ValidateForm('choretracking-form');
|
||||
});
|
21
public/viewjs/components/chorecard.js
Normal file
21
public/viewjs/components/chorecard.js
Normal file
@ -0,0 +1,21 @@
|
||||
Grocy.Components.ChoreCard = { };
|
||||
|
||||
Grocy.Components.ChoreCard.Refresh = function(choreId)
|
||||
{
|
||||
Grocy.Api.Get('chores/get-chore-details/' + choreId,
|
||||
function(choreDetails)
|
||||
{
|
||||
$('#chorecard-chore-name').text(choreDetails.chore.name);
|
||||
$('#chorecard-chore-last-tracked').text((choreDetails.last_tracked || L('never')));
|
||||
$('#chorecard-chore-last-tracked-timeago').text($.timeago(choreDetails.last_tracked || ''));
|
||||
$('#chorecard-chore-tracked-count').text((choreDetails.tracked_count || '0'));
|
||||
$('#chorecard-chore-last-done-by').text((choreDetails.last_done_by.display_name || L('Unknown')));
|
||||
|
||||
EmptyElementWhenMatches('#chorecard-chore-last-tracked-timeago', L('timeago_nan'));
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
console.error(xhr);
|
||||
}
|
||||
);
|
||||
};
|
@ -1,21 +0,0 @@
|
||||
Grocy.Components.HabitCard = { };
|
||||
|
||||
Grocy.Components.HabitCard.Refresh = function(habitId)
|
||||
{
|
||||
Grocy.Api.Get('habits/get-habit-details/' + habitId,
|
||||
function(habitDetails)
|
||||
{
|
||||
$('#habitcard-habit-name').text(habitDetails.habit.name);
|
||||
$('#habitcard-habit-last-tracked').text((habitDetails.last_tracked || L('never')));
|
||||
$('#habitcard-habit-last-tracked-timeago').text($.timeago(habitDetails.last_tracked || ''));
|
||||
$('#habitcard-habit-tracked-count').text((habitDetails.tracked_count || '0'));
|
||||
$('#habitcard-habit-last-done-by').text((habitDetails.last_done_by.display_name || L('Unknown')));
|
||||
|
||||
EmptyElementWhenMatches('#habitcard-habit-last-tracked-timeago', L('timeago_nan'));
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
console.error(xhr);
|
||||
}
|
||||
);
|
||||
};
|
@ -1,71 +0,0 @@
|
||||
$('#save-habit-button').on('click', function(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
|
||||
if (Grocy.EditMode === 'create')
|
||||
{
|
||||
Grocy.Api.Post('add-object/habits', $('#habit-form').serializeJSON(),
|
||||
function(result)
|
||||
{
|
||||
window.location.href = U('/habits');
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
||||
}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
Grocy.Api.Post('edit-object/habits/' + Grocy.EditObjectId, $('#habit-form').serializeJSON(),
|
||||
function(result)
|
||||
{
|
||||
window.location.href = U('/habits');
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
$('#habit-form input').keyup(function(event)
|
||||
{
|
||||
Grocy.FrontendHelpers.ValidateForm('habit-form');
|
||||
});
|
||||
|
||||
$('#habit-form input').keydown(function(event)
|
||||
{
|
||||
if (event.keyCode === 13) //Enter
|
||||
{
|
||||
if (document.getElementById('habit-form').checkValidity() === false) //There is at least one validation error
|
||||
{
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#save-habit-button').click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#name').focus();
|
||||
Grocy.FrontendHelpers.ValidateForm('habit-form');
|
||||
|
||||
$('.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(L('This means it is estimated that a new execution of this habit is tracked #1 days after the last was tracked', periodDays.toString()));
|
||||
$('#habit-period-type-info').removeClass('d-none');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#habit-period-type-info').addClass('d-none');
|
||||
}
|
||||
});
|
@ -1,82 +0,0 @@
|
||||
$('#save-habittracking-button').on('click', function(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
|
||||
var jsonForm = $('#habittracking-form').serializeJSON();
|
||||
|
||||
Grocy.Api.Get('habits/get-habit-details/' + jsonForm.habit_id,
|
||||
function (habitDetails)
|
||||
{
|
||||
Grocy.Api.Get('habits/track-habit-execution/' + jsonForm.habit_id + '?tracked_time=' + Grocy.Components.DateTimePicker.GetValue() + "&done_by=" + Grocy.Components.UserPicker.GetValue(),
|
||||
function(result)
|
||||
{
|
||||
toastr.success(L('Tracked execution of habit #1 on #2', habitDetails.habit.name, Grocy.Components.DateTimePicker.GetValue()));
|
||||
|
||||
$('#habit_id').val('');
|
||||
$('#habit_id_text_input').focus();
|
||||
$('#habit_id_text_input').val('');
|
||||
Grocy.Components.DateTimePicker.SetValue(moment().format('YYYY-MM-DD HH:mm:ss'));
|
||||
$('#habit_id_text_input').trigger('change');
|
||||
Grocy.FrontendHelpers.ValidateForm('habittracking-form');
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
console.error(xhr);
|
||||
}
|
||||
);
|
||||
},
|
||||
function(xhr)
|
||||
{
|
||||
console.error(xhr);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
$('#habit_id').on('change', function(e)
|
||||
{
|
||||
var input = $('#habit_id_text_input').val().toString();
|
||||
$('#habit_id_text_input').val(input);
|
||||
$('#habit_id').data('combobox').refresh();
|
||||
|
||||
var habitId = $(e.target).val();
|
||||
if (habitId)
|
||||
{
|
||||
Grocy.Components.HabitCard.Refresh(habitId);
|
||||
Grocy.Components.DateTimePicker.GetInputElement().focus();
|
||||
Grocy.FrontendHelpers.ValidateForm('habittracking-form');
|
||||
}
|
||||
});
|
||||
|
||||
$('.combobox').combobox({
|
||||
appendId: '_text_input'
|
||||
});
|
||||
|
||||
$('#habit_id_text_input').focus();
|
||||
$('#habit_id_text_input').trigger('change');
|
||||
Grocy.FrontendHelpers.ValidateForm('habittracking-form');
|
||||
|
||||
$('#habittracking-form input').keyup(function (event)
|
||||
{
|
||||
Grocy.FrontendHelpers.ValidateForm('habittracking-form');
|
||||
});
|
||||
|
||||
$('#habittracking-form input').keydown(function(event)
|
||||
{
|
||||
if (event.keyCode === 13) //Enter
|
||||
{
|
||||
if (document.getElementById('habittracking-form').checkValidity() === false) //There is at least one validation error
|
||||
{
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#save-habittracking-button').click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Grocy.Components.DateTimePicker.GetInputElement().on('keypress', function(e)
|
||||
{
|
||||
Grocy.FrontendHelpers.ValidateForm('habittracking-form');
|
||||
});
|
20
routes.php
20
routes.php
@ -38,13 +38,13 @@ $app->group('', function()
|
||||
$this->get('/recipe/{recipeId}', '\Grocy\Controllers\RecipesController:RecipeEditForm');
|
||||
$this->get('/recipe/{recipeId}/pos/{recipePosId}', '\Grocy\Controllers\RecipesController:RecipePosEditForm');
|
||||
|
||||
// Habit routes
|
||||
$this->get('/habitsoverview', '\Grocy\Controllers\HabitsController:Overview');
|
||||
$this->get('/habittracking', '\Grocy\Controllers\HabitsController:TrackHabitExecution');
|
||||
$this->get('/habitsanalysis', '\Grocy\Controllers\HabitsController:Analysis');
|
||||
// Chore routes
|
||||
$this->get('/choresoverview', '\Grocy\Controllers\ChoresController:Overview');
|
||||
$this->get('/choretracking', '\Grocy\Controllers\ChoresController:TrackChoreExecution');
|
||||
$this->get('/choresanalysis', '\Grocy\Controllers\ChoresController:Analysis');
|
||||
|
||||
$this->get('/habits', '\Grocy\Controllers\HabitsController:HabitsList');
|
||||
$this->get('/habit/{habitId}', '\Grocy\Controllers\HabitsController:HabitEditForm');
|
||||
$this->get('/chores', '\Grocy\Controllers\ChoresController:ChoresList');
|
||||
$this->get('/chore/{choreId}', '\Grocy\Controllers\ChoresController:ChoreEditForm');
|
||||
|
||||
// Battery routes
|
||||
$this->get('/batteriesoverview', '\Grocy\Controllers\BatteriesController:Overview');
|
||||
@ -93,10 +93,10 @@ $app->group('/api', function()
|
||||
$this->get('/recipes/add-not-fulfilled-products-to-shopping-list/{recipeId}', '\Grocy\Controllers\RecipesApiController:AddNotFulfilledProductsToShoppingList');
|
||||
$this->get('/recipes/consume-recipe/{recipeId}', '\Grocy\Controllers\RecipesApiController:ConsumeRecipe');
|
||||
|
||||
// Habits
|
||||
$this->get('/habits/track-habit-execution/{habitId}', '\Grocy\Controllers\HabitsApiController:TrackHabitExecution');
|
||||
$this->get('/habits/get-habit-details/{habitId}', '\Grocy\Controllers\HabitsApiController:HabitDetails');
|
||||
$this->get('/habits/get-current', '\Grocy\Controllers\HabitsApiController:Current');
|
||||
// Chores
|
||||
$this->get('/chores/track-chore-execution/{choreId}', '\Grocy\Controllers\ChoresApiController:TrackChoreExecution');
|
||||
$this->get('/chores/get-chore-details/{choreId}', '\Grocy\Controllers\ChoresApiController:ChoreDetails');
|
||||
$this->get('/chores/get-current', '\Grocy\Controllers\ChoresApiController:Current');
|
||||
|
||||
// Batteries
|
||||
$this->get('/batteries/track-charge-cycle/{batteryId}', '\Grocy\Controllers\BatteriesApiController:TrackChargeCycle');
|
||||
|
74
services/ChoresService.php
Normal file
74
services/ChoresService.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Services;
|
||||
|
||||
class ChoresService extends BaseService
|
||||
{
|
||||
const CHORE_TYPE_MANUALLY = 'manually';
|
||||
const CHORE_TYPE_DYNAMIC_REGULAR = 'dynamic-regular';
|
||||
|
||||
public function GetCurrent()
|
||||
{
|
||||
$sql = 'SELECT * from chores_current';
|
||||
return $this->DatabaseService->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
|
||||
}
|
||||
|
||||
public function GetChoreDetails(int $choreId)
|
||||
{
|
||||
if (!$this->ChoreExists($choreId))
|
||||
{
|
||||
throw new \Exception('Chore does not exist');
|
||||
}
|
||||
|
||||
$chore = $this->Database->chores($choreId);
|
||||
$choreTrackedCount = $this->Database->chores_log()->where('chore_id', $choreId)->count();
|
||||
$choreLastTrackedTime = $this->Database->chores_log()->where('chore_id', $choreId)->max('tracked_time');
|
||||
$nextExeuctionTime = $this->Database->chores_current()->where('chore_id', $choreId)->min('next_estimated_execution_time');
|
||||
|
||||
$lastChoreLogRow = $this->Database->chores_log()->where('chore_id = :1 AND tracked_time = :2', $choreId, $choreLastTrackedTime)->fetch();
|
||||
$lastDoneByUser = null;
|
||||
if ($lastChoreLogRow !== null && !empty($lastChoreLogRow))
|
||||
{
|
||||
$usersService = new UsersService();
|
||||
$users = $usersService->GetUsersAsDto();
|
||||
$lastDoneByUser = FindObjectInArrayByPropertyValue($users, 'id', $lastChoreLogRow->done_by_user_id);
|
||||
}
|
||||
|
||||
return array(
|
||||
'chore' => $chore,
|
||||
'last_tracked' => $choreLastTrackedTime,
|
||||
'tracked_count' => $choreTrackedCount,
|
||||
'last_done_by' => $lastDoneByUser,
|
||||
'next_estimated_execution_time' => $nextExeuctionTime
|
||||
);
|
||||
}
|
||||
|
||||
public function TrackChore(int $choreId, string $trackedTime, $doneBy = GROCY_USER_ID)
|
||||
{
|
||||
if (!$this->ChoreExists($choreId))
|
||||
{
|
||||
throw new \Exception('Chore does not exist');
|
||||
}
|
||||
|
||||
$userRow = $this->Database->users()->where('id = :1', $doneBy)->fetch();
|
||||
if ($userRow === null)
|
||||
{
|
||||
throw new \Exception('User does not exist');
|
||||
}
|
||||
|
||||
$logRow = $this->Database->chores_log()->createRow(array(
|
||||
'chore_id' => $choreId,
|
||||
'tracked_time' => $trackedTime,
|
||||
'done_by_user_id' => $doneBy
|
||||
));
|
||||
$logRow->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function ChoreExists($choreId)
|
||||
{
|
||||
$choreRow = $this->Database->chores()->where('id = :1', $choreId)->fetch();
|
||||
return $choreRow !== null;
|
||||
}
|
||||
}
|
@ -78,9 +78,9 @@ class DemoDataGeneratorService extends BaseService
|
||||
INSERT INTO recipes_pos (recipe_id, product_id, amount, qu_id, only_check_single_unit_in_stock) VALUES (4, 21, 200, 8, 1);
|
||||
INSERT INTO recipes_pos (recipe_id, product_id, amount, qu_id, only_check_single_unit_in_stock) VALUES (4, 22, 200, 8, 1);
|
||||
|
||||
INSERT INTO habits (name, period_type, period_days) VALUES ('{$localizationService->Localize('Changed towels in the bathroom')}', 'manually', 5); --1
|
||||
INSERT INTO habits (name, period_type, period_days) VALUES ('{$localizationService->Localize('Cleaned the kitchen floor')}', 'dynamic-regular', 7); --2
|
||||
INSERT INTO habits (name, period_type, period_days) VALUES ('{$localizationService->Localize('Lawn mowed in the garden')}', 'dynamic-regular', 21); --3
|
||||
INSERT INTO chores (name, period_type, period_days) VALUES ('{$localizationService->Localize('Changed towels in the bathroom')}', 'manually', 5); --1
|
||||
INSERT INTO chores (name, period_type, period_days) VALUES ('{$localizationService->Localize('Cleaned the kitchen floor')}', 'dynamic-regular', 7); --2
|
||||
INSERT INTO chores (name, period_type, period_days) VALUES ('{$localizationService->Localize('Lawn mowed in the garden')}', 'dynamic-regular', 21); --3
|
||||
|
||||
INSERT INTO batteries (name, description, used_in) VALUES ('{$localizationService->Localize('Battery')}1', '{$localizationService->Localize('Warranty ends')} 2023', '{$localizationService->Localize('TV remote control')}'); --1
|
||||
INSERT INTO batteries (name, description, used_in) VALUES ('{$localizationService->Localize('Battery')}2', '{$localizationService->Localize('Warranty ends')} 2022', '{$localizationService->Localize('Alarm clock')}'); --2
|
||||
@ -164,13 +164,13 @@ class DemoDataGeneratorService extends BaseService
|
||||
$stockService->AddProduct(22, 1, date('Y-m-d', strtotime('+200 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice());
|
||||
$stockService->AddMissingProductsToShoppingList();
|
||||
|
||||
$habitsService = new HabitsService();
|
||||
$habitsService->TrackHabit(1, date('Y-m-d H:i:s', strtotime('-5 days')));
|
||||
$habitsService->TrackHabit(1, date('Y-m-d H:i:s', strtotime('-10 days')));
|
||||
$habitsService->TrackHabit(1, date('Y-m-d H:i:s', strtotime('-15 days')));
|
||||
$habitsService->TrackHabit(2, date('Y-m-d H:i:s', strtotime('-10 days')));
|
||||
$habitsService->TrackHabit(2, date('Y-m-d H:i:s', strtotime('-20 days')));
|
||||
$habitsService->TrackHabit(3, date('Y-m-d H:i:s', strtotime('-17 days')));
|
||||
$choresService = new ChoresService();
|
||||
$choresService->TrackChore(1, date('Y-m-d H:i:s', strtotime('-5 days')));
|
||||
$choresService->TrackChore(1, date('Y-m-d H:i:s', strtotime('-10 days')));
|
||||
$choresService->TrackChore(1, date('Y-m-d H:i:s', strtotime('-15 days')));
|
||||
$choresService->TrackChore(2, date('Y-m-d H:i:s', strtotime('-10 days')));
|
||||
$choresService->TrackChore(2, date('Y-m-d H:i:s', strtotime('-20 days')));
|
||||
$choresService->TrackChore(3, date('Y-m-d H:i:s', strtotime('-17 days')));
|
||||
|
||||
$batteriesService = new BatteriesService();
|
||||
$batteriesService->TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-200 days')));
|
||||
|
@ -1,74 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Services;
|
||||
|
||||
class HabitsService extends BaseService
|
||||
{
|
||||
const HABIT_TYPE_MANUALLY = 'manually';
|
||||
const HABIT_TYPE_DYNAMIC_REGULAR = 'dynamic-regular';
|
||||
|
||||
public function GetCurrent()
|
||||
{
|
||||
$sql = 'SELECT * from habits_current';
|
||||
return $this->DatabaseService->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
|
||||
}
|
||||
|
||||
public function GetHabitDetails(int $habitId)
|
||||
{
|
||||
if (!$this->HabitExists($habitId))
|
||||
{
|
||||
throw new \Exception('Habit does not exist');
|
||||
}
|
||||
|
||||
$habit = $this->Database->habits($habitId);
|
||||
$habitTrackedCount = $this->Database->habits_log()->where('habit_id', $habitId)->count();
|
||||
$habitLastTrackedTime = $this->Database->habits_log()->where('habit_id', $habitId)->max('tracked_time');
|
||||
$nextExeuctionTime = $this->Database->habits_current()->where('habit_id', $habitId)->min('next_estimated_execution_time');
|
||||
|
||||
$lastHabitLogRow = $this->Database->habits_log()->where('habit_id = :1 AND tracked_time = :2', $habitId, $habitLastTrackedTime)->fetch();
|
||||
$lastDoneByUser = null;
|
||||
if ($lastHabitLogRow !== null && !empty($lastHabitLogRow))
|
||||
{
|
||||
$usersService = new UsersService();
|
||||
$users = $usersService->GetUsersAsDto();
|
||||
$lastDoneByUser = FindObjectInArrayByPropertyValue($users, 'id', $lastHabitLogRow->done_by_user_id);
|
||||
}
|
||||
|
||||
return array(
|
||||
'habit' => $habit,
|
||||
'last_tracked' => $habitLastTrackedTime,
|
||||
'tracked_count' => $habitTrackedCount,
|
||||
'last_done_by' => $lastDoneByUser,
|
||||
'next_estimated_execution_time' => $nextExeuctionTime
|
||||
);
|
||||
}
|
||||
|
||||
public function TrackHabit(int $habitId, string $trackedTime, $doneBy = GROCY_USER_ID)
|
||||
{
|
||||
if (!$this->HabitExists($habitId))
|
||||
{
|
||||
throw new \Exception('Habit does not exist');
|
||||
}
|
||||
|
||||
$userRow = $this->Database->users()->where('id = :1', $doneBy)->fetch();
|
||||
if ($userRow === null)
|
||||
{
|
||||
throw new \Exception('User does not exist');
|
||||
}
|
||||
|
||||
$logRow = $this->Database->habits_log()->createRow(array(
|
||||
'habit_id' => $habitId,
|
||||
'tracked_time' => $trackedTime,
|
||||
'done_by_user_id' => $doneBy
|
||||
));
|
||||
$logRow->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function HabitExists($habitId)
|
||||
{
|
||||
$habitRow = $this->Database->habits()->where('id = :1', $habitId)->fetch();
|
||||
return $habitRow !== null;
|
||||
}
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@if($mode == 'edit')
|
||||
@section('title', $L('Edit habit'))
|
||||
@section('title', $L('Edit chore'))
|
||||
@else
|
||||
@section('title', $L('Create habit'))
|
||||
@section('title', $L('Create chore'))
|
||||
@endif
|
||||
|
||||
@section('viewJsName', 'habitform')
|
||||
@section('viewJsName', 'choreform')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
@ -16,44 +16,44 @@
|
||||
<script>Grocy.EditMode = '{{ $mode }}';</script>
|
||||
|
||||
@if($mode == 'edit')
|
||||
<script>Grocy.EditObjectId = {{ $habit->id }};</script>
|
||||
<script>Grocy.EditObjectId = {{ $chore->id }};</script>
|
||||
@endif
|
||||
|
||||
<form id="habit-form" novalidate>
|
||||
<form id="chore-form" novalidate>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">{{ $L('Name') }}</label>
|
||||
<input type="text" class="form-control" required id="name" name="name" value="@if($mode == 'edit'){{ $habit->name }}@endif">
|
||||
<input type="text" class="form-control" required id="name" name="name" value="@if($mode == 'edit'){{ $chore->name }}@endif">
|
||||
<div class="invalid-feedback">{{ $L('A name is required') }}</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="description">{{ $L('Description') }}</label>
|
||||
<textarea class="form-control" rows="2" id="description" name="description">@if($mode == 'edit'){{ $habit->description }}@endif</textarea>
|
||||
<textarea class="form-control" rows="2" id="description" name="description">@if($mode == 'edit'){{ $chore->description }}@endif</textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="period_type">{{ $L('Period type') }}</label>
|
||||
<select required class="form-control input-group-habit-period-type" id="period_type" name="period_type">
|
||||
<select required class="form-control input-group-chore-period-type" id="period_type" name="period_type">
|
||||
@foreach($periodTypes as $periodType)
|
||||
<option @if($mode == 'edit' && $periodType == $habit->period_type) selected="selected" @endif value="{{ $periodType }}">{{ $L($periodType) }}</option>
|
||||
<option @if($mode == 'edit' && $periodType == $chore->period_type) selected="selected" @endif value="{{ $periodType }}">{{ $L($periodType) }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<div class="invalid-feedback">{{ $L('A period type is required') }}</div>
|
||||
</div>
|
||||
|
||||
@php if($mode == 'edit') { $value = $habit->period_days; } else { $value = 0; } @endphp
|
||||
@php if($mode == 'edit') { $value = $chore->period_days; } else { $value = 0; } @endphp
|
||||
@include('components.numberpicker', array(
|
||||
'id' => 'period_days',
|
||||
'label' => 'Period days',
|
||||
'value' => $value,
|
||||
'min' => '0',
|
||||
'additionalCssClasses' => 'input-group-habit-period-type',
|
||||
'additionalCssClasses' => 'input-group-chore-period-type',
|
||||
'invalidFeedback' => $L('This cannot be negative'),
|
||||
'additionalHtmlElements' => '<p id="habit-period-type-info" class="form-text text-muted small d-none"></p>'
|
||||
'additionalHtmlElements' => '<p id="chore-period-type-info" class="form-text text-muted small d-none"></p>'
|
||||
))
|
||||
|
||||
<button id="save-habit-button" type="submit" class="btn btn-success">{{ $L('Save') }}</button>
|
||||
<button id="save-chore-button" type="submit" class="btn btn-success">{{ $L('Save') }}</button>
|
||||
|
||||
</form>
|
||||
</div>
|
@ -1,15 +1,15 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('title', $L('Habits'))
|
||||
@section('activeNav', 'habits')
|
||||
@section('viewJsName', 'habits')
|
||||
@section('title', $L('Chores'))
|
||||
@section('activeNav', 'chores')
|
||||
@section('viewJsName', 'chores')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h1>
|
||||
@yield('title')
|
||||
<a class="btn btn-outline-dark" href="{{ $U('/habit/new') }}">
|
||||
<a class="btn btn-outline-dark" href="{{ $U('/chore/new') }}">
|
||||
<i class="fas fa-plus"></i> {{ $L('Add') }}
|
||||
</a>
|
||||
</h1>
|
||||
@ -25,7 +25,7 @@
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<table id="habits-table" class="table table-sm table-striped dt-responsive">
|
||||
<table id="chores-table" class="table table-sm table-striped dt-responsive">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
@ -36,27 +36,27 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($habits as $habit)
|
||||
@foreach($chores as $chore)
|
||||
<tr>
|
||||
<td class="fit-content">
|
||||
<a class="btn btn-info btn-sm" href="{{ $U('/habit/') }}{{ $habit->id }}">
|
||||
<a class="btn btn-info btn-sm" href="{{ $U('/chore/') }}{{ $chore->id }}">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
<a class="btn btn-danger btn-sm habit-delete-button" href="#" data-habit-id="{{ $habit->id }}" data-habit-name="{{ $habit->name }}">
|
||||
<a class="btn btn-danger btn-sm chore-delete-button" href="#" data-chore-id="{{ $chore->id }}" data-chore-name="{{ $chore->name }}">
|
||||
<i class="fas fa-trash"></i>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{{ $habit->name }}
|
||||
{{ $chore->name }}
|
||||
</td>
|
||||
<td>
|
||||
{{ $L($habit->period_type) }}
|
||||
{{ $L($chore->period_type) }}
|
||||
</td>
|
||||
<td>
|
||||
{{ $habit->period_days }}
|
||||
{{ $chore->period_days }}
|
||||
</td>
|
||||
<td>
|
||||
{{ $habit->description }}
|
||||
{{ $chore->description }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
@ -1,8 +1,8 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('title', $L('Habits analysis'))
|
||||
@section('activeNav', 'habitsanalysis')
|
||||
@section('viewJsName', 'habitsanalysis')
|
||||
@section('title', $L('Chores analysis'))
|
||||
@section('activeNav', 'choresanalysis')
|
||||
@section('viewJsName', 'choresanalysis')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
@ -13,11 +13,11 @@
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-xs-12 col-md-6 col-xl-3">
|
||||
<label for="habit-filter">{{ $L('Filter by habit') }}</label> <i class="fas fa-filter"></i>
|
||||
<select class="form-control" id="habit-filter">
|
||||
<label for="chore-filter">{{ $L('Filter by chore') }}</label> <i class="fas fa-filter"></i>
|
||||
<select class="form-control" id="chore-filter">
|
||||
<option value="all">{{ $L('All') }}</option>
|
||||
@foreach($habits as $habit)
|
||||
<option value="{{ $habit->id }}">{{ $habit->name }}</option>
|
||||
@foreach($chores as $chore)
|
||||
<option value="{{ $chore->id }}">{{ $chore->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
@ -29,27 +29,27 @@
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<table id="habits-analysis-table" class="table table-sm table-striped dt-responsive">
|
||||
<table id="chores-analysis-table" class="table table-sm table-striped dt-responsive">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ $L('Habit') }}</th>
|
||||
<th>{{ $L('Chore') }}</th>
|
||||
<th>{{ $L('Tracked time') }}</th>
|
||||
<th>{{ $L('Done by') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($habitsLog as $habitLogEntry)
|
||||
@foreach($choresLog as $choreLogEntry)
|
||||
<tr>
|
||||
<td>
|
||||
{{ FindObjectInArrayByPropertyValue($habits, 'id', $habitLogEntry->habit_id)->name }}
|
||||
{{ FindObjectInArrayByPropertyValue($chores, 'id', $choreLogEntry->chore_id)->name }}
|
||||
</td>
|
||||
<td>
|
||||
{{ $habitLogEntry->tracked_time }}
|
||||
<time class="timeago timeago-contextual" datetime="{{ $habitLogEntry->tracked_time }}"></time>
|
||||
{{ $choreLogEntry->tracked_time }}
|
||||
<time class="timeago timeago-contextual" datetime="{{ $choreLogEntry->tracked_time }}"></time>
|
||||
</td>
|
||||
<td>
|
||||
@if ($habitLogEntry->done_by_user_id !== null && !empty($habitLogEntry->done_by_user_id))
|
||||
{{ GetUserDisplayName(FindObjectInArrayByPropertyValue($users, 'id', $habitLogEntry->done_by_user_id)) }}
|
||||
@if ($choreLogEntry->done_by_user_id !== null && !empty($choreLogEntry->done_by_user_id))
|
||||
{{ GetUserDisplayName(FindObjectInArrayByPropertyValue($users, 'id', $choreLogEntry->done_by_user_id)) }}
|
||||
@else
|
||||
{{ $L('Unknown') }}
|
||||
@endif
|
72
views/choresoverview.blade.php
Normal file
72
views/choresoverview.blade.php
Normal file
@ -0,0 +1,72 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('title', $L('Chores overview'))
|
||||
@section('activeNav', 'choresoverview')
|
||||
@section('viewJsName', 'choresoverview')
|
||||
|
||||
@push('pageScripts')
|
||||
<script src="{{ $U('/node_modules/jquery-ui-dist/jquery-ui.min.js?v=', true) }}{{ $version }}"></script>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h1>@yield('title')</h1>
|
||||
<p id="info-due-chores" data-next-x-days="{{ $nextXDays }}" class="btn btn-lg btn-warning no-real-button responsive-button mr-2"></p>
|
||||
<p id="info-overdue-chores" class="btn btn-lg btn-danger no-real-button responsive-button"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-xs-12 col-md-6 col-xl-3">
|
||||
<label for="search">{{ $L('Search') }}</label> <i class="fas fa-search"></i>
|
||||
<input type="text" class="form-control" id="search">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<table id="chores-overview-table" class="table table-sm table-striped dt-responsive">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>{{ $L('Chore') }}</th>
|
||||
<th>{{ $L('Next estimated tracking') }}</th>
|
||||
<th>{{ $L('Last tracked') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($currentChores as $curentChoreEntry)
|
||||
<tr id="chore-{{ $curentChoreEntry->chore_id }}-row" class="@if(FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->period_type === \Grocy\Services\ChoresService::CHORE_TYPE_DYNAMIC_REGULAR && $curentChoreEntry->next_estimated_execution_time < date('Y-m-d H:i:s')) table-danger @elseif(FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->period_type === \Grocy\Services\ChoresService::CHORE_TYPE_DYNAMIC_REGULAR && $curentChoreEntry->next_estimated_execution_time < date('Y-m-d H:i:s', strtotime("+$nextXDays days"))) table-warning @endif">
|
||||
<td class="fit-content">
|
||||
<a class="btn btn-success btn-sm track-chore-button" href="#" data-toggle="tooltip" title="{{ $L('Track execution of chore #1', FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->name) }}"
|
||||
data-chore-id="{{ $curentChoreEntry->chore_id }}"
|
||||
data-chore-name="{{ FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->name }}">
|
||||
<i class="fas fa-play"></i>
|
||||
</a>
|
||||
<a class="btn btn-info btn-sm" href="{{ $U('/choresanalysis?chore=') }}{{ $curentChoreEntry->chore_id }}">
|
||||
<i class="fas fa-chart-line"></i>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{{ FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->name }}
|
||||
</td>
|
||||
<td>
|
||||
@if(FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->period_type === \Grocy\Services\ChoresService::CHORE_TYPE_DYNAMIC_REGULAR)
|
||||
<span id="chore-{{ $curentChoreEntry->chore_id }}-next-execution-time">{{ $curentChoreEntry->next_estimated_execution_time }}</span>
|
||||
<time id="chore-{{ $curentChoreEntry->chore_id }}-next-execution-time-timeago" class="timeago timeago-contextual" datetime="{{ $curentChoreEntry->next_estimated_execution_time }}"></time>
|
||||
@else
|
||||
...
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
<span id="chore-{{ $curentChoreEntry->chore_id }}-last-tracked-time">{{ $curentChoreEntry->last_tracked_time }}</span>
|
||||
<time id="chore-{{ $curentChoreEntry->chore_id }}-last-tracked-time-timeago" class="timeago timeago-contextual" datetime="{{ $curentChoreEntry->last_tracked_time }}"></time>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@stop
|
@ -1,25 +1,25 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('title', $L('Habit tracking'))
|
||||
@section('activeNav', 'habittracking')
|
||||
@section('viewJsName', 'habittracking')
|
||||
@section('title', $L('Chore tracking'))
|
||||
@section('activeNav', 'choretracking')
|
||||
@section('viewJsName', 'choretracking')
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-md-6 col-xl-4 pb-3">
|
||||
<h1>@yield('title')</h1>
|
||||
|
||||
<form id="habittracking-form" novalidate>
|
||||
<form id="choretracking-form" novalidate>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="habit_id">{{ $L('Habit') }}</label>
|
||||
<select class="form-control combobox" id="habit_id" name="habit_id" required>
|
||||
<label for="chore_id">{{ $L('Chore') }}</label>
|
||||
<select class="form-control combobox" id="chore_id" name="chore_id" required>
|
||||
<option value=""></option>
|
||||
@foreach($habits as $habit)
|
||||
<option value="{{ $habit->id }}">{{ $habit->name }}</option>
|
||||
@foreach($chores as $chore)
|
||||
<option value="{{ $chore->id }}">{{ $chore->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<div class="invalid-feedback">{{ $L('You have to select a habit') }}</div>
|
||||
<div class="invalid-feedback">{{ $L('You have to select a chore') }}</div>
|
||||
</div>
|
||||
|
||||
@include('components.datetimepicker', array(
|
||||
@ -39,13 +39,13 @@
|
||||
'prefillByUserId' => GROCY_USER_ID
|
||||
))
|
||||
|
||||
<button id="save-habittracking-button" type="submit" class="btn btn-success">{{ $L('OK') }}</button>
|
||||
<button id="save-choretracking-button" type="submit" class="btn btn-success">{{ $L('OK') }}</button>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6 col-xl-4">
|
||||
@include('components.habitcard')
|
||||
@include('components.chorecard')
|
||||
</div>
|
||||
</div>
|
||||
@stop
|
15
views/components/chorecard.blade.php
Normal file
15
views/components/chorecard.blade.php
Normal file
@ -0,0 +1,15 @@
|
||||
@push('componentScripts')
|
||||
<script src="{{ $U('/viewjs/components/chorecard.js', true) }}?v={{ $version }}"></script>
|
||||
@endpush
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<i class="fas fa-refresh"></i> {{ $L('Chore overview') }}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h3><span id="chorecard-chore-name"></span></h3>
|
||||
<strong>{{ $L('Tracked count') }}:</strong> <span id="chorecard-chore-tracked-count"></span><br>
|
||||
<strong>{{ $L('Last tracked') }}:</strong> <span id="chorecard-chore-last-tracked"></span> <time id="chorecard-chore-last-tracked-timeago" class="timeago timeago-contextual"></time><br>
|
||||
<strong>{{ $L('Last done by') }}:</strong> <span id="chorecard-chore-last-done-by"></span>
|
||||
</div>
|
||||
</div>
|
@ -1,15 +0,0 @@
|
||||
@push('componentScripts')
|
||||
<script src="{{ $U('/viewjs/components/habitcard.js', true) }}?v={{ $version }}"></script>
|
||||
@endpush
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<i class="fas fa-refresh"></i> {{ $L('Habit overview') }}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h3><span id="habitcard-habit-name"></span></h3>
|
||||
<strong>{{ $L('Tracked count') }}:</strong> <span id="habitcard-habit-tracked-count"></span><br>
|
||||
<strong>{{ $L('Last tracked') }}:</strong> <span id="habitcard-habit-last-tracked"></span> <time id="habitcard-habit-last-tracked-timeago" class="timeago timeago-contextual"></time><br>
|
||||
<strong>{{ $L('Last done by') }}:</strong> <span id="habitcard-habit-last-done-by"></span>
|
||||
</div>
|
||||
</div>
|
@ -1,72 +0,0 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('title', $L('Habits overview'))
|
||||
@section('activeNav', 'habitsoverview')
|
||||
@section('viewJsName', 'habitsoverview')
|
||||
|
||||
@push('pageScripts')
|
||||
<script src="{{ $U('/node_modules/jquery-ui-dist/jquery-ui.min.js?v=', true) }}{{ $version }}"></script>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h1>@yield('title')</h1>
|
||||
<p id="info-due-habits" data-next-x-days="{{ $nextXDays }}" class="btn btn-lg btn-warning no-real-button responsive-button mr-2"></p>
|
||||
<p id="info-overdue-habits" class="btn btn-lg btn-danger no-real-button responsive-button"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-xs-12 col-md-6 col-xl-3">
|
||||
<label for="search">{{ $L('Search') }}</label> <i class="fas fa-search"></i>
|
||||
<input type="text" class="form-control" id="search">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<table id="habits-overview-table" class="table table-sm table-striped dt-responsive">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>{{ $L('Habit') }}</th>
|
||||
<th>{{ $L('Next estimated tracking') }}</th>
|
||||
<th>{{ $L('Last tracked') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($currentHabits as $curentHabitEntry)
|
||||
<tr id="habit-{{ $curentHabitEntry->habit_id }}-row" class="@if(FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->period_type === \Grocy\Services\HabitsService::HABIT_TYPE_DYNAMIC_REGULAR && $curentHabitEntry->next_estimated_execution_time < date('Y-m-d H:i:s')) table-danger @elseif(FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->period_type === \Grocy\Services\HabitsService::HABIT_TYPE_DYNAMIC_REGULAR && $curentHabitEntry->next_estimated_execution_time < date('Y-m-d H:i:s', strtotime("+$nextXDays days"))) table-warning @endif">
|
||||
<td class="fit-content">
|
||||
<a class="btn btn-success btn-sm track-habit-button" href="#" data-toggle="tooltip" title="{{ $L('Track execution of habit #1', FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->name) }}"
|
||||
data-habit-id="{{ $curentHabitEntry->habit_id }}"
|
||||
data-habit-name="{{ FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->name }}">
|
||||
<i class="fas fa-play"></i>
|
||||
</a>
|
||||
<a class="btn btn-info btn-sm" href="{{ $U('/habitsanalysis?habit=') }}{{ $curentHabitEntry->habit_id }}">
|
||||
<i class="fas fa-chart-line"></i>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{{ FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->name }}
|
||||
</td>
|
||||
<td>
|
||||
@if(FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->period_type === \Grocy\Services\HabitsService::HABIT_TYPE_DYNAMIC_REGULAR)
|
||||
<span id="habit-{{ $curentHabitEntry->habit_id }}-next-execution-time">{{ $curentHabitEntry->next_estimated_execution_time }}</span>
|
||||
<time id="habit-{{ $curentHabitEntry->habit_id }}-next-execution-time-timeago" class="timeago timeago-contextual" datetime="{{ $curentHabitEntry->next_estimated_execution_time }}"></time>
|
||||
@else
|
||||
...
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
<span id="habit-{{ $curentHabitEntry->habit_id }}-last-tracked-time">{{ $curentHabitEntry->last_tracked_time }}</span>
|
||||
<time id="habit-{{ $curentHabitEntry->habit_id }}-last-tracked-time-timeago" class="timeago timeago-contextual" datetime="{{ $curentHabitEntry->last_tracked_time }}"></time>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@stop
|
@ -60,10 +60,10 @@
|
||||
<span class="nav-link-text">{{ $L('Stock overview') }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="{{ $L('Habits overview') }}" data-nav-for-page="habitsoverview">
|
||||
<a class="nav-link discrete-link" href="{{ $U('/habitsoverview') }}">
|
||||
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="{{ $L('Chores overview') }}" data-nav-for-page="choresoverview">
|
||||
<a class="nav-link discrete-link" href="{{ $U('/choresoverview') }}">
|
||||
<i class="fas fa-tachometer-alt"></i>
|
||||
<span class="nav-link-text">{{ $L('Habits overview') }}</span>
|
||||
<span class="nav-link-text">{{ $L('Chores overview') }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="{{ $L('Batteries overview') }}" data-nav-for-page="batteriesoverview">
|
||||
@ -103,10 +103,10 @@
|
||||
<span class="nav-link-text">{{ $L('Inventory') }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="{{ $L('Habit tracking') }}" data-nav-for-page="habittracking">
|
||||
<a class="nav-link discrete-link" href="{{ $U('/habittracking') }}">
|
||||
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="{{ $L('Chore tracking') }}" data-nav-for-page="choretracking">
|
||||
<a class="nav-link discrete-link" href="{{ $U('/choretracking') }}">
|
||||
<i class="fas fa-play"></i>
|
||||
<span class="nav-link-text">{{ $L('Habit tracking') }}</span>
|
||||
<span class="nav-link-text">{{ $L('Chore tracking') }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" data-toggle="tooltip" data-placement="right" title="{{ $L('Battery tracking') }}" data-nav-for-page="batterytracking">
|
||||
@ -140,10 +140,10 @@
|
||||
<span class="nav-link-text">{{ $L('Quantity units') }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li data-nav-for-page="habits" data-sub-menu-of="#top-nav-manager-master-data">
|
||||
<a class="nav-link discrete-link" href="{{ $U('/habits') }}">
|
||||
<li data-nav-for-page="chores" data-sub-menu-of="#top-nav-manager-master-data">
|
||||
<a class="nav-link discrete-link" href="{{ $U('/chores') }}">
|
||||
<i class="fas fa-sync-alt"></i>
|
||||
<span class="nav-link-text">{{ $L('Habits') }}</span>
|
||||
<span class="nav-link-text">{{ $L('Chores') }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li data-nav-for-page="batteries" data-sub-menu-of="#top-nav-manager-master-data">
|
||||
|
Loading…
x
Reference in New Issue
Block a user