incr/resources/js/components/Transactions/AddPurchaseForm.tsx
2025-07-10 17:20:48 +02:00

126 lines
No EOL
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import InputError from '@/components/InputError';
import { useForm } from '@inertiajs/react';
import { LoaderCircle } from 'lucide-react';
import { FormEventHandler, useEffect } from 'react';
interface PurchaseFormData {
date: string;
shares: string;
price_per_share: string;
total_cost: string;
}
export default function AddPurchaseForm() {
const { data, setData, post, processing, errors, reset } = useForm<PurchaseFormData>({
date: new Date().toISOString().split('T')[0], // Today's date in YYYY-MM-DD format
shares: '',
price_per_share: '',
total_cost: '',
});
// Auto-calculate total cost when shares or price changes
useEffect(() => {
if (data.shares && data.price_per_share) {
const shares = parseFloat(data.shares);
const pricePerShare = parseFloat(data.price_per_share);
if (!isNaN(shares) && !isNaN(pricePerShare)) {
const totalCost = (shares * pricePerShare).toFixed(2);
setData('total_cost', totalCost);
}
}
}, [data.shares, data.price_per_share, setData]);
const submit: FormEventHandler = (e) => {
e.preventDefault();
post(route('purchases.store'), {
onSuccess: () => {
reset();
setData('date', new Date().toISOString().split('T')[0]);
},
});
};
return (
<Card className="w-full max-w-md">
<CardHeader>
<CardTitle>Add VWCE Purchase</CardTitle>
</CardHeader>
<CardContent>
<form onSubmit={submit} className="space-y-4">
<div>
<Label htmlFor="date">Purchase Date</Label>
<Input
id="date"
type="date"
value={data.date}
onChange={(e) => setData('date', e.target.value)}
max={new Date().toISOString().split('T')[0]}
/>
<InputError message={errors.date} />
</div>
<div>
<Label htmlFor="shares">Number of Shares</Label>
<Input
id="shares"
type="number"
step="0.000001"
min="0"
placeholder="1.234567"
value={data.shares}
onChange={(e) => setData('shares', e.target.value)}
/>
<InputError message={errors.shares} />
</div>
<div>
<Label htmlFor="price_per_share">Price per Share ()</Label>
<Input
id="price_per_share"
type="number"
step="0.01"
min="0"
placeholder="123.45"
value={data.price_per_share}
onChange={(e) => setData('price_per_share', e.target.value)}
/>
<InputError message={errors.price_per_share} />
</div>
<div>
<Label htmlFor="total_cost">Total Cost ()</Label>
<Input
id="total_cost"
type="number"
step="0.01"
min="0"
placeholder="1234.56"
value={data.total_cost}
onChange={(e) => setData('total_cost', e.target.value)}
className="bg-neutral-50 dark:bg-neutral-800"
/>
<p className="text-xs text-neutral-500 mt-1">
Auto-calculated from shares × price
</p>
<InputError message={errors.total_cost} />
</div>
<Button
type="submit"
disabled={processing}
className="w-full"
>
{processing && <LoaderCircle className="mr-2 h-4 w-4 animate-spin" />}
Add Purchase
</Button>
</form>
</CardContent>
</Card>
);
}