Fix budget update issues

Addresses delayed notifications and data loss after budget updates and page transitions.
This commit is contained in:
gpt-engineer-app[bot]
2025-03-16 07:05:20 +00:00
parent 61b00cfdcb
commit d59fb97f7c
9 changed files with 523 additions and 126 deletions

View File

@@ -34,6 +34,7 @@ const BudgetInputCard: React.FC<BudgetGoalProps> = ({
return numericValue.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
};
// 초기값 변경시 입력 필드 값 업데이트
useEffect(() => {
setBudgetInputs({
daily: initialBudgets.daily > 0 ? initialBudgets.daily.toString() : '',
@@ -53,9 +54,21 @@ const BudgetInputCard: React.FC<BudgetGoalProps> = ({
const handleSave = () => {
const amount = parseInt(budgetInputs[selectedTab].replace(/,/g, ''), 10) || 0;
onSave(selectedTab, amount);
// Close the collapsible after saving
if (amount <= 0) {
return; // 0 이하의 금액은 저장하지 않음
}
// 즉시 입력 필드를 업데이트하여 사용자에게 피드백 제공
setBudgetInputs(prev => ({
...prev,
[selectedTab]: amount.toString()
}));
// 즉시 콜랩시블을 닫아 사용자에게 완료 피드백 제공
setIsOpen(false);
// 예산 저장
onSave(selectedTab, amount);
};
// 비어있으면 빈 문자열을, 그렇지 않으면 포맷팅된 문자열을 반환

View File

@@ -1,8 +1,9 @@
import React, { useEffect } from 'react';
import React, { useEffect, useRef } from 'react';
import { Input } from '@/components/ui/input';
import { EXPENSE_CATEGORIES } from '@/constants/categoryIcons';
import { useIsMobile } from '@/hooks/use-mobile';
import { toast } from '@/components/ui/use-toast';
interface CategoryBudgetInputsProps {
categoryBudgets: Record<string, number>;
@@ -14,6 +15,7 @@ const CategoryBudgetInputs: React.FC<CategoryBudgetInputsProps> = ({
handleCategoryInputChange
}) => {
const isMobile = useIsMobile();
const previousBudgetsRef = useRef<Record<string, number>>({});
// Format number with commas for display
const formatWithCommas = (value: number): string => {
@@ -26,6 +28,12 @@ const CategoryBudgetInputs: React.FC<CategoryBudgetInputsProps> = ({
// Remove all non-numeric characters before passing to parent handler
const numericValue = e.target.value.replace(/[^0-9]/g, '');
handleCategoryInputChange(numericValue, category);
// 사용자에게 시각적 피드백 제공
e.target.classList.add('border-green-500');
setTimeout(() => {
e.target.classList.remove('border-green-500');
}, 300);
};
// 컴포넌트가 마운트될 때 categoryBudgets가 로컬 스토리지에서 다시 로드되도록 이벤트 리스너 설정
@@ -44,6 +52,24 @@ const CategoryBudgetInputs: React.FC<CategoryBudgetInputsProps> = ({
};
}, []);
// 값이 변경될 때마다 토스트 메시지 표시
useEffect(() => {
const hasChanges = Object.keys(categoryBudgets).some(
category => categoryBudgets[category] !== previousBudgetsRef.current[category]
);
const totalBudget = Object.values(categoryBudgets).reduce((sum, val) => sum + val, 0);
const previousTotal = Object.values(previousBudgetsRef.current).reduce((sum, val) => sum + val, 0);
// 이전 값과 다르고, 총 예산이 있는 경우 토스트 표시
if (hasChanges && totalBudget > 0 && totalBudget !== previousTotal) {
// 토스트 메시지는 storage에서 처리
}
// 현재 값을 이전 값으로 업데이트
previousBudgetsRef.current = { ...categoryBudgets };
}, [categoryBudgets]);
return (
<div className="space-y-2 w-full">
{EXPENSE_CATEGORIES.map(category => (
@@ -53,7 +79,7 @@ const CategoryBudgetInputs: React.FC<CategoryBudgetInputsProps> = ({
value={formatWithCommas(categoryBudgets[category] || 0)}
onChange={(e) => handleInput(e, category)}
placeholder="예산 입력"
className={`neuro-pressed ${isMobile ? 'w-[150px]' : 'max-w-[150px]'} text-xs`}
className={`neuro-pressed transition-colors duration-300 ${isMobile ? 'w-[150px]' : 'max-w-[150px]'} text-xs`}
/>
</div>
))}