release
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
// src/pages/LoginPage.js
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Box, Typography, Paper } from '@mui/material';
|
||||
import { useAuth } from '../contexts/AuthContext';
|
||||
import LoginForm from '../components/auth/LoginForm';
|
||||
|
||||
const LoginPage = () => {
|
||||
const navigate = useNavigate();
|
||||
const { currentUser, login } = useAuth();
|
||||
const [error, setError] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
if (currentUser) {
|
||||
navigate('/');
|
||||
}
|
||||
}, [currentUser, navigate]);
|
||||
|
||||
const handleLogin = async (userId, password) => {
|
||||
try {
|
||||
setError('');
|
||||
const success = await login(userId, password);
|
||||
if (success) {
|
||||
navigate('/');
|
||||
} else {
|
||||
setError('아이디 또는 비밀번호가 올바르지 않습니다.');
|
||||
}
|
||||
} catch (err) {
|
||||
setError('로그인 중 오류가 발생했습니다. 다시 시도해주세요.');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
minHeight: '100vh',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
p: 2
|
||||
}}
|
||||
>
|
||||
<Paper
|
||||
elevation={3}
|
||||
sx={{
|
||||
width: '100%',
|
||||
maxWidth: 400,
|
||||
p: 4,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center'
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
component="h1"
|
||||
variant="h4"
|
||||
gutterBottom
|
||||
sx={{ mb: 4 }}
|
||||
>
|
||||
마이구독
|
||||
</Typography>
|
||||
|
||||
<LoginForm
|
||||
onSubmit={handleLogin}
|
||||
error={error}
|
||||
/>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginPage;
|
||||
@@ -0,0 +1,73 @@
|
||||
// src/pages/MainPage.js
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Box } from '@mui/material';
|
||||
import { useAuth } from '../contexts/AuthContext';
|
||||
import TotalFee from '../components/main/TotalFee';
|
||||
import MySubscriptions from '../components/main/MySubscriptions';
|
||||
import RecommendCategory from '../components/main/RecommendCategory';
|
||||
import LoadingSpinner from '../components/common/LoadingSpinner';
|
||||
import ErrorMessage from '../components/common/ErrorMessage';
|
||||
import { mySubscriptionApi, recommendApi, handleApiResponse } from '../services/api';
|
||||
|
||||
const MainPage = () => {
|
||||
const navigate = useNavigate();
|
||||
const { currentUser, authInitialized } = useAuth();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
const [totalFee, setTotalFee] = useState(null);
|
||||
const [subscriptions, setSubscriptions] = useState([]);
|
||||
const [recommendedCategory, setRecommendedCategory] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
// 로그인 체크
|
||||
if (authInitialized && !currentUser) { // loading 상태 체크 추가
|
||||
navigate('/login');
|
||||
return;
|
||||
}
|
||||
|
||||
if(authInitialized) {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
const [totalFeeResponse, subscriptionsResponse, recommendResponse] = await Promise.all([
|
||||
mySubscriptionApi.getTotalFee(currentUser.userId),
|
||||
mySubscriptionApi.getMySubscriptions(currentUser.userId),
|
||||
recommendApi.getRecommendedCategory(currentUser.userId)
|
||||
]);
|
||||
|
||||
setTotalFee(handleApiResponse(totalFeeResponse));
|
||||
setSubscriptions(handleApiResponse(subscriptionsResponse));
|
||||
setRecommendedCategory(handleApiResponse(recommendResponse));
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchData();
|
||||
}
|
||||
|
||||
}, [currentUser, navigate, authInitialized]);
|
||||
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <ErrorMessage message={error} />;
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<TotalFee
|
||||
totalFee={totalFee?.totalFee}
|
||||
feeLevel={totalFee?.feeLevel}
|
||||
/>
|
||||
<MySubscriptions subscriptions={subscriptions} />
|
||||
{recommendedCategory && (
|
||||
<RecommendCategory {...recommendedCategory} />
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default MainPage;
|
||||
@@ -0,0 +1,87 @@
|
||||
// src/pages/SubscriptionDetailPage.js
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { useAuth } from '../contexts/AuthContext';
|
||||
import SubscriptionDetail from '../components/subscriptions/SubscriptionDetail';
|
||||
import LoadingSpinner from '../components/common/LoadingSpinner';
|
||||
import ErrorMessage from '../components/common/ErrorMessage';
|
||||
import { mySubscriptionApi, handleApiResponse } from '../services/api';
|
||||
|
||||
const SubscriptionDetailPage = () => {
|
||||
const { id } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const { currentUser, authInitialized } = useAuth();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
const [subscription, setSubscription] = useState(null);
|
||||
const [isSubscribed, setIsSubscribed] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (authInitialized && !currentUser) { // login여부가 완료되고 현재 유저 정보가 없을때 로그인 페이지로 보냄
|
||||
navigate('/login');
|
||||
return;
|
||||
}
|
||||
|
||||
if(authInitialized) {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
// 구독 상세 정보와 사용자의 구독 목록을 동시에 조회
|
||||
const [detailResponse, mySubsResponse] = await Promise.all([
|
||||
mySubscriptionApi.getSubscriptionDetail(id),
|
||||
mySubscriptionApi.getMySubscriptions(currentUser.userId)
|
||||
]);
|
||||
|
||||
const detailData = handleApiResponse(detailResponse);
|
||||
const mySubsData = handleApiResponse(mySubsResponse);
|
||||
|
||||
setSubscription(detailData);
|
||||
|
||||
// 현재 서비스가 사용자의 구독 목록에 있는지 확인
|
||||
setIsSubscribed(mySubsData.some(sub => sub.id === parseInt(id)));
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchData();
|
||||
}
|
||||
}, [currentUser, navigate, id, authInitialized]);
|
||||
|
||||
const handleSubscribe = async () => {
|
||||
try {
|
||||
await mySubscriptionApi.subscribe(id, currentUser.userId);
|
||||
navigate('/');
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancel = async () => {
|
||||
try {
|
||||
await mySubscriptionApi.cancelSubscription(id);
|
||||
navigate('/');
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <ErrorMessage message={error} />;
|
||||
if (!subscription) return <ErrorMessage message="구독 서비스를 찾을 수 없습니다." />;
|
||||
|
||||
return (
|
||||
<SubscriptionDetail
|
||||
{...subscription}
|
||||
isSubscribed={isSubscribed}
|
||||
onSubscribe={handleSubscribe}
|
||||
onCancel={handleCancel}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default SubscriptionDetailPage;
|
||||
@@ -0,0 +1,94 @@
|
||||
// src/pages/SubscriptionListPage.js
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import { useAuth } from '../contexts/AuthContext';
|
||||
import { Box } from '@mui/material';
|
||||
import CategoryList from '../components/subscriptions/CategoryList';
|
||||
import SubscriptionList from '../components/subscriptions/SubscriptionList';
|
||||
import LoadingSpinner from '../components/common/LoadingSpinner';
|
||||
import ErrorMessage from '../components/common/ErrorMessage';
|
||||
import { mySubscriptionApi, handleApiResponse } from '../services/api';
|
||||
|
||||
const SubscriptionListPage = () => {
|
||||
const navigate = useNavigate();
|
||||
const { currentUser, authInitialized } = useAuth();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
const [categories, setCategories] = useState([]);
|
||||
const [services, setServices] = useState([]);
|
||||
const selectedCategory = searchParams.get('category') || '';
|
||||
|
||||
useEffect(() => {
|
||||
if (authInitialized && !currentUser) { // login여부가 완료되고 현재 유저 정보가 없을때 로그인 페이지로 보냄
|
||||
navigate('/login');
|
||||
return;
|
||||
}
|
||||
|
||||
if(authInitialized) {
|
||||
const fetchCategories = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
const response = await mySubscriptionApi.getCategories();
|
||||
const categoryList = handleApiResponse(response);
|
||||
setCategories(categoryList);
|
||||
|
||||
// 선택된 카테고리가 없으면 첫 번째 카테고리 선택
|
||||
if (!selectedCategory && categoryList.length > 0) {
|
||||
setSearchParams({ category: categoryList[0].categoryId });
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchCategories();
|
||||
}
|
||||
|
||||
}, [currentUser, navigate, selectedCategory, setSearchParams, authInitialized]);
|
||||
|
||||
useEffect(() => {
|
||||
if(authInitialized) {
|
||||
const fetchServices = async () => {
|
||||
if (!selectedCategory) return;
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
const response = await mySubscriptionApi.getServicesByCategory(selectedCategory);
|
||||
setServices(handleApiResponse(response));
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchServices();
|
||||
}
|
||||
|
||||
}, [selectedCategory, authInitialized]);
|
||||
|
||||
const handleCategoryChange = (categoryId) => {
|
||||
setSearchParams({ category: categoryId });
|
||||
};
|
||||
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <ErrorMessage message={error} />;
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<CategoryList
|
||||
categories={categories}
|
||||
selectedCategory={selectedCategory}
|
||||
onCategoryChange={handleCategoryChange}
|
||||
/>
|
||||
<SubscriptionList services={services} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default SubscriptionListPage;
|
||||
Reference in New Issue
Block a user