diff --git a/resources/js/pages/Scenarios/Show.tsx b/resources/js/pages/Scenarios/Show.tsx index 3dd4444..7901a53 100644 --- a/resources/js/pages/Scenarios/Show.tsx +++ b/resources/js/pages/Scenarios/Show.tsx @@ -6,7 +6,7 @@ import InlineEditInput from '@/components/InlineEditInput'; import InlineEditSelect from '@/components/InlineEditSelect'; import SettingsPanel from '@/components/SettingsPanel'; import { csrfToken } from '@/lib/utils'; -import { type Bucket, type Scenario } from '@/types'; +import { type Bucket, type DistributionPreview, type Scenario } from '@/types'; interface Props { scenario: Scenario; @@ -60,10 +60,75 @@ export default function Show({ scenario, buckets }: Props) { const [isSettingsOpen, setIsSettingsOpen] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); const [formData, setFormData] = useState({ ...defaultFormData }); + const [incomeAmount, setIncomeAmount] = useState(''); + const [distribution, setDistribution] = useState(null); + const [isDistributing, setIsDistributing] = useState(false); + const [isSaving, setIsSaving] = useState(false); const containerRef = useRef(null); const incomeRef = useRef(null); const bucketRefs = useRef>(new Map()); + const handleDistribute = async () => { + const dollars = parseFloat(incomeAmount); + if (!dollars || dollars <= 0) return; + + setIsDistributing(true); + try { + const response = await fetch(`/scenarios/${scenario.id}/projections/preview`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-TOKEN': csrfToken(), + }, + body: JSON.stringify({ amount: dollarsToCents(dollars) }), + }); + + if (response.ok) { + setDistribution(await response.json()); + } else { + console.error('Distribution preview failed:', response.status, await response.text()); + } + } catch (error) { + console.error('Error fetching distribution preview:', error); + } finally { + setIsDistributing(false); + } + }; + + const handleSaveDistribution = async () => { + const dollars = parseFloat(incomeAmount); + if (!dollars || dollars <= 0 || !distribution) return; + + setIsSaving(true); + try { + const response = await fetch(`/scenarios/${scenario.id}/projections/apply`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-TOKEN': csrfToken(), + }, + body: JSON.stringify({ amount: dollarsToCents(dollars) }), + }); + + if (response.ok) { + setDistribution(null); + setIncomeAmount(''); + router.reload({ only: ['buckets'] }); + } else { + console.error('Apply distribution failed:', response.status, await response.text()); + } + } catch (error) { + console.error('Error applying distribution:', error); + } finally { + setIsSaving(false); + } + }; + + const handleIncomeChange = (e: React.ChangeEvent) => { + setIncomeAmount(e.target.value); + setDistribution(null); + }; + const openCreateModal = () => { setFormData({ ...defaultFormData }); setIsCreateModalOpen(true); @@ -228,14 +293,32 @@ export default function Show({ scenario, buckets }: Props) { INCOME -
+
+ + {distribution && ( + + )}
diff --git a/resources/js/types/index.d.ts b/resources/js/types/index.d.ts index 0f409b4..2e49cc4 100644 --- a/resources/js/types/index.d.ts +++ b/resources/js/types/index.d.ts @@ -50,6 +50,20 @@ export interface Scenario { updated_at: string; } +export interface AllocationPreview { + bucket_id: string; + bucket_name: string; + bucket_type: string; + allocated_amount: number; + remaining_capacity: number | null; +} + +export interface DistributionPreview { + allocations: AllocationPreview[]; + total_allocated: number; + unallocated: number; +} + export interface SharedData { name: string; quote: { message: string; author: string };