1 - Expose UUIDs in API responses and update frontend types
This commit is contained in:
parent
367f255200
commit
72cc6ff0b7
12 changed files with 43 additions and 31 deletions
|
|
@ -19,7 +19,7 @@ public function index(Scenario $scenario): JsonResponse
|
||||||
->get()
|
->get()
|
||||||
->map(function ($bucket) {
|
->map(function ($bucket) {
|
||||||
return [
|
return [
|
||||||
'id' => $bucket->id,
|
'id' => $bucket->uuid,
|
||||||
'name' => $bucket->name,
|
'name' => $bucket->name,
|
||||||
'priority' => $bucket->priority,
|
'priority' => $bucket->priority,
|
||||||
'sort_order' => $bucket->sort_order,
|
'sort_order' => $bucket->sort_order,
|
||||||
|
|
@ -136,12 +136,12 @@ public function updatePriorities(Request $request, Scenario $scenario): JsonResp
|
||||||
{
|
{
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
'bucket_priorities' => 'required|array',
|
'bucket_priorities' => 'required|array',
|
||||||
'bucket_priorities.*.id' => 'required|exists:buckets,id',
|
'bucket_priorities.*.id' => 'required|exists:buckets,uuid',
|
||||||
'bucket_priorities.*.priority' => 'required|integer|min:1',
|
'bucket_priorities.*.priority' => 'required|integer|min:1',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
foreach ($validated['bucket_priorities'] as $bucketData) {
|
foreach ($validated['bucket_priorities'] as $bucketData) {
|
||||||
$bucket = Bucket::find($bucketData['id']);
|
$bucket = Bucket::where('uuid', $bucketData['id'])->first();
|
||||||
if ($bucket && $bucket->scenario_id === $scenario->id) {
|
if ($bucket && $bucket->scenario_id === $scenario->id) {
|
||||||
$bucket->update([
|
$bucket->update([
|
||||||
'priority' => $bucketData['priority'],
|
'priority' => $bucketData['priority'],
|
||||||
|
|
@ -161,7 +161,7 @@ public function updatePriorities(Request $request, Scenario $scenario): JsonResp
|
||||||
private function formatBucketResponse(Bucket $bucket): array
|
private function formatBucketResponse(Bucket $bucket): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'id' => $bucket->id,
|
'id' => $bucket->uuid,
|
||||||
'name' => $bucket->name,
|
'name' => $bucket->name,
|
||||||
'priority' => $bucket->priority,
|
'priority' => $bucket->priority,
|
||||||
'sort_order' => $bucket->sort_order,
|
'sort_order' => $bucket->sort_order,
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ public function rules(): array
|
||||||
],
|
],
|
||||||
'start_date' => ['required', 'date', 'date_format:Y-m-d'],
|
'start_date' => ['required', 'date', 'date_format:Y-m-d'],
|
||||||
'end_date' => ['nullable', 'date', 'date_format:Y-m-d', 'after_or_equal:start_date'],
|
'end_date' => ['nullable', 'date', 'date_format:Y-m-d', 'after_or_equal:start_date'],
|
||||||
'bucket_id' => ['nullable', 'exists:buckets,id'],
|
'bucket_id' => ['nullable', 'exists:buckets,uuid'],
|
||||||
'description' => ['nullable', 'string', 'max:1000'],
|
'description' => ['nullable', 'string', 'max:1000'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
@ -67,7 +67,7 @@ public function withValidator($validator): void
|
||||||
$scenario = $this->route('scenario');
|
$scenario = $this->route('scenario');
|
||||||
|
|
||||||
$bucketBelongsToScenario = $scenario->buckets()
|
$bucketBelongsToScenario = $scenario->buckets()
|
||||||
->where('id', $this->bucket_id)
|
->where('uuid', $this->bucket_id)
|
||||||
->exists();
|
->exists();
|
||||||
|
|
||||||
if (! $bucketBelongsToScenario) {
|
if (! $bucketBelongsToScenario) {
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ public function rules(): array
|
||||||
],
|
],
|
||||||
'start_date' => ['required', 'date', 'date_format:Y-m-d'],
|
'start_date' => ['required', 'date', 'date_format:Y-m-d'],
|
||||||
'end_date' => ['nullable', 'date', 'date_format:Y-m-d', 'after_or_equal:start_date'],
|
'end_date' => ['nullable', 'date', 'date_format:Y-m-d', 'after_or_equal:start_date'],
|
||||||
'bucket_id' => ['nullable', 'exists:buckets,id'],
|
'bucket_id' => ['nullable', 'exists:buckets,uuid'],
|
||||||
'description' => ['nullable', 'string', 'max:1000'],
|
'description' => ['nullable', 'string', 'max:1000'],
|
||||||
'is_active' => ['boolean'],
|
'is_active' => ['boolean'],
|
||||||
];
|
];
|
||||||
|
|
@ -61,7 +61,7 @@ public function withValidator($validator): void
|
||||||
// Validate that the bucket belongs to the stream's scenario
|
// Validate that the bucket belongs to the stream's scenario
|
||||||
if ($this->bucket_id) {
|
if ($this->bucket_id) {
|
||||||
$bucketBelongsToScenario = $stream->scenario->buckets()
|
$bucketBelongsToScenario = $stream->scenario->buckets()
|
||||||
->where('id', $this->bucket_id)
|
->where('uuid', $this->bucket_id)
|
||||||
->exists();
|
->exists();
|
||||||
|
|
||||||
if (! $bucketBelongsToScenario) {
|
if (! $bucketBelongsToScenario) {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ class BucketResource extends JsonResource
|
||||||
public function toArray(Request $request): array
|
public function toArray(Request $request): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'id' => $this->id,
|
'id' => $this->uuid,
|
||||||
'name' => $this->name,
|
'name' => $this->name,
|
||||||
'priority' => $this->priority,
|
'priority' => $this->priority,
|
||||||
'sort_order' => $this->sort_order,
|
'sort_order' => $this->sort_order,
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ class DrawResource extends JsonResource
|
||||||
public function toArray(Request $request): array
|
public function toArray(Request $request): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'id' => $this->id,
|
'id' => $this->uuid,
|
||||||
'bucket_id' => $this->bucket_id,
|
'bucket_id' => $this->bucket?->uuid,
|
||||||
'amount' => $this->amount_currency,
|
'amount' => $this->amount_currency,
|
||||||
'formatted_amount' => $this->formatted_amount,
|
'formatted_amount' => $this->formatted_amount,
|
||||||
'date' => $this->date->format('Y-m-d'),
|
'date' => $this->date->format('Y-m-d'),
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ class InflowResource extends JsonResource
|
||||||
public function toArray(Request $request): array
|
public function toArray(Request $request): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'id' => $this->id,
|
'id' => $this->uuid,
|
||||||
'stream_id' => $this->stream_id,
|
'stream_id' => $this->stream?->uuid,
|
||||||
'amount' => $this->amount_currency,
|
'amount' => $this->amount_currency,
|
||||||
'formatted_amount' => $this->formatted_amount,
|
'formatted_amount' => $this->formatted_amount,
|
||||||
'date' => $this->date->format('Y-m-d'),
|
'date' => $this->date->format('Y-m-d'),
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,9 @@ class OutflowResource extends JsonResource
|
||||||
public function toArray(Request $request): array
|
public function toArray(Request $request): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'id' => $this->id,
|
'id' => $this->uuid,
|
||||||
'stream_id' => $this->stream_id,
|
'stream_id' => $this->stream?->uuid,
|
||||||
'bucket_id' => $this->bucket_id,
|
'bucket_id' => $this->bucket?->uuid,
|
||||||
'amount' => $this->amount_currency,
|
'amount' => $this->amount_currency,
|
||||||
'formatted_amount' => $this->formatted_amount,
|
'formatted_amount' => $this->formatted_amount,
|
||||||
'date' => $this->date->format('Y-m-d'),
|
'date' => $this->date->format('Y-m-d'),
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ class ScenarioResource extends JsonResource
|
||||||
public function toArray(Request $request): array
|
public function toArray(Request $request): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'id' => $this->id,
|
'id' => $this->uuid,
|
||||||
'name' => $this->name,
|
'name' => $this->name,
|
||||||
'description' => $this->description,
|
'description' => $this->description,
|
||||||
'created_at' => $this->created_at,
|
'created_at' => $this->created_at,
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ class StreamResource extends JsonResource
|
||||||
public function toArray(Request $request): array
|
public function toArray(Request $request): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'id' => $this->id,
|
'id' => $this->uuid,
|
||||||
'name' => $this->name,
|
'name' => $this->name,
|
||||||
'type' => $this->type,
|
'type' => $this->type,
|
||||||
'type_label' => $this->getTypeLabel(),
|
'type_label' => $this->getTypeLabel(),
|
||||||
|
|
@ -19,7 +19,7 @@ public function toArray(Request $request): array
|
||||||
'frequency_label' => $this->getFrequencyLabel(),
|
'frequency_label' => $this->getFrequencyLabel(),
|
||||||
'start_date' => $this->start_date->format('Y-m-d'),
|
'start_date' => $this->start_date->format('Y-m-d'),
|
||||||
'end_date' => $this->end_date?->format('Y-m-d'),
|
'end_date' => $this->end_date?->format('Y-m-d'),
|
||||||
'bucket_id' => $this->bucket_id,
|
'bucket_id' => $this->bucket?->uuid,
|
||||||
'bucket_name' => $this->bucket?->name,
|
'bucket_name' => $this->bucket?->name,
|
||||||
'description' => $this->description,
|
'description' => $this->description,
|
||||||
'is_active' => $this->is_active,
|
'is_active' => $this->is_active,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Repositories;
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Models\Bucket;
|
||||||
use App\Models\Scenario;
|
use App\Models\Scenario;
|
||||||
use App\Models\Stream;
|
use App\Models\Stream;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
@ -11,7 +12,7 @@ class StreamRepository
|
||||||
public function getForScenario(Scenario $scenario): Collection
|
public function getForScenario(Scenario $scenario): Collection
|
||||||
{
|
{
|
||||||
return $scenario->streams()
|
return $scenario->streams()
|
||||||
->with('bucket:id,name')
|
->with('bucket:id,uuid,name')
|
||||||
->orderBy('type')
|
->orderBy('type')
|
||||||
->orderBy('name')
|
->orderBy('name')
|
||||||
->get();
|
->get();
|
||||||
|
|
@ -19,11 +20,15 @@ public function getForScenario(Scenario $scenario): Collection
|
||||||
|
|
||||||
public function create(Scenario $scenario, array $data): Stream
|
public function create(Scenario $scenario, array $data): Stream
|
||||||
{
|
{
|
||||||
|
$this->resolveBucketId($data);
|
||||||
|
|
||||||
return $scenario->streams()->create($data);
|
return $scenario->streams()->create($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(Stream $stream, array $data): Stream
|
public function update(Stream $stream, array $data): Stream
|
||||||
{
|
{
|
||||||
|
$this->resolveBucketId($data);
|
||||||
|
|
||||||
$stream->update($data);
|
$stream->update($data);
|
||||||
|
|
||||||
return $stream->fresh('bucket');
|
return $stream->fresh('bucket');
|
||||||
|
|
@ -46,17 +51,24 @@ public function toggleActive(Stream $stream): Stream
|
||||||
/**
|
/**
|
||||||
* Check if a bucket belongs to the scenario
|
* Check if a bucket belongs to the scenario
|
||||||
*/
|
*/
|
||||||
public function bucketBelongsToScenario(Scenario $scenario, ?int $bucketId): bool
|
public function bucketBelongsToScenario(Scenario $scenario, ?string $bucketUuid): bool
|
||||||
{
|
{
|
||||||
if (! $bucketId) {
|
if (! $bucketUuid) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $scenario->buckets()
|
return $scenario->buckets()
|
||||||
->where('id', $bucketId)
|
->where('uuid', $bucketUuid)
|
||||||
->exists();
|
->exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function resolveBucketId(array &$data): void
|
||||||
|
{
|
||||||
|
if (! empty($data['bucket_id'])) {
|
||||||
|
$data['bucket_id'] = Bucket::where('uuid', $data['bucket_id'])->value('id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get streams grouped by type
|
* Get streams grouped by type
|
||||||
*/
|
*/
|
||||||
|
|
@ -64,12 +76,12 @@ public function getGroupedByType(Scenario $scenario): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'income' => $scenario->streams()
|
'income' => $scenario->streams()
|
||||||
->with('bucket:id,name')
|
->with('bucket:id,uuid,name')
|
||||||
->byType(Stream::TYPE_INCOME)
|
->byType(Stream::TYPE_INCOME)
|
||||||
->orderBy('name')
|
->orderBy('name')
|
||||||
->get(),
|
->get(),
|
||||||
'expense' => $scenario->streams()
|
'expense' => $scenario->streams()
|
||||||
->with('bucket:id,name')
|
->with('bucket:id,uuid,name')
|
||||||
->byType(Stream::TYPE_EXPENSE)
|
->byType(Stream::TYPE_EXPENSE)
|
||||||
->orderBy('name')
|
->orderBy('name')
|
||||||
->get(),
|
->get(),
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { Head, router } from '@inertiajs/react';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
interface Scenario {
|
interface Scenario {
|
||||||
id: number;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,14 @@ import { Head, Link, router } from '@inertiajs/react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
interface Scenario {
|
interface Scenario {
|
||||||
id: number;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Bucket {
|
interface Bucket {
|
||||||
id: number;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
priority: number;
|
priority: number;
|
||||||
sort_order: number;
|
sort_order: number;
|
||||||
|
|
@ -23,7 +23,7 @@ interface Bucket {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Stream {
|
interface Stream {
|
||||||
id: number;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
type: 'income' | 'expense';
|
type: 'income' | 'expense';
|
||||||
type_label: string;
|
type_label: string;
|
||||||
|
|
@ -32,7 +32,7 @@ interface Stream {
|
||||||
frequency_label: string;
|
frequency_label: string;
|
||||||
start_date: string;
|
start_date: string;
|
||||||
end_date: string | null;
|
end_date: string | null;
|
||||||
bucket_id: number | null;
|
bucket_id: string | null;
|
||||||
bucket_name: string | null;
|
bucket_name: string | null;
|
||||||
description: string | null;
|
description: string | null;
|
||||||
is_active: boolean;
|
is_active: boolean;
|
||||||
|
|
@ -140,7 +140,7 @@ export default function Show({ scenario, buckets, streams = { data: [] }, stream
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePriorityChange = async (bucketId: number, direction: 'up' | 'down') => {
|
const handlePriorityChange = async (bucketId: string, direction: 'up' | 'down') => {
|
||||||
const bucket = buckets.data.find(b => b.id === bucketId);
|
const bucket = buckets.data.find(b => b.id === bucketId);
|
||||||
if (!bucket) return;
|
if (!bucket) return;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue