243 lines
7.7 KiB
TypeScript
243 lines
7.7 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogDescription,
|
|
} from '@/components/ui/dialog';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Input } from '@/components/ui/input';
|
|
import { Label } from '@/components/ui/label';
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from '@/components/ui/select';
|
|
import { SavingsConfig } from '@/lib/storage';
|
|
import { DollarSign, Target } from 'lucide-react';
|
|
|
|
interface SavingsSetupDialogProps {
|
|
open: boolean;
|
|
onClose: () => void;
|
|
onSave: (config: SavingsConfig) => void;
|
|
existingConfig: SavingsConfig | null;
|
|
}
|
|
|
|
const CURRENCIES = [
|
|
{ code: 'USD', symbol: '$', name: 'US Dollar' },
|
|
{ code: 'EUR', symbol: '€', name: 'Euro' },
|
|
{ code: 'GBP', symbol: '£', name: 'British Pound' },
|
|
{ code: 'CAD', symbol: 'C$', name: 'Canadian Dollar' },
|
|
{ code: 'AUD', symbol: 'A$', name: 'Australian Dollar' },
|
|
];
|
|
|
|
export function SavingsSetupDialog({
|
|
open,
|
|
onClose,
|
|
onSave,
|
|
existingConfig,
|
|
}: SavingsSetupDialogProps) {
|
|
const [costPerUnit, setCostPerUnit] = useState('');
|
|
const [unitsPerDay, setUnitsPerDay] = useState('');
|
|
const [currency, setCurrency] = useState('');
|
|
const [substance, setSubstance] = useState<'nicotine' | 'weed' | ''>('');
|
|
const [savingsGoal, setSavingsGoal] = useState('');
|
|
const [goalName, setGoalName] = useState('');
|
|
|
|
useEffect(() => {
|
|
if (existingConfig) {
|
|
setCostPerUnit(existingConfig.costPerUnit.toString());
|
|
setUnitsPerDay(existingConfig.unitsPerDay.toString());
|
|
setCurrency(existingConfig.currency);
|
|
setSubstance(existingConfig.substance);
|
|
setSavingsGoal(existingConfig.savingsGoal?.toString() || '');
|
|
setGoalName(existingConfig.goalName || '');
|
|
} else {
|
|
setCostPerUnit('');
|
|
setUnitsPerDay('');
|
|
setCurrency('');
|
|
setSubstance('');
|
|
setSavingsGoal('');
|
|
setGoalName('');
|
|
}
|
|
}, [existingConfig, open]);
|
|
|
|
const handleSave = () => {
|
|
const cost = parseFloat(costPerUnit);
|
|
const units = parseFloat(unitsPerDay);
|
|
|
|
if (isNaN(cost) || isNaN(units) || cost <= 0 || units <= 0) {
|
|
return;
|
|
}
|
|
|
|
const config: SavingsConfig = {
|
|
costPerUnit: cost,
|
|
unitsPerDay: units,
|
|
currency,
|
|
substance: substance as 'nicotine' | 'weed',
|
|
savingsGoal: savingsGoal ? parseFloat(savingsGoal) : null,
|
|
goalName: goalName.trim() || null,
|
|
};
|
|
|
|
onSave(config);
|
|
};
|
|
|
|
const isValid =
|
|
costPerUnit &&
|
|
unitsPerDay &&
|
|
currency &&
|
|
substance &&
|
|
parseFloat(costPerUnit) > 0 &&
|
|
parseFloat(unitsPerDay) > 0;
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={(isOpen) => !isOpen && onClose()}>
|
|
<DialogContent className="sm:max-w-md">
|
|
<DialogHeader>
|
|
<DialogTitle className="flex items-center gap-2">
|
|
<DollarSign className="h-5 w-5 text-emerald-500" />
|
|
{existingConfig ? 'Edit Savings Tracker' : 'Set Up Savings Tracker'}
|
|
</DialogTitle>
|
|
<DialogDescription>
|
|
Enter your usage costs to track how much you're saving
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<div className="space-y-4 py-4">
|
|
{/* Substance Selection */}
|
|
<div className="space-y-2">
|
|
<Label>What are you tracking?</Label>
|
|
<Select value={substance} onValueChange={(v) => setSubstance(v as 'nicotine' | 'weed')}>
|
|
<SelectTrigger>
|
|
<SelectValue placeholder="Select substance" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="nicotine">Nicotine (Vape/Cigarettes)</SelectItem>
|
|
<SelectItem value="weed">Marijuana</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
{/* Currency Selection */}
|
|
<div className="space-y-2">
|
|
<Label>Currency</Label>
|
|
<Select value={currency} onValueChange={setCurrency}>
|
|
<SelectTrigger>
|
|
<SelectValue placeholder="Select currency" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{CURRENCIES.map((curr) => (
|
|
<SelectItem key={curr.code} value={curr.code}>
|
|
{curr.symbol} {curr.name}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
{/* Cost Per Unit */}
|
|
<div className="space-y-2">
|
|
<Label htmlFor="costPerUnit">
|
|
Cost per pack/cartridge/unit
|
|
</Label>
|
|
<div className="relative">
|
|
<span className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground">
|
|
{CURRENCIES.find((c) => c.code === currency)?.symbol || '$'}
|
|
</span>
|
|
<Input
|
|
id="costPerUnit"
|
|
type="number"
|
|
min="0"
|
|
step="0.01"
|
|
value={costPerUnit}
|
|
onChange={(e) => setCostPerUnit(e.target.value)}
|
|
className="pl-8"
|
|
placeholder="10.00"
|
|
/>
|
|
</div>
|
|
<p className="text-xs text-muted-foreground">
|
|
How much does one pack or cartridge cost?
|
|
</p>
|
|
</div>
|
|
|
|
{/* Units Per Week */}
|
|
<div className="space-y-2">
|
|
<Label htmlFor="unitsPerDay">
|
|
Packs/vapes per week (before quitting)
|
|
</Label>
|
|
<Input
|
|
id="unitsPerDay"
|
|
type="number"
|
|
min="0"
|
|
step="0.1"
|
|
value={unitsPerDay}
|
|
onChange={(e) => setUnitsPerDay(e.target.value)}
|
|
placeholder="1"
|
|
/>
|
|
<p className="text-xs text-muted-foreground">
|
|
How many packs/vapes did you typically use per week?
|
|
</p>
|
|
</div>
|
|
|
|
{/* Optional: Savings Goal */}
|
|
<div className="pt-4 border-t space-y-4">
|
|
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
<Target className="h-4 w-4" />
|
|
<span>See your real time savings:</span>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="savingsGoal">Target amount</Label>
|
|
<div className="relative">
|
|
<span className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground">
|
|
{CURRENCIES.find((c) => c.code === currency)?.symbol || '$'}
|
|
</span>
|
|
<Input
|
|
id="savingsGoal"
|
|
type="number"
|
|
min="0"
|
|
step="1"
|
|
value={savingsGoal}
|
|
onChange={(e) => setSavingsGoal(e.target.value)}
|
|
className="pl-8"
|
|
placeholder="500"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="goalName">What are you saving for?</Label>
|
|
<Input
|
|
id="goalName"
|
|
type="text"
|
|
value={goalName}
|
|
onChange={(e) => setGoalName(e.target.value)}
|
|
placeholder="e.g., New Phone, Vacation"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Actions */}
|
|
<div className="flex gap-2 pt-4">
|
|
<Button onClick={onClose} variant="outline" className="flex-1">
|
|
Cancel
|
|
</Button>
|
|
<Button
|
|
onClick={handleSave}
|
|
disabled={!isValid}
|
|
className="flex-1"
|
|
>
|
|
{existingConfig ? 'Update' : 'Save'}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|