feat: Clerk + Supabase 통합 시스템 구현 완료
주요 변경사항: • Clerk 인증 시스템 통합 및 설정 • Supabase 데이터베이스 스키마 설계 및 적용 • JWT 기반 Row Level Security (RLS) 정책 구현 • 기존 Appwrite 인증을 Clerk로 완전 교체 기술적 개선: • 무한 로딩 문제 해결 - Index.tsx 인증 로직 수정 • React root 마운팅 오류 수정 - main.tsx 개선 • CORS 설정 추가 - vite.config.ts 수정 • Sentry 에러 모니터링 통합 추가된 컴포넌트: • AuthGuard: 인증 보호 컴포넌트 • SignIn/SignUp: Clerk 기반 인증 UI • ClerkProvider: Clerk 설정 래퍼 • EnvTest: 개발환경 디버깅 도구 데이터베이스: • user_profiles, transactions, budgets, category_budgets 테이블 • Clerk JWT 토큰 기반 RLS 정책 • 자동 사용자 프로필 생성 및 동기화 Task Master: • Task 11.1, 11.2, 11.4 완료 • 프로젝트 관리 시스템 업데이트 Note: ESLint 정리는 별도 커밋에서 진행 예정 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,20 +1,37 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { useState, useEffect, Suspense, lazy } from "react";
|
||||
import { logger } from "@/utils/logger";
|
||||
import NavBar from "@/components/NavBar";
|
||||
import ExpenseChart from "@/components/ExpenseChart";
|
||||
import AddTransactionButton from "@/components/AddTransactionButton";
|
||||
import { useBudget } from "@/stores";
|
||||
import { MONTHS_KR } from "@/hooks/useTransactions";
|
||||
import { useIsMobile } from "@/hooks/use-mobile";
|
||||
import { getCategoryColor } from "@/utils/categoryColorUtils";
|
||||
import { MonthlyData } from "@/types";
|
||||
|
||||
// 새로 분리한 컴포넌트들 불러오기
|
||||
import PeriodSelector from "@/components/analytics/PeriodSelector";
|
||||
import SummaryCards from "@/components/analytics/SummaryCards";
|
||||
import MonthlyComparisonChart from "@/components/analytics/MonthlyComparisonChart";
|
||||
import CategorySpendingList from "@/components/analytics/CategorySpendingList";
|
||||
import PaymentMethodChart from "@/components/analytics/PaymentMethodChart";
|
||||
// 차트 관련 컴포넌트들을 동적 import로 변경
|
||||
const ExpenseChart = lazy(() => import("@/components/ExpenseChart"));
|
||||
const PeriodSelector = lazy(
|
||||
() => import("@/components/analytics/PeriodSelector")
|
||||
);
|
||||
const SummaryCards = lazy(() => import("@/components/analytics/SummaryCards"));
|
||||
const MonthlyComparisonChart = lazy(
|
||||
() => import("@/components/analytics/MonthlyComparisonChart")
|
||||
);
|
||||
const CategorySpendingList = lazy(
|
||||
() => import("@/components/analytics/CategorySpendingList")
|
||||
);
|
||||
const PaymentMethodChart = lazy(
|
||||
() => import("@/components/analytics/PaymentMethodChart")
|
||||
);
|
||||
const AddTransactionButton = lazy(
|
||||
() => import("@/components/AddTransactionButton")
|
||||
);
|
||||
|
||||
// 로딩 스피너 컴포넌트
|
||||
const ChartLoadingSpinner = () => (
|
||||
<div className="h-48 flex items-center justify-center">
|
||||
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"></div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const Analytics = () => {
|
||||
const [_selectedPeriod, _setSelectedPeriod] = useState("이번 달");
|
||||
@@ -143,27 +160,33 @@ const Analytics = () => {
|
||||
<h1 className="font-bold neuro-text mb-3 text-xl">지출 분석</h1>
|
||||
|
||||
{/* Period Selector */}
|
||||
<PeriodSelector
|
||||
selectedPeriod={_selectedPeriod}
|
||||
onPrevPeriod={handlePrevPeriod}
|
||||
onNextPeriod={handleNextPeriod}
|
||||
/>
|
||||
<Suspense fallback={<ChartLoadingSpinner />}>
|
||||
<PeriodSelector
|
||||
selectedPeriod={_selectedPeriod}
|
||||
onPrevPeriod={handlePrevPeriod}
|
||||
onNextPeriod={handleNextPeriod}
|
||||
/>
|
||||
</Suspense>
|
||||
|
||||
{/* Summary Cards */}
|
||||
<SummaryCards
|
||||
totalBudget={totalBudget}
|
||||
totalExpense={totalExpense}
|
||||
savingsPercentage={savingsPercentage}
|
||||
/>
|
||||
<Suspense fallback={<ChartLoadingSpinner />}>
|
||||
<SummaryCards
|
||||
totalBudget={totalBudget}
|
||||
totalExpense={totalExpense}
|
||||
savingsPercentage={savingsPercentage}
|
||||
/>
|
||||
</Suspense>
|
||||
</header>
|
||||
|
||||
{/* Monthly Comparison Chart */}
|
||||
<div className="mb-8 w-full">
|
||||
<h2 className="text-lg font-semibold mb-3">월별 그래프</h2>
|
||||
<MonthlyComparisonChart
|
||||
monthlyData={monthlyData}
|
||||
isEmpty={totalBudget === 0 && totalExpense === 0}
|
||||
/>
|
||||
<Suspense fallback={<ChartLoadingSpinner />}>
|
||||
<MonthlyComparisonChart
|
||||
monthlyData={monthlyData}
|
||||
isEmpty={totalBudget === 0 && totalExpense === 0}
|
||||
/>
|
||||
</Suspense>
|
||||
</div>
|
||||
|
||||
{/* 카테고리 비율과 지출을 하나의 카드로 합침 */}
|
||||
@@ -173,14 +196,18 @@ const Analytics = () => {
|
||||
{expenseData.some((item) => item.value > 0) ? (
|
||||
<>
|
||||
<div className="h-72 flex items-center justify-center">
|
||||
<ExpenseChart data={expenseData} />
|
||||
<Suspense fallback={<ChartLoadingSpinner />}>
|
||||
<ExpenseChart data={expenseData} />
|
||||
</Suspense>
|
||||
</div>
|
||||
{/* 원그래프 아래에 카테고리 지출 목록 추가 */}
|
||||
<CategorySpendingList
|
||||
categories={categorySpending}
|
||||
totalExpense={totalExpense}
|
||||
showCard={false} // 카드 감싸지 않도록 설정
|
||||
/>
|
||||
<Suspense fallback={<ChartLoadingSpinner />}>
|
||||
<CategorySpendingList
|
||||
categories={categorySpending}
|
||||
totalExpense={totalExpense}
|
||||
showCard={false} // 카드 감싸지 않도록 설정
|
||||
/>
|
||||
</Suspense>
|
||||
</>
|
||||
) : (
|
||||
<div className="h-52 w-full flex items-center justify-center text-gray-400">
|
||||
@@ -192,16 +219,24 @@ const Analytics = () => {
|
||||
|
||||
{/* 결제 방법 차트 추가 */}
|
||||
<h2 className="text-lg font-semibold mb-3">결제 방법 비율</h2>
|
||||
<PaymentMethodChart
|
||||
data={paymentMethodData}
|
||||
isEmpty={!hasPaymentData}
|
||||
/>
|
||||
<Suspense fallback={<ChartLoadingSpinner />}>
|
||||
<PaymentMethodChart
|
||||
data={paymentMethodData}
|
||||
isEmpty={!hasPaymentData}
|
||||
/>
|
||||
</Suspense>
|
||||
|
||||
{/* 결제 방법 차트 아래 80px 여유 공간 추가 */}
|
||||
<div className="h-20"></div>
|
||||
</div>
|
||||
|
||||
<AddTransactionButton />
|
||||
<Suspense
|
||||
fallback={
|
||||
<div className="fixed bottom-20 right-4 w-14 h-14 rounded-full bg-gray-200 animate-pulse"></div>
|
||||
}
|
||||
>
|
||||
<AddTransactionButton />
|
||||
</Suspense>
|
||||
<NavBar />
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user