feat(dashboard): add price dashboard with Zonneplan integration

This commit is contained in:
2026-08-01 19:53:18 +02:00
parent 49919fef32
commit 1cd905ca4a
29 changed files with 1701 additions and 28 deletions
@@ -0,0 +1,60 @@
<?php
namespace App\Features\Dashboard\Clients;
use App\Features\Dashboard\Contracts\PriceClient;
use Exception;
use Illuminate\Http\Client\Factory;
use Illuminate\Support\Facades\Log;
use Throwable;
class ZonneplanPriceClient implements PriceClient
{
public function __construct(
private readonly Factory $http,
) {}
public function getElectricityPrices(): array
{
return $this->get('/energy-prices/electricity/upcoming');
}
public function getGasPrices(): array
{
return $this->get('/energy-prices/gas/upcoming');
}
/** @return array<int, array<string, mixed>> */
private function get(string $path): array
{
try {
$response = $this->http
->baseUrl(config('api.baseurl'))
->withQueryParameters([
'secret' => config('api.key'),
])
->timeout(10)
->retry(2, 100)
->get($path);
$response->throw();
Log::info('Zonneplan API opgehaald', [
'path' => $path,
'status' => $response->status(),
]);
return $response->json('data', []);
} catch (Throwable $e) {
Log::error('Zonneplan API aanroep mislukt', [
'path' => $path,
'message' => $e->getMessage(),
]);
throw new Exception(
"Kon energieprijzen niet ophalen voor {$path}",
previous: $e,
);
}
}
}
@@ -0,0 +1,10 @@
<?php
namespace App\Features\Dashboard\Contracts;
interface PriceClient
{
public function getElectricityPrices(): array;
public function getGasPrices(): array;
}
@@ -0,0 +1,12 @@
<?php
namespace App\Features\Dashboard\Contracts;
use Illuminate\Support\Collection;
interface PriceRepository
{
public function retrieveElectricity(): Collection;
public function retrieveGas(): Collection;
}
@@ -0,0 +1,15 @@
<?php
namespace App\Features\Dashboard\Controllers;
use App\Features\Dashboard\Data\DashboardData;
use App\Features\Dashboard\Services\DashboardService;
use App\Http\Controllers\Controller;
class DashboardController extends Controller
{
public function index(DashboardService $dashboardService)
{
return inertia('dashboard::index', DashboardData::from($dashboardService->getDashboardData()));
}
}
@@ -0,0 +1,17 @@
<?php
namespace App\Features\Dashboard\Data;
use Spatie\LaravelData\Data;
class DashboardData extends Data
{
/**
* @property array<ElectricityData> $electricity
* @property array<GasData> $gas
*/
public function __construct(
public array $electricity,
public array $gas
) {}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Features\Dashboard\Data;
use Carbon\Carbon;
use Spatie\LaravelData\Attributes\MapInputName;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\Mappers\SnakeCaseMapper;
#[MapInputName(SnakeCaseMapper::class)]
class ElectricityData extends Data
{
public function __construct(
public Carbon $startDate,
public Carbon $endDate,
public string $period,
public ?int $marketPrice,
public ?float $totalPriceTaxIncluded,
public ?int $priceInclHandlingVat,
public ?int $priceTaxWithVat,
public ?string $pricingProfile,
public ?int $carbonFootprintInGram,
public ?int $sustainabilityScore,
public Carbon $startDateDatetime,
) {}
}
+23
View File
@@ -0,0 +1,23 @@
<?php
namespace App\Features\Dashboard\Data;
use Carbon\Carbon;
use Spatie\LaravelData\Attributes\MapInputName;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\Mappers\SnakeCaseMapper;
#[MapInputName(SnakeCaseMapper::class)]
class GasData extends Data
{
public function __construct(
public Carbon $startDate,
public Carbon $endDate,
public string $period,
public int $marketPrice,
public float $totalPriceTaxIncluded,
public int $priceInclHandlingVat,
public int $priceTaxWithVat,
public Carbon $startDateDatetime,
) {}
}
@@ -0,0 +1,33 @@
<?php
namespace App\Features\Dashboard\Repositories;
use App\Features\Dashboard\Contracts\PriceClient;
use App\Features\Dashboard\Contracts\PriceRepository as ContractsPriceRepository;
use App\Features\Dashboard\Data\ElectricityData;
use App\Features\Dashboard\Data\GasData;
use Illuminate\Support\Collection;
use Override;
class ZonneplanPriceRepository implements ContractsPriceRepository
{
public function __construct(
public PriceClient $client
) {}
#[Override]
public function retrieveElectricity(): Collection
{
$data = $this->client->getElectricityPrices();
return collect(ElectricityData::collect($data));
}
#[Override]
public function retrieveGas(): Collection
{
$data = $this->client->getGasPrices();
return collect(GasData::collect($data));
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Features\Dashboard\Services;
use App\Features\Dashboard\Contracts\PriceRepository;
class DashboardService
{
public function __construct(
public PriceRepository $repository
) {}
public function getDashboardData(): array
{
return [
'electricity' => $this->repository->retrieveElectricity(),
'gas' => $this->repository->retrieveGas(),
];
}
}
+6 -1
View File
@@ -2,6 +2,10 @@
namespace App\Providers;
use App\Features\Dashboard\Clients\ZonneplanPriceClient;
use App\Features\Dashboard\Contracts\PriceClient;
use App\Features\Dashboard\Contracts\PriceRepository;
use App\Features\Dashboard\Repositories\ZonneplanPriceRepository;
use Carbon\CarbonImmutable;
use Illuminate\Support\Facades\Date;
use Illuminate\Support\Facades\DB;
@@ -15,7 +19,8 @@ class AppServiceProvider extends ServiceProvider
*/
public function register(): void
{
//
$this->app->bind(PriceRepository::class, ZonneplanPriceRepository::class);
$this->app->bind(PriceClient::class, ZonneplanPriceClient::class);
}
/**
@@ -0,0 +1,27 @@
<?php
namespace App\Providers;
use Carbon\Carbon;
use Spatie\LaravelTypeScriptTransformer\LaravelData\Transformers\DataClassTransformer;
use Spatie\LaravelTypeScriptTransformer\TypeScriptTransformerApplicationServiceProvider as BaseTypeScriptTransformerServiceProvider;
use Spatie\TypeScriptTransformer\Formatters\PrettierFormatter;
use Spatie\TypeScriptTransformer\Transformers\AttributedClassTransformer;
use Spatie\TypeScriptTransformer\Transformers\EnumTransformer;
use Spatie\TypeScriptTransformer\TypeScriptTransformerConfigFactory;
use Spatie\TypeScriptTransformer\Writers\GlobalNamespaceWriter;
class TypeScriptTransformerServiceProvider extends BaseTypeScriptTransformerServiceProvider
{
protected function configure(TypeScriptTransformerConfigFactory $config): void
{
$config
->transformer(AttributedClassTransformer::class)
->transformer(EnumTransformer::class)
->transformer(DataClassTransformer::class)
->transformDirectories(app_path())
->writer(new GlobalNamespaceWriter('generated.d.ts'))
->replaceType(Carbon::class, 'string')
->formatter(PrettierFormatter::class);
}
}
+1
View File
@@ -10,6 +10,7 @@ use Illuminate\Http\Request;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
+2 -3
View File
@@ -1,7 +1,6 @@
<?php
use App\Providers\AppServiceProvider;
return [
AppServiceProvider::class,
App\Providers\AppServiceProvider::class,
App\Providers\TypeScriptTransformerServiceProvider::class,
];
+4 -1
View File
@@ -12,8 +12,11 @@
"php": "^8.3",
"inertiajs/inertia-laravel": "^3.0",
"laravel/framework": "^13.17",
"laravel/sanctum": "^4.0",
"laravel/tinker": "^3.0",
"laravel/wayfinder": "^0.1.14"
"laravel/wayfinder": "^0.1.14",
"spatie/laravel-data": "^4.23",
"spatie/laravel-typescript-transformer": "^3.3"
},
"require-dev": {
"fakerphp/faker": "^1.24",
Generated
+896 -2
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "2aa48cb18d9117816dd50919f7821eae",
"content-hash": "74c9f4a64b7072e442dd9bc4225562b2",
"packages": [
{
"name": "brick/math",
@@ -209,6 +209,54 @@
},
"time": "2024-07-08T12:26:09+00:00"
},
{
"name": "doctrine/deprecations",
"version": "1.1.6",
"source": {
"type": "git",
"url": "https://github.com/doctrine/deprecations.git",
"reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca",
"reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"conflict": {
"phpunit/phpunit": "<=7.5 || >=14"
},
"require-dev": {
"doctrine/coding-standard": "^9 || ^12 || ^14",
"phpstan/phpstan": "1.4.10 || 2.1.30",
"phpstan/phpstan-phpunit": "^1.0 || ^2",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12.4 || ^13.0",
"psr/log": "^1 || ^2 || ^3"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
},
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\Deprecations\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
"source": "https://github.com/doctrine/deprecations/tree/1.1.6"
},
"time": "2026-02-07T07:09:04+00:00"
},
{
"name": "doctrine/inflector",
"version": "2.1.0",
@@ -1129,6 +1177,50 @@
},
"time": "2026-07-29T09:10:23+00:00"
},
{
"name": "jetbrains/phpstorm-stubs",
"version": "v2026.2",
"source": {
"type": "git",
"url": "https://github.com/JetBrains/phpstorm-stubs",
"reference": "709e512210784a7c0a677b3a89d35def844a59b9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/JetBrains/phpstorm-stubs/zipball/709e512210784a7c0a677b3a89d35def844a59b9",
"reference": "709e512210784a7c0a677b3a89d35def844a59b9",
"shasum": ""
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^v3.86",
"nikic/php-parser": "^v5.6",
"phpdocumentor/reflection-docblock": "^5.6",
"phpunit/phpunit": "^12.3"
},
"type": "library",
"autoload": {
"files": [
"PhpStormStubsMap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"description": "PHP runtime & extensions header files for PhpStorm",
"homepage": "https://www.jetbrains.com/phpstorm",
"keywords": [
"autocomplete",
"code",
"inference",
"inspection",
"jetbrains",
"phpstorm",
"stubs",
"type"
],
"time": "2026-06-12T13:19:10+00:00"
},
{
"name": "laravel/framework",
"version": "v13.23.0",
@@ -1415,6 +1507,69 @@
},
"time": "2026-06-26T00:11:25+00:00"
},
{
"name": "laravel/sanctum",
"version": "v4.3.3",
"source": {
"type": "git",
"url": "https://github.com/laravel/sanctum.git",
"reference": "fee27a573d1a013af3721d86153a65e0b11927e6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/sanctum/zipball/fee27a573d1a013af3721d86153a65e0b11927e6",
"reference": "fee27a573d1a013af3721d86153a65e0b11927e6",
"shasum": ""
},
"require": {
"ext-json": "*",
"illuminate/console": "^11.0|^12.0|^13.0",
"illuminate/contracts": "^11.0|^12.0|^13.0",
"illuminate/database": "^11.0|^12.0|^13.0",
"illuminate/support": "^11.0|^12.0|^13.0",
"php": "^8.2",
"symfony/console": "^7.0|^8.0"
},
"require-dev": {
"mockery/mockery": "^1.6",
"orchestra/testbench": "^9.15|^10.8|^11.0",
"phpstan/phpstan": "^1.10"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Laravel\\Sanctum\\SanctumServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Laravel\\Sanctum\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "Laravel Sanctum provides a featherweight authentication system for SPAs and simple APIs.",
"keywords": [
"auth",
"laravel",
"sanctum"
],
"support": {
"issues": "https://github.com/laravel/sanctum/issues",
"source": "https://github.com/laravel/sanctum"
},
"time": "2026-06-23T18:26:55+00:00"
},
{
"name": "laravel/serializable-closure",
"version": "v2.0.15",
@@ -2677,6 +2832,182 @@
],
"time": "2026-02-16T23:10:27+00:00"
},
{
"name": "phpdocumentor/reflection-common",
"version": "2.2.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionCommon.git",
"reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
"reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-2.x": "2.x-dev"
}
},
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jaap van Otterdijk",
"email": "opensource@ijaap.nl"
}
],
"description": "Common reflection classes used by phpdocumentor to reflect the code structure",
"homepage": "http://www.phpdoc.org",
"keywords": [
"FQSEN",
"phpDocumentor",
"phpdoc",
"reflection",
"static analysis"
],
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
"source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x"
},
"time": "2020-06-27T09:03:43+00:00"
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "6.0.3",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "7bae67520aa9f5ecc506d646810bd40d9da54582"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/7bae67520aa9f5ecc506d646810bd40d9da54582",
"reference": "7bae67520aa9f5ecc506d646810bd40d9da54582",
"shasum": ""
},
"require": {
"doctrine/deprecations": "^1.1",
"ext-filter": "*",
"php": "^7.4 || ^8.0",
"phpdocumentor/reflection-common": "^2.2",
"phpdocumentor/type-resolver": "^2.0",
"phpstan/phpdoc-parser": "^2.0",
"webmozart/assert": "^1.9.1 || ^2"
},
"require-dev": {
"mockery/mockery": "~1.3.5 || ~1.6.0",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-mockery": "^1.1",
"phpstan/phpstan-webmozart-assert": "^1.2",
"phpunit/phpunit": "^9.5",
"psalm/phar": "^5.26",
"shipmonk/dead-code-detector": "^0.5.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.x-dev"
}
},
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mike van Riel",
"email": "me@mikevanriel.com"
},
{
"name": "Jaap van Otterdijk",
"email": "opensource@ijaap.nl"
}
],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/6.0.3"
},
"time": "2026-03-18T20:49:53+00:00"
},
{
"name": "phpdocumentor/type-resolver",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "327a05bbee54120d4786a0dc67aad30226ad4cf9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/327a05bbee54120d4786a0dc67aad30226ad4cf9",
"reference": "327a05bbee54120d4786a0dc67aad30226ad4cf9",
"shasum": ""
},
"require": {
"doctrine/deprecations": "^1.0",
"php": "^7.4 || ^8.0",
"phpdocumentor/reflection-common": "^2.0",
"phpstan/phpdoc-parser": "^2.0"
},
"require-dev": {
"ext-tokenizer": "*",
"phpbench/phpbench": "^1.2",
"phpstan/extension-installer": "^1.4",
"phpstan/phpstan": "^2.1",
"phpstan/phpstan-phpunit": "^2.0",
"phpunit/phpunit": "^9.5",
"psalm/phar": "^4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-1.x": "1.x-dev",
"dev-2.x": "2.x-dev"
}
},
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mike van Riel",
"email": "me@mikevanriel.com"
}
],
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/2.0.0"
},
"time": "2026-01-06T21:53:42+00:00"
},
{
"name": "phpoption/phpoption",
"version": "1.9.5",
@@ -3488,6 +3819,503 @@
},
"time": "2026-06-18T03:57:49+00:00"
},
{
"name": "roave/better-reflection",
"version": "6.72.0",
"source": {
"type": "git",
"url": "https://github.com/Roave/BetterReflection.git",
"reference": "b34deeed26ec22233b1a776591ef45abc154a17d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Roave/BetterReflection/zipball/b34deeed26ec22233b1a776591ef45abc154a17d",
"reference": "b34deeed26ec22233b1a776591ef45abc154a17d",
"shasum": ""
},
"require": {
"ext-json": "*",
"jetbrains/phpstorm-stubs": "2026.2",
"nikic/php-parser": "^5.8.0",
"php": "~8.4.1 || ~8.5.0"
},
"conflict": {
"thecodingmachine/safe": "<1.1.3"
},
"require-dev": {
"phpbench/phpbench": "^1.7.0",
"phpunit/phpunit": "^13.2.4"
},
"suggest": {
"composer/composer": "Required to use the ComposerSourceLocator"
},
"type": "library",
"autoload": {
"psr-4": {
"Roave\\BetterReflection\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "James Titcumb",
"email": "james@asgrim.com",
"homepage": "https://github.com/asgrim"
},
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com",
"homepage": "https://ocramius.github.io/"
},
{
"name": "Gary Hockin",
"email": "gary@roave.com",
"homepage": "https://github.com/geeh"
},
{
"name": "Jaroslav Hanslík",
"email": "kukulich@kukulich.cz",
"homepage": "https://github.com/kukulich"
}
],
"description": "Better Reflection - an improved code reflection API",
"support": {
"issues": "https://github.com/Roave/BetterReflection/issues",
"source": "https://github.com/Roave/BetterReflection/tree/6.72.0"
},
"time": "2026-07-22T18:50:32+00:00"
},
{
"name": "spatie/file-system-watcher",
"version": "1.2.1",
"source": {
"type": "git",
"url": "https://github.com/spatie/file-system-watcher.git",
"reference": "2fe96de88af6660b3ab7658a8f1d41b10ad0aff6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/file-system-watcher/zipball/2fe96de88af6660b3ab7658a8f1d41b10ad0aff6",
"reference": "2fe96de88af6660b3ab7658a8f1d41b10ad0aff6",
"shasum": ""
},
"require": {
"php": "^8.3",
"symfony/process": "^7.0|^8.0"
},
"require-dev": {
"pestphp/pest": "^4.0",
"spatie/ray": "^1.22",
"spatie/temporary-directory": "^2.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\Watcher\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "freek@spatie.be",
"role": "Developer"
}
],
"description": "Watch changes in the file system using PHP",
"homepage": "https://github.com/spatie/file-system-watcher",
"keywords": [
"file-system-watcher",
"spatie"
],
"support": {
"issues": "https://github.com/spatie/file-system-watcher/issues",
"source": "https://github.com/spatie/file-system-watcher/tree/1.2.1"
},
"funding": [
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2025-11-26T10:41:42+00:00"
},
{
"name": "spatie/laravel-data",
"version": "4.23.0",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-data.git",
"reference": "230543769c996e407fec2873930626aed7dd0d3b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-data/zipball/230543769c996e407fec2873930626aed7dd0d3b",
"reference": "230543769c996e407fec2873930626aed7dd0d3b",
"shasum": ""
},
"require": {
"illuminate/contracts": "^10.0|^11.0|^12.0|^13.0",
"php": "^8.1",
"phpdocumentor/reflection-common": "^2.2",
"phpdocumentor/reflection-docblock": "^5.3 || ^6.0",
"phpdocumentor/type-resolver": "^1.7 || ^2.0",
"spatie/laravel-package-tools": "^1.9.0",
"spatie/php-structure-discoverer": "^2.0"
},
"require-dev": {
"fakerphp/faker": "^1.14",
"friendsofphp/php-cs-fixer": "^3.0",
"inertiajs/inertia-laravel": "^2.0|^3.0",
"livewire/livewire": "^3.0|^4.0",
"mockery/mockery": "^1.6",
"nesbot/carbon": "^2.63|^3.0",
"orchestra/testbench": "^8.37.0|^9.16|^10.9|^11.0",
"pestphp/pest": "^2.36|^3.8|^4.3",
"pestphp/pest-plugin-laravel": "^2.4|^3.0|^4.0",
"pestphp/pest-plugin-livewire": "^2.1|^3.0|^4.0",
"phpbench/phpbench": "^1.2",
"phpstan/extension-installer": "^1.1",
"spatie/invade": "^1.0",
"spatie/laravel-typescript-transformer": "^2.5",
"spatie/pest-plugin-snapshots": "^2.1",
"spatie/test-time": "^1.2"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Spatie\\LaravelData\\LaravelDataServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Spatie\\LaravelData\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ruben Van Assche",
"email": "ruben@spatie.be",
"role": "Developer"
}
],
"description": "Create unified resources and data transfer objects",
"homepage": "https://github.com/spatie/laravel-data",
"keywords": [
"laravel",
"laravel-data",
"spatie"
],
"support": {
"issues": "https://github.com/spatie/laravel-data/issues",
"source": "https://github.com/spatie/laravel-data/tree/4.23.0"
},
"funding": [
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2026-05-08T14:41:13+00:00"
},
{
"name": "spatie/laravel-package-tools",
"version": "1.93.1",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-package-tools.git",
"reference": "d5552849801f2642aea710557463234b59ef65eb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/d5552849801f2642aea710557463234b59ef65eb",
"reference": "d5552849801f2642aea710557463234b59ef65eb",
"shasum": ""
},
"require": {
"illuminate/contracts": "^10.0|^11.0|^12.0|^13.0",
"php": "^8.1"
},
"require-dev": {
"mockery/mockery": "^1.5",
"orchestra/testbench": "^8.0|^9.2|^10.0|^11.0",
"pestphp/pest": "^2.1|^3.1|^4.0",
"phpunit/php-code-coverage": "^10.0|^11.0|^12.0",
"phpunit/phpunit": "^10.5|^11.5|^12.5",
"spatie/pest-plugin-test-time": "^2.2|^3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\LaravelPackageTools\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "freek@spatie.be",
"role": "Developer"
}
],
"description": "Tools for creating Laravel packages",
"homepage": "https://github.com/spatie/laravel-package-tools",
"keywords": [
"laravel-package-tools",
"spatie"
],
"support": {
"issues": "https://github.com/spatie/laravel-package-tools/issues",
"source": "https://github.com/spatie/laravel-package-tools/tree/1.93.1"
},
"funding": [
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2026-05-19T14:06:37+00:00"
},
{
"name": "spatie/laravel-typescript-transformer",
"version": "3.3.0",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-typescript-transformer.git",
"reference": "1978273b6407adf78f7f55833423a81ace6ba03c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-typescript-transformer/zipball/1978273b6407adf78f7f55833423a81ace6ba03c",
"reference": "1978273b6407adf78f7f55833423a81ace6ba03c",
"shasum": ""
},
"require": {
"illuminate/contracts": "^11.0|^12.0|^13.0",
"php": "^8.2",
"spatie/typescript-transformer": "^3.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.0",
"orchestra/testbench": "^9.0|^10.0|^11.0",
"pestphp/pest": "^3.0|^4.2",
"pestphp/pest-plugin-arch": "^3.0|^4.0",
"pestphp/pest-plugin-laravel": "^3.0|^4.0",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^2.0",
"phpstan/phpstan-deprecation-rules": "^2.0",
"phpstan/phpstan-phpunit": "^2.0",
"spatie/laravel-data": "^4.0"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Spatie\\LaravelTypeScriptTransformer\\TypeScriptTransformerServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Spatie\\LaravelTypeScriptTransformer\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ruben Van Assche",
"email": "ruben@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
}
],
"description": "Transform your PHP structures to TypeScript types",
"homepage": "https://github.com/spatie/typescript-transformer",
"keywords": [
"spatie",
"typescript-transformer"
],
"support": {
"issues": "https://github.com/spatie/laravel-typescript-transformer/issues",
"source": "https://github.com/spatie/laravel-typescript-transformer/tree/3.3.0"
},
"funding": [
{
"url": "https://spatie.be/open-source/support-us",
"type": "custom"
},
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2026-06-19T12:19:54+00:00"
},
{
"name": "spatie/php-structure-discoverer",
"version": "2.4.4",
"source": {
"type": "git",
"url": "https://github.com/spatie/php-structure-discoverer.git",
"reference": "fa2b7dae8e8a22c0306154c4b052420e054f7e2b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/php-structure-discoverer/zipball/fa2b7dae8e8a22c0306154c4b052420e054f7e2b",
"reference": "fa2b7dae8e8a22c0306154c4b052420e054f7e2b",
"shasum": ""
},
"require": {
"illuminate/collections": "^11.0|^12.0|^13.0",
"php": "^8.3",
"spatie/laravel-package-tools": "^1.92.7",
"symfony/finder": "^6.0|^7.3.5|^8.0"
},
"require-dev": {
"amphp/parallel": "^2.3.2",
"illuminate/console": "^11.0|^12.0|^13.0",
"nunomaduro/collision": "^7.0|^8.8.3",
"orchestra/testbench": "^9.5|^10.8|^11.0",
"pestphp/pest": "^3.8|^4.0",
"pestphp/pest-plugin-laravel": "^3.2|^4.0",
"phpstan/extension-installer": "^1.4.3",
"phpstan/phpstan-deprecation-rules": "^1.2.1",
"phpstan/phpstan-phpunit": "^1.4.2",
"spatie/laravel-ray": "^1.43.1"
},
"suggest": {
"amphp/parallel": "When you want to use the Parallel discover worker"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Spatie\\StructureDiscoverer\\StructureDiscovererServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Spatie\\StructureDiscoverer\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ruben Van Assche",
"email": "ruben@spatie.be",
"role": "Developer"
}
],
"description": "Automatically discover structures within your PHP application",
"homepage": "https://github.com/spatie/php-structure-discoverer",
"keywords": [
"discover",
"laravel",
"php",
"php-structure-discoverer"
],
"support": {
"issues": "https://github.com/spatie/php-structure-discoverer/issues",
"source": "https://github.com/spatie/php-structure-discoverer/tree/2.4.4"
},
"funding": [
{
"url": "https://github.com/LaravelAutoDiscoverer",
"type": "github"
}
],
"time": "2026-06-15T07:14:32+00:00"
},
{
"name": "spatie/typescript-transformer",
"version": "3.3.0",
"source": {
"type": "git",
"url": "https://github.com/spatie/typescript-transformer.git",
"reference": "025f73d12a4c0b44d0ceb3e472d56ec540286697"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/typescript-transformer/zipball/025f73d12a4c0b44d0ceb3e472d56ec540286697",
"reference": "025f73d12a4c0b44d0ceb3e472d56ec540286697",
"shasum": ""
},
"require": {
"php": "^8.2",
"phpstan/phpdoc-parser": "^2.3",
"roave/better-reflection": "^6.41",
"spatie/file-system-watcher": "^1.1",
"spatie/php-structure-discoverer": "^2.2",
"symfony/process": "^7.0|^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.0",
"pestphp/pest": "^3.0|^4.0",
"pestphp/pest-plugin-arch": "^3.0|^4.0",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^2.0",
"phpstan/phpstan-deprecation-rules": "^2.0",
"phpstan/phpstan-phpunit": "^2.0",
"spatie/ray": "^1.41",
"spatie/temporary-directory": "^2.1"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\TypeScriptTransformer\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ruben Van Assche",
"email": "ruben@spatie.be",
"role": "Developer"
}
],
"description": "This is my package typescript-transformer",
"homepage": "https://github.com/spatie/typescript-transformer",
"keywords": [
"spatie",
"typescript-transformer"
],
"support": {
"issues": "https://github.com/spatie/typescript-transformer/issues",
"source": "https://github.com/spatie/typescript-transformer/tree/3.3.0"
},
"funding": [
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2026-06-19T14:00:51+00:00"
},
{
"name": "symfony/clock",
"version": "v8.1.0",
@@ -6180,6 +7008,72 @@
}
],
"time": "2026-04-26T05:33:54+00:00"
},
{
"name": "webmozart/assert",
"version": "2.4.1",
"source": {
"type": "git",
"url": "https://github.com/webmozarts/assert.git",
"reference": "2ccb7c2e821038c03a3e6e1700c570c158c55f70"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/2ccb7c2e821038c03a3e6e1700c570c158c55f70",
"reference": "2ccb7c2e821038c03a3e6e1700c570c158c55f70",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-date": "*",
"ext-filter": "*",
"php": "^8.2"
},
"suggest": {
"ext-intl": "",
"ext-simplexml": "",
"ext-spl": ""
},
"type": "library",
"extra": {
"psalm": {
"pluginClass": "Webmozart\\Assert\\PsalmPlugin"
},
"branch-alias": {
"dev-master": "2.0-dev",
"dev-feature/2-0": "2.0-dev"
}
},
"autoload": {
"psr-4": {
"Webmozart\\Assert\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Bernhard Schussek",
"email": "bschussek@gmail.com"
},
{
"name": "Woody Gilk",
"email": "woody.gilk@gmail.com"
}
],
"description": "Assertions to validate method input/output with nice error messages.",
"keywords": [
"assert",
"check",
"validate"
],
"support": {
"issues": "https://github.com/webmozarts/assert/issues",
"source": "https://github.com/webmozarts/assert/tree/2.4.1"
},
"time": "2026-06-15T15:31:57+00:00"
}
],
"packages-dev": [
@@ -8812,5 +9706,5 @@
"php": "^8.3"
},
"platform-dev": {},
"plugin-api-version": "2.6.0"
"plugin-api-version": "2.9.0"
}
+6
View File
@@ -0,0 +1,6 @@
<?php
return [
'key' => env('API_KEY'),
'baseurl' => env('API_BASEURL'),
];
+217
View File
@@ -0,0 +1,217 @@
<?php
use Illuminate\Contracts\Support\Arrayable;
use Spatie\LaravelData\Casts\DateTimeInterfaceCast;
use Spatie\LaravelData\Casts\EnumCast;
use Spatie\LaravelData\Normalizers\ArrayableNormalizer;
use Spatie\LaravelData\Normalizers\ArrayNormalizer;
use Spatie\LaravelData\Normalizers\JsonNormalizer;
use Spatie\LaravelData\Normalizers\ModelNormalizer;
use Spatie\LaravelData\Normalizers\ObjectNormalizer;
use Spatie\LaravelData\RuleInferrers\AttributesRuleInferrer;
use Spatie\LaravelData\RuleInferrers\BuiltInTypesRuleInferrer;
use Spatie\LaravelData\RuleInferrers\NullableRuleInferrer;
use Spatie\LaravelData\RuleInferrers\RequiredRuleInferrer;
use Spatie\LaravelData\RuleInferrers\SometimesRuleInferrer;
use Spatie\LaravelData\Support\Creation\ValidationStrategy;
use Spatie\LaravelData\Transformers\ArrayableTransformer;
use Spatie\LaravelData\Transformers\DateTimeInterfaceTransformer;
use Spatie\LaravelData\Transformers\EnumTransformer;
return [
/*
* The package will use this format when working with dates. If this option
* is an array, it will try to convert from the first format that works,
* and will serialize dates using the first format from the array.
*/
'date_format' => [
'Y-m-d\TH:i:s.u\Z', 'Y-m-d\TH:i:s.uP', 'Y-m-d H:i:s', 'U',
],
/*
* When transforming or casting dates, the following timezone will be used to
* convert the date to the correct timezone. If set to null no timezone will
* be passed.
*/
'date_timezone' => null,
/*
* It is possible to enable certain features of the package, these would otherwise
* be breaking changes, and thus they are disabled by default. In the next major
* version of the package, these features will be enabled by default.
*/
'features' => [
'cast_and_transform_iterables' => false,
/*
* When trying to set a computed property value, the package will throw an exception.
* You can disable this behaviour by setting this option to true, which will then just
* ignore the value being passed into the computed property and recalculate it.
*/
'ignore_exception_when_trying_to_set_computed_property_value' => false,
],
/*
* Global transformers will take complex types and transform them into simple
* types.
*/
'transformers' => [
DateTimeInterface::class => DateTimeInterfaceTransformer::class,
Arrayable::class => ArrayableTransformer::class,
BackedEnum::class => EnumTransformer::class,
],
/*
* Global casts will cast values into complex types when creating a data
* object from simple types.
*/
'casts' => [
DateTimeInterface::class => DateTimeInterfaceCast::class,
BackedEnum::class => EnumCast::class,
// Enumerable::class => Spatie\LaravelData\Casts\EnumerableCast::class,
],
/*
* Rule inferrers can be configured here. They will automatically add
* validation rules to properties of a data object based upon
* the type of the property.
*/
'rule_inferrers' => [
SometimesRuleInferrer::class,
NullableRuleInferrer::class,
RequiredRuleInferrer::class,
BuiltInTypesRuleInferrer::class,
AttributesRuleInferrer::class,
],
/*
* Normalizers return an array representation of the payload, or null if
* it cannot normalize the payload. The normalizers below are used for
* every data object, unless overridden in a specific data object class.
*/
'normalizers' => [
ModelNormalizer::class,
// Spatie\LaravelData\Normalizers\FormRequestNormalizer::class,
ArrayableNormalizer::class,
ObjectNormalizer::class,
ArrayNormalizer::class,
JsonNormalizer::class,
],
/*
* Data objects can be wrapped into a key like 'data' when used as a resource,
* this key can be set globally here for all data objects. You can pass in
* `null` if you want to disable wrapping.
*/
'wrap' => null,
/*
* Adds a specific caster to the Symphony VarDumper component which hides
* some properties from data objects and collections when being dumped
* by `dump` or `dd`. Can be 'enabled', 'disabled' or 'development'
* which will only enable the caster locally.
*/
'var_dumper_caster_mode' => 'development',
/*
* It is possible to skip the PHP reflection analysis of data objects
* when running in production. This will speed up the package. You
* can configure where data objects are stored and which cache
* store should be used.
*
* Structures are cached forever as they'll become stale when your
* application is deployed with changes. You can set a duration
* in seconds if you want the cache to clear after a certain
* timeframe.
*/
'structure_caching' => [
'enabled' => true,
'directories' => [app_path('Data')],
'cache' => [
'store' => env('CACHE_STORE', env('CACHE_DRIVER', 'file')),
'prefix' => 'laravel-data',
'duration' => null,
],
'reflection_discovery' => [
'enabled' => true,
'base_path' => base_path(),
'root_namespace' => null,
],
],
/*
* A data object can be validated when created using a factory or when calling the from
* method. By default, only when a request is passed the data is being validated. This
* behaviour can be changed to always validate or to completely disable validation.
*/
'validation_strategy' => ValidationStrategy::OnlyRequests->value,
/*
* A data object can map the names of its properties when transforming (output) or when
* creating (input). By default, the package will not map any names. You can set a
* global strategy here, or override it on a specific data object.
*/
'name_mapping_strategy' => [
'input' => null,
'output' => null,
],
/*
* When using an invalid include, exclude, only or except partial, the package will
* throw an exception. You can disable this behaviour by setting this option to true.
*/
'ignore_invalid_partials' => false,
/*
* When transforming a nested chain of data objects, the package can end up in an infinite
* loop when including a recursive relationship. The max transformation depth can be
* set as a safety measure to prevent this from happening. When set to null, the
* package will not enforce a maximum depth.
*/
'max_transformation_depth' => null,
/*
* When the maximum transformation depth is reached, the package will throw an exception.
* You can disable this behaviour by setting this option to true which will return an
* empty array.
*/
'throw_when_max_transformation_depth_reached' => true,
/*
* When using the `make:data` command, the package will use these settings to generate
* the data classes. You can override these settings by passing options to the command.
*/
'commands' => [
/*
* Provides default configuration for the `make:data` command. These settings can be overridden with options
* passed directly to the `make:data` command for generating single Data classes, or if not set they will
* automatically fall back to these defaults. See `php artisan make:data --help` for more information
*/
'make' => [
/*
* The default namespace for generated Data classes. This exists under the application's root namespace,
* so the default 'Data` will end up as '\App\Data', and generated Data classes will be placed in the
* app/Data/ folder. Data classes can live anywhere, but this is where `make:data` will put them.
*/
'namespace' => 'Data',
/*
* This suffix will be appended to all data classes generated by make:data, so that they are less likely
* to conflict with other related classes, controllers or models with a similar name without resorting
* to adding an alias for the Data object. Set to a blank string (not null) to disable.
*/
'suffix' => 'Data',
],
],
/*
* When using Livewire, the package allows you to enable or disable the synths
* these synths will automatically handle the data objects and their
* properties when used in a Livewire component.
*/
'livewire' => [
'enable_synths' => false,
],
];
+87
View File
@@ -0,0 +1,87 @@
<?php
use Illuminate\Cookie\Middleware\EncryptCookies;
use Illuminate\Foundation\Http\Middleware\ValidateCsrfToken;
use Laravel\Sanctum\Http\Middleware\AuthenticateSession;
use Laravel\Sanctum\Sanctum;
return [
/*
|--------------------------------------------------------------------------
| Stateful Domains
|--------------------------------------------------------------------------
|
| Requests from the following domains / hosts will receive stateful API
| authentication cookies. Typically, these should include your local
| and production domains which access your API via a frontend SPA.
|
*/
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
Sanctum::currentApplicationUrlWithPort(),
// Sanctum::currentRequestHost(),
))),
/*
|--------------------------------------------------------------------------
| Sanctum Guards
|--------------------------------------------------------------------------
|
| This array contains the authentication guards that will be checked when
| Sanctum is trying to authenticate a request. If none of these guards
| are able to authenticate the request, Sanctum will use the bearer
| token that's present on an incoming request for authentication.
|
*/
'guard' => ['web'],
/*
|--------------------------------------------------------------------------
| Expiration Minutes
|--------------------------------------------------------------------------
|
| This value controls the number of minutes until an issued token will be
| considered expired. This will override any values set in the token's
| "expires_at" attribute, but first-party sessions are not affected.
|
*/
'expiration' => null,
/*
|--------------------------------------------------------------------------
| Token Prefix
|--------------------------------------------------------------------------
|
| Sanctum can prefix new tokens in order to take advantage of numerous
| security scanning initiatives maintained by open source platforms
| that notify developers if they commit tokens into repositories.
|
| See: https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning
|
*/
'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''),
/*
|--------------------------------------------------------------------------
| Sanctum Middleware
|--------------------------------------------------------------------------
|
| When authenticating your first-party SPA with Sanctum you may need to
| customize some of the middleware Sanctum uses while processing the
| request. You may change the middleware listed below as required.
|
*/
'middleware' => [
'authenticate_session' => AuthenticateSession::class,
'encrypt_cookies' => EncryptCookies::class,
'validate_csrf_token' => ValidateCsrfToken::class,
],
];
@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('personal_access_tokens', function (Blueprint $table) {
$table->id();
$table->morphs('tokenable');
$table->text('name');
$table->string('token', 64)->unique();
$table->text('abilities')->nullable();
$table->timestamp('last_used_at')->nullable();
$table->timestamp('expires_at')->nullable()->index();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('personal_access_tokens');
}
};
+132 -17
View File
@@ -1,5 +1,5 @@
{
"name": "html",
"name": "Zonneplan",
"lockfileVersion": 3,
"requires": true,
"packages": {
@@ -9,6 +9,7 @@
"@inertiajs/vue3": "^3.0.0",
"@tailwindcss/vite": "^4.1.11",
"@vitejs/plugin-vue": "^6.0.0",
"axios": "^1.19.0",
"clsx": "^2.1.1",
"concurrently": "^9.0.1",
"laravel-vite-plugin": "^3.1",
@@ -2053,6 +2054,18 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
"license": "MIT",
"dependencies": {
"debug": "4"
},
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/ajv": {
"version": "6.15.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
@@ -2240,6 +2253,12 @@
"node": ">= 0.4"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT"
},
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
@@ -2256,6 +2275,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/axios": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.19.0.tgz",
"integrity": "sha512-ht/iuYZXEjFxLH/Hkezgd7m6JKlHHXEUSneaDz8uZe1Gj5QZtCnpyDsckvAiEnT89OEbCLmnte4R4sn7P0EKFw==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.16.0",
"form-data": "^4.0.6",
"https-proxy-agent": "^5.0.1",
"proxy-from-env": "^2.1.0"
}
},
"node_modules/balanced-match": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
@@ -2322,7 +2353,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@@ -2428,6 +2458,18 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT"
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -2558,7 +2600,6 @@
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -2615,6 +2656,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/detect-libc": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
@@ -2641,7 +2691,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
@@ -2775,7 +2824,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -2785,7 +2833,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -2795,7 +2842,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz",
"integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
@@ -2808,7 +2854,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@@ -3543,6 +3588,26 @@
"dev": true,
"license": "ISC"
},
"node_modules/follow-redirects": {
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
"integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/for-each": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
@@ -3559,6 +3624,22 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/form-data": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz",
"integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.4",
"mime-types": "^2.1.35"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -3577,7 +3658,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -3640,7 +3720,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
@@ -3665,7 +3744,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"dev": true,
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
@@ -3753,7 +3831,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -3823,7 +3900,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -3836,7 +3912,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
@@ -3852,7 +3927,6 @@
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
"integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==",
"dev": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
@@ -3871,6 +3945,19 @@
"he": "bin/he"
}
},
"node_modules/https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
"license": "MIT",
"dependencies": {
"agent-base": "6",
"debug": "4"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -4824,7 +4911,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -4867,6 +4953,27 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/minimatch": {
"version": "10.2.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz",
@@ -4897,7 +5004,6 @@
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true,
"license": "MIT"
},
"node_modules/muggle-string": {
@@ -5402,6 +5508,15 @@
}
}
},
"node_modules/proxy-from-env": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
"integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==",
"license": "MIT",
"engines": {
"node": ">=10"
}
},
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+2 -1
View File
@@ -14,8 +14,8 @@
},
"devDependencies": {
"@eslint/js": "^9.19.0",
"@stylistic/eslint-plugin": "^5.10.0",
"@laravel/vite-plugin-wayfinder": "^0.1.3",
"@stylistic/eslint-plugin": "^5.10.0",
"@types/node": "^22.13.5",
"@vue/eslint-config-typescript": "^14.3.0",
"eslint": "^9.17.0",
@@ -33,6 +33,7 @@
"@inertiajs/vue3": "^3.0.0",
"@tailwindcss/vite": "^4.1.11",
"@vitejs/plugin-vue": "^6.0.0",
"axios": "^1.19.0",
"clsx": "^2.1.1",
"concurrently": "^9.0.1",
"laravel-vite-plugin": "^3.1",
+19
View File
@@ -1,4 +1,5 @@
import { createInertiaApp } from '@inertiajs/vue3';
import { DefineComponent } from 'vue';
const appName = import.meta.env.VITE_APP_NAME || 'Laravel';
@@ -7,4 +8,22 @@ createInertiaApp({
progress: {
color: '#4B5563',
},
resolve(name) {
const pages = import.meta.glob<DefineComponent>(
['./features/*/pages/*.vue', './pages/*.vue'],
{
eager: true,
},
);
if (name.includes('::')) {
const n = name.split('::');
const domain = n[0];
const page = n[1][0].toUpperCase() + n[1].slice(1).toLowerCase();
return pages[`./features/${domain}/pages/${page}.vue`];
}
return pages[`./pages/${name}.vue`];
},
});
@@ -0,0 +1,3 @@
<script setup lang="ts"></script>
<template></template>
@@ -0,0 +1,3 @@
export default function DashboardViewModel() {
return {};
}
+35
View File
@@ -0,0 +1,35 @@
declare namespace App {
namespace Features {
namespace Dashboard {
namespace DTO {
export type DashboardData = {
electricity: App.Features.Dashboard.DTO.ElectricityData;
gas: App.Features.Dashboard.DTO.GasData;
};
export type ElectricityData = {
startDate: string;
endDate: string;
period: string;
marketPrice: number | null;
totalPriceTaxIncluded: number | null;
priceInclHandlingVat: number | null;
priceTaxWithVat: number | null;
pricingProfile: string | null;
carbonFootprintInGram: number | null;
sustainabilityScore: number | null;
startDateDatetime: string;
};
export type GasData = {
startDate: string;
endDate: string;
period: string;
marketPrice: number;
totalPriceTaxIncluded: number;
priceInclHandlingVat: number;
priceTaxWithVat: number;
startDateDatetime: string;
};
}
}
}
}
@@ -0,0 +1,3 @@
{
"generated.d.ts": "237c6a8a14bec8d9c63d81a00b842cf6"
}
+1 -1
View File
@@ -10,7 +10,7 @@
@fonts
@vite(['resources/css/app.css', 'resources/js/app.ts', "resources/js/pages/{$page['component']}.vue"])
@vite(['resources/css/app.css', 'resources/js/app.ts'])
<x-inertia::head>
<title>{{ config('app.name', 'Laravel') }}</title>
</x-inertia::head>
+6
View File
@@ -0,0 +1,6 @@
<?php
use App\Features\Dashboard\Controllers\DashboardController;
use Illuminate\Support\Facades\Route;
Route::get('/energy-prices', [DashboardController::class, 'index'])->name('dashboard.index');
+1 -1
View File
@@ -2,4 +2,4 @@
use Illuminate\Support\Facades\Route;
Route::inertia('/', 'Welcome')->name('home');
Route::inertia('/', 'dashboard::index');