UI test fixes
This commit is contained in:
parent
8f168d3bb2
commit
0f02939f27
3 changed files with 19 additions and 19 deletions
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace App\Actions;
|
namespace App\Actions;
|
||||||
|
|
||||||
use App\Models\Bucket;
|
use App\Enums\BucketAllocationTypeEnum;
|
||||||
use App\Models\Scenario;
|
use App\Models\Scenario;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
|
@ -24,8 +24,8 @@ public function execute(array $data): Scenario
|
||||||
|
|
||||||
private function createDefaultBuckets(Scenario $scenario): void
|
private function createDefaultBuckets(Scenario $scenario): void
|
||||||
{
|
{
|
||||||
$this->createBucketAction->execute($scenario, 'Monthly Expenses', Bucket::TYPE_FIXED_LIMIT, 0, 1);
|
$this->createBucketAction->execute($scenario, 'Monthly Expenses', BucketAllocationTypeEnum::FIXED_LIMIT, 0, 1);
|
||||||
$this->createBucketAction->execute($scenario, 'Emergency Fund', Bucket::TYPE_FIXED_LIMIT, 0, 2);
|
$this->createBucketAction->execute($scenario, 'Emergency Fund', BucketAllocationTypeEnum::FIXED_LIMIT, 0, 2);
|
||||||
$this->createBucketAction->execute($scenario, 'Investments', Bucket::TYPE_UNLIMITED, null, 3);
|
$this->createBucketAction->execute($scenario, 'Investments', BucketAllocationTypeEnum::UNLIMITED, null, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace App\Services\Streams;
|
namespace App\Services\Streams;
|
||||||
|
|
||||||
use App\Models\Stream;
|
use App\Enums\StreamTypeEnum;
|
||||||
use App\Models\Scenario;
|
use App\Models\Scenario;
|
||||||
|
|
||||||
readonly class StatsService
|
readonly class StatsService
|
||||||
|
|
@ -14,18 +14,18 @@ public function getSummaryStats(Scenario $scenario): array
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
$totalMonthlyIncome = $streams
|
$totalMonthlyIncome = $streams
|
||||||
->where('type', Stream::TYPE_INCOME)
|
->where('type', StreamTypeEnum::INCOME)
|
||||||
->sum(fn($stream) => $stream->getMonthlyEquivalent());
|
->sum(fn($stream) => $stream->getMonthlyEquivalent());
|
||||||
|
|
||||||
$totalMonthlyExpenses = $streams
|
$totalMonthlyExpenses = $streams
|
||||||
->where('type', Stream::TYPE_EXPENSE)
|
->where('type', StreamTypeEnum::EXPENSE)
|
||||||
->sum(fn($stream) => $stream->getMonthlyEquivalent());
|
->sum(fn($stream) => $stream->getMonthlyEquivalent());
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'total_streams' => $streams->count(),
|
'total_streams' => $streams->count(),
|
||||||
'active_streams' => $streams->where('is_active', true)->count(),
|
'active_streams' => $streams->where('is_active', true)->count(),
|
||||||
'income_streams' => $streams->where('type', Stream::TYPE_INCOME)->count(),
|
'income_streams' => $streams->where('type', StreamTypeEnum::INCOME)->count(),
|
||||||
'expense_streams' => $streams->where('type', Stream::TYPE_EXPENSE)->count(),
|
'expense_streams' => $streams->where('type', StreamTypeEnum::EXPENSE)->count(),
|
||||||
'monthly_income' => $totalMonthlyIncome,
|
'monthly_income' => $totalMonthlyIncome,
|
||||||
'monthly_expenses' => $totalMonthlyExpenses,
|
'monthly_expenses' => $totalMonthlyExpenses,
|
||||||
'monthly_net' => $totalMonthlyIncome - $totalMonthlyExpenses,
|
'monthly_net' => $totalMonthlyIncome - $totalMonthlyExpenses,
|
||||||
|
|
|
||||||
|
|
@ -51,12 +51,12 @@ interface StreamStats {
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
scenario: Scenario;
|
scenario: Scenario;
|
||||||
buckets: Bucket[];
|
buckets: { data: Bucket[] };
|
||||||
streams: Stream[];
|
streams: { data: Stream[] };
|
||||||
streamStats?: StreamStats;
|
streamStats?: StreamStats;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Show({ scenario, buckets, streams = [], streamStats }: Props) {
|
export default function Show({ scenario, buckets, streams = { data: [] }, streamStats }: Props) {
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const [editingBucket, setEditingBucket] = useState<Bucket | null>(null);
|
const [editingBucket, setEditingBucket] = useState<Bucket | null>(null);
|
||||||
|
|
@ -141,13 +141,13 @@ export default function Show({ scenario, buckets, streams = [], streamStats }: P
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePriorityChange = async (bucketId: number, direction: 'up' | 'down') => {
|
const handlePriorityChange = async (bucketId: number, direction: 'up' | 'down') => {
|
||||||
const bucket = buckets.find(b => b.id === bucketId);
|
const bucket = buckets.data.find(b => b.id === bucketId);
|
||||||
if (!bucket) return;
|
if (!bucket) return;
|
||||||
|
|
||||||
const newPriority = direction === 'up' ? bucket.priority - 1 : bucket.priority + 1;
|
const newPriority = direction === 'up' ? bucket.priority - 1 : bucket.priority + 1;
|
||||||
|
|
||||||
// Don't allow moving beyond bounds
|
// Don't allow moving beyond bounds
|
||||||
if (newPriority < 1 || newPriority > buckets.length) return;
|
if (newPriority < 1 || newPriority > buckets.data.length) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/buckets/${bucketId}`, {
|
const response = await fetch(`/buckets/${bucketId}`, {
|
||||||
|
|
@ -218,7 +218,7 @@ export default function Show({ scenario, buckets, streams = [], streamStats }: P
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
{buckets.map((bucket) => (
|
{buckets.data.map((bucket) => (
|
||||||
<div
|
<div
|
||||||
key={bucket.id}
|
key={bucket.id}
|
||||||
className="rounded-lg bg-white p-6 shadow transition-shadow hover:shadow-lg border-l-4 border-blue-500"
|
className="rounded-lg bg-white p-6 shadow transition-shadow hover:shadow-lg border-l-4 border-blue-500"
|
||||||
|
|
@ -245,7 +245,7 @@ export default function Show({ scenario, buckets, streams = [], streamStats }: P
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => handlePriorityChange(bucket.id, 'down')}
|
onClick={() => handlePriorityChange(bucket.id, 'down')}
|
||||||
disabled={bucket.priority === buckets.length}
|
disabled={bucket.priority === buckets.data.length}
|
||||||
className="p-1 rounded hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed"
|
className="p-1 rounded hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
title="Move down in priority"
|
title="Move down in priority"
|
||||||
>
|
>
|
||||||
|
|
@ -388,7 +388,7 @@ export default function Show({ scenario, buckets, streams = [], streamStats }: P
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{streams.length === 0 ? (
|
{streams.data.length === 0 ? (
|
||||||
<div className="rounded-lg bg-white p-8 text-center shadow">
|
<div className="rounded-lg bg-white p-8 text-center shadow">
|
||||||
<p className="text-gray-600">No streams yet. Add income or expense streams to start tracking cash flow.</p>
|
<p className="text-gray-600">No streams yet. Add income or expense streams to start tracking cash flow.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -424,7 +424,7 @@ export default function Show({ scenario, buckets, streams = [], streamStats }: P
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="divide-y divide-gray-200 bg-white">
|
<tbody className="divide-y divide-gray-200 bg-white">
|
||||||
{streams.map((stream) => (
|
{streams.data.map((stream) => (
|
||||||
<tr key={stream.id}>
|
<tr key={stream.id}>
|
||||||
<td className="whitespace-nowrap px-6 py-4 text-sm font-medium text-gray-900">
|
<td className="whitespace-nowrap px-6 py-4 text-sm font-medium text-gray-900">
|
||||||
{stream.name}
|
{stream.name}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue