Skip to content

Commit 95895a4

Browse files
committed
Added tanstack devtools and fixed some error
1 parent 2133d84 commit 95895a4

8 files changed

Lines changed: 337 additions & 21 deletions

File tree

frontend/package-lock.json

Lines changed: 35 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
},
1616
"dependencies": {
1717
"@tanstack/react-query": "^5.80.6",
18+
"@tanstack/react-query-devtools": "^5.80.7",
1819
"react": "^19.1.0",
1920
"react-dom": "^19.1.0",
2021
"react-hook-form": "^7.57.0",

frontend/src/App.tsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1-
import './App.css';
1+
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
2+
import ComplexesPage from './pages/ComplexesPage';
3+
// import ComplexDetailPage from './pages/ComplexDetailPage'; // 将来的に
4+
// import ComplexFormPage from './pages/ComplexFormPage'; // 将来的に
25

36
function App() {
47
return (
5-
<>
6-
<div>
7-
<h1>Re:Fuel</h1>
8-
</div>
9-
</>
8+
<Router>
9+
<Routes>
10+
<Route path="/" element={<ComplexesPage />} />
11+
{/* 他のルートもここに追加 */}
12+
{/* <Route path="/complexes/new" element={<ComplexFormPage mode="create" />} /> */}
13+
{/* <Route path="/complexes/:id/edit" element={<ComplexFormPage mode="edit" />} /> */}
14+
{/* <Route path="/complexes/:id" element={<ComplexDetailPage />} /> */}
15+
</Routes>
16+
</Router>
1017
);
1118
}
1219

frontend/src/components/complexes/organisms/ComplexCard.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,14 @@ const ActionsWrapper = styled.div`
6969
margin-top: auto; /* Pushes actions to the bottom */
7070
`;
7171

72+
// TODO: Remove eslint-disable-next-line after refactoring
7273
interface ComplexCardProps {
7374
complex: Complex;
75+
// eslint-disable-next-line no-unused-vars
7476
onViewGoals: (id: number) => void;
77+
// eslint-disable-next-line no-unused-vars
7578
onEdit: (id: number) => void;
79+
// eslint-disable-next-line no-unused-vars
7680
onDelete: (id: number) => void;
7781
animationDelay: number;
7882
}

frontend/src/components/complexes/organisms/ComplexList.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@ const ListWrapper = styled.div`
1212

1313
interface ComplexListProps {
1414
complexes: Complex[];
15+
// eslint-disable-next-line no-unused-vars
1516
onViewGoals: (id: number) => void;
17+
// eslint-disable-next-line no-unused-vars
1618
onEdit: (id: number) => void;
19+
// eslint-disable-next-line no-unused-vars
1720
onDelete: (id: number) => void;
1821
onAddNewComplex: () => void; // For NoComplexesMessage
1922
}

frontend/src/main.tsx

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,33 @@
1-
import { StrictMode } from 'react';
2-
import { createRoot } from 'react-dom/client';
3-
import './index.css';
4-
import App from './App.tsx';
1+
import React from 'react';
2+
import ReactDOM from 'react-dom/client';
3+
import App from './App';
4+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
5+
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
6+
import { GlobalStyles } from './styles/GlobalStyles';
7+
import { ThemeProvider } from 'styled-components'; // 必要であれば
58

6-
createRoot(document.getElementById('root')!).render(
7-
<StrictMode>
8-
<App />
9-
</StrictMode>
9+
// React Query Client
10+
const queryClient = new QueryClient();
11+
12+
// Styled Componentsのテーマ (任意)
13+
const theme = {
14+
colors: {
15+
primary: '#007aff',
16+
background: '#f8f9fa',
17+
text: '#212529',
18+
},
19+
};
20+
21+
ReactDOM.createRoot(document.getElementById('root')!).render(
22+
<React.StrictMode>
23+
<QueryClientProvider client={queryClient}>
24+
<ThemeProvider theme={theme}>
25+
{' '}
26+
{/* ThemeProviderでテーマを適用 */}
27+
<GlobalStyles />
28+
<App />
29+
</ThemeProvider>
30+
<ReactQueryDevtools initialIsOpen={false} />
31+
</QueryClientProvider>
32+
</React.StrictMode>
1033
);
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
import React, { useState, useEffect } from 'react';
2+
import styled from 'styled-components';
3+
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
4+
import Header from '../components/common/molecules/Header';
5+
// import Footer from '../components/footer/Footer';
6+
import ComplexList from '../components/complexes/organisms/ComplexList';
7+
import type { Complex } from '../types/complex';
8+
// import { fetchComplexes, deleteComplex } from '../services/api'; // APIサービスを想定
9+
10+
const PageWrapper = styled.div`
11+
display: flex;
12+
flex-direction: column;
13+
min-height: 100vh;
14+
`;
15+
16+
const MainContent = styled.main`
17+
flex-grow: 1;
18+
max-width: 1200px;
19+
margin: 0 auto;
20+
padding: 2rem 1rem; /* 32px 16px */
21+
width: 100%;
22+
`;
23+
24+
const PageTitleWrapper = styled.div`
25+
margin-bottom: 2.5rem; /* 40px */
26+
text-align: center;
27+
`;
28+
29+
const PageTitle = styled.h2`
30+
font-size: 2.25rem; /* 36px */
31+
font-weight: 700;
32+
color: #1d1d1f;
33+
margin-bottom: 0.5rem; /* 8px */
34+
`;
35+
36+
const PageSubtitle = styled.p`
37+
font-size: 1.125rem; /* 18px */
38+
color: #58585b; /* Apple風のサブテキストカラー */
39+
max-width: 600px;
40+
margin: 0 auto;
41+
`;
42+
43+
// --- ダミーデータとダミーAPI関数 ---
44+
const dummyComplexesData: Complex[] = [
45+
{
46+
id: 1,
47+
user_id: 'user-test-123',
48+
content:
49+
'人前で話すのが極度に苦手で、声が震えてしまう。特に大人数の前だと頭が真っ白になる。',
50+
category: 'コミュニケーション',
51+
created_at: '2023-10-27T10:00:00Z',
52+
updated_at: '2023-10-26T10:00:00Z',
53+
},
54+
{
55+
id: 2,
56+
user_id: 'user-test-123',
57+
content:
58+
'計画を立てても三日坊主で終わってしまう。継続力がない自分に嫌気がさす。',
59+
category: '自己管理',
60+
created_at: '2023-10-26T14:30:00Z',
61+
updated_at: '2023-10-25T14:30:00Z',
62+
},
63+
{
64+
id: 3,
65+
user_id: 'user-test-123',
66+
content: '他人の評価を気にしすぎて、自分の意見をなかなか言い出せない。',
67+
category: '対人関係',
68+
created_at: '2023-10-25T09:15:00Z',
69+
updated_at: '2023-10-24T09:15:00Z',
70+
},
71+
];
72+
73+
// ダミーのAPIフェッチ関数 (TanStack Query用)
74+
const fetchComplexes = async (): Promise<Complex[]> => {
75+
console.log('Fetching complexes...');
76+
// APIエンドポイント: GET /api/v1/complexes
77+
// const response = await fetch('/api/v1/complexes', { headers: {'X-User-ID': 'test-user-uuid-12345'} });
78+
// if (!response.ok) throw new Error('Network response was not ok');
79+
// return response.json();
80+
return new Promise((resolve) =>
81+
// eslint-disable-next-line no-undef
82+
setTimeout(() => resolve(dummyComplexesData), 1000)
83+
);
84+
};
85+
86+
// ダミーの削除API関数
87+
const deleteComplexAPI = async (id: number): Promise<void> => {
88+
console.log(`Deleting complex with id: ${id}`);
89+
// APIエンドポイント: DELETE /api/v1/complexes/${id}
90+
// const response = await fetch(`/api/v1/complexes/${id}`, { method: 'DELETE', headers: {'X-User-ID': 'test-user-uuid-12345'} });
91+
// if (!response.ok) throw new Error('Failed to delete complex');
92+
return new Promise((resolve) =>
93+
// eslint-disable-next-line no-undef
94+
setTimeout(() => {
95+
const index = dummyComplexesData.findIndex((c) => c.id === id);
96+
if (index > -1) dummyComplexesData.splice(index, 1);
97+
resolve();
98+
}, 500)
99+
);
100+
};
101+
// --- ここまでダミー ---
102+
103+
const ComplexesPage: React.FC = () => {
104+
const queryClient = useQueryClient();
105+
106+
// TanStack Query を使用してデータをフェッチ
107+
const {
108+
data: complexes = [],
109+
isLoading,
110+
error,
111+
} = useQuery<Complex[], Error>({
112+
queryKey: ['complexes'],
113+
queryFn: fetchComplexes,
114+
// staleTime: 5 * 60 * 1000, // 5 minutes
115+
});
116+
117+
// 削除ミューテーション
118+
const deleteMutation = useMutation<void, Error, number>({
119+
mutationFn: deleteComplexAPI,
120+
onSuccess: () => {
121+
queryClient.invalidateQueries({ queryKey: ['complexes'] }); // キャッシュを無効化して再フェッチ
122+
// eslint-disable-next-line no-undef
123+
alert('コンプレックスを削除しました(ダミー)');
124+
},
125+
onError: (err) => {
126+
// eslint-disable-next-line no-undef
127+
alert(`削除に失敗しました: ${err.message}`);
128+
},
129+
});
130+
131+
const handleAddNewComplex = () => {
132+
console.log('新しいコンプレックスを登録');
133+
// TODO: React Routerを使用して登録ページへ遷移
134+
// eslint-disable-next-line no-undef
135+
alert('コンプレックス登録画面へ(未実装)');
136+
};
137+
138+
const handleViewGoals = (id: number) => {
139+
console.log(`目標を見る/設定: Complex ID ${id}`);
140+
// TODO: React Routerを使用して目標設定ページへ遷移
141+
// eslint-disable-next-line no-undef
142+
alert(`コンプレックスID ${id} の目標設定画面へ(未実装)`);
143+
};
144+
145+
const handleEditComplex = (id: number) => {
146+
console.log(`編集: Complex ID ${id}`);
147+
// TODO: React Routerを使用して編集ページへ遷移
148+
// eslint-disable-next-line no-undef
149+
alert(`コンプレックスID ${id} の編集画面へ(未実装)`);
150+
};
151+
152+
const handleDeleteComplex = (id: number) => {
153+
if (window.confirm(`コンプレックスID ${id} を本当に削除しますか?`)) {
154+
deleteMutation.mutate(id);
155+
}
156+
};
157+
158+
// ローディングとエラー表示のデモ
159+
const [showDummyData, setShowDummyData] = useState(false);
160+
useEffect(() => {
161+
// eslint-disable-next-line no-undef
162+
const timer = setTimeout(() => {
163+
setShowDummyData(true);
164+
// 0件表示のテストのため、初期は空配列を渡す
165+
if (complexes.length === 0 && !isLoading && !error) {
166+
// このデモでは、TanStack Queryがダミーデータをフェッチするので、
167+
// 0件表示はComplexListコンポーネントの初期状態に依存します。
168+
// 実際のAPI連携では、isLoadingとerrorの状態を見て適切に処理します。
169+
}
170+
}, 2000); // 2秒後にダミーデータを表示する(実際はTanStack Queryが管理)
171+
// eslint-disable-next-line no-undef
172+
return () => clearTimeout(timer);
173+
}, [isLoading, error, complexes]);
174+
175+
if (isLoading && !showDummyData)
176+
return (
177+
<PageWrapper>
178+
<MainContent>
179+
<PageTitle>読み込み中...</PageTitle>
180+
</MainContent>
181+
</PageWrapper>
182+
); // 初期ローディング
183+
if (error)
184+
return (
185+
<PageWrapper>
186+
<MainContent>
187+
<PageTitle>エラー: {error.message}</PageTitle>
188+
</MainContent>
189+
</PageWrapper>
190+
);
191+
192+
return (
193+
<PageWrapper>
194+
<Header onAddNewComplex={handleAddNewComplex} />
195+
<MainContent>
196+
<PageTitleWrapper>
197+
<PageTitle>あなたのコンプレックス</PageTitle>
198+
<PageSubtitle>
199+
ここでは、あなたが登録したコンプレックスを確認し、それらを成長の糧に変えるための第一歩を踏み出せます。
200+
</PageSubtitle>
201+
</PageTitleWrapper>
202+
<ComplexList
203+
complexes={showDummyData ? complexes : []} // デモ用: TanStack Queryがデータを管理
204+
onViewGoals={handleViewGoals}
205+
onEdit={handleEditComplex}
206+
onDelete={handleDeleteComplex}
207+
onAddNewComplex={handleAddNewComplex}
208+
/>
209+
</MainContent>
210+
{/* <Footer /> */} {/* フッターは必要に応じて追加 */}
211+
</PageWrapper>
212+
);
213+
};
214+
215+
export default ComplexesPage;

0 commit comments

Comments
 (0)