work on ui; backend
This commit is contained in:
parent
1b30d21ae5
commit
a55d46cbed
@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\EntryRequest;
|
||||
use App\Models\Entry;
|
||||
use App\Models\Habit;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
@ -19,8 +21,27 @@ public function create(Habit $habit)
|
||||
]);
|
||||
}
|
||||
|
||||
public function store($request)
|
||||
public function store(EntryRequest $request)
|
||||
{
|
||||
$habit = Habit::find($request->input('habit-id'));
|
||||
|
||||
// If value doesn't exist (checkbox not checked), set it to '0', else '1'.
|
||||
if (is_null($request->input('value'))) {
|
||||
$value = 0;
|
||||
} elseif ($request->input('value') === "ON") {
|
||||
$value = 1;
|
||||
} else {
|
||||
$value = $request->input('value');
|
||||
}
|
||||
|
||||
Entry::create([
|
||||
'habit_id' => $habit->id,
|
||||
'value' => $value,
|
||||
'date' => $request->input('input-date'),
|
||||
'note' => $request->input('note'),
|
||||
]);
|
||||
|
||||
return redirect()->route('habits.show', $habit)->with('success');
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
|
@ -31,13 +31,13 @@ public function store(HabitsRequest $request)
|
||||
|
||||
$habit = new Habit($validata->all());
|
||||
$habit->user_id = $request->user()->id;
|
||||
|
||||
$habit->save();
|
||||
|
||||
// Category - add if a name is entered
|
||||
if (!is_null($validata->only('category')['category'])) {
|
||||
$category = Category::firstOrCreate(['name' => $validata->only('category')['category']]);
|
||||
$habit->category()->associate($category);
|
||||
$habit->save();
|
||||
}
|
||||
|
||||
// Tags
|
||||
@ -46,8 +46,9 @@ public function store(HabitsRequest $request)
|
||||
|
||||
foreach ($tagsArray as $tag) {
|
||||
$tag = Tag::firstOrCreate(['name' => $tag], ['habit_id' => $habit->id]);
|
||||
$habit->tags()->sync($tag);
|
||||
$habit->tags()->attach($tag);
|
||||
}
|
||||
$habit->save();
|
||||
}
|
||||
|
||||
return redirect()->route('habits.index')->with('status', 'created');
|
||||
|
23
app/Http/Requests/EntryRequest.php
Normal file
23
app/Http/Requests/EntryRequest.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class EntryRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'habit-id' => ['required', 'exists:habits,id'],
|
||||
'value' => ['nullable'],
|
||||
'input-date' => ['required', 'date'],
|
||||
'note' => ['nullable', 'string'],
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
@ -12,6 +12,8 @@ class Entry extends Model
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'habit_id',
|
||||
'value',
|
||||
'date',
|
||||
'note'
|
||||
];
|
||||
|
@ -11,8 +11,10 @@ public function up()
|
||||
$table->id();
|
||||
|
||||
$table->foreignId('habit_id')->constrained();
|
||||
|
||||
$table->float('value')->default(0);
|
||||
$table->date('date')->default(now());
|
||||
$table->string('note')->default("");
|
||||
$table->string('note')->default("")->nullable();
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
|
@ -23,7 +23,7 @@ public function run(): void
|
||||
->create();
|
||||
|
||||
Tag::factory()
|
||||
->count(10)
|
||||
->count(5)
|
||||
->create();
|
||||
|
||||
User::factory()->create([
|
||||
@ -35,7 +35,7 @@ public function run(): void
|
||||
|
||||
Habit::factory()
|
||||
->count(5)
|
||||
->has(Entry::factory()->count(50))
|
||||
->has(Entry::factory()->count(5))
|
||||
->create();
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
<x-app-layout>
|
||||
<x-header-h2> Insert Entry for {{$habit->name}}</x-header-h2>
|
||||
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="max-w-5xl mx-auto sm:px-6 lg:px-8">
|
||||
|
||||
<form action="{{route('entries.store')}}" method="post">
|
||||
@csrf
|
||||
|
||||
<div class="sm:px-6 lg:px-8 grid grid-cols-4 items-stretch sm:gap-6 lg:gap-8 py-4 mx-auto">
|
||||
<div class="sm:px-6 lg:px-8 grid grid-cols-3 items-stretch sm:gap-6 lg:gap-8 py-4 mx-auto">
|
||||
|
||||
<!-- To Do Type -->
|
||||
@if($habit->type === 'todo')
|
||||
@ -19,8 +20,9 @@
|
||||
</div>
|
||||
<div class="mx-auto">
|
||||
<input type="checkbox"
|
||||
class="rounded w-32 h-32 shadow-md bg-gray-50 dark:bg-gray-900 text-green-500 dark:text-green-600"
|
||||
name="is_done" id="is-done"
|
||||
class="rounded w-32 h-32 dark:bg-gray-900 border-gray-300 dark:border-gray-700 text-indigo-600 shadow-md
|
||||
focus:ring-indigo-500 dark:focus:ring-indigo-600 dark:focus:ring-offset-gray-800 duration-300"
|
||||
name="value" id="value" value="1"
|
||||
onclick="toggleCheckboxText(this)"/>
|
||||
</div>
|
||||
<div>
|
||||
@ -39,24 +41,26 @@ class="rounded w-32 h-32 shadow-md bg-gray-50 dark:bg-gray-900 text-green-500 da
|
||||
@endif
|
||||
|
||||
<!-- Note and Date -->
|
||||
<div class="col-span-3 bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg h-full">
|
||||
<div class="col-span-2 bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg h-full">
|
||||
<div class="p-6 text-gray-900 dark:text-gray-100">
|
||||
<div>
|
||||
<x-input-label for="note">Note</x-input-label>
|
||||
<textarea name="note" id="note" rows="2" placeholder="Adding a note is optional."
|
||||
class="w-full border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-sm disabled:opacity-50"></textarea>
|
||||
<textarea name="note" id="note" rows="2" placeholder="Adding a note is optional."
|
||||
class="w-full border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-sm disabled:opacity-50"></textarea>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<x-input-label for="input-date">Date</x-input-label>
|
||||
<x-text-input type="date" name="input-date" value="{{today()->format('Y-m-d')}}"
|
||||
max="{{today()->format('Y-m-d')}}">
|
||||
</x-text-input>
|
||||
</div>
|
||||
|
||||
<div class="float-right">
|
||||
<x-primary-button class="">Insert entry</x-primary-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="habit-id" value="{{$habit->id}}">
|
||||
<div class="float-right mt-auto mr-6">
|
||||
<x-primary-button class="">Insert entry</x-primary-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -66,7 +70,7 @@ class="w-full border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gr
|
||||
<script>
|
||||
var checkboxText = document.getElementById('done-text');
|
||||
|
||||
toggleCheckboxText(document.getElementById('is-done')); // Run function once to make sure text matches on reload
|
||||
toggleCheckboxText(document.getElementById('value')); // Run function once to make sure text matches on reload
|
||||
|
||||
function toggleCheckboxText(checkbox) {
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
<div>
|
||||
<x-input-label for="name" :value="__('Name')"/>
|
||||
<x-text-input id="name" class="block mt-1 w-full" type="text" name="name"
|
||||
placeholder="Habit name" required
|
||||
placeholder="Swimming" required
|
||||
:value="old('name')" required autofocus autocomplete="name"/>
|
||||
<x-input-error :messages="$errors->get('name')" class="mt-2"/>
|
||||
</div>
|
||||
@ -25,7 +25,7 @@
|
||||
<div class="mt-6">
|
||||
<x-input-label for="category" value="Category"/>
|
||||
<x-text-input id="category" class="block mt-1 w-full" type="text" name="category"
|
||||
placeholder="Category name"
|
||||
placeholder="Exercise"
|
||||
:value="old('category')" autocomplete="category"/>
|
||||
<x-input-error :messages="$errors->get('category')" class="mt-2"/>
|
||||
</div>
|
||||
@ -34,7 +34,7 @@
|
||||
<div class="mt-6">
|
||||
<x-input-label for="tag" value="Tags"/>
|
||||
<x-text-input id="tag" class="block mt-1 w-full" type="text" name="tags"
|
||||
placeholder="First tag, second tag, guten tag..."
|
||||
placeholder="Exercise, swimming, health"
|
||||
:value="old('tag')" autocomplete="tag"/>
|
||||
<x-input-error :messages="$errors->get('tag')" class="mt-2"/>
|
||||
</div>
|
||||
@ -45,13 +45,13 @@
|
||||
<!-- Type -->
|
||||
<div class="">
|
||||
<x-input-label for="habit_type" value="Habit Type"></x-input-label>
|
||||
<div class="flex items-center mb-1">
|
||||
<div class="flex items-center mb-1 mt-1">
|
||||
|
||||
<!-- Radio button: todo-->
|
||||
<input id="habit-type-1" type="radio" value="todo" name="type"
|
||||
onclick="toggleHabitValueSuffix(true)" checked
|
||||
class="w-4 h-4 text-blue-600 bg-gray-50 border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
|
||||
<label for="habit-type-1" class="ml-2">Todo / done</label>
|
||||
<label for="habit-type-1" class="ml-2">Todo</label>
|
||||
</div>
|
||||
|
||||
<!-- Radio button: value-->
|
||||
@ -59,29 +59,34 @@ class="w-4 h-4 text-blue-600 bg-gray-50 border-gray-300 focus:ring-blue-500 dark
|
||||
<input id="habit-type-2" type="radio" value="value" name="type"
|
||||
onclick="toggleHabitValueSuffix(false)"
|
||||
class="w-4 h-4 text-blue-600 bg-gray-50 border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
|
||||
<label for="habit-type-2" class="ml-2 ">Value / suffix</label>
|
||||
<label for="habit-type-2" class="ml-2 ">Amount and suffix</label>
|
||||
</div>
|
||||
|
||||
<!-- Value / Suffix -->
|
||||
<x-input-label for="value" value="Value and suffix" class="mt-4"
|
||||
id="habit-suffix-label"/>
|
||||
<!-- Radio button: barely know her -->
|
||||
{{-- <div class="flex items-center mb-1">--}}
|
||||
{{-- <input id="habit-type-3" type="radio" value="track" name="type"--}}
|
||||
{{-- onclick="toggleTracker()"--}}
|
||||
{{-- class="w-4 h-4 text-blue-600 bg-gray-50 border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">--}}
|
||||
{{-- <label for="habit-type-3" class="ml-2 ">Trackable</label>--}}
|
||||
{{-- </div>--}}
|
||||
|
||||
<x-text-input id="habit-value-amount" class="inline-block mt-1 w-20" type="number"
|
||||
placeholder="" min="0" value="1"
|
||||
name="value" required disabled/>
|
||||
<x-input-error :messages="$errors->get('value')" class="mt-2"/>
|
||||
<!-- Value / Suffix -->
|
||||
<x-input-label for="value" value="Suffix" class="mt-4"
|
||||
id="habit-suffix-label"/>
|
||||
|
||||
<x-text-input id="habit-suffix-name" class="inline-block mt-1 disabled:opacity-50 w-1/2"
|
||||
type="text" name="suffix" disabled required
|
||||
placeholder="Suffix"
|
||||
placeholder="minutes"
|
||||
:value="old('suffix')" autocomplete="suffix"/>
|
||||
<x-input-error :messages="$errors->get('suffix')" class="mt-2"/>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Schedule -->
|
||||
<div class="mt-6">
|
||||
<x-input-label for="schedule-value" value="Schedule Recurrence"></x-input-label>
|
||||
<div class="text-sm my-2 text-gray-700 mr-20">
|
||||
The recurrence value determines how often you will be inquired about this habit. Note: this is different from setting a goal.
|
||||
</div>
|
||||
<div class="inline-block mt-1 pr-1">
|
||||
Every
|
||||
</div>
|
||||
@ -112,19 +117,19 @@ class="inline-block w-fit border-gray-300 dark:border-gray-700 dark:bg-gray-900
|
||||
<x-pagecard>
|
||||
<div class="">
|
||||
<x-input-label value="Goal Type"></x-input-label>
|
||||
<div class="text-sm my-3">
|
||||
Adding a goal changes the display mode from the value and suffix to a calculated
|
||||
percentage.
|
||||
<div class="text-sm my-2 text-gray-700">
|
||||
Setting a goal will show you how well you're doing, based on the entries made.
|
||||
If you only want to record the frequency of an activity, you don't need to set a goal.
|
||||
</div>
|
||||
<div class="flex items-center mb-1">
|
||||
<input id="goal-type-1" type="radio" value="none" name="goal_type"
|
||||
onclick="toggleGoalSchedule(true)"
|
||||
onclick="toggleGoalSchedule(true)" checked
|
||||
class="w-4 h-4 text-blue-600 bg-gray-50 border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
|
||||
<label for="goal-type-1" class="ml-2">No goal</label>
|
||||
</div>
|
||||
<div class="flex items-center mb-1">
|
||||
<input id="goal-type-2" type="radio" value="schedule" name="goal_type"
|
||||
checked onclick="toggleGoalSchedule(true)"
|
||||
onclick="toggleGoalSchedule(true)"
|
||||
class="w-4 h-4 text-blue-600 bg-gray-50 border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
|
||||
<label for="goal-type-2" class="ml-2 ">Same as schedule</label>
|
||||
</div>
|
||||
@ -159,7 +164,7 @@ class="inline-block w-fit border-gray-300 dark:border-gray-700 dark:bg-gray-900
|
||||
starting
|
||||
</div>
|
||||
|
||||
<x-text-input type="date" class="inline-block mt-1" name="goal_start" id="goal_start"
|
||||
<x-text-input type="date" class="inline-block mt-1" name="goal-start" id="goal-start"
|
||||
value="{{$today}}" disabled
|
||||
required></x-text-input>
|
||||
</div>
|
||||
@ -182,16 +187,28 @@ class="inline-block w-fit border-gray-300 dark:border-gray-700 dark:bg-gray-900
|
||||
|
||||
|
||||
<script>
|
||||
// const habit_value = document.getElementById('habit-value-amount');
|
||||
const habit_suffix = document.getElementById('habit-suffix-name');
|
||||
|
||||
const goal_amount = document.getElementById('goal-schedule-amount');
|
||||
const goal_unit = document.getElementById('goal-schedule-unit');
|
||||
const goal_start = document.getElementById('goal_start');
|
||||
|
||||
function toggleHabitValueSuffix(value) {
|
||||
document.getElementById('habit-value-amount').disabled = value;
|
||||
document.getElementById('habit-suffix-name').disabled = value;
|
||||
// habit_value.disabled = value;
|
||||
habit_suffix.disabled = value;
|
||||
}
|
||||
|
||||
function toggleGoalSchedule(value) {
|
||||
document.getElementById('goal-schedule-amount').disabled = value;
|
||||
document.getElementById('goal-schedule-unit').disabled = value;
|
||||
document.getElementById('goal_start').disabled = value;
|
||||
goal_amount.disabled = value;
|
||||
goal_unit.disabled = value;
|
||||
goal_start.disabled = value;
|
||||
}
|
||||
|
||||
// function toggleTracker() {
|
||||
// habit_value.disabled = true;
|
||||
// habit_suffix.disabled = !value;
|
||||
// }
|
||||
</script>
|
||||
|
||||
</x-app-layout>
|
||||
|
@ -21,6 +21,9 @@
|
||||
<table class="table-auto text-left text-gray-700 dark:text-gray-400">
|
||||
<thead class="text-gray-900 bg-gray-100 dark:bg-gray-700 dark:text-gray-200">
|
||||
<tr>
|
||||
<th scope="col" class="px-4 py-2">
|
||||
Value
|
||||
</th>
|
||||
<th scope="col" class="px-4 py-2">
|
||||
Date
|
||||
</th>
|
||||
@ -32,6 +35,18 @@
|
||||
<tbody>
|
||||
@foreach($entries as $entry)
|
||||
<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700 even:bg-gray-50 hover:bg-gray-100 dark:hover:bg-gray-600">
|
||||
<td class="px-4 py-2">
|
||||
@if($habit->type === 'todo')
|
||||
@if($entry->value == 0)
|
||||
Not done
|
||||
@else
|
||||
Done
|
||||
@endif
|
||||
@else
|
||||
{{$entry->value . $habit->suffix}}
|
||||
@endif
|
||||
|
||||
</td>
|
||||
<td class="text-left px-4 py-2">
|
||||
{{$entry->date}}
|
||||
</td>
|
||||
|
Loading…
x
Reference in New Issue
Block a user