From ced02a2ab23623a9167c15eb4f79c9f8b24a6328 Mon Sep 17 00:00:00 2001 From: myrmidex Date: Sun, 22 Mar 2026 03:05:23 +0100 Subject: [PATCH] 2 - Clean up dead code and restyle inline edit components --- app/Http/Controllers/ScenarioController.php | 7 - resources/js/components/AppSidebarHeader.tsx | 5 +- .../components/IncomeDistributionPreview.tsx | 220 ------------------ resources/js/components/InlineEditInput.tsx | 10 +- resources/js/components/InlineEditSelect.tsx | 10 +- resources/js/components/SettingsPanel.tsx | 1 - resources/js/pages/Scenarios/Show.tsx | 7 +- 7 files changed, 13 insertions(+), 247 deletions(-) delete mode 100644 resources/js/components/IncomeDistributionPreview.tsx diff --git a/app/Http/Controllers/ScenarioController.php b/app/Http/Controllers/ScenarioController.php index 61784ba..d2aa199 100644 --- a/app/Http/Controllers/ScenarioController.php +++ b/app/Http/Controllers/ScenarioController.php @@ -9,11 +9,8 @@ use App\Http\Requests\UpdateScenarioRequest; use App\Http\Resources\BucketResource; use App\Http\Resources\ScenarioResource; -use App\Http\Resources\StreamResource; use App\Models\Scenario; use App\Repositories\ScenarioRepository; -use App\Repositories\StreamRepository; -use App\Services\Streams\StatsService; use Illuminate\Http\JsonResponse; use Illuminate\Http\RedirectResponse; use Inertia\Inertia; @@ -23,11 +20,9 @@ class ScenarioController extends Controller { public function __construct( private readonly ScenarioRepository $scenarioRepository, - private readonly StreamRepository $streamRepository, private readonly CreateScenarioAction $createScenarioAction, private readonly UpdateScenarioAction $updateScenarioAction, private readonly DeleteScenarioAction $deleteScenarioAction, - private readonly StatsService $statsService ) {} public function index(): Response @@ -46,8 +41,6 @@ public function show(Scenario $scenario): Response return Inertia::render('Scenarios/Show', [ 'scenario' => ScenarioResource::make($scenario)->resolve(), 'buckets' => BucketResource::collection($scenario->buckets), - 'streams' => StreamResource::collection($this->streamRepository->getForScenario($scenario)), - 'streamStats' => $this->statsService->getSummaryStats($scenario), ]); } diff --git a/resources/js/components/AppSidebarHeader.tsx b/resources/js/components/AppSidebarHeader.tsx index cfcc4d5..a322885 100644 --- a/resources/js/components/AppSidebarHeader.tsx +++ b/resources/js/components/AppSidebarHeader.tsx @@ -32,10 +32,7 @@ export function AppSidebarHeader({ - + ); } diff --git a/resources/js/components/IncomeDistributionPreview.tsx b/resources/js/components/IncomeDistributionPreview.tsx deleted file mode 100644 index d72154c..0000000 --- a/resources/js/components/IncomeDistributionPreview.tsx +++ /dev/null @@ -1,220 +0,0 @@ -import { useState } from 'react'; -import { router } from '@inertiajs/react'; -import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'; -import { Button } from '@/components/ui/button'; - -interface Allocation { - bucket_id: string; - bucket_name: string; - bucket_type: 'need' | 'want' | 'overflow'; - allocated_amount: number; - remaining_capacity: number | null; -} - -interface PreviewResult { - allocations: Allocation[]; - total_allocated: number; - unallocated: number; -} - -interface IncomeDistributionPreviewProps { - scenarioId: string; -} - -const bucketTypeColor = { - need: 'bg-blue-100 text-blue-800', - want: 'bg-green-100 text-green-800', - overflow: 'bg-amber-100 text-amber-800', -} as const; - -const csrfToken = () => - document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || ''; - -export default function IncomeDistributionPreview({ scenarioId }: IncomeDistributionPreviewProps) { - const [amount, setAmount] = useState(''); - const [preview, setPreview] = useState(null); - const [isLoading, setIsLoading] = useState(false); - const [isApplying, setIsApplying] = useState(false); - const [error, setError] = useState(null); - const [applied, setApplied] = useState(false); - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setIsLoading(true); - setError(null); - setApplied(false); - - const parsed = parseFloat(amount); - if (isNaN(parsed) || parsed <= 0) { - setError('Please enter a valid amount'); - setIsLoading(false); - return; - } - - try { - const response = await fetch(`/scenarios/${scenarioId}/projections/preview`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRF-TOKEN': csrfToken(), - }, - body: JSON.stringify({ amount: Math.round(parsed * 100) }), - }); - - if (!response.ok) { - let message = 'Failed to preview allocation'; - try { - const data = await response.json(); - message = data.message || message; - } catch { /* non-JSON error body */ } - setError(message); - setPreview(null); - return; - } - - const data: PreviewResult = await response.json(); - setPreview(data); - } catch { - setError('Failed to connect to server'); - setPreview(null); - } finally { - setIsLoading(false); - } - }; - - const handleApply = async () => { - if (isApplying) return; - - const parsed = parseFloat(amount); - if (isNaN(parsed) || parsed <= 0) return; - - setIsApplying(true); - setError(null); - - try { - const response = await fetch(`/scenarios/${scenarioId}/projections/apply`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRF-TOKEN': csrfToken(), - }, - body: JSON.stringify({ amount: Math.round(parsed * 100) }), - }); - - if (!response.ok) { - let message = 'Failed to save distribution'; - try { - const data = await response.json(); - message = data.message || message; - } catch { /* non-JSON error body */ } - setError(message); - return; - } - - setPreview(null); - setAmount(''); - setApplied(true); - router.reload({ only: ['buckets'] }); - } catch { - setError('Failed to connect to server'); - } finally { - setIsApplying(false); - } - }; - - return ( - - - Income Distribution Preview - - -
-
- - setAmount(e.target.value)} - className="block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 text-gray-900" - placeholder="e.g., 3000" - step="0.01" - min="0.01" - required - /> -
- -
- - {error && ( -
- {error} -
- )} - - {applied && ( -
- Distribution saved successfully. Bucket balances have been updated. -
- )} - - {preview && ( -
- {preview.allocations.length > 0 ? ( -
- {preview.allocations.map((allocation) => ( -
-
- - {allocation.bucket_type} - - {allocation.bucket_name} -
-
- - ${(allocation.allocated_amount / 100).toFixed(2)} - - {allocation.remaining_capacity !== null && ( - - (${(allocation.remaining_capacity / 100).toFixed(2)} remaining) - - )} -
-
- ))} -
- ) : ( -

No buckets to allocate to.

- )} - -
- Total Allocated - ${(preview.total_allocated / 100).toFixed(2)} -
- - {preview.unallocated > 0 && ( -
- Unallocated - ${(preview.unallocated / 100).toFixed(2)} -
- )} - - {preview.allocations.length > 0 && ( - - )} -
- )} -
-
- ); -} diff --git a/resources/js/components/InlineEditInput.tsx b/resources/js/components/InlineEditInput.tsx index f008441..5045a82 100644 --- a/resources/js/components/InlineEditInput.tsx +++ b/resources/js/components/InlineEditInput.tsx @@ -113,7 +113,7 @@ export default function InlineEditInput(props: InlineEditInputProps) { min={props.type !== 'text' ? props.min : undefined} step={props.type !== 'text' ? props.step : undefined} disabled={status === 'saving'} - className={`rounded border border-blue-300 bg-white px-2 py-0.5 text-sm text-gray-900 outline-none focus:ring-2 focus:ring-blue-500 ${isText ? 'w-48' : 'w-24'} ${className}`} + className={`border border-red-500 bg-black px-2 py-0.5 text-sm text-red-500 font-mono outline-none focus:ring-1 focus:ring-red-500 ${isText ? 'w-48' : 'w-24'} ${className}`} /> ); } @@ -123,13 +123,13 @@ export default function InlineEditInput(props: InlineEditInputProps) { onClick={startEditing} className={`inline-flex items-center gap-1 ${ disabled - ? 'cursor-default text-gray-400' - : 'cursor-pointer rounded px-1 py-0.5 hover:bg-blue-50 hover:text-blue-700' + ? 'cursor-default text-red-500/30' + : 'cursor-pointer px-1 py-0.5 hover:text-red-300' } ${className}`} > {displayValue} - {status === 'success' && } - {status === 'error' && } + {status === 'success' && OK} + {status === 'error' && ERR} ); } diff --git a/resources/js/components/InlineEditSelect.tsx b/resources/js/components/InlineEditSelect.tsx index 750febe..c9dcc9b 100644 --- a/resources/js/components/InlineEditSelect.tsx +++ b/resources/js/components/InlineEditSelect.tsx @@ -70,7 +70,7 @@ export default function InlineEditSelect({ onChange={handleChange} onBlur={handleBlur} disabled={status === 'saving'} - className={`rounded border border-blue-300 bg-white px-2 py-0.5 text-sm text-gray-900 outline-none focus:ring-2 focus:ring-blue-500 ${className}`} + className={`border border-red-500 bg-black px-2 py-0.5 text-sm text-red-500 font-mono outline-none focus:ring-1 focus:ring-red-500 ${className}`} > {options.map((opt) => (