Reverted to edit edt-df6bf84a-482f-4f45-8871-2125b421fdb0: "Add bottom padding to screen

Adds 100px bottom padding to the screen."
This commit is contained in:
gpt-engineer-app[bot]
2025-03-23 10:11:05 +00:00
parent 8cf2e70050
commit 2c99bbce88
11 changed files with 192 additions and 278 deletions

View File

@@ -1,4 +1,6 @@
#Tue Mar 18 00:16:17 KST 2025
buildNumber=2
versionCode=1
versionName=1.0.2
versionName=1.0.1

View File

@@ -12,56 +12,8 @@ NC='\033[0m' # No Color
# 프로젝트 디렉토리로 이동
cd "$(dirname "$0")"
# 버전 정보 파일 경로
VERSION_PROPS_FILE="android/version.properties"
# 현재 버전 정보 읽기
if [ -f "$VERSION_PROPS_FILE" ]; then
CURRENT_VERSION_NAME=$(grep "versionName" "$VERSION_PROPS_FILE" | cut -d'=' -f2)
CURRENT_VERSION_CODE=$(grep "versionCode" "$VERSION_PROPS_FILE" | cut -d'=' -f2)
CURRENT_BUILD_NUMBER=$(grep "buildNumber" "$VERSION_PROPS_FILE" | cut -d'=' -f2)
echo -e "${YELLOW}현재 버전 정보:${NC}"
echo -e "버전 이름: ${GREEN}$CURRENT_VERSION_NAME${NC}"
echo -e "버전 코드: ${GREEN}$CURRENT_VERSION_CODE${NC}"
echo -e "빌드 번호: ${GREEN}$CURRENT_BUILD_NUMBER${NC}"
# 버전 수정 여부 확인
echo -e "\n${YELLOW}버전 정보를 수정하시겠습니까? (y/n)${NC}"
read -r UPDATE_VERSION
if [[ "$UPDATE_VERSION" == "y" || "$UPDATE_VERSION" == "Y" ]]; then
echo -e "\n${YELLOW}새 버전 이름을 입력하세요 (현재: $CURRENT_VERSION_NAME):${NC}"
read -r NEW_VERSION_NAME
if [ -z "$NEW_VERSION_NAME" ]; then
NEW_VERSION_NAME=$CURRENT_VERSION_NAME
fi
echo -e "${YELLOW}새 버전 코드를 입력하세요 (현재: $CURRENT_VERSION_CODE):${NC}"
read -r NEW_VERSION_CODE
if [ -z "$NEW_VERSION_CODE" ]; then
NEW_VERSION_CODE=$CURRENT_VERSION_CODE
fi
# 버전 정보 업데이트
sed -i '' "s/versionName=$CURRENT_VERSION_NAME/versionName=$NEW_VERSION_NAME/g" "$VERSION_PROPS_FILE"
sed -i '' "s/versionCode=$CURRENT_VERSION_CODE/versionCode=$NEW_VERSION_CODE/g" "$VERSION_PROPS_FILE"
echo -e "\n${GREEN}버전 정보가 업데이트되었습니다:${NC}"
echo -e "버전 이름: ${GREEN}$NEW_VERSION_NAME${NC}"
echo -e "버전 코드: ${GREEN}$NEW_VERSION_CODE${NC}"
else
echo -e "${YELLOW}현재 버전 정보를 유지합니다.${NC}"
fi
else
echo -e "${RED}버전 정보 파일을 찾을 수 없습니다: $VERSION_PROPS_FILE${NC}"
exit 1
fi
# 빌드 타입 선택 메뉴
echo -e "\n${YELLOW}Zellyy Finance 앱 빌드 스크립트${NC}"
echo -e "${YELLOW}Zellyy Finance 앱 빌드 스크립트${NC}"
echo -e "${YELLOW}=============================${NC}"
echo -e "빌드 타입을 선택하세요:"
echo -e "1) 디버그 빌드 (개발 및 테스트용)"
@@ -179,15 +131,15 @@ if [ "$BUILD_TYPE" = "debug" ]; then
fi
APK_PATH="app/build/outputs/apk/debug/app-debug.apk"
DEST_PATH="$HOME/Dev/zellyy-finance-debug.apk"
DEST_PATH="$HOME/zellyy-finance-debug.apk"
if [ -f "$APK_PATH" ]; then
echo -e "${GREEN}디버그 APK 빌드 성공!${NC}"
echo -e "APK 파일 위치: $(pwd)/$APK_PATH"
# Dev 디렉토리로 APK 복사
# 디렉토리로 APK 복사
cp "$APK_PATH" "$DEST_PATH"
echo -e "${GREEN}APK를 Dev 디렉토리에 복사했습니다: $DEST_PATH${NC}"
echo -e "${GREEN}APK를 디렉토리에 복사했습니다: $DEST_PATH${NC}"
# 연결된 기기 확인
DEVICES=$(adb devices | grep -v "List" | grep "device" | wc -l)
@@ -227,15 +179,15 @@ elif [ "$BUILD_TYPE" = "release-aab" ]; then
fi
AAB_PATH="app/build/outputs/bundle/release/app-release.aab"
DEST_PATH="$HOME/Dev/zellyy-finance-release.aab"
DEST_PATH="$HOME/zellyy-finance-release.aab"
if [ -f "$AAB_PATH" ]; then
echo -e "${GREEN}릴리즈 AAB 빌드 성공!${NC}"
echo -e "AAB 파일 위치: $(pwd)/$AAB_PATH"
# Dev 디렉토리로 AAB 복사
# 디렉토리로 AAB 복사
cp "$AAB_PATH" "$DEST_PATH"
echo -e "${GREEN}AAB를 Dev 디렉토리에 복사했습니다: $DEST_PATH${NC}"
echo -e "${GREEN}AAB를 디렉토리에 복사했습니다: $DEST_PATH${NC}"
echo -e "${YELLOW}다음 단계:${NC}"
echo "1. Google Play Console에 AAB 파일 업로드: $DEST_PATH"
@@ -255,15 +207,15 @@ elif [ "$BUILD_TYPE" = "release-apk" ]; then
fi
SIGNED_APK_PATH="app/build/outputs/apk/release/app-release.apk"
DEST_PATH="$HOME/Dev/zellyy-finance-release.apk"
DEST_PATH="$HOME/zellyy-finance-release.apk"
if [ -f "$SIGNED_APK_PATH" ]; then
echo -e "${GREEN}서명된 릴리즈 APK 빌드 성공!${NC}"
echo -e "APK 파일 위치: $(pwd)/$SIGNED_APK_PATH"
# Dev 디렉토리로 APK 복사
# 디렉토리로 APK 복사
cp "$SIGNED_APK_PATH" "$DEST_PATH"
echo -e "${GREEN}서명된 APK를 Dev 디렉토리에 복사했습니다: $DEST_PATH${NC}"
echo -e "${GREEN}서명된 APK를 디렉토리에 복사했습니다: $DEST_PATH${NC}"
# 연결된 기기 확인
DEVICES=$(adb devices | grep -v "List" | grep "device" | wc -l)

57
build-ios.sh Executable file → Normal file
View File

@@ -12,55 +12,8 @@ NC='\033[0m' # No Color
# 프로젝트 디렉토리로 이동
cd "$(dirname "$0")"
# 프로젝트 파일 경로
XCODEPROJ_FILE="ios/App/App.xcodeproj/project.pbxproj"
# 현재 버전 및 빌드 번호 가져오기
if [ -f "$XCODEPROJ_FILE" ]; then
MARKETING_VERSION=$(grep -A 1 "MARKETING_VERSION" "$XCODEPROJ_FILE" | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -1)
CURRENT_PROJECT_VERSION=$(grep -A 1 "CURRENT_PROJECT_VERSION" "$XCODEPROJ_FILE" | grep -o '[0-9]\+' | head -1)
echo -e "${YELLOW}현재 버전 정보:${NC}"
echo -e "마케팅 버전: ${GREEN}$MARKETING_VERSION${NC}"
echo -e "빌드 번호: ${GREEN}$CURRENT_PROJECT_VERSION${NC}"
# 버전 수정 여부 확인
echo -e "\n${YELLOW}버전 정보를 수정하시겠습니까? (y/n)${NC}"
read -r UPDATE_VERSION
if [[ "$UPDATE_VERSION" == "y" || "$UPDATE_VERSION" == "Y" ]]; then
echo -e "\n${YELLOW}새 마케팅 버전을 입력하세요 (현재: $MARKETING_VERSION):${NC}"
read -r NEW_MARKETING_VERSION
if [ -z "$NEW_MARKETING_VERSION" ]; then
NEW_MARKETING_VERSION=$MARKETING_VERSION
fi
echo -e "${YELLOW}새 빌드 번호를 입력하세요 (현재: $CURRENT_PROJECT_VERSION):${NC}"
read -r NEW_PROJECT_VERSION
if [ -z "$NEW_PROJECT_VERSION" ]; then
NEW_PROJECT_VERSION=$CURRENT_PROJECT_VERSION
fi
# 버전 정보 업데이트
# macOS에서는 sed -i에 백업 확장자를 지정해야 함
sed -i '' "s/MARKETING_VERSION = $MARKETING_VERSION;/MARKETING_VERSION = $NEW_MARKETING_VERSION;/g" "$XCODEPROJ_FILE"
sed -i '' "s/CURRENT_PROJECT_VERSION = $CURRENT_PROJECT_VERSION;/CURRENT_PROJECT_VERSION = $NEW_PROJECT_VERSION;/g" "$XCODEPROJ_FILE"
echo -e "\n${GREEN}버전 정보가 업데이트되었습니다:${NC}"
echo -e "마케팅 버전: ${GREEN}$NEW_MARKETING_VERSION${NC}"
echo -e "빌드 번호: ${GREEN}$NEW_PROJECT_VERSION${NC}"
else
echo -e "${YELLOW}현재 버전 정보를 유지합니다.${NC}"
fi
else
echo -e "${RED}프로젝트 파일을 찾을 수 없습니다: $XCODEPROJ_FILE${NC}"
exit 1
fi
# 빌드 타입 선택 메뉴
echo -e "\n${YELLOW}Zellyy Finance iOS 앱 빌드 스크립트${NC}"
echo -e "${YELLOW}Zellyy Finance iOS 앱 빌드 스크립트${NC}"
echo -e "${YELLOW}=============================${NC}"
echo -e "빌드 타입을 선택하세요:"
echo -e "1) 디버그 빌드 (개발 및 테스트용)"
@@ -307,9 +260,9 @@ EOF
echo -e "${GREEN}디버그용 IPA 파일 생성 성공!${NC}"
echo -e "IPA 파일 위치: $(pwd)/$DEBUG_IPA_PATH"
# Dev 디렉토리로 IPA 복사
# 디렉토리로 IPA 복사
cp "$DEBUG_IPA_PATH" "$DEBUG_DEST_PATH"
echo -e "${GREEN}IPA를 Dev 디렉토리에 복사했습니다: $DEBUG_DEST_PATH${NC}"
echo -e "${GREEN}IPA를 디렉토리에 복사했습니다: $DEBUG_DEST_PATH${NC}"
echo -e "${YELLOW}다음 방법으로 다른 기기에 설치할 수 있습니다:${NC}"
echo "1. Apple Configurator 2 앱 사용"
@@ -362,9 +315,9 @@ elif [ "$BUILD_TYPE" = "release" ]; then
echo -e "${GREEN}IPA 파일 생성 성공!${NC}"
echo -e "IPA 파일 위치: $(pwd)/$IPA_PATH"
# Dev 디렉토리로 IPA 복사
# 디렉토리로 IPA 복사
cp "$IPA_PATH" "$DEST_PATH"
echo -e "${GREEN}IPA를 Dev 디렉토리에 복사했습니다: $DEST_PATH${NC}"
echo -e "${GREEN}IPA를 디렉토리에 복사했습니다: $DEST_PATH${NC}"
echo -e "${YELLOW}다음 단계:${NC}"
echo "1. App Store Connect에 로그인: https://appstoreconnect.apple.com"

View File

@@ -13,7 +13,7 @@ interface BudgetData {
remainingAmount: number;
}
export interface BudgetTabContentProps {
interface BudgetTabContentProps {
data: BudgetData;
formatCurrency: (amount: number) => string;
calculatePercentage: (spent: number, target: number) => number;
@@ -26,12 +26,6 @@ const BudgetTabContent: React.FC<BudgetTabContentProps> = ({
calculatePercentage,
onSaveBudget
}) => {
// 데이터 유효성 체크 - 데이터가 없으면 기본값 사용
if (!data) {
console.warn('BudgetTabContent: data prop이 제공되지 않았습니다. 기본값을 사용합니다.');
data = { targetAmount: 0, spentAmount: 0, remainingAmount: 0 };
}
const {
categoryBudgets,
showBudgetInput,

View File

@@ -1,4 +1,3 @@
import React from 'react';
import { Transaction } from '@/contexts/budget/types';
import TransactionEditDialog from './TransactionEditDialog';
@@ -9,7 +8,7 @@ import { useRecentTransactions } from '@/hooks/transactions/useRecentTransaction
import { useRecentTransactionsDialog } from '@/hooks/transactions/useRecentTransactionsDialog';
import RecentTransactionItem from './recent-transactions/RecentTransactionItem';
export interface RecentTransactionsSectionProps {
interface RecentTransactionsSectionProps {
transactions: Transaction[];
onUpdateTransaction?: (transaction: Transaction) => void;
}

View File

@@ -12,7 +12,6 @@ interface SafeAreaContainerProps {
/**
* 플랫폼별 안전 영역(Safe Area)을 고려한 컨테이너 컴포넌트
* iOS에서는 노치/다이나믹 아일랜드를 고려한 여백 적용
* CSS 변수와 env() 함수를 사용하여 정확한 안전 영역 계산
*/
const SafeAreaContainer: React.FC<SafeAreaContainerProps> = ({
children,
@@ -25,24 +24,17 @@ const SafeAreaContainer: React.FC<SafeAreaContainerProps> = ({
// 마운트 시 플랫폼 확인
useEffect(() => {
setIsIOS(isIOSPlatform());
// iOS 디버깅용 로그
if (isIOSPlatform()) {
console.info('iOS 플랫폼 감지됨 - 안전 영역 적용');
}
}, []);
// 플랫폼에 따른 클래스 결정
let safeAreaClass = '';
if (isIOS) {
safeAreaClass = 'ios-safe-area';
if (bottomOnly) safeAreaClass += ' ios-safe-area-bottom-only';
if (topOnly) safeAreaClass += ' ios-safe-area-top-only';
if (!bottomOnly) safeAreaClass += ' pt-12'; // iOS 상단 안전 영역
if (!topOnly) safeAreaClass += ' pb-8'; // iOS 하단 안전 영역
} else {
// 안드로이드 기본 여백
safeAreaClass = 'android-safe-area';
if (!bottomOnly) safeAreaClass += ' pt-4'; // 안드로이드 상단 여백
if (!topOnly) safeAreaClass += ' pb-4'; // 안드로이드 하단 여백
}
return (

View File

@@ -1,51 +0,0 @@
import React, { useEffect, useState } from 'react';
import { isIOSPlatform } from '@/utils/platform';
/**
* 안전 영역(Safe Area) 디버그 컴포넌트
* 노치나 다이나믹 아일랜드 등 iOS 기기의 안전 영역을 시각적으로 표시
*/
const SafeAreaDebug = () => {
const [isIOS, setIsIOS] = useState(false);
const [safeAreaTop, setSafeAreaTop] = useState('0px');
const [safeAreaBottom, setSafeAreaBottom] = useState('0px');
useEffect(() => {
setIsIOS(isIOSPlatform());
// iOS에서만 안전 영역 값 가져오기 시도
if (isIOSPlatform()) {
// CSS 변수에서 값 가져오기 시도
const computedStyle = getComputedStyle(document.documentElement);
const topInset = computedStyle.getPropertyValue('--safe-area-top') ||
computedStyle.getPropertyValue('env(safe-area-inset-top)') ||
'0px';
const bottomInset = computedStyle.getPropertyValue('--safe-area-bottom') ||
computedStyle.getPropertyValue('env(safe-area-inset-bottom)') ||
'0px';
setSafeAreaTop(topInset);
setSafeAreaBottom(bottomInset);
console.info('iOS 안전 영역 감지:', {
top: topInset,
bottom: bottomInset
});
}
}, []);
if (!isIOS) {
return null; // iOS가 아니면 렌더링하지 않음
}
return (
<div className="fixed bottom-0 left-0 z-50 p-2 bg-black/70 text-white text-xs rounded-tr-md">
<div>Safe Area Top: {safeAreaTop}</div>
<div>Safe Area Bottom: {safeAreaBottom}</div>
</div>
);
};
export default SafeAreaDebug;

View File

@@ -37,18 +37,15 @@ export const useBudgetTabContent = ({
calculatePercentage,
onSaveBudget
}: UseBudgetTabContentProps): UseBudgetTabContentReturn => {
// 데이터가 undefined인 경우를 방지하기 위한 기본값 설정
const safeData = data || { targetAmount: 0, spentAmount: 0, remainingAmount: 0 };
const [categoryBudgets, setCategoryBudgets] = useState<Record<string, number>>({});
const [showBudgetInput, setShowBudgetInput] = useState(false);
const spentAmount = safeData.spentAmount;
const targetAmount = safeData.targetAmount;
const spentAmount = data.spentAmount;
const targetAmount = data.targetAmount;
// 로그 추가 - 받은 데이터 확인
useEffect(() => {
console.log(`BudgetTabContent 수신 데이터:`, safeData);
}, [safeData]);
console.log(`BudgetTabContent 수신 데이터:`, data);
}, [data]);
// 전역 예산 데이터가 변경되었을 때 로컬 상태 갱신
useEffect(() => {

View File

@@ -150,28 +150,7 @@
@apply neuro-pressed px-4 py-3 w-full focus:outline-none focus:ring-2 focus:ring-neuro-accent/30;
}
/* 안전 영역 관련 개선된 클래스 */
.ios-safe-area {
padding-top: max(1rem, env(safe-area-inset-top));
padding-bottom: max(1rem, env(safe-area-inset-bottom));
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
}
.ios-safe-area-top-only {
padding-top: max(1rem, env(safe-area-inset-top));
padding-bottom: 1rem;
}
.ios-safe-area-bottom-only {
padding-top: 1rem;
padding-bottom: max(1rem, env(safe-area-inset-bottom));
}
.android-safe-area {
padding: 1rem;
}
/* 안전 영역 관련 클래스 */
.has-safe-area-top {
padding-top: max(1rem, env(safe-area-inset-top));
}
@@ -289,16 +268,6 @@
--safe-area-bottom: env(safe-area-inset-bottom);
padding-bottom: var(--safe-area-bottom);
}
/* iOS 안전 영역 디버깅 클래스 */
.debug-safe-areas {
--safe-area-top-color: rgba(255, 0, 0, 0.2);
--safe-area-bottom-color: rgba(0, 0, 255, 0.2);
background:
linear-gradient(to bottom, var(--safe-area-top-color) 0, var(--safe-area-top-color) env(safe-area-inset-top), transparent env(safe-area-inset-top)),
linear-gradient(to top, var(--safe-area-bottom-color) 0, var(--safe-area-bottom-color) env(safe-area-inset-bottom), transparent env(safe-area-inset-bottom));
}
}
.font-inter {

View File

@@ -1,65 +1,174 @@
import React, { useEffect } from 'react';
import NavBar from '../components/NavBar';
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import BudgetTabContent from '@/components/BudgetTabContent';
import RecentTransactionsSection from '@/components/RecentTransactionsSection';
import NavBar from '@/components/NavBar';
import AddTransactionButton from '@/components/AddTransactionButton';
import Header from '@/components/Header';
import { useBudget } from '@/contexts/budget';
import SafeAreaContainer from '@/components/SafeAreaContainer';
import { formatCurrency } from '@/utils/formatters';
import WelcomeDialog from '@/components/onboarding/WelcomeDialog';
import HomeContent from '@/components/home/HomeContent';
import { useBudget } from '@/contexts/budget/BudgetContext';
import { useAuth } from '@/contexts/auth';
import { useWelcomeDialog } from '@/hooks/useWelcomeDialog';
import { useDataInitialization } from '@/hooks/useDataInitialization';
import { useIsMobile } from '@/hooks/use-mobile';
import useNotifications from '@/hooks/useNotifications';
// 메인 컴포넌트
const Index = () => {
const { transactions, budgetData, handleBudgetGoalUpdate } = useBudget();
// 데이터 구조 확인용 로깅
const {
transactions,
budgetData,
selectedTab,
setSelectedTab,
handleBudgetGoalUpdate,
updateTransaction,
getCategorySpending,
resetBudgetData
} = useBudget();
const { user } = useAuth();
const { showWelcome, checkWelcomeDialogState, handleCloseWelcome } = useWelcomeDialog();
const { isInitialized } = useDataInitialization(resetBudgetData);
const isMobile = useIsMobile();
const { addNotification } = useNotifications();
// 초기화 후 환영 메시지 표시 상태 확인
useEffect(() => {
console.info('Index 페이지 마운트, 현재 데이터 상태:');
console.info('트랜잭션 수:', transactions?.length);
console.info('예산 데이터:', budgetData);
}, [transactions, budgetData]);
// 예산 퍼센트 계산 함수
const calculatePercentage = (spent: number, target: number) => {
if (target <= 0) return 0;
return Math.min(100, Math.round((spent / target) * 100));
};
if (isInitialized) {
const timeoutId = setTimeout(checkWelcomeDialogState, 500);
return () => clearTimeout(timeoutId);
}
}, [isInitialized, checkWelcomeDialogState]);
// 앱 시작시 예시 알림 추가 (실제 앱에서는 필요한 이벤트에 따라 알림 추가)
useEffect(() => {
// 환영 메시지가 이미 표시되었는지 확인하는 키
const welcomeNotificationSent = sessionStorage.getItem('welcomeNotificationSent');
if (isInitialized && user && !welcomeNotificationSent) {
// 사용자 로그인 시 알림 예시 (한 번만 실행)
const timeoutId = setTimeout(() => {
addNotification(
'환영합니다!',
'젤리의 적자탈출에 오신 것을 환영합니다. 예산을 설정하고 지출을 기록해보세요.'
);
// 세션 스토리지에 환영 메시지 표시 여부 저장
sessionStorage.setItem('welcomeNotificationSent', 'true');
}, 2000);
return () => clearTimeout(timeoutId);
}
}, [isInitialized, user, addNotification]);
// 페이지가 처음 로드될 때 데이터 로딩 확인
useEffect(() => {
console.log('Index 페이지 마운트, 현재 데이터 상태:');
console.log('트랜잭션:', transactions.length);
console.log('예산 데이터:', budgetData);
// 페이지 마운트 시 데이터 동기화 이벤트 수동 발생
try {
window.dispatchEvent(new Event('transactionUpdated'));
window.dispatchEvent(new Event('budgetDataUpdated'));
window.dispatchEvent(new Event('categoryBudgetsUpdated'));
} catch (e) {
console.error('이벤트 발생 오류:', e);
}
// 백업된 데이터 복구 확인 (메인 데이터가 없는 경우만)
try {
if (!localStorage.getItem('budgetData')) {
const budgetBackup = localStorage.getItem('budgetData_backup');
if (budgetBackup) {
console.log('예산 데이터 백업에서 복구');
localStorage.setItem('budgetData', budgetBackup);
window.dispatchEvent(new Event('budgetDataUpdated'));
}
}
if (!localStorage.getItem('categoryBudgets')) {
const categoryBackup = localStorage.getItem('categoryBudgets_backup');
if (categoryBackup) {
console.log('카테고리 예산 백업에서 복구');
localStorage.setItem('categoryBudgets', categoryBackup);
window.dispatchEvent(new Event('categoryBudgetsUpdated'));
}
}
if (!localStorage.getItem('transactions')) {
const transactionBackup = localStorage.getItem('transactions_backup');
if (transactionBackup) {
console.log('트랜잭션 백업에서 복구');
localStorage.setItem('transactions', transactionBackup);
window.dispatchEvent(new Event('transactionUpdated'));
}
}
} catch (error) {
console.error('백업 복구 시도 중 오류:', error);
}
}, [transactions.length, budgetData]);
// 앱이 포커스를 얻었을 때 데이터를 새로고침
useEffect(() => {
const handleFocus = () => {
console.log('창이 포커스를 얻음 - 데이터 새로고침');
// 이벤트 발생시켜 데이터 새로고침
try {
window.dispatchEvent(new Event('storage'));
window.dispatchEvent(new Event('transactionUpdated'));
window.dispatchEvent(new Event('budgetDataUpdated'));
window.dispatchEvent(new Event('categoryBudgetsUpdated'));
} catch (e) {
console.error('이벤트 발생 오류:', e);
}
};
// 포커스 이벤트
window.addEventListener('focus', handleFocus);
// 가시성 변경 이벤트 (백그라운드에서 전경으로 돌아올 때)
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
console.log('페이지가 다시 보임 - 데이터 새로고침');
handleFocus();
}
});
// 정기적인 데이터 새로고침 (10초마다)
const refreshInterval = setInterval(() => {
if (document.visibilityState === 'visible') {
console.log('정기 새로고침 - 데이터 업데이트');
handleFocus();
}
}, 10000);
return () => {
window.removeEventListener('focus', handleFocus);
document.removeEventListener('visibilitychange', () => {});
clearInterval(refreshInterval);
};
}, []);
return (
<SafeAreaContainer className="min-h-screen bg-neuro-background">
<div className="min-h-screen bg-neuro-background pb-24">
<div className="max-w-md mx-auto px-6">
<Header />
<Tabs defaultValue="budget" className="w-full mt-4">
<TabsList className="grid w-full grid-cols-2 mb-8">
<TabsTrigger value="budget"></TabsTrigger>
<TabsTrigger value="recent"> </TabsTrigger>
</TabsList>
<TabsContent value="budget" className="focus-visible:outline-none">
{budgetData && budgetData.monthly && (
<BudgetTabContent
data={budgetData.monthly}
formatCurrency={formatCurrency}
calculatePercentage={calculatePercentage}
onSaveBudget={(amount, categoryBudgets) =>
handleBudgetGoalUpdate('monthly', amount, categoryBudgets)
}
/>
)}
</TabsContent>
<TabsContent value="recent" className="focus-visible:outline-none">
<RecentTransactionsSection
transactions={transactions || []}
onUpdateTransaction={transaction => console.log('트랜잭션 업데이트', transaction)}
/>
</TabsContent>
</Tabs>
<HomeContent
transactions={transactions}
budgetData={budgetData}
selectedTab={selectedTab}
setSelectedTab={setSelectedTab}
handleBudgetGoalUpdate={handleBudgetGoalUpdate}
updateTransaction={updateTransaction}
getCategorySpending={getCategorySpending}
/>
</div>
<AddTransactionButton />
<NavBar />
</SafeAreaContainer>
{/* 첫 사용자 안내 팝업 */}
<WelcomeDialog open={showWelcome} onClose={handleCloseWelcome} />
</div>
);
};

View File

@@ -1,3 +1,4 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import NavBar from '@/components/NavBar';
@@ -7,7 +8,6 @@ import { User, CreditCard, Bell, Lock, HelpCircle, LogOut, ChevronRight } from '
import { cn } from '@/lib/utils';
import { useAuth } from '@/contexts/auth';
import { useToast } from '@/hooks/useToast.wrapper';
import SafeAreaContainer from '@/components/SafeAreaContainer';
const SettingsOption = ({
icon: Icon,
@@ -57,8 +57,7 @@ const Settings = () => {
navigate(path);
};
return (
<SafeAreaContainer className="min-h-screen bg-neuro-background">
return <div className="min-h-screen bg-neuro-background pb-24">
<div className="max-w-md mx-auto px-6">
{/* Header */}
<header className="py-4">
@@ -122,8 +121,7 @@ const Settings = () => {
</div>
<NavBar />
</SafeAreaContainer>
);
</div>;
};
export default Settings;