Implement first-time user experience

- Implement default state for new users.
- Add a simple tutorial popup for first-time users.
This commit is contained in:
gpt-engineer-app[bot]
2025-03-15 22:47:32 +00:00
parent db6c8431ec
commit 44789fa388
3 changed files with 141 additions and 5 deletions

View File

@@ -0,0 +1,88 @@
import React from "react";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator";
import { ArrowRight, Wallet, PieChart, LineChart } from "lucide-react";
interface WelcomeDialogProps {
open: boolean;
onClose: () => void;
}
const WelcomeDialog: React.FC<WelcomeDialogProps> = ({ open, onClose }) => {
return (
<Dialog open={open} onOpenChange={onClose}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle className="text-center text-2xl text-neuro-income mb-2">
!
</DialogTitle>
<DialogDescription className="text-center">
.
</DialogDescription>
</DialogHeader>
<div className="space-y-4 my-2">
<div className="flex items-start gap-3">
<div className="bg-neuro-background p-2 rounded-full">
<Wallet className="h-5 w-5 text-neuro-income" />
</div>
<div>
<h3 className="font-medium"> </h3>
<p className="text-sm text-gray-500">
, .
</p>
</div>
</div>
<Separator />
<div className="flex items-start gap-3">
<div className="bg-neuro-background p-2 rounded-full">
<PieChart className="h-5 w-5 text-neuro-income" />
</div>
<div>
<h3 className="font-medium"> </h3>
<p className="text-sm text-gray-500">
.
</p>
</div>
</div>
<Separator />
<div className="flex items-start gap-3">
<div className="bg-neuro-background p-2 rounded-full">
<LineChart className="h-5 w-5 text-neuro-income" />
</div>
<div>
<h3 className="font-medium"> </h3>
<p className="text-sm text-gray-500">
.
</p>
</div>
</div>
</div>
<DialogFooter className="sm:justify-center">
<Button
className="w-full sm:w-auto bg-neuro-income text-white hover:bg-neuro-income/90"
onClick={onClose}
>
<ArrowRight className="ml-2 h-4 w-4" />
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
};
export default WelcomeDialog;

View File

@@ -6,7 +6,12 @@ import { DEFAULT_CATEGORY_BUDGETS, getInitialBudgetData } from './budgetUtils';
export const loadTransactionsFromStorage = (): Transaction[] => { export const loadTransactionsFromStorage = (): Transaction[] => {
const storedTransactions = localStorage.getItem('transactions'); const storedTransactions = localStorage.getItem('transactions');
if (storedTransactions) { if (storedTransactions) {
return JSON.parse(storedTransactions); try {
return JSON.parse(storedTransactions);
} catch (error) {
console.error('트랜잭션 데이터 파싱 오류:', error);
return [];
}
} }
return []; return [];
}; };
@@ -20,8 +25,16 @@ export const saveTransactionsToStorage = (transactions: Transaction[]): void =>
export const loadCategoryBudgetsFromStorage = (): Record<string, number> => { export const loadCategoryBudgetsFromStorage = (): Record<string, number> => {
const storedCategoryBudgets = localStorage.getItem('categoryBudgets'); const storedCategoryBudgets = localStorage.getItem('categoryBudgets');
if (storedCategoryBudgets) { if (storedCategoryBudgets) {
return JSON.parse(storedCategoryBudgets); try {
return JSON.parse(storedCategoryBudgets);
} catch (error) {
console.error('카테고리 예산 데이터 파싱 오류:', error);
return DEFAULT_CATEGORY_BUDGETS;
}
} }
// 새 사용자를 위한 기본 카테고리 예산 저장
saveCategoryBudgetsToStorage(DEFAULT_CATEGORY_BUDGETS);
return DEFAULT_CATEGORY_BUDGETS; return DEFAULT_CATEGORY_BUDGETS;
}; };
@@ -34,9 +47,20 @@ export const saveCategoryBudgetsToStorage = (categoryBudgets: Record<string, num
export const loadBudgetDataFromStorage = (): BudgetData => { export const loadBudgetDataFromStorage = (): BudgetData => {
const storedBudgetData = localStorage.getItem('budgetData'); const storedBudgetData = localStorage.getItem('budgetData');
if (storedBudgetData) { if (storedBudgetData) {
return JSON.parse(storedBudgetData); try {
return JSON.parse(storedBudgetData);
} catch (error) {
console.error('예산 데이터 파싱 오류:', error);
const initialData = getInitialBudgetData();
saveBudgetDataToStorage(initialData);
return initialData;
}
} }
return getInitialBudgetData();
// 새 사용자를 위한 기본 예산 데이터 저장
const initialData = getInitialBudgetData();
saveBudgetDataToStorage(initialData);
return initialData;
}; };
// 예산 데이터 저장 // 예산 데이터 저장

View File

@@ -1,13 +1,15 @@
import React from 'react'; import React, { useState, useEffect } from 'react';
import NavBar from '@/components/NavBar'; import NavBar from '@/components/NavBar';
import AddTransactionButton from '@/components/AddTransactionButton'; import AddTransactionButton from '@/components/AddTransactionButton';
import Header from '@/components/Header'; import Header from '@/components/Header';
import BudgetProgressCard from '@/components/BudgetProgressCard'; import BudgetProgressCard from '@/components/BudgetProgressCard';
import BudgetCategoriesSection from '@/components/BudgetCategoriesSection'; import BudgetCategoriesSection from '@/components/BudgetCategoriesSection';
import RecentTransactionsSection from '@/components/RecentTransactionsSection'; import RecentTransactionsSection from '@/components/RecentTransactionsSection';
import WelcomeDialog from '@/components/onboarding/WelcomeDialog';
import { formatCurrency, calculatePercentage } from '@/utils/formatters'; import { formatCurrency, calculatePercentage } from '@/utils/formatters';
import { useBudget } from '@/contexts/BudgetContext'; import { useBudget } from '@/contexts/BudgetContext';
import { useAuth } from '@/contexts/auth';
// 메인 컴포넌트 // 메인 컴포넌트
const Index = () => { const Index = () => {
@@ -21,6 +23,25 @@ const Index = () => {
getCategorySpending getCategorySpending
} = useBudget(); } = useBudget();
const { user } = useAuth();
const [showWelcome, setShowWelcome] = useState(false);
// 첫 방문 여부 확인
useEffect(() => {
const hasVisitedBefore = localStorage.getItem('hasVisitedBefore');
if (!hasVisitedBefore) {
setShowWelcome(true);
// 방문 기록 저장
localStorage.setItem('hasVisitedBefore', 'true');
}
}, []);
// 환영 팝업 닫기
const handleCloseWelcome = () => {
setShowWelcome(false);
};
return ( return (
<div className="min-h-screen bg-neuro-background pb-24"> <div className="min-h-screen bg-neuro-background pb-24">
<div className="max-w-md mx-auto px-6"> <div className="max-w-md mx-auto px-6">
@@ -48,6 +69,9 @@ const Index = () => {
</div> </div>
<AddTransactionButton /> <AddTransactionButton />
<NavBar /> <NavBar />
{/* 첫 사용자 안내 팝업 */}
<WelcomeDialog open={showWelcome} onClose={handleCloseWelcome} />
</div> </div>
); );
}; };