Update budget card

Update the budget card to allow users to input daily, weekly, and monthly goals.
Change the title of the second card to "목표 입력".
This commit is contained in:
gpt-engineer-app[bot]
2025-03-08 08:29:18 +00:00
parent 0971572898
commit 2bd19aad8e
2 changed files with 186 additions and 25 deletions

View File

@@ -0,0 +1,122 @@
import React, { useState, useEffect } from 'react';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { Check } from 'lucide-react';
interface BudgetGoalProps {
initialBudgets: {
daily: number;
weekly: number;
monthly: number;
};
onSave: (type: 'daily' | 'weekly' | 'monthly', amount: number) => void;
}
const BudgetInputCard: React.FC<BudgetGoalProps> = ({ initialBudgets, onSave }) => {
const [selectedTab, setSelectedTab] = useState<'daily' | 'weekly' | 'monthly'>('daily');
const [budgetInputs, setBudgetInputs] = useState({
daily: initialBudgets.daily.toString(),
weekly: initialBudgets.weekly.toString(),
monthly: initialBudgets.monthly.toString(),
});
// Format for display without commas
const formatForInput = (amount: number) => {
return amount.toString();
};
// Format with commas for display
const formatWithCommas = (amount: string) => {
return amount.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
};
useEffect(() => {
setBudgetInputs({
daily: formatForInput(initialBudgets.daily),
weekly: formatForInput(initialBudgets.weekly),
monthly: formatForInput(initialBudgets.monthly),
});
}, [initialBudgets]);
const handleInputChange = (value: string, type: 'daily' | 'weekly' | 'monthly') => {
// Remove all non-numeric characters
const numericValue = value.replace(/[^0-9]/g, '');
setBudgetInputs(prev => ({
...prev,
[type]: numericValue
}));
};
const handleSave = () => {
const amount = parseInt(budgetInputs[selectedTab], 10) || 0;
onSave(selectedTab, amount);
};
return (
<div className="neuro-card">
<Tabs defaultValue="daily" value={selectedTab} onValueChange={(value) => setSelectedTab(value as 'daily' | 'weekly' | 'monthly')} className="w-full">
<TabsList className="grid grid-cols-3 mb-4 bg-transparent">
<TabsTrigger value="daily" className="data-[state=active]:shadow-neuro-pressed data-[state=active]:bg-transparent">
</TabsTrigger>
<TabsTrigger value="weekly" className="data-[state=active]:shadow-neuro-pressed data-[state=active]:bg-transparent">
</TabsTrigger>
<TabsTrigger value="monthly" className="data-[state=active]:shadow-neuro-pressed data-[state=active]:bg-transparent">
</TabsTrigger>
</TabsList>
<TabsContent value="daily" className="space-y-4 mt-0">
<div className="flex items-center space-x-2">
<Input
value={budgetInputs.daily}
onChange={(e) => handleInputChange(e.target.value, 'daily')}
placeholder="목표 금액 입력"
className="neuro-pressed"
/>
<Button onClick={handleSave} size="icon" className="neuro-flat">
<Check size={18} />
</Button>
</div>
<p className="text-xs text-gray-500"> : {formatWithCommas(budgetInputs.daily)}</p>
</TabsContent>
<TabsContent value="weekly" className="space-y-4 mt-0">
<div className="flex items-center space-x-2">
<Input
value={budgetInputs.weekly}
onChange={(e) => handleInputChange(e.target.value, 'weekly')}
placeholder="목표 금액 입력"
className="neuro-pressed"
/>
<Button onClick={handleSave} size="icon" className="neuro-flat">
<Check size={18} />
</Button>
</div>
<p className="text-xs text-gray-500"> : {formatWithCommas(budgetInputs.weekly)}</p>
</TabsContent>
<TabsContent value="monthly" className="space-y-4 mt-0">
<div className="flex items-center space-x-2">
<Input
value={budgetInputs.monthly}
onChange={(e) => handleInputChange(e.target.value, 'monthly')}
placeholder="목표 금액 입력"
className="neuro-pressed"
/>
<Button onClick={handleSave} size="icon" className="neuro-flat">
<Check size={18} />
</Button>
</div>
<p className="text-xs text-gray-500"> : {formatWithCommas(budgetInputs.monthly)}</p>
</TabsContent>
</Tabs>
</div>
);
};
export default BudgetInputCard;

View File

@@ -1,39 +1,44 @@
import React, { useState } from 'react';
import NavBar from '@/components/NavBar';
import BudgetCard from '@/components/BudgetCard';
import BudgetInputCard from '@/components/BudgetInputCard';
import TransactionCard, { Transaction } from '@/components/TransactionCard';
import AddTransactionButton from '@/components/AddTransactionButton';
import { Wallet, TrendingUp, Bell } from 'lucide-react';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { toast } from '@/components/ui/use-toast';
const Index = () => {
const [selectedTab, setSelectedTab] = useState("daily");
// Sample data - in a real app, this would come from a data source
const transactions: Transaction[] = [{
id: '1',
title: '식료품 구매',
amount: 25000,
date: '오늘, 12:30 PM',
category: 'shopping',
type: 'expense'
}, {
id: '2',
title: '주유소',
amount: 50000,
date: '어제, 3:45 PM',
category: 'transportation',
type: 'expense'
}, {
id: '3',
title: '월급',
amount: 2500000,
date: '2일전, 9:00 AM',
category: 'income',
type: 'income'
}];
const transactions: Transaction[] = [
{
id: '1',
title: '식료품 구매',
amount: 25000,
date: '오늘, 12:30 PM',
category: 'shopping',
type: 'expense'
}, {
id: '2',
title: '주유소',
amount: 50000,
date: '어제, 3:45 PM',
category: 'transportation',
type: 'expense'
}, {
id: '3',
title: '월급',
amount: 2500000,
date: '2일전, 9:00 AM',
category: 'income',
type: 'income'
}
];
// 예산 데이터 - 실제 앱에서는 백엔드에서 가져와야 함
const budgetData = {
const [budgetData, setBudgetData] = useState({
daily: {
targetAmount: 30000,
spentAmount: 15000,
@@ -49,7 +54,8 @@ const Index = () => {
spentAmount: 750000,
remainingAmount: 450000
}
};
});
const formatCurrency = (amount: number) => {
return new Intl.NumberFormat('ko-KR', {
style: 'currency',
@@ -62,6 +68,28 @@ const Index = () => {
const calculatePercentage = (spent: number, target: number) => {
return Math.min(Math.round(spent / target * 100), 100);
};
// 예산 목표 업데이트 함수
const handleBudgetGoalUpdate = (type: 'daily' | 'weekly' | 'monthly', amount: number) => {
setBudgetData(prev => {
const remainingAmount = Math.max(0, amount - prev[type].spentAmount);
return {
...prev,
[type]: {
...prev[type],
targetAmount: amount,
remainingAmount: remainingAmount
}
};
});
toast({
title: "목표 업데이트 완료",
description: `${type === 'daily' ? '일일' : type === 'weekly' ? '주간' : '월간'} 목표가 ${amount.toLocaleString()}원으로 설정되었습니다.`
});
};
return <div className="min-h-screen bg-neuro-background pb-24">
<div className="max-w-md mx-auto px-6">
{/* Header */}
@@ -182,6 +210,17 @@ const Index = () => {
</Tabs>
</div>
{/* 목표 입력 */}
<h2 className="text-lg font-semibold mb-3 mt-8"> </h2>
<BudgetInputCard
initialBudgets={{
daily: budgetData.daily.targetAmount,
weekly: budgetData.weekly.targetAmount,
monthly: budgetData.monthly.targetAmount
}}
onSave={handleBudgetGoalUpdate}
/>
{/* Budget Progress */}
<h2 className="text-lg font-semibold mb-3 mt-8"> </h2>
<div className="grid gap-4 mb-8">
@@ -205,4 +244,4 @@ const Index = () => {
<NavBar />
</div>;
};
export default Index;
export default Index;