fromis_9/frontend-temp/src/App.jsx

147 lines
5.4 KiB
React
Raw Normal View History

import { useState } from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { isMobile } from "react-device-detect";
import { useQuery } from "@tanstack/react-query";
import { cn, getTodayKST, formatFullDate } from "@/utils";
import { useAuthStore, useUIStore } from "@/stores";
import { memberApi, scheduleApi } from "@/api";
/**
* 프로미스나인 팬사이트 메인
*
* Phase 4: API 계층 완료
* - api/client.js: 기본 fetch 클라이언트 (공개/인증)
* - api/schedules.js: 스케줄 API
* - api/albums.js: 앨범 API
* - api/members.js: 멤버 API
* - api/auth.js: 인증 API
*/
function App() {
const today = getTodayKST();
const { isAuthenticated } = useAuthStore();
const { showSuccess, showError, toasts } = useUIStore();
const [apiTest, setApiTest] = useState(null);
// React Query로 멤버 데이터 조회
const { data: members, isLoading: membersLoading } = useQuery({
queryKey: ["members"],
queryFn: memberApi.getMembers,
});
// React Query로 카테고리 데이터 조회
const { data: categories, isLoading: categoriesLoading } = useQuery({
queryKey: ["categories"],
queryFn: scheduleApi.getCategories,
});
const handleTestApi = async () => {
try {
const data = await memberApi.getMembers();
setApiTest(`멤버 ${data.length}명 조회 성공!`);
showSuccess("API 호출 성공!");
} catch (error) {
setApiTest(`에러: ${error.message}`);
showError("API 호출 실패");
}
};
return (
<BrowserRouter>
<Routes>
<Route
path="/"
element={
<div className="min-h-screen flex items-center justify-center bg-gray-50 p-4">
<div className="text-center space-y-4 max-w-md w-full">
<h1 className="text-2xl font-bold text-primary mb-2">
fromis_9 Frontend Refactoring
</h1>
<p className="text-gray-600">Phase 4 완료 - API 계층</p>
<p className={cn("text-sm", isMobile ? "text-blue-500" : "text-green-500")}>
디바이스: {isMobile ? "모바일" : "PC"}
</p>
<div className="mt-6 p-4 bg-white rounded-lg shadow text-left text-sm space-y-3">
<p><strong>오늘:</strong> {formatFullDate(today)}</p>
<p><strong>인증:</strong> {isAuthenticated ? "✅" : "❌"}</p>
<div className="border-t pt-3">
<p className="font-semibold mb-2">API 테스트 (React Query)</p>
<div className="space-y-2">
<p>
<strong>멤버:</strong>{" "}
{membersLoading ? "로딩 중..." : `${members?.length || 0}`}
</p>
{members && (
<div className="flex flex-wrap gap-1">
{members.map((m) => (
<span key={m.id} className="px-2 py-0.5 bg-gray-100 rounded text-xs">
{m.name}
</span>
))}
</div>
)}
</div>
<div className="space-y-2 mt-3">
<p>
<strong>카테고리:</strong>{" "}
{categoriesLoading ? "로딩 중..." : `${categories?.length || 0}`}
</p>
{categories && (
<div className="flex flex-wrap gap-1">
{categories.map((c) => (
<span
key={c.id}
className="px-2 py-0.5 rounded text-xs text-white"
style={{ backgroundColor: c.color }}
>
{c.name}
</span>
))}
</div>
)}
</div>
</div>
<div className="border-t pt-3">
<p className="font-semibold mb-2">직접 API 호출 테스트</p>
<button
onClick={handleTestApi}
className="px-3 py-1 bg-primary text-white rounded text-xs"
>
멤버 API 호출
</button>
{apiTest && <p className="mt-2 text-xs text-gray-600">{apiTest}</p>}
</div>
</div>
</div>
{/* 토스트 표시 */}
<div className="fixed bottom-4 right-4 space-y-2">
{toasts.map((toast) => (
<div
key={toast.id}
className={cn(
"px-4 py-2 rounded shadow-lg text-white text-sm",
toast.type === "success" && "bg-green-500",
toast.type === "error" && "bg-red-500",
toast.type === "warning" && "bg-yellow-500",
toast.type === "info" && "bg-blue-500"
)}
>
{toast.message}
</div>
))}
</div>
</div>
}
/>
</Routes>
</BrowserRouter>
);
}
export default App;