Refactor budget input card
The budget input card will now be a collapsible element, only showing its title until expanded. This change is intended to reduce visual clutter on the main screen.
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
|
||||
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';
|
||||
import { Check, ChevronDown, ChevronUp } from 'lucide-react';
|
||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';
|
||||
|
||||
interface BudgetGoalProps {
|
||||
initialBudgets: {
|
||||
daily: number;
|
||||
@@ -11,6 +14,7 @@ interface BudgetGoalProps {
|
||||
};
|
||||
onSave: (type: 'daily' | 'weekly' | 'monthly', amount: number) => void;
|
||||
}
|
||||
|
||||
const BudgetInputCard: React.FC<BudgetGoalProps> = ({
|
||||
initialBudgets,
|
||||
onSave
|
||||
@@ -21,6 +25,7 @@ const BudgetInputCard: React.FC<BudgetGoalProps> = ({
|
||||
weekly: initialBudgets.weekly.toString(),
|
||||
monthly: initialBudgets.monthly.toString()
|
||||
});
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
// Format for display without commas
|
||||
const formatForInput = (amount: number) => {
|
||||
@@ -31,6 +36,7 @@ const BudgetInputCard: React.FC<BudgetGoalProps> = ({
|
||||
const formatWithCommas = (amount: string) => {
|
||||
return amount.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setBudgetInputs({
|
||||
daily: formatForInput(initialBudgets.daily),
|
||||
@@ -38,6 +44,7 @@ const BudgetInputCard: React.FC<BudgetGoalProps> = ({
|
||||
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, '');
|
||||
@@ -46,48 +53,70 @@ const BudgetInputCard: React.FC<BudgetGoalProps> = ({
|
||||
[type]: numericValue
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
const amount = parseInt(budgetInputs[selectedTab], 10) || 0;
|
||||
onSave(selectedTab, amount);
|
||||
// Close the collapsible after saving
|
||||
setIsOpen(false);
|
||||
};
|
||||
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 text-slate-50 bg-slate-400 hover:bg-slate-300">
|
||||
<Check size={18} />
|
||||
</Button>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500">현재 일일 목표: {formatWithCommas(budgetInputs.daily)}원</p>
|
||||
</TabsContent>
|
||||
return (
|
||||
<Collapsible
|
||||
open={isOpen}
|
||||
onOpenChange={setIsOpen}
|
||||
className="neuro-card"
|
||||
>
|
||||
<CollapsibleTrigger className="flex items-center justify-between w-full p-4">
|
||||
<span className="text-sm font-medium">예산 목표 설정하기</span>
|
||||
{isOpen ? (
|
||||
<ChevronUp size={18} className="text-gray-500" />
|
||||
) : (
|
||||
<ChevronDown size={18} className="text-gray-500" />
|
||||
)}
|
||||
</CollapsibleTrigger>
|
||||
|
||||
<CollapsibleContent className="px-4 pb-4">
|
||||
<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="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 bg-slate-400 hover:bg-slate-300">
|
||||
<Check size={18} />
|
||||
</Button>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500">현재 주간 목표: {formatWithCommas(budgetInputs.weekly)}원</p>
|
||||
</TabsContent>
|
||||
<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 text-slate-50 bg-slate-400 hover:bg-slate-300">
|
||||
<Check size={18} />
|
||||
</Button>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500">현재 일일 목표: {formatWithCommas(budgetInputs.daily)}원</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 bg-slate-400 hover:bg-slate-300">
|
||||
<Check size={18} />
|
||||
</Button>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500">현재 월간 목표: {formatWithCommas(budgetInputs.monthly)}원</p>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>;
|
||||
<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 bg-slate-400 hover:bg-slate-300">
|
||||
<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 bg-slate-400 hover:bg-slate-300">
|
||||
<Check size={18} />
|
||||
</Button>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500">현재 월간 목표: {formatWithCommas(budgetInputs.monthly)}원</p>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
);
|
||||
};
|
||||
export default BudgetInputCard;
|
||||
|
||||
export default BudgetInputCard;
|
||||
|
||||
@@ -4,7 +4,7 @@ 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 { Bell } from 'lucide-react';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { toast } from '@/components/ui/use-toast';
|
||||
|
||||
@@ -100,7 +100,7 @@ const Index = () => {
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* 목표 진행 상황 - 제목을 카드 위로 이동 */}
|
||||
{/* 목표 진행 상황 */}
|
||||
<h2 className="text-lg font-semibold mb-3">예산과 지출</h2>
|
||||
<div className="neuro-card mb-6 overflow-hidden">
|
||||
<Tabs defaultValue="daily" value={selectedTab} onValueChange={setSelectedTab} className="w-full">
|
||||
@@ -205,15 +205,7 @@ 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">
|
||||
<BudgetCard title="식비" current={240000} total={400000} color="neuro-income" />
|
||||
@@ -221,8 +213,15 @@ const Index = () => {
|
||||
<BudgetCard title="교통비" current={190000} total={200000} color="neuro-income" />
|
||||
</div>
|
||||
|
||||
{/* Recent Transactions */}
|
||||
<h2 className="text-lg font-semibold mb-3">최근 지출</h2>
|
||||
{/* 예산 입력 카드 - 이제는 접힌 상태로 표시됩니다 */}
|
||||
<BudgetInputCard initialBudgets={{
|
||||
daily: budgetData.daily.targetAmount,
|
||||
weekly: budgetData.weekly.targetAmount,
|
||||
monthly: budgetData.monthly.targetAmount
|
||||
}} onSave={handleBudgetGoalUpdate} />
|
||||
|
||||
{/* 최근 지출 */}
|
||||
<h2 className="text-lg font-semibold mb-3 mt-8">최근 지출</h2>
|
||||
<div className="grid gap-3 mb-6">
|
||||
{transactions.map(transaction => <TransactionCard key={transaction.id} transaction={transaction} />)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user