mirror of https://github.com/kcal-app/kcal.git
Refactor goals with a "frequency" attribute
This commit is contained in:
parent
a26a4c71d0
commit
3a36f648db
|
|
@ -24,8 +24,7 @@ class GoalController extends Controller
|
||||||
}
|
}
|
||||||
return view('goals.index')
|
return view('goals.index')
|
||||||
->with('date', $date)
|
->with('date', $date)
|
||||||
->with('goals', Auth::user()->getGoalsByTime($date))
|
->with('goals', Auth::user()->getGoalsByTime($date));
|
||||||
->with('goalOptions', Goal::getGoalOptions());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -61,7 +60,8 @@ class GoalController extends Controller
|
||||||
{
|
{
|
||||||
return view('goals.edit')
|
return view('goals.edit')
|
||||||
->with('goal', $goal)
|
->with('goal', $goal)
|
||||||
->with('goalOptions', Goal::getGoalOptions());
|
->with('nameOptions', Goal::getNameOptions())
|
||||||
|
->with('frequencyOptions', Goal::$frequencyOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -72,11 +72,11 @@ class GoalController extends Controller
|
||||||
$attributes = $request->validate([
|
$attributes = $request->validate([
|
||||||
'from' => ['nullable', 'date'],
|
'from' => ['nullable', 'date'],
|
||||||
'to' => ['nullable', 'date'],
|
'to' => ['nullable', 'date'],
|
||||||
'goal' => ['required', 'string'],
|
'frequency' => ['nullable', 'string'],
|
||||||
'amount' => ['required', 'numeric'],
|
'name' => ['required', 'string'],
|
||||||
|
'goal' => ['required', 'numeric'],
|
||||||
]);
|
]);
|
||||||
$goal->fill(array_filter($attributes))
|
$goal->fill($attributes)->user()->associate(Auth::user());
|
||||||
->user()->associate(Auth::user());
|
|
||||||
$goal->save();
|
$goal->save();
|
||||||
session()->flash('message', "Goal updated!");
|
session()->flash('message', "Goal updated!");
|
||||||
return redirect()->route('goals.show', $goal);
|
return redirect()->route('goals.show', $goal);
|
||||||
|
|
@ -87,9 +87,7 @@ class GoalController extends Controller
|
||||||
*/
|
*/
|
||||||
public function delete(Goal $goal): View
|
public function delete(Goal $goal): View
|
||||||
{
|
{
|
||||||
return view('goals.delete')
|
return view('goals.delete')->with('goal', $goal);
|
||||||
->with('goal', $goal)
|
|
||||||
->with('goalOptions', Goal::getGoalOptions());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -14,19 +14,22 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
* @property int $user_id
|
* @property int $user_id
|
||||||
* @property \datetime|null $from
|
* @property \datetime|null $from
|
||||||
* @property \datetime|null $to
|
* @property \datetime|null $to
|
||||||
* @property string $goal
|
* @property string|null $frequency
|
||||||
* @property float $amount
|
* @property string $name
|
||||||
|
* @property float $goal
|
||||||
* @property \Illuminate\Support\Carbon|null $created_at
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read string $summary
|
||||||
* @property-read \App\Models\User $user
|
* @property-read \App\Models\User $user
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|Goal newModelQuery()
|
* @method static \Illuminate\Database\Eloquent\Builder|Goal newModelQuery()
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|Goal newQuery()
|
* @method static \Illuminate\Database\Eloquent\Builder|Goal newQuery()
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|Goal query()
|
* @method static \Illuminate\Database\Eloquent\Builder|Goal query()
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereAmount($value)
|
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereCreatedAt($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereFrequency($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereFrom($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereFrom($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereGoal($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereGoal($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereId($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereName($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereTo($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereTo($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereUpdatedAt($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereUpdatedAt($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereUserId($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereUserId($value)
|
||||||
|
|
@ -36,14 +39,22 @@ final class Goal extends Model
|
||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supported options for thr frequency attribute.
|
||||||
|
*/
|
||||||
|
public static array $frequencyOptions = [
|
||||||
|
['value' => 'daily', 'label' => 'daily'],
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
|
'frequency',
|
||||||
'from',
|
'from',
|
||||||
'to',
|
|
||||||
'goal',
|
'goal',
|
||||||
'amount',
|
'name',
|
||||||
|
'to',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -51,8 +62,15 @@ final class Goal extends Model
|
||||||
*/
|
*/
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'from' => 'datetime:Y-m-d',
|
'from' => 'datetime:Y-m-d',
|
||||||
|
'goal' => 'float',
|
||||||
'to' => 'datetime:Y-m-d',
|
'to' => 'datetime:Y-m-d',
|
||||||
'amount' => 'float',
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
protected $appends = [
|
||||||
|
'summary',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -62,18 +80,20 @@ final class Goal extends Model
|
||||||
return $this->belongsTo(User::class);
|
return $this->belongsTo(User::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getSummaryAttribute(): string {
|
||||||
|
$nameOptions = self::getNameOptions();
|
||||||
|
return number_format($this->goal) . "{$nameOptions[$this->name]['unit']} {$nameOptions[$this->name]['label']} {$this->frequency}";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get options for the "goal" column.
|
* Get options for the "name" column.
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public static function getGoalOptions(): array {
|
public static function getNameOptions(): array {
|
||||||
$options = [];
|
$options = [];
|
||||||
foreach (Nutrients::$all as $nutrient) {
|
foreach (Nutrients::$all as $nutrient) {
|
||||||
$key = "{$nutrient['value']}_per_day";
|
$options[$nutrient['value']] = [
|
||||||
$options[$key] = [
|
'value' => $nutrient['value'],
|
||||||
'value' => $key,
|
'label' => $nutrient['label'],
|
||||||
'label' => "{$nutrient['value']} per day",
|
|
||||||
'unit' => $nutrient['unit'],
|
'unit' => $nutrient['unit'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -79,7 +80,7 @@ final class User extends Authenticatable
|
||||||
*/
|
*/
|
||||||
public function getGoalsByTime(?Carbon $date = null): array {
|
public function getGoalsByTime(?Carbon $date = null): array {
|
||||||
$now = $date ?? Carbon::now();
|
$now = $date ?? Carbon::now();
|
||||||
$goals = ['past' => [], 'present' => [], 'future' => []];
|
$goals = ['past' => new Collection(), 'present' => new Collection(), 'future' => new Collection()];
|
||||||
Goal::all()->where('user_id', Auth::user()->id)
|
Goal::all()->where('user_id', Auth::user()->id)
|
||||||
->each(function ($item) use(&$goals, $now) {
|
->each(function ($item) use(&$goals, $now) {
|
||||||
if ($item->to && $now->isAfter($item->to)) {
|
if ($item->to && $now->isAfter($item->to)) {
|
||||||
|
|
|
||||||
|
|
@ -10,21 +10,21 @@ class Nutrients
|
||||||
public static float $gramsPerOunce = 28.349523125;
|
public static float $gramsPerOunce = 28.349523125;
|
||||||
|
|
||||||
public static array $all = [
|
public static array $all = [
|
||||||
['value' => 'calories', 'unit' => null],
|
['value' => 'calories', 'label' => 'calories', 'unit' => null],
|
||||||
['value' => 'fat', 'unit' => 'g'],
|
['value' => 'carbohydrates', 'label' => 'carbohydrates', 'unit' => 'g'],
|
||||||
['value' => 'cholesterol', 'unit' => 'mg'],
|
['value' => 'cholesterol', 'label' => 'cholesterol', 'unit' => 'mg'],
|
||||||
['value' => 'sodium', 'unit' => 'mg'],
|
['value' => 'fat', 'label' => 'fat', 'unit' => 'g'],
|
||||||
['value' => 'carbohydrates', 'unit' => 'g'],
|
['value' => 'protein', 'label' => 'protein', 'unit' => 'g'],
|
||||||
['value' => 'protein', 'unit' => 'g'],
|
['value' => 'sodium', 'label' => 'sodium', 'unit' => 'mg'],
|
||||||
];
|
];
|
||||||
|
|
||||||
public static array $units = [
|
public static array $units = [
|
||||||
['value' => 'tsp', 'label' => 'tsp.'],
|
|
||||||
['value' => 'tbsp', 'label' => 'tbsp.'],
|
|
||||||
['value' => 'cup', 'label' => 'cup'],
|
['value' => 'cup', 'label' => 'cup'],
|
||||||
['value' => 'oz', 'label' => 'oz'],
|
|
||||||
['value' => 'gram', 'label' => 'grams'],
|
['value' => 'gram', 'label' => 'grams'],
|
||||||
|
['value' => 'oz', 'label' => 'oz'],
|
||||||
['value' => 'serving', 'label' => 'servings'],
|
['value' => 'serving', 'label' => 'servings'],
|
||||||
|
['value' => 'tbsp', 'label' => 'tbsp.'],
|
||||||
|
['value' => 'tsp', 'label' => 'tsp.'],
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,9 @@ class CreateGoalsTable extends Migration
|
||||||
$table->foreignIdFor(User::class)->constrained()->cascadeOnUpdate()->cascadeOnDelete();
|
$table->foreignIdFor(User::class)->constrained()->cascadeOnUpdate()->cascadeOnDelete();
|
||||||
$table->date('from')->nullable();
|
$table->date('from')->nullable();
|
||||||
$table->date('to')->nullable();
|
$table->date('to')->nullable();
|
||||||
$table->string('goal');
|
$table->string('frequency')->nullable();
|
||||||
$table->unsignedFloat('amount');
|
$table->string('name');
|
||||||
|
$table->unsignedFloat('goal');
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
$table->index('user_id');
|
$table->index('user_id');
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
@method('delete')
|
@method('delete')
|
||||||
@csrf
|
@csrf
|
||||||
<div class="text-lg pb-3">
|
<div class="text-lg pb-3">
|
||||||
Are you sure what to delete your <span class="font-extrabold">{{ $goalOptions[$goal->goal]['label'] }}</span> goal?
|
Are you sure what to delete your <span class="font-extrabold">{{ $goal->summary }}</span> goal?
|
||||||
</div>
|
</div>
|
||||||
<x-inputs.button class="bg-red-800 hover:bg-red-700">
|
<x-inputs.button class="bg-red-800 hover:bg-red-700">
|
||||||
Yes, delete
|
Yes, delete
|
||||||
|
|
|
||||||
|
|
@ -32,24 +32,36 @@
|
||||||
:value="old('to', $goal->to)" />
|
:value="old('to', $goal->to)" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Amount -->
|
<!-- Frequency -->
|
||||||
<div class="flex-auto">
|
<div class="flex-auto">
|
||||||
<x-inputs.label for="amount" value="Amount" />
|
<x-inputs.label for="frequency" value="Frequency" />
|
||||||
<x-inputs.input name="amount"
|
<x-inputs.select name="frequency"
|
||||||
type="number"
|
class="block w-full"
|
||||||
step="any"
|
:options="$frequencyOptions"
|
||||||
class="block w-full"
|
:selectedValue="old('frequency', $goal->frequency)">
|
||||||
:value="old('amount', $goal->amount)"/>
|
</x-inputs.select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Name -->
|
||||||
|
<div class="flex-auto">
|
||||||
|
<x-inputs.label for="name" value="Trackable" />
|
||||||
|
<x-inputs.select name="name"
|
||||||
|
class="block w-full"
|
||||||
|
:options="$nameOptions"
|
||||||
|
:selectedValue="old('name', $goal->name)"
|
||||||
|
required>
|
||||||
|
</x-inputs.select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Goal -->
|
<!-- Goal -->
|
||||||
<div class="flex-auto">
|
<div class="flex-auto">
|
||||||
<x-inputs.label for="goal" value="Goal" />
|
<x-inputs.label for="goal" value="Goal" />
|
||||||
<x-inputs.select name="goal"
|
<x-inputs.input name="goal"
|
||||||
class="block w-full"
|
type="number"
|
||||||
:options="$goalOptions"
|
step="any"
|
||||||
:selectedValue="old('goal', $goal->goal)">
|
class="block w-full"
|
||||||
</x-inputs.select>
|
:value="old('goal', $goal->goal)"
|
||||||
|
required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -36,10 +36,9 @@
|
||||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||||
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
|
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
|
||||||
<div class="p-6 bg-white border-b border-gray-200">
|
<div class="p-6 bg-white border-b border-gray-200">
|
||||||
<h3 class="text-xl font-semibold text-gray-800">Goals</h3>
|
|
||||||
@forelse($goals['present'] as $goal)
|
@forelse($goals['present'] as $goal)
|
||||||
<details>
|
<details>
|
||||||
<summary>{{ number_format($goal->amount, 0) }}{{ $goalOptions[$goal->goal]['unit'] }} {{ $goalOptions[$goal->goal]['label'] }}</summary>
|
<summary>{{ $goal->summary }}</summary>
|
||||||
TODO: Details for the day!
|
TODO: Details for the day!
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<a class="text-gray-500 hover:text-gray-700 hover:border-gray-300 text-sm"
|
<a class="text-gray-500 hover:text-gray-700 hover:border-gray-300 text-sm"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<x-app-layout>
|
<x-app-layout>
|
||||||
<x-slot name="header">
|
<x-slot name="header">
|
||||||
<h2 class="font-semibold text-xl text-gray-800 leading-tight flex flex-auto">
|
<h2 class="font-semibold text-xl text-gray-800 leading-tight flex flex-auto">
|
||||||
TODO: GOAL NAME
|
{{ $goal->summary }}
|
||||||
<a class="ml-2 text-gray-500 hover:text-gray-700 hover:border-gray-300 text-sm"
|
<a class="ml-2 text-gray-500 hover:text-gray-700 hover:border-gray-300 text-sm"
|
||||||
href="{{ route('goals.edit', $goal) }}">
|
href="{{ route('goals.edit', $goal) }}">
|
||||||
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue