Merge remote-tracking branch 'origin/main' into demo

This commit is contained in:
Christopher C. Wells 2021-05-24 07:45:59 -07:00
commit 13b10038d7
41 changed files with 1489 additions and 1372 deletions

View File

@ -3,6 +3,9 @@ on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
test:
runs-on: ubuntu-latest

View File

@ -63,6 +63,7 @@ namespace PHPSTORM_META {
'Illuminate\Contracts\Pipeline\Hub' => \Illuminate\Pipeline\Hub::class,
'Illuminate\Contracts\Queue\EntityResolver' => \Illuminate\Database\Eloquent\QueueEntityResolver::class,
'Illuminate\Contracts\Routing\ResponseFactory' => \Illuminate\Routing\ResponseFactory::class,
'Illuminate\Contracts\Validation\UncompromisedVerifier' => \Illuminate\Validation\NotPwnedVerifier::class,
'Illuminate\Database\Console\DbCommand' => \Illuminate\Database\Console\DbCommand::class,
'Illuminate\Foundation\Mix' => \Illuminate\Foundation\Mix::class,
'Illuminate\Foundation\PackageManifest' => \Illuminate\Foundation\PackageManifest::class,
@ -88,7 +89,6 @@ namespace PHPSTORM_META {
'auth.password.broker' => \Illuminate\Auth\Passwords\PasswordBroker::class,
'blade.compiler' => \Illuminate\View\Compilers\BladeCompiler::class,
'cache' => \Illuminate\Cache\CacheManager::class,
'cache.dynamodb.client' => \Aws\DynamoDb\DynamoDbClient::class,
'cache.store' => \Illuminate\Cache\Repository::class,
'command.auth.resets.clear' => \Illuminate\Auth\Console\ClearResetsCommand::class,
'command.cache.clear' => \Illuminate\Cache\Console\ClearCommand::class,
@ -272,6 +272,7 @@ namespace PHPSTORM_META {
'Illuminate\Contracts\Pipeline\Hub' => \Illuminate\Pipeline\Hub::class,
'Illuminate\Contracts\Queue\EntityResolver' => \Illuminate\Database\Eloquent\QueueEntityResolver::class,
'Illuminate\Contracts\Routing\ResponseFactory' => \Illuminate\Routing\ResponseFactory::class,
'Illuminate\Contracts\Validation\UncompromisedVerifier' => \Illuminate\Validation\NotPwnedVerifier::class,
'Illuminate\Database\Console\DbCommand' => \Illuminate\Database\Console\DbCommand::class,
'Illuminate\Foundation\Mix' => \Illuminate\Foundation\Mix::class,
'Illuminate\Foundation\PackageManifest' => \Illuminate\Foundation\PackageManifest::class,
@ -297,7 +298,6 @@ namespace PHPSTORM_META {
'auth.password.broker' => \Illuminate\Auth\Passwords\PasswordBroker::class,
'blade.compiler' => \Illuminate\View\Compilers\BladeCompiler::class,
'cache' => \Illuminate\Cache\CacheManager::class,
'cache.dynamodb.client' => \Aws\DynamoDb\DynamoDbClient::class,
'cache.store' => \Illuminate\Cache\Repository::class,
'command.auth.resets.clear' => \Illuminate\Auth\Console\ClearResetsCommand::class,
'command.cache.clear' => \Illuminate\Cache\Console\ClearCommand::class,
@ -481,6 +481,7 @@ namespace PHPSTORM_META {
'Illuminate\Contracts\Pipeline\Hub' => \Illuminate\Pipeline\Hub::class,
'Illuminate\Contracts\Queue\EntityResolver' => \Illuminate\Database\Eloquent\QueueEntityResolver::class,
'Illuminate\Contracts\Routing\ResponseFactory' => \Illuminate\Routing\ResponseFactory::class,
'Illuminate\Contracts\Validation\UncompromisedVerifier' => \Illuminate\Validation\NotPwnedVerifier::class,
'Illuminate\Database\Console\DbCommand' => \Illuminate\Database\Console\DbCommand::class,
'Illuminate\Foundation\Mix' => \Illuminate\Foundation\Mix::class,
'Illuminate\Foundation\PackageManifest' => \Illuminate\Foundation\PackageManifest::class,
@ -506,7 +507,6 @@ namespace PHPSTORM_META {
'auth.password.broker' => \Illuminate\Auth\Passwords\PasswordBroker::class,
'blade.compiler' => \Illuminate\View\Compilers\BladeCompiler::class,
'cache' => \Illuminate\Cache\CacheManager::class,
'cache.dynamodb.client' => \Aws\DynamoDb\DynamoDbClient::class,
'cache.store' => \Illuminate\Cache\Repository::class,
'command.auth.resets.clear' => \Illuminate\Auth\Console\ClearResetsCommand::class,
'command.cache.clear' => \Illuminate\Cache\Console\ClearCommand::class,
@ -690,6 +690,7 @@ namespace PHPSTORM_META {
'Illuminate\Contracts\Pipeline\Hub' => \Illuminate\Pipeline\Hub::class,
'Illuminate\Contracts\Queue\EntityResolver' => \Illuminate\Database\Eloquent\QueueEntityResolver::class,
'Illuminate\Contracts\Routing\ResponseFactory' => \Illuminate\Routing\ResponseFactory::class,
'Illuminate\Contracts\Validation\UncompromisedVerifier' => \Illuminate\Validation\NotPwnedVerifier::class,
'Illuminate\Database\Console\DbCommand' => \Illuminate\Database\Console\DbCommand::class,
'Illuminate\Foundation\Mix' => \Illuminate\Foundation\Mix::class,
'Illuminate\Foundation\PackageManifest' => \Illuminate\Foundation\PackageManifest::class,
@ -715,7 +716,6 @@ namespace PHPSTORM_META {
'auth.password.broker' => \Illuminate\Auth\Passwords\PasswordBroker::class,
'blade.compiler' => \Illuminate\View\Compilers\BladeCompiler::class,
'cache' => \Illuminate\Cache\CacheManager::class,
'cache.dynamodb.client' => \Aws\DynamoDb\DynamoDbClient::class,
'cache.store' => \Illuminate\Cache\Repository::class,
'command.auth.resets.clear' => \Illuminate\Auth\Console\ClearResetsCommand::class,
'command.cache.clear' => \Illuminate\Cache\Console\ClearCommand::class,
@ -899,6 +899,7 @@ namespace PHPSTORM_META {
'Illuminate\Contracts\Pipeline\Hub' => \Illuminate\Pipeline\Hub::class,
'Illuminate\Contracts\Queue\EntityResolver' => \Illuminate\Database\Eloquent\QueueEntityResolver::class,
'Illuminate\Contracts\Routing\ResponseFactory' => \Illuminate\Routing\ResponseFactory::class,
'Illuminate\Contracts\Validation\UncompromisedVerifier' => \Illuminate\Validation\NotPwnedVerifier::class,
'Illuminate\Database\Console\DbCommand' => \Illuminate\Database\Console\DbCommand::class,
'Illuminate\Foundation\Mix' => \Illuminate\Foundation\Mix::class,
'Illuminate\Foundation\PackageManifest' => \Illuminate\Foundation\PackageManifest::class,
@ -924,7 +925,6 @@ namespace PHPSTORM_META {
'auth.password.broker' => \Illuminate\Auth\Passwords\PasswordBroker::class,
'blade.compiler' => \Illuminate\View\Compilers\BladeCompiler::class,
'cache' => \Illuminate\Cache\CacheManager::class,
'cache.dynamodb.client' => \Aws\DynamoDb\DynamoDbClient::class,
'cache.store' => \Illuminate\Cache\Repository::class,
'command.auth.resets.clear' => \Illuminate\Auth\Console\ClearResetsCommand::class,
'command.cache.clear' => \Illuminate\Cache\Console\ClearCommand::class,
@ -1108,6 +1108,7 @@ namespace PHPSTORM_META {
'Illuminate\Contracts\Pipeline\Hub' => \Illuminate\Pipeline\Hub::class,
'Illuminate\Contracts\Queue\EntityResolver' => \Illuminate\Database\Eloquent\QueueEntityResolver::class,
'Illuminate\Contracts\Routing\ResponseFactory' => \Illuminate\Routing\ResponseFactory::class,
'Illuminate\Contracts\Validation\UncompromisedVerifier' => \Illuminate\Validation\NotPwnedVerifier::class,
'Illuminate\Database\Console\DbCommand' => \Illuminate\Database\Console\DbCommand::class,
'Illuminate\Foundation\Mix' => \Illuminate\Foundation\Mix::class,
'Illuminate\Foundation\PackageManifest' => \Illuminate\Foundation\PackageManifest::class,
@ -1133,7 +1134,6 @@ namespace PHPSTORM_META {
'auth.password.broker' => \Illuminate\Auth\Passwords\PasswordBroker::class,
'blade.compiler' => \Illuminate\View\Compilers\BladeCompiler::class,
'cache' => \Illuminate\Cache\CacheManager::class,
'cache.dynamodb.client' => \Aws\DynamoDb\DynamoDbClient::class,
'cache.store' => \Illuminate\Cache\Repository::class,
'command.auth.resets.clear' => \Illuminate\Auth\Console\ClearResetsCommand::class,
'command.cache.clear' => \Illuminate\Cache\Console\ClearCommand::class,
@ -1317,6 +1317,7 @@ namespace PHPSTORM_META {
'Illuminate\Contracts\Pipeline\Hub' => \Illuminate\Pipeline\Hub::class,
'Illuminate\Contracts\Queue\EntityResolver' => \Illuminate\Database\Eloquent\QueueEntityResolver::class,
'Illuminate\Contracts\Routing\ResponseFactory' => \Illuminate\Routing\ResponseFactory::class,
'Illuminate\Contracts\Validation\UncompromisedVerifier' => \Illuminate\Validation\NotPwnedVerifier::class,
'Illuminate\Database\Console\DbCommand' => \Illuminate\Database\Console\DbCommand::class,
'Illuminate\Foundation\Mix' => \Illuminate\Foundation\Mix::class,
'Illuminate\Foundation\PackageManifest' => \Illuminate\Foundation\PackageManifest::class,
@ -1342,7 +1343,6 @@ namespace PHPSTORM_META {
'auth.password.broker' => \Illuminate\Auth\Passwords\PasswordBroker::class,
'blade.compiler' => \Illuminate\View\Compilers\BladeCompiler::class,
'cache' => \Illuminate\Cache\CacheManager::class,
'cache.dynamodb.client' => \Aws\DynamoDb\DynamoDbClient::class,
'cache.store' => \Illuminate\Cache\Repository::class,
'command.auth.resets.clear' => \Illuminate\Auth\Console\ClearResetsCommand::class,
'command.cache.clear' => \Illuminate\Cache\Console\ClearCommand::class,
@ -1526,6 +1526,7 @@ namespace PHPSTORM_META {
'Illuminate\Contracts\Pipeline\Hub' => \Illuminate\Pipeline\Hub::class,
'Illuminate\Contracts\Queue\EntityResolver' => \Illuminate\Database\Eloquent\QueueEntityResolver::class,
'Illuminate\Contracts\Routing\ResponseFactory' => \Illuminate\Routing\ResponseFactory::class,
'Illuminate\Contracts\Validation\UncompromisedVerifier' => \Illuminate\Validation\NotPwnedVerifier::class,
'Illuminate\Database\Console\DbCommand' => \Illuminate\Database\Console\DbCommand::class,
'Illuminate\Foundation\Mix' => \Illuminate\Foundation\Mix::class,
'Illuminate\Foundation\PackageManifest' => \Illuminate\Foundation\PackageManifest::class,
@ -1551,7 +1552,6 @@ namespace PHPSTORM_META {
'auth.password.broker' => \Illuminate\Auth\Passwords\PasswordBroker::class,
'blade.compiler' => \Illuminate\View\Compilers\BladeCompiler::class,
'cache' => \Illuminate\Cache\CacheManager::class,
'cache.dynamodb.client' => \Aws\DynamoDb\DynamoDbClient::class,
'cache.store' => \Illuminate\Cache\Repository::class,
'command.auth.resets.clear' => \Illuminate\Auth\Console\ClearResetsCommand::class,
'command.cache.clear' => \Illuminate\Cache\Console\ClearCommand::class,
@ -1735,6 +1735,7 @@ namespace PHPSTORM_META {
'Illuminate\Contracts\Pipeline\Hub' => \Illuminate\Pipeline\Hub::class,
'Illuminate\Contracts\Queue\EntityResolver' => \Illuminate\Database\Eloquent\QueueEntityResolver::class,
'Illuminate\Contracts\Routing\ResponseFactory' => \Illuminate\Routing\ResponseFactory::class,
'Illuminate\Contracts\Validation\UncompromisedVerifier' => \Illuminate\Validation\NotPwnedVerifier::class,
'Illuminate\Database\Console\DbCommand' => \Illuminate\Database\Console\DbCommand::class,
'Illuminate\Foundation\Mix' => \Illuminate\Foundation\Mix::class,
'Illuminate\Foundation\PackageManifest' => \Illuminate\Foundation\PackageManifest::class,
@ -1760,7 +1761,6 @@ namespace PHPSTORM_META {
'auth.password.broker' => \Illuminate\Auth\Passwords\PasswordBroker::class,
'blade.compiler' => \Illuminate\View\Compilers\BladeCompiler::class,
'cache' => \Illuminate\Cache\CacheManager::class,
'cache.dynamodb.client' => \Aws\DynamoDb\DynamoDbClient::class,
'cache.store' => \Illuminate\Cache\Repository::class,
'command.auth.resets.clear' => \Illuminate\Auth\Console\ClearResetsCommand::class,
'command.cache.clear' => \Illuminate\Cache\Console\ClearCommand::class,
@ -1944,6 +1944,7 @@ namespace PHPSTORM_META {
'Illuminate\Contracts\Pipeline\Hub' => \Illuminate\Pipeline\Hub::class,
'Illuminate\Contracts\Queue\EntityResolver' => \Illuminate\Database\Eloquent\QueueEntityResolver::class,
'Illuminate\Contracts\Routing\ResponseFactory' => \Illuminate\Routing\ResponseFactory::class,
'Illuminate\Contracts\Validation\UncompromisedVerifier' => \Illuminate\Validation\NotPwnedVerifier::class,
'Illuminate\Database\Console\DbCommand' => \Illuminate\Database\Console\DbCommand::class,
'Illuminate\Foundation\Mix' => \Illuminate\Foundation\Mix::class,
'Illuminate\Foundation\PackageManifest' => \Illuminate\Foundation\PackageManifest::class,
@ -1969,7 +1970,6 @@ namespace PHPSTORM_META {
'auth.password.broker' => \Illuminate\Auth\Passwords\PasswordBroker::class,
'blade.compiler' => \Illuminate\View\Compilers\BladeCompiler::class,
'cache' => \Illuminate\Cache\CacheManager::class,
'cache.dynamodb.client' => \Aws\DynamoDb\DynamoDbClient::class,
'cache.store' => \Illuminate\Cache\Repository::class,
'command.auth.resets.clear' => \Illuminate\Auth\Console\ClearResetsCommand::class,
'command.cache.clear' => \Illuminate\Cache\Console\ClearCommand::class,
@ -2153,6 +2153,7 @@ namespace PHPSTORM_META {
'Illuminate\Contracts\Pipeline\Hub' => \Illuminate\Pipeline\Hub::class,
'Illuminate\Contracts\Queue\EntityResolver' => \Illuminate\Database\Eloquent\QueueEntityResolver::class,
'Illuminate\Contracts\Routing\ResponseFactory' => \Illuminate\Routing\ResponseFactory::class,
'Illuminate\Contracts\Validation\UncompromisedVerifier' => \Illuminate\Validation\NotPwnedVerifier::class,
'Illuminate\Database\Console\DbCommand' => \Illuminate\Database\Console\DbCommand::class,
'Illuminate\Foundation\Mix' => \Illuminate\Foundation\Mix::class,
'Illuminate\Foundation\PackageManifest' => \Illuminate\Foundation\PackageManifest::class,
@ -2178,7 +2179,6 @@ namespace PHPSTORM_META {
'auth.password.broker' => \Illuminate\Auth\Passwords\PasswordBroker::class,
'blade.compiler' => \Illuminate\View\Compilers\BladeCompiler::class,
'cache' => \Illuminate\Cache\CacheManager::class,
'cache.dynamodb.client' => \Aws\DynamoDb\DynamoDbClient::class,
'cache.store' => \Illuminate\Cache\Repository::class,
'command.auth.resets.clear' => \Illuminate\Auth\Console\ClearResetsCommand::class,
'command.cache.clear' => \Illuminate\Cache\Console\ClearCommand::class,

View File

@ -3,7 +3,7 @@
/**
* A helper file for Laravel, to provide autocomplete information to your IDE
* Generated for Laravel 8.38.0.
* Generated for Laravel 8.42.1.
*
* This file should not be included in your code, only analyzed by your IDE!
*
@ -989,6 +989,7 @@
* @param \Closure|string|null $concrete
* @param bool $shared
* @return void
* @throws \TypeError
* @static
*/
public static function bind($abstract, $concrete = null, $shared = false)
@ -1862,6 +1863,20 @@
{
/** @var \Illuminate\Auth\SessionGuard $instance */
return $instance->attempt($credentials, $remember);
}
/**
* Attempt to authenticate a user with credentials and additional callbacks.
*
* @param array $credentials
* @param array|callable $callbacks
* @param false $remember
* @return bool
* @static
*/
public static function attemptWhen($credentials = [], $callbacks = null, $remember = false)
{
/** @var \Illuminate\Auth\SessionGuard $instance */
return $instance->attemptWhen($credentials, $callbacks, $remember);
}
/**
* Log the given user ID into the application.
@ -2863,6 +2878,7 @@
*
* @param mixed $command
* @return mixed
* @throws \RuntimeException
* @static
*/
public static function dispatchToQueue($command)
@ -2945,6 +2961,45 @@
{
/** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */
$instance->assertNotDispatched($command, $callback);
}
/**
* Assert if a job was explicitly dispatched synchronously based on a truth-test callback.
*
* @param string|\Closure $command
* @param callable|int|null $callback
* @return void
* @static
*/
public static function assertDispatchedSync($command, $callback = null)
{
/** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */
$instance->assertDispatchedSync($command, $callback);
}
/**
* Assert if a job was pushed synchronously a number of times.
*
* @param string $command
* @param int $times
* @return void
* @static
*/
public static function assertDispatchedSyncTimes($command, $times = 1)
{
/** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */
$instance->assertDispatchedSyncTimes($command, $times);
}
/**
* Determine if a job was dispatched based on a truth-test callback.
*
* @param string|\Closure $command
* @param callable|null $callback
* @return void
* @static
*/
public static function assertNotDispatchedSync($command, $callback = null)
{
/** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */
$instance->assertNotDispatchedSync($command, $callback);
}
/**
* Assert if a job was dispatched after the response was sent based on a truth-test callback.
@ -3034,6 +3089,19 @@
{
/** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */
return $instance->dispatched($command, $callback);
}
/**
* Get all of the jobs dispatched synchronously matching a truth-test callback.
*
* @param string $command
* @param callable|null $callback
* @return \Illuminate\Support\Collection
* @static
*/
public static function dispatchedSync($command, $callback = null)
{
/** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */
return $instance->dispatchedSync($command, $callback);
}
/**
* Get all of the jobs dispatched after the response was sent matching a truth-test callback.
@ -3079,6 +3147,18 @@
* @return bool
* @static
*/
public static function hasDispatchedSync($command)
{
/** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */
return $instance->hasDispatchedSync($command);
}
/**
* Determine if there are any stored commands for a given class.
*
* @param string $command
* @return bool
* @static
*/
public static function hasDispatchedAfterResponse($command)
{
/** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */
@ -4041,6 +4121,20 @@
{
/** @var \Illuminate\Cookie\CookieJar $instance */
$instance->queue(...$parameters);
}
/**
* Queue a cookie to expire with the next response.
*
* @param string $name
* @param string|null $path
* @param string|null $domain
* @return void
* @static
*/
public static function expire($name, $path = null, $domain = null)
{
/** @var \Illuminate\Cookie\CookieJar $instance */
$instance->expire($name, $path, $domain);
}
/**
* Remove a cookie from the queue.
@ -4374,6 +4468,18 @@
{
/** @var \Illuminate\Database\DatabaseManager $instance */
$instance->setReconnector($reconnector);
}
/**
* Set the application instance used by the manager.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return \Illuminate\Database\DatabaseManager
* @static
*/
public static function setApplication($app)
{
/** @var \Illuminate\Database\DatabaseManager $instance */
return $instance->setApplication($app);
}
/**
* Determine if the connected database is a MariaDB database.
@ -5185,6 +5291,7 @@
*
* @param callable $callback
* @return void
* @throws \RuntimeException
* @static
*/
public static function afterCommit($callback)
@ -5576,6 +5683,7 @@
* @param string $path
* @param array $data
* @return mixed
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
* @static
*/
public static function requireOnce($path, $data = [])
@ -5731,6 +5839,7 @@
* @param string $target
* @param string $link
* @return void
* @throws \RuntimeException
* @static
*/
public static function relativeLink($target, $link)
@ -5791,6 +5900,7 @@
*
* @param string $path
* @return string|null
* @throws \RuntimeException
* @static
*/
public static function guessExtension($path)
@ -6536,13 +6646,16 @@
* @method static \Illuminate\Http\Client\PendingRequest asForm()
* @method static \Illuminate\Http\Client\PendingRequest asJson()
* @method static \Illuminate\Http\Client\PendingRequest asMultipart()
* @method static \Illuminate\Http\Client\PendingRequest attach(string $name, string $contents, string|null $filename = null, array $headers = [])
* @method static \Illuminate\Http\Client\PendingRequest async()
* @method static \Illuminate\Http\Client\PendingRequest attach(string|array $name, string $contents = '', string|null $filename = null, array $headers = [])
* @method static \Illuminate\Http\Client\PendingRequest baseUrl(string $url)
* @method static \Illuminate\Http\Client\PendingRequest beforeSending(callable $callback)
* @method static \Illuminate\Http\Client\PendingRequest bodyFormat(string $format)
* @method static \Illuminate\Http\Client\PendingRequest contentType(string $contentType)
* @method static \Illuminate\Http\Client\PendingRequest dd()
* @method static \Illuminate\Http\Client\PendingRequest dump()
* @method static \Illuminate\Http\Client\PendingRequest retry(int $times, int $sleep = 0)
* @method static \Illuminate\Http\Client\PendingRequest sink($to)
* @method static \Illuminate\Http\Client\PendingRequest sink(string|resource $to)
* @method static \Illuminate\Http\Client\PendingRequest stub(callable $callback)
* @method static \Illuminate\Http\Client\PendingRequest timeout(int $seconds)
* @method static \Illuminate\Http\Client\PendingRequest withBasicAuth(string $username, string $password)
@ -6550,17 +6663,16 @@
* @method static \Illuminate\Http\Client\PendingRequest withCookies(array $cookies, string $domain)
* @method static \Illuminate\Http\Client\PendingRequest withDigestAuth(string $username, string $password)
* @method static \Illuminate\Http\Client\PendingRequest withHeaders(array $headers)
* @method static \Illuminate\Http\Client\PendingRequest withMiddleware(callable $middleware)
* @method static \Illuminate\Http\Client\PendingRequest withOptions(array $options)
* @method static \Illuminate\Http\Client\PendingRequest withToken(string $token, string $type = 'Bearer')
* @method static \Illuminate\Http\Client\PendingRequest withUserAgent(string $userAgent)
* @method static \Illuminate\Http\Client\PendingRequest withoutRedirecting()
* @method static \Illuminate\Http\Client\PendingRequest withoutVerifying()
* @method static \Illuminate\Http\Client\PendingRequest dump()
* @method static \Illuminate\Http\Client\PendingRequest dd()
* @method static \Illuminate\Http\Client\PendingRequest async()
* @method static \Illuminate\Http\Client\Pool pool(callable $callback)
* @method static array pool(callable $callback)
* @method static \Illuminate\Http\Client\Response delete(string $url, array $data = [])
* @method static \Illuminate\Http\Client\Response get(string $url, array $query = [])
* @method static \Illuminate\Http\Client\Response head(string $url, array $query = [])
* @method static \Illuminate\Http\Client\Response get(string $url, array|string|null $query = null)
* @method static \Illuminate\Http\Client\Response head(string $url, array|string|null $query = null)
* @method static \Illuminate\Http\Client\Response patch(string $url, array $data = [])
* @method static \Illuminate\Http\Client\Response post(string $url, array $data = [])
* @method static \Illuminate\Http\Client\Response put(string $url, array $data = [])
@ -6966,6 +7078,7 @@
*
* @param string $locale
* @return void
* @throws \InvalidArgumentException
* @static
*/
public static function setLocale($locale)
@ -7334,6 +7447,7 @@
*
* @param array $config
* @return \Swift_Transport
* @throws \InvalidArgumentException
* @static
*/
public static function createTransport($config)
@ -10080,7 +10194,7 @@
* if the proxy is trusted (see "setTrustedProxies()"), otherwise it returns
* the latter (from the "SERVER_PROTOCOL" server parameter).
*
* @return string
* @return string|null
* @static
*/
public static function getProtocolVersion()
@ -11103,8 +11217,8 @@
* @method static \Illuminate\Routing\RouteRegistrar middleware(array|string|null $middleware)
* @method static \Illuminate\Routing\RouteRegistrar name(string $value)
* @method static \Illuminate\Routing\RouteRegistrar namespace(string|null $value)
* @method static \Illuminate\Routing\RouteRegistrar prefix(string $prefix)
* @method static \Illuminate\Routing\RouteRegistrar where(array $where)
* @method static \Illuminate\Routing\RouteRegistrar prefix(string $prefix)
* @method static \Illuminate\Routing\RouteRegistrar where(array $where)
* @see \Illuminate\Routing\Router
*/
class Route {
@ -12084,6 +12198,7 @@
*
* @param string $type
* @return void
* @throws \InvalidArgumentException
* @static
*/
public static function defaultMorphKeyType($type)
@ -14681,6 +14796,7 @@
* @param string $name
* @param string|null $content
* @return void
* @throws \InvalidArgumentException
* @static
*/
public static function slot($name, $content = null)
@ -15197,6 +15313,26 @@
{
/** @var \Facade\FlareClient\Flare $instance */
return $instance->determineVersionUsing($determineVersionCallable);
}
/**
*
*
* @static
*/
public static function reportErrorLevels($reportErrorLevels)
{
/** @var \Facade\FlareClient\Flare $instance */
return $instance->reportErrorLevels($reportErrorLevels);
}
/**
*
*
* @static
*/
public static function filterExceptionsUsing($filterExceptionsCallable)
{
/** @var \Facade\FlareClient\Flare $instance */
return $instance->filterExceptionsUsing($filterExceptionsCallable);
}
/**
*
@ -16046,6 +16182,23 @@ namespace {
return $instance->simplePaginate($perPage, $columns, $pageName, $page);
}
/**
* Paginate the given query into a cursor paginator.
*
* @param int|null $perPage
* @param array $columns
* @param string $cursorName
* @param string|null $cursor
* @return \Illuminate\Contracts\Pagination\Paginator
* @throws \Illuminate\Pagination\CursorPaginationException
* @static
*/
public static function cursorPaginate($perPage = null, $columns = [], $cursorName = 'cursor', $cursor = null)
{
/** @var \Illuminate\Database\Eloquent\Builder $instance */
return $instance->cursorPaginate($perPage, $columns, $cursorName, $cursor);
}
/**
* Save a new model and return the instance.
*
@ -16138,6 +16291,19 @@ namespace {
return $instance->without($relations);
}
/**
* Set the relationships that should be eager loaded while removing any previously added eager loading specifications.
*
* @param mixed $relations
* @return \Illuminate\Database\Eloquent\Builder|static
* @static
*/
public static function withOnly($relations)
{
/** @var \Illuminate\Database\Eloquent\Builder $instance */
return $instance->withOnly($relations);
}
/**
* Create a new instance of the model being queried.
*
@ -16646,6 +16812,19 @@ namespace {
return $instance->withAvg($relation, $column);
}
/**
* Add subselect queries to include the existence of related models.
*
* @param string|array $relation
* @return \Illuminate\Database\Eloquent\Builder|static
* @static
*/
public static function withExists($relation)
{
/** @var \Illuminate\Database\Eloquent\Builder $instance */
return $instance->withExists($relation);
}
/**
* Merge the where constraints from another query to the current query.
*
@ -16705,6 +16884,7 @@ namespace {
* @param callable $callback
* @param int $count
* @return bool
* @throws \RuntimeException
* @static
*/
public static function each($callback, $count = 1000)
@ -16750,6 +16930,7 @@ namespace {
*
* @param int $chunkSize
* @return \Illuminate\Support\LazyCollection
* @throws \InvalidArgumentException
* @static
*/
public static function lazy($chunkSize = 1000)
@ -16765,6 +16946,7 @@ namespace {
* @param string|null $column
* @param string|null $alias
* @return \Illuminate\Support\LazyCollection
* @throws \InvalidArgumentException
* @static
*/
public static function lazyById($chunkSize = 1000, $column = null, $alias = null)

View File

@ -6,8 +6,6 @@ use App\Http\Requests\UpdateGoalRequest;
use App\Models\Goal;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
class GoalController extends Controller
@ -15,17 +13,10 @@ class GoalController extends Controller
/**
* Display a listing of the resource.
*/
public function index(Request $request): View
public function index(): View
{
if ($request->date) {
$date = Carbon::createFromFormat('Y-m-d', $request->date);
}
else {
$date = Carbon::now();
}
return view('goals.index')
->with('date', $date)
->with('goals', Auth::user()->getGoalsByTime($date));
->with('goals', Goal::whereUserId(Auth::user()->id)->get());
}
/**
@ -51,10 +42,7 @@ class GoalController extends Controller
*/
public function show(Goal $goal): View
{
return view('goals.show')
->with('goal', $goal)
->with('nameOptions', Goal::getNameOptions())
->with('frequencyOptions', Goal::$frequencyOptions);
return view('goals.show')->with('goal', $goal);
}
/**
@ -62,10 +50,7 @@ class GoalController extends Controller
*/
public function edit(Goal $goal): View
{
return view('goals.edit')
->with('goal', $goal)
->with('nameOptions', Goal::getNameOptions())
->with('frequencyOptions', Goal::$frequencyOptions);
return view('goals.edit')->with('goal', $goal);
}
/**
@ -74,10 +59,16 @@ class GoalController extends Controller
public function update(UpdateGoalRequest $request, Goal $goal): RedirectResponse
{
$attributes = $request->validated();
if (isset($attributes['days'])) {
$attributes['days'] = array_sum($attributes['days']);
}
else if (!empty($goal->days)) {
$attributes['days'] = null;
}
$goal->fill($attributes)->user()->associate(Auth::user());
$goal->save();
session()->flash('message', "Goal updated!");
return redirect()->route('goals.show', $goal);
return redirect()->route('goals.index');
}
/**

View File

@ -0,0 +1,24 @@
<?php
namespace App\Http\Controllers;
use App\Models\JournalDate;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class JournalDateController extends Controller
{
/**
* Change the goals for a journal date.
*/
public function updateGoal(Request $request, JournalDate $journalDate): RedirectResponse
{
$attributes = $request->validate(['goal' => 'exists:App\Models\Goal,id']);
$journalDate->goal()->associate($attributes['goal'])->save();
return redirect()->route('journal-entries.index', [
'date' => $journalDate->date->format('Y-m-d')
]);
}
}

View File

@ -8,6 +8,8 @@ namespace App\Http\Controllers;
use App\Http\Requests\StoreFromNutrientsJournalEntryRequest;
use App\Http\Requests\StoreJournalEntryRequest;
use App\Models\Food;
use App\Models\Goal;
use App\Models\JournalDate;
use App\Models\JournalEntry;
use App\Models\Recipe;
use App\Support\ArrayFormat;
@ -42,25 +44,36 @@ class JournalEntryController extends Controller
}
// Get daily goals data for user.
$goals = Auth::user()->getGoalsByTime($date);
$dailyGoals = [];
foreach (Nutrients::all()->pluck('value') as $nutrient) {
$goal = $goals['present']
->where('frequency', 'daily')
->where('name', $nutrient)
->first();
if ($goal) {
$dailyGoals[$goal->name] = round($sums[$goal->name] / $goal->goal * 100);
if ($dailyGoals[$goal->name] > 0) {
$dailyGoals[$goal->name] .= '%';
$goal = Auth::user()->getGoalByDate($date);
$goalProgress = [];
if ($goal) {
foreach (Nutrients::all()->pluck('value') as $nutrient) {
if ($goal->{$nutrient} > 0) {
$goalProgress[$nutrient] = round($sums[$nutrient] / $goal->{$nutrient} * 100);
$goalProgress[$nutrient] .= '%';
}
}
}
// Get all goals as options to change for the date.
$goalOptions = Goal::whereUserId(Auth::user()->id)
->orderBy('name')
->get()
->map(function (Goal $goal) {
return ['value' => $goal->id, 'label' => $goal->name];
});
// Get the associated journal date.
// @todo Refactor journal date as a relationship on journal entries.
$journalDate = JournalDate::getOrCreateJournalDate(Auth::user(), $date);
return view('journal-entries.index')
->with('entries', $entries)
->with('sums', $sums)
->with('dailyGoals', $dailyGoals)
->with('currentGoal', $goal)
->with('goalProgress', $goalProgress)
->with('goalOptions', $goalOptions)
->with('journalDate', $journalDate)
->with('date', $date);
}

View File

@ -14,11 +14,15 @@ class UpdateGoalRequest extends FormRequest
public function rules(): array
{
return [
'from' => ['nullable', 'date'],
'to' => ['nullable', 'date'],
'frequency' => ['required', 'string'],
'name' => ['required', 'string'],
'goal' => ['required', 'numeric', 'min:0'],
'days' => ['nullable', 'array'],
'days.*' => ['nullable', 'numeric', 'min:0', 'max:64'],
'calories' => ['nullable', 'numeric', 'min:0'],
'fat' => ['nullable', 'numeric', 'min:0'],
'cholesterol' => ['nullable', 'numeric', 'min:0'],
'sodium' => ['nullable', 'numeric', 'min:0'],
'carbohydrates' => ['nullable', 'numeric', 'min:0'],
'protein' => ['nullable', 'numeric', 'min:0'],
];
}

View File

@ -23,7 +23,7 @@ class GoalAdapter extends AdapterBase
/**
* {@inheritdoc}
*/
protected $defaultSort = ['-from', '-to'];
protected $defaultSort = ['-name'];
/**
* @inheritdoc

View File

@ -25,6 +25,7 @@ class FoodSchema extends SchemaProvider
*/
public function getAttributes($resource): array
{
/** @var \App\Models\Food $resource */
return [
'slug' => $resource->slug,
'name' => $resource->name,

View File

@ -25,12 +25,17 @@ class GoalSchema extends SchemaProvider
*/
public function getAttributes($resource): array
{
/** @var \App\Models\Goal $resource */
return [
'frequency' => $resource->frequency,
'from' => $resource->from,
'goal' => $resource->goal,
'name' => $resource->name,
'to' => $resource->to,
'days' => $resource->days,
'daysFormatted' => $resource->days_formatted,
'calories' => $resource->calories,
'carbohydrates' => $resource->carbohydrates,
'cholesterol' => $resource->cholesterol,
'fat' => $resource->fat,
'protein' => $resource->protein,
'sodium' => $resource->sodium,
];
}

View File

@ -25,6 +25,7 @@ class IngredientAmountSchema extends SchemaProvider
*/
public function getAttributes($resource): array
{
/** @var \App\Models\IngredientAmount $resource */
return [
'amount' => $resource->amount,
'amountFormatted' => $resource->amount_formatted,

View File

@ -25,6 +25,7 @@ class JournalEntrySchema extends SchemaProvider
*/
public function getAttributes($resource): array
{
/** @var \App\Models\JournalEntry $resource */
return [
'calories' => $resource->calories,
'carbohydrates' => $resource->carbohydrates,

View File

@ -25,6 +25,7 @@ class RecipeSchema extends SchemaProvider
*/
public function getAttributes($resource): array
{
/** @var \App\Models\Recipe $resource */
return [
'slug' => $resource->slug,
'name' => $resource->name,

View File

@ -25,6 +25,7 @@ class RecipeSeparatorSchema extends SchemaProvider
*/
public function getAttributes($resource): array
{
/** @var \App\Models\RecipeSeparator $resource */
return [
'container' => $resource->container,
'weight' => $resource->weight,

View File

@ -25,6 +25,7 @@ class RecipeStepSchema extends SchemaProvider
*/
public function getAttributes($resource): array
{
/** @var \App\Models\RecipeStep $resource */
return [
'number' => $resource->number,
'step' => $resource->step,

View File

@ -25,6 +25,7 @@ class TagSchema extends SchemaProvider
*/
public function getAttributes($resource): array
{
/** @var \App\Models\Tag $resource */
return [
'name' => $resource->name,
'slug' => $resource->slug,

View File

@ -25,6 +25,7 @@ class UserSchema extends SchemaProvider
*/
public function getAttributes($resource): array
{
/** @var \App\Models\User $resource */
return [
'username' => $resource->username,
'name' => $resource->name,

View File

@ -2,82 +2,151 @@
namespace App\Models;
use App\Support\Nutrients;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Str;
use Illuminate\Support\Collection;
/**
* App\Models\Goal
*
* @property int $id
* @property int $user_id
* @property \datetime|null $from
* @property \datetime|null $to
* @property string|null $frequency
* @property int $days
* @property string $name
* @property float $goal
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read string $summary
* @property float|null $calories
* @property float|null $fat
* @property float|null $cholesterol
* @property float|null $sodium
* @property float|null $carbohydrates
* @property float|null $protein
* @property-read \App\Models\User $user
* @method static \Database\Factories\GoalFactory factory(...$parameters)
* @method static \Illuminate\Database\Eloquent\Builder|Goal newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Goal newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Goal query()
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereCalories($value)
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereCarbohydrates($value)
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereCholesterol($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 whereDays($value)
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereFat($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 whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereProtein($value)
* @method static \Illuminate\Database\Eloquent\Builder|Goal whereSodium($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 whereUserId($value)
* @mixin \Eloquent
* @method static \Database\Factories\GoalFactory factory(...$parameters)
* @property-read array $days_formatted
*/
final class Goal extends Model
{
use HasFactory;
/**
* Supported options for thr frequency attribute.
*/
public static array $frequencyOptions = [
'daily' => [
'value' => 'daily',
'label' => 'daily'
],
];
/**
* @inheritdoc
*/
protected $fillable = [
'frequency',
'from',
'goal',
'name',
'to',
// Bitwise field: mon=1, tue=2, wed=4, thu=8, fri=16, sat=32, sun=64.
'days',
'calories',
'carbohydrates',
'cholesterol',
'fat',
'protein',
'sodium',
];
/**
* @inheritdoc
*/
protected $casts = [
'from' => 'datetime:Y-m-d',
'goal' => 'float',
'to' => 'datetime:Y-m-d',
'days' => 'int',
'calories' => 'float',
'carbohydrates' => 'float',
'cholesterol' => 'float',
'fat' => 'float',
'protein' => 'float',
'sodium' => 'float',
];
/**
* @inheritdoc
*/
protected $appends = [
'summary',
'days_formatted',
];
/**
* Get the days for the goals as strings in array keyed by dow.
*/
public function getDaysFormattedAttribute(): Collection {
if (empty($this->days)) {
return new Collection([]);
}
return self::days()->filter(function ($day) {
if (($this->days & $day['value']) != 0) {
return true;
}
return false;
});
}
/**
* Get all supported days and metadata.
*
* Each entry has the following keys:
* - value: Day value (used for bitwise operations).
* - label: Human-readable name for the day.
* - dow: ISO-8601 numeric representation of the day of the week.
*/
public static function days(): Collection
{
return new Collection([
[
'value' => 1,
'label' => 'monday',
'dow' => 1,
],
[
'value' => 2,
'label' => 'tuesday',
'dow' => 2,
],
[
'value' => 4,
'label' => 'wednesday',
'dow' => 3,
],
[
'value' => 8,
'label' => 'thursday',
'dow' => 4,
],
[
'value' => 16,
'label' => 'friday',
'dow' => 5,
],
[
'value' => 32,
'label' => 'saturday',
'dow' => 6,
],
[
'value' => 64,
'label' => 'sunday',
'dow' => 7,
],
]);
}
/**
* Get the User this goal belongs to.
*/
@ -85,23 +154,4 @@ final class Goal extends Model
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 "name" column.
*/
public static function getNameOptions(): array {
$options = [];
foreach (Nutrients::all() as $nutrient) {
$options[$nutrient['value']] = [
'value' => $nutrient['value'],
'label' => Str::ucfirst($nutrient['label']),
'unit' => $nutrient['unit'],
];
}
return $options;
}
}

View File

@ -150,8 +150,6 @@ final class IngredientAmount extends Model
* @param array $parameters
*
* @return mixed
*
* @noinspection PhpMissingParamTypeInspection
*/
public function __call($method, $parameters): mixed {
if (in_array($method, $this->nutrientMethods)) {

View File

@ -0,0 +1,84 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Carbon;
/**
* App\Models\JournalDate
*
* @property int $id
* @property \datetime $date
* @property int $user_id
* @property int|null $goal_id
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \App\Models\Goal|null $goal
* @property-read \App\Models\User $user
* @method static \Illuminate\Database\Eloquent\Builder|JournalDate newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|JournalDate newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|JournalDate query()
* @method static \Illuminate\Database\Eloquent\Builder|JournalDate whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|JournalDate whereDate($value)
* @method static \Illuminate\Database\Eloquent\Builder|JournalDate whereGoalId($value)
* @method static \Illuminate\Database\Eloquent\Builder|JournalDate whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|JournalDate whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|JournalDate whereUserId($value)
* @mixin \Eloquent
* @method static \Database\Factories\JournalDateFactory factory(...$parameters)
*/
final class JournalDate extends Model
{
use HasFactory;
/**
* @inheritdoc
*/
protected $fillable = [
'date',
];
/**
* @inheritdoc
*/
protected $casts = [
'date' => 'datetime:Y-m-d',
];
/**
* Get the Goal for this date.
*/
public function goal(): BelongsTo {
return $this->belongsTo(Goal::class);
}
/**
* Get the User this journal date belongs to.
*/
public function user(): BelongsTo {
return $this->belongsTo(User::class);
}
/**
* Gets a journal date for a user and date, creating a new one if necessary.
*
* @param \App\Models\User $user
* User.
* @param \Illuminate\Support\Carbon $date
* Date.
*
* @return \App\Models\JournalDate
* Journal date for provided user and date.
*/
public static function getOrCreateJournalDate(User $user, Carbon $date): JournalDate {
/** @var \App\Models\JournalDate $journal_date */
$journal_date = $user->journalDates()->whereDate('date', '=', $date)->first();
if (empty($journal_date)) {
$journal_date = JournalDate::make(['date' => $date])->user()->associate($user);
}
return $journal_date;
}
}

View File

@ -8,7 +8,6 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
@ -50,6 +49,8 @@ use Spatie\MediaLibrary\MediaCollections\Models\Media;
* @method static \Illuminate\Database\Eloquent\Builder|User whereSlug($value)
* @method static \Illuminate\Database\Eloquent\Builder|User withUniqueSlugConstraints(\Illuminate\Database\Eloquent\Model $model, string $attribute, array $config, string $slug)
* @mixin \Eloquent
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\JournalDate[] $journalDates
* @property-read int|null $journal_dates_count
*/
final class User extends Authenticatable implements HasMedia
{
@ -98,6 +99,13 @@ final class User extends Authenticatable implements HasMedia
return $this->hasMany(Goal::class);
}
/**
* Get the User's journal dates.
*/
public function journalDates(): HasMany {
return $this->hasMany(JournalDate::class);
}
/**
* Get the User's journal entries.
*/
@ -106,30 +114,33 @@ final class User extends Authenticatable implements HasMedia
}
/**
* Get User's past, present, and future goals.
* Get user's goal (if one exists) for a specific date.
*
* @return \App\Models\Goal[]
* The primary use for a JournalDate entry right now is the goal so this
* method also creates a JournalDate if one does not already exist.
*/
public function getGoalsByTime(?Carbon $date = null): array {
$now = $date ?? Carbon::now();
$goals = ['past' => new Collection(), 'present' => new Collection(), 'future' => new Collection()];
Goal::all()->where('user_id', Auth::user()->id)
->each(function ($item) use(&$goals, $now) {
if ($item->to && $now->isAfter($item->to)) {
$goals['past'][$item->id] = $item;
}
elseif ($item->from && $now->isBefore($item->from)) {
$goals['future'][$item->id] = $item;
}
elseif (
empty($item->from)
|| empty($item->to)
|| $now->isBetween($item->from, $item->to)
) {
$goals['present'][$item->id] = $item;
}
});
return $goals;
public function getGoalByDate(Carbon $date): ?Goal {
$journal_date = JournalDate::getOrCreateJournalDate($this, $date);
if ($journal_date->goal) {
return $journal_date->goal;
}
// Check for a goal based on day of week configurations.
$day = Goal::days()->firstWhere('dow', $date->format('N'));
if (!$day) {
throw new \BadMethodCallException("No day with `dow` value {$date->format('N')}.");
}
/** @var \App\Models\Goal $goal */
$goal = $this->goals()->whereRaw("(days & {$day['value']}) != 0")->first();
if (!empty($goal)) {
$journal_date->goal()->associate($goal);
}
if ($journal_date->hasChanges(['date', 'goal'])) {
$journal_date->save();
}
return $goal;
}
/**

View File

@ -13,13 +13,11 @@ class Nutrients
/**
* Get all supported units and metadata.
*
* Each entry has two keys:
* Each entry has the following keys:
* - value: Machine name for the unit.
* - label: Human-readable name for the unit.
* - plural: Human-readable plural form of the unit name.
* - type: Unit type -- matching types can be converted.
*
* @return \Illuminate\Support\Collection
*/
public static function units(): Collection {
return new Collection([

609
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@
namespace Database\Factories;
use App\Models\Goal;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class GoalFactory extends Factory
@ -15,16 +16,18 @@ class GoalFactory extends Factory
/**
* {@inheritdoc}
*/
public function definition()
public function definition(): array
{
$from = $this->faker->dateTimeThisMonth;
$to = $this->faker->dateTimeBetween($from, '+1 year');
return [
'from' => $this->faker->randomElement([$from, null]),
'to' => $this->faker->randomElement([$to, null]),
'frequency' => $this->faker->randomElement(Goal::$frequencyOptions)['value'],
'name' => $this->faker->randomElement(Goal::getNameOptions())['value'],
'goal' => $this->faker->numberBetween(0, 2000),
'user_id' => User::factory(),
'name' => $this->faker->words(asText: true),
'days' => $this->faker->numberBetween(1, Goal::days()->pluck('value')->sum()),
'calories' => $this->faker->numberBetween(1600, 2500),
'fat' => $this->faker->numberBetween(40, 90),
'cholesterol' => $this->faker->numberBetween(int2: 500),
'sodium' => $this->faker->numberBetween(int2: 3000),
'carbohydrates' => $this->faker->numberBetween(50, 100),
'protein' => $this->faker->numberBetween(90, 200),
];
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace Database\Factories;
use App\Models\Goal;
use App\Models\JournalDate;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class JournalDateFactory extends Factory
{
/**
* {@inheritdoc}
*/
protected $model = JournalDate::class;
/**
* {@inheritdoc}
*/
public function definition(): array
{
return [
'date' => $this->faker->dateTimeThisMonth,
'user_id' => User::factory(),
'goal_id' => Goal::factory(),
];
}
}

View File

@ -21,6 +21,7 @@ class DatabaseSeeder extends Seeder
*/
public function run(): void
{
/** @var \App\Models\User $user */
$user = User::factory()->admin()->create([
'username' => 'kcal',
'password' => Hash::make('kcal'),
@ -28,15 +29,8 @@ class DatabaseSeeder extends Seeder
'remember_token' => Str::random(10),
]);
$goals = [];
foreach (Nutrients::all() as $nutrient) {
$goals[] = [
'frequency' => 'daily',
'name' => $nutrient['value'],
'goal' => $nutrient['rdi'],
];
}
Goal::factory()->for($user)->createMany($goals);
// Goals will probably overlap but that's OK.
Goal::factory()->for($user)->count(3)->create();
$foods = Food::factory()->count(100)->create();
$recipes = Recipe::factory()

View File

@ -17,11 +17,14 @@ class CreateGoalsTable extends Migration
Schema::create('goals', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(User::class)->constrained()->cascadeOnUpdate()->cascadeOnDelete();
$table->date('from')->nullable();
$table->date('to')->nullable();
$table->string('frequency')->nullable();
$table->string('name');
$table->unsignedFloat('goal');
$table->unsignedTinyInteger('days')->nullable();
$table->unsignedFloat('calories')->nullable();
$table->unsignedFloat('fat')->nullable();
$table->unsignedFloat('cholesterol')->nullable();
$table->unsignedFloat('sodium')->nullable();
$table->unsignedFloat('carbohydrates')->nullable();
$table->unsignedFloat('protein')->nullable();
$table->timestamps();
$table->index('user_id');
});

View File

@ -0,0 +1,37 @@
<?php
use App\Models\Goal;
use App\Models\User;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateJournalDatesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('journal_dates', function (Blueprint $table) {
$table->id();
$table->date('date')->useCurrent();
$table->foreignIdFor(User::class)->constrained()->cascadeOnUpdate()->cascadeOnDelete();
$table->foreignIdFor(Goal::class)->nullable()->constrained()->cascadeOnUpdate()->cascadeOnDelete();
$table->timestamps();
$table->unique(['date', 'user_id']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('journal_dates');
}
}

1101
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -16,16 +16,16 @@
"autoprefixer": "^10.2.5",
"axios": "^0.21.1",
"cross-env": "^7.0",
"laravel-mix": "^6.0.16",
"laravel-mix": "^6.0.19",
"lodash": "^4.17.21",
"postcss-import": "^14.0.1",
"postcss-import": "^14.0.2",
"quill": "^1.3.7",
"resolve-url-loader": "^3.1.2",
"tailwindcss": "^2.1.1",
"resolve-url-loader": "^4.0.0",
"tailwindcss": "^2.1.2",
"vue-template-compiler": "^2.6.12"
},
"dependencies": {
"@shopify/draggable": "^1.0.0-beta.12",
"alpine-magic-helpers": "^1.2.0"
"alpine-magic-helpers": "^1.2.2"
}
}

2
public/css/app.css vendored

File diff suppressed because one or more lines are too long

2
public/js/app.js vendored

File diff suppressed because one or more lines are too long

View File

@ -15,7 +15,8 @@
'disabled:opacity-25',
'transition',
'ease-in-out',
'duration-150'
'duration-150',
'cursor-pointer',
];
@endphp
<a {{ $attributes->merge(['class' => implode(' ', $classes)]) }}>

View File

@ -4,10 +4,10 @@
<a href="{{ $model->getFirstMedia()->getFullUrl() }}" target="_blank">
{{ $model->getFirstMedia()($previewName) }}
</a>
<fieldset class="flex space-x-2 mt-1 items-center">
<x-inputs.label for="remove_image" class="text-red-800" value="Remove this image" />
<x-inputs.label class="inline-flex items-center">
<x-inputs.input type="checkbox" name="remove_image" value="1" />
</fieldset>
<span class="ml-2 text-red-800">Remove this image</span>
</x-inputs.label>
</div>
@endif
<div>

View File

@ -9,61 +9,47 @@
@csrf
<div class="flex flex-col space-y-4">
<div class="flex flex-col space-y-4 md:flex-row md:space-x-4 md:space-y-0">
<!-- From -->
<!-- Name -->
<div class="flex-auto">
<x-inputs.label for="from" value="From"/>
<x-inputs.input name="from"
type="date"
class="block w-full"
:value="old('from', $goal->from?->toDateString())"
:hasError="$errors->has('from')" />
</div>
<x-inputs.label for="name" value="Name" />
<!-- To -->
<div class="flex-auto">
<x-inputs.label for="to" value="To"/>
<x-inputs.input name="to"
type="date"
class="block w-full"
:value="old('to', $goal->to?->toDateString())"
:hasError="$errors->has('to')" />
</div>
<!-- Frequency -->
<div class="flex-auto">
<x-inputs.label for="frequency" value="Frequency" />
<x-inputs.select name="frequency"
class="block w-full"
:options="$frequencyOptions"
:selectedValue="old('frequency', $goal->frequency)"
:hasError="$errors->has('frequency')">
</x-inputs.select>
</div>
<!-- Trackable -->
<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)"
:hasError="$errors->has('name')"
required>
</x-inputs.select>
</div>
<!-- Goal -->
<div class="flex-auto">
<x-inputs.label for="goal" value="Goal" />
<x-inputs.input name="goal"
type="number"
step="any"
class="block w-full"
:value="old('goal', $goal->goal)"
:hasError="$errors->has('goal')"
<x-inputs.input name="name"
type="text"
class="block mt-1 w-full"
:value="old('name', $goal->name)"
required />
</div>
</div>
<div class="flex flex-col space-y-4 md:flex-row md:space-x-4 md:space-y-0">
<!-- Days of the week -->
<fieldset>
<legend class="block font-medium text-sm text-gray-700">Days of the week</legend>
<div class="flex flex-col justify-content divide-x border rounded-md shadow-sm border-gray-300 md:inline-flex md:flex-row">
@foreach(\App\Models\Goal::days() as $day)
<x-inputs.label class="inline-flex justify-center p-2">
<x-inputs.input type="checkbox" name="days[]" :value="$day['value']" :checked="($goal->days & $day['value']) != 0" />
<span class="ml-2">{{ \Illuminate\Support\Str::ucfirst($day['label']) }}</span>
</x-inputs.label>
@endforeach
</div>
</fieldset>
</div>
<div class="flex flex-col space-y-4 md:flex-row md:space-y-0">
@foreach (\App\Support\Nutrients::all()->sortBy('weight') as $nutrient)
<!-- {{ ucfirst($nutrient['value']) }} -->
<div class="flex-auto">
<x-inputs.label for="{{ $nutrient['value'] }}"
:value="ucfirst($nutrient['value']) . ($nutrient['unit'] ? ' (' . $nutrient['unit'] . ')' : '')"/>
<x-inputs.input name="{{ $nutrient['value'] }}"
type="number"
step="any"
class="block w-full mt-1 md:w-5/6"
:value="old($nutrient['value'], $goal->{$nutrient['value']})"
:hasError="$errors->has($nutrient['value'])"/>
</div>
@endforeach
</div>
</div>
<div class="flex items-center justify-end mt-4">

View File

@ -1,63 +1,53 @@
<x-app-layout>
<x-slot name="title">My Goals - {{ $date->format('D, j M Y') }}</x-slot>
<x-slot name="title">My Goals</x-slot>
<x-slot name="header">
<div class="flex justify-between items-center">
<h1 class="leading-tight text-center">
<div class="text-2xl font-semibold text-gray-800">My Goals</div>
<div class="flex items-center space-x-2">
<div>
<a class="text-gray-500 hover:text-gray-700 hover:border-gray-300"
href="{{ route(Route::current()->getName(), ['date' => $date->copy()->subDay(1)->toDateString()]) }}">
<svg class="w-6 h-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm.707-10.293a1 1 0 00-1.414-1.414l-3 3a1 1 0 000 1.414l3 3a1 1 0 001.414-1.414L9.414 11H13a1 1 0 100-2H9.414l1.293-1.293z" clip-rule="evenodd" />
</svg>
</a>
</div>
<div class="text-base text-gray-500">
<form x-data method="GET" action="{{ route('goals.index') }}">
<x-inputs.input name="date"
type="date"
class="border-0 shadow-none p-0 text-center"
:value="$date->toDateString()"
x-on:change="$el.submit();"
required />
</form>
</div>
<div>
<a class="text-gray-500 hover:text-gray-700 hover:border-gray-300"
href="{{ route(Route::current()->getName(), ['date' => $date->copy()->addDay(1)->toDateString()]) }}">
<svg class="w-6 h-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-8.707l-3-3a1 1 0 00-1.414 1.414L10.586 9H7a1 1 0 100 2h3.586l-1.293 1.293a1 1 0 101.414 1.414l3-3a1 1 0 000-1.414z" clip-rule="evenodd" />
</svg>
</a>
</div>
</div>
</h1>
<h1 class="font-semibold text-2xl text-gray-800 leading-tight">My Goals</h1>
<x-button-link.green href="{{ route('goals.create') }}" class="text-sm">
Add Goal
</x-button-link.green>
</div>
</x-slot>
<div class="space-y-4">
@forelse($goals['present'] as $goal)
<div class="flex space-x-2 items-center">
<a class="text-gray-500 hover:text-gray-700 hover:border-gray-300 text-sm"
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">
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z" />
<path fill-rule="evenodd" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" clip-rule="evenodd" />
</svg>
</a>
<a class="text-red-500 hover:text-red-700 hover:border-red-300 text-sm"
href="{{ route('goals.delete', $goal) }}">
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
</svg>
</a>
<div class="text-lg font-bold">{{ $goal->summary }}</div>
</div>
@empty
<div>No goals set.</div>
@endforelse
</div>
<table class="w-full table-fixed">
<thead>
<tr class="bg-gray-200 text-gray-600 uppercase text-sm leading-normal">
<th class="py-3 px-6 text-left">Name</th>
<th class="hidden py-3 px-6 text-left lg:table-cell">Days of Week</th>
<th class="hidden py-3 px-6 text-left sm:table-cell">Total Calories</th>
<th class="py-3 px-6 text-left">Operations</th>
</tr>
</thead>
<tbody>
@foreach($goals as $goal)
<tr class="border-b border-gray-200">
<td class="py-3 px-6">
<a class="text-gray-500 hover:text-gray-700 hover:border-gray-300"
href="{{ route('goals.show', $goal) }}">
{{ $goal->name }}
</a>
</td>
<td class="hidden py-3 px-6 lg:table-cell">
@empty($goal->days_formatted->count())
<em>none</em>
@else
{{ $goal->days_formatted->pluck('label')->join(', ') }}
@endempty
</td>
<td class="hidden py-3 px-6 sm:table-cell">
{{ number_format($goal->calories) }}
</td>
<td class="py-3 px-6">
<div class="flex flex-col space-y-2 justify-start sm:flex-row sm:space-x-2 sm:space-y-0">
<x-button-link.gray href="{{ route('goals.edit', $goal) }}">
Edit
</x-button-link.gray>
<x-button-link.red href="{{ route('goals.delete', $goal) }}">
Delete
</x-button-link.red>
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</x-app-layout>

View File

@ -1,33 +1,67 @@
<x-app-layout>
<x-slot name="title">Goal</x-slot>
<x-slot name="title">{{ $goal->name }}</x-slot>
<x-slot name="header">
<h1 class="font-semibold text-xl text-gray-800 leading-tight flex flex-auto">
{{ $goal->summary }}
<a class="ml-2 text-gray-500 hover:text-gray-700 hover:border-gray-300 text-sm"
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">
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z" />
<path fill-rule="evenodd" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" clip-rule="evenodd" />
</svg>
</a>
<a class="h-6 w-6 text-red-500 hover:text-red-700 hover:border-red-300 float-right text-sm"
href="{{ route('goals.delete', $goal) }}">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
</svg>
</a>
<h1 class="font-semibold text-xl text-gray-800 leading-tight flex flex-auto items-center">
{{ $goal->name }}
</h1>
</x-slot>
<div class="grid grid-cols-2 gap-y-1 gap-x-3 max-w-md inline-grid">
<div class="font-bold">From</div>
<div>{{ $goal->from?->toDateString() ?? 'Any' }}</div>
<div class="font-bold">To</div>
<div>{{ $goal->to?->toDateString() ?? 'Any' }}</div>
<div class="font-bold">Frequency</div>
<div>{{ \Illuminate\Support\Str::ucfirst($frequencyOptions[$goal->frequency]['label']) }}</div>
<div class="font-bold">Trackable</div>
<div>{{ \Illuminate\Support\Str::ucfirst($nameOptions[$goal->name]['label']) }}</div>
<div class="font-bold">Goal</div>
<div>{{ $goal->goal }}{{ $nameOptions[$goal->name]['unit'] }}</div>
<div class="flex flex-col-reverse justify-between pb-4 md:flex-row md:space-x-4">
<div class="flex-1">
<section>
Default goal <span class="font-bold">{{ $goal->days_formatted->count() }}</span> days per week.
@if($goal->days_formatted->count() > 1)
<ul class="list-disc list-inside pt-2">
@foreach($goal->days_formatted->pluck('label') as $day)
<li>{{ \Illuminate\Support\Str::ucfirst($day) }}</li>
@endforeach
</ul>
@endif
</section>
</div>
<aside class="flex flex-col space-y-4 mt-8 sm:mt-0 sm:max-w-xs">
<section class="p-1 border-2 border-black font-sans md:w-72">
<h1 class="text-3xl font-extrabold leading-none border-b-8 border-black">Goals</h1>
<h2 class="font-bold text-right">Amount per day</h2>
<section class="flex justify-between items-end font-extrabold">
<h1 class="text-3xl">Calories</h1>
<div class="text-4xl">{{ number_format($goal->calories) }}</div>
</section>
<div class="border-t-4 border-black text-sm">
<hr class="border-gray-500"/>
<section class="flex justify-between">
<h1 class="font-bold">Total Fat</h1>
<div>{{ number_format($goal->fat) }}g</div>
</section>
<hr class="border-gray-500"/>
<section class="flex justify-between">
<h1 class="font-bold">Cholesterol</h1>
<div>{{ number_format($goal->cholesterol) }}mg</div>
</section>
<hr class="border-gray-500"/>
<section class="flex justify-between">
<h1 class="font-bold">Sodium</h1>
<div>{{ number_format($goal->sodium) }}mg</div>
</section>
<hr class="border-gray-500"/>
<section class="flex justify-between">
<h1 class="font-bold">Total Carbohydrate</h1>
<div>{{ number_format($goal->carbohydrates) }}g</div>
</section>
<hr class="border-gray-500"/>
<section class="flex justify-between">
<h1 class="font-bold">Protein</h1>
<div>{{ number_format($goal->protein) }}g</div>
</section>
</div>
</section>
<section class="flex flex-row space-x-2 justify-around md:flex-col md:space-y-2 md:space-x-0">
<x-button-link.gray href="{{ route('goals.edit', $goal) }}">
Edit Goal
</x-button-link.gray>
<x-button-link.red href="{{ route('goals.delete', $goal) }}">
Delete Goal
</x-button-link.red>
</section>
</aside>
</div>
</x-app-layout>

View File

@ -23,10 +23,10 @@
</svg>
</x-inputs.icon-green>
<div class="flex items-center justify-end mt-4 space-x-4">
<fieldset class="flex space-x-2">
<x-inputs.input name="group_entries" type="checkbox" class="h-5 w-5" value="1" />
<x-inputs.label for="groupEntries" value="Group entries by day and meal" />
</fieldset>
<x-inputs.label class="inline-flex items-center">
<x-inputs.input type="checkbox" name="group_entries" class="h-5 w-5" value="1" />
<span class="ml-2">Group entries by day and meal</span>
</x-inputs.label>
<x-inputs.button x-on:click="removeTemplate($el);">Add entries</x-inputs.button>
</div>
</div>

View File

@ -51,7 +51,7 @@
<span class="text-lg">{{ number_format($sums['calories']) }}</span>
</div>
<div class="font-extrabold text-right text-lg">
{{ $dailyGoals['calories'] ?? 'N/A' }}
{{ $goalProgress['calories'] ?? 'N/A' }}
</div>
</div>
<div class="flex justify-between items-baseline border-b border-gray-300 text-sm">
@ -60,7 +60,7 @@
{{ number_format($sums['fat']) }}g
</div>
<div class="text-right">
{{ $dailyGoals['fat'] ?? 'N/A' }}
{{ $goalProgress['fat'] ?? 'N/A' }}
</div>
</div>
<div class="flex justify-between items-baseline border-b border-gray-300 text-sm">
@ -69,7 +69,7 @@
{{ number_format($sums['cholesterol']) }}mg
</div>
<div class="text-right">
{{ $dailyGoals['cholesterol'] ?? 'N/A' }}
{{ $goalProgress['cholesterol'] ?? 'N/A' }}
</div>
</div>
<div class="flex justify-between items-baseline border-b border-gray-300 text-sm">
@ -78,7 +78,7 @@
{{ number_format($sums['sodium']) }}mg
</div>
<div class="text-right">
{{ $dailyGoals['sodium'] ?? 'N/A' }}
{{ $goalProgress['sodium'] ?? 'N/A' }}
</div>
</div>
<div class="flex justify-between items-baseline border-b border-gray-300 text-sm">
@ -87,7 +87,7 @@
{{ number_format($sums['carbohydrates']) }}g
</div>
<div class="text-right">
{{ $dailyGoals['carbohydrates'] ?? 'N/A' }}
{{ $goalProgress['carbohydrates'] ?? 'N/A' }}
</div>
</div>
<div class="flex justify-between items-baseline text-sm">
@ -96,9 +96,43 @@
{{ number_format($sums['protein']) }}g
</div>
<div class="text-right">
{{ $dailyGoals['protein'] ?? 'N/A' }}
{{ $goalProgress['protein'] ?? 'N/A' }}
</div>
</div>
<section class="pt-2" x-data="{ showGoalChangeForm: false }">
<h4 class="font-semibold text-lg">
Goal
<span class="text-sm text-gray-500 hover:text-gray-700 hover:border-gray-300 font-normal cursor-pointer"
x-show="!showGoalChangeForm"
x-on:click="showGoalChangeForm = !showGoalChangeForm">[change]</span>
</h4>
<div x-show="!showGoalChangeForm">
@empty($currentGoal)
<div class="italic">No goal.</div>
@else
<a class="text-gray-500 hover:text-gray-700 hover:border-gray-300"
href="{{ route('goals.show', $currentGoal) }}">
{{ $currentGoal->name }}
</a>
@endempty
</div>
<div x-show="showGoalChangeForm">
<form method="POST" action="{{ route('journal-dates.update.goal', $journalDate) }}">
@csrf
<x-inputs.select name="goal"
class="block w-full"
:options="$goalOptions ?? []"
:selectedValue="$currentGoal?->id ?? null">
</x-inputs.select>
<div class="flex items-center justify-start mt-4">
<x-inputs.button class="bg-green-800 hover:bg-green-700">Change Goal</x-inputs.button>
<x-button-link.red class="ml-3" x-on:click="showGoalChangeForm = !showGoalChangeForm">
Cancel
</x-button-link.red>
</div>
</form>
</div>
</section>
</div>
<div class="w-full sm:w-3/5 md:w-2/3 lg:w-3/4 flex flex-col space-y-4">
@foreach(['breakfast', 'lunch', 'dinner', 'snacks'] as $meal)
@ -110,9 +144,9 @@
</div>
<span class="text-sm text-gray-500">
@foreach(\App\Support\Nutrients::all()->sortBy('weight') as $nutrient)
{{ \App\Support\Nutrients::round($entries->where('meal', $meal)->sum($nutrient['value']), $nutrient['value']) }}{{ $nutrient['unit'] }}
{{ $nutrient['value'] }}@if(!$loop->last), @endif
@endforeach
{{ \App\Support\Nutrients::round($entries->where('meal', $meal)->sum($nutrient['value']), $nutrient['value']) }}{{ $nutrient['unit'] }}
{{ $nutrient['value'] }}@if(!$loop->last), @endif
@endforeach
</span>
</h3>
@forelse($entries->where('meal', $meal) as $entry)

View File

@ -3,6 +3,7 @@
use App\Http\Controllers\FoodController;
use App\Http\Controllers\GoalController;
use App\Http\Controllers\IngredientPickerController;
use App\Http\Controllers\JournalDateController;
use App\Http\Controllers\JournalEntryController;
use App\Http\Controllers\ProfileController;
use App\Http\Controllers\RecipeController;
@ -30,6 +31,9 @@ Route::middleware(['auth'])->group(function () {
// Ingredient picker.
Route::get('/ingredient-picker/search', [IngredientPickerController::class, 'search'])->name('ingredient-picker.search');
// Journal dates.
Route::post('/journal-dates/{journal_date}/update/goal', [JournalDateController::class, 'updateGoal'])->name('journal-dates.update.goal');
// Journal entries.
Route::get('/journal-entries/create/from-nutrients', [JournalEntryController::class, 'createFromNutrients'])->name('journal-entries.create.from-nutrients');
Route::post('/journal-entries/create/from-nutrients', [JournalEntryController::class, 'storeFromNutrients'])->name('journal-entries.store.from-nutrients');

View File

@ -41,4 +41,39 @@ class GoalControllerTest extends HttpControllerTestCase
return $this->factory()->for($this->user)->create();
}
/**
* @inheritdoc
*/
public function testCanAddInstance(): void
{
$create_url = action([$this->class(), 'create']);
$response = $this->get($create_url);
$response->assertOk();
$data = $this->factory()->makeOne()->toArray();
$data['days'] = Goal::days()->pluck('value')->random(3)->toArray();
$store_url = action([$this->class(), 'store']);
$response = $this->post($store_url, $data);
$response->assertSessionHasNoErrors();
}
/**
* @inheritdoc
*/
public function testCanEditInstance(): void
{
$instance = $this->createInstance();
$edit_url = action([$this->class(), 'edit'], [$this->routeKey() => $instance]);
$response = $this->get($edit_url);
$response->assertOk();
$data = $this->factory()->makeOne()->toArray();
$data['days'] = Goal::days()->pluck('value')->random(3)->toArray();
$put_url = action([$this->class(), 'update'], [$this->routeKey() => $instance]);
$response = $this->put($put_url, $data);
$response->assertSessionHasNoErrors();
}
}