diff --git a/backend/controllers/subscriptionController.js b/backend/controllers/subscriptionController.js index 826550d..277c62f 100644 --- a/backend/controllers/subscriptionController.js +++ b/backend/controllers/subscriptionController.js @@ -216,6 +216,61 @@ exports.getClubSubscription = async (req, res) => { } }; +// 클럽의 현재 구독 정보 반환 +exports.getCurrentSubscription = async (req, res) => { + const { clubId } = req.body; + if (!clubId) { + return res.status(400).json({ message: '클럽 ID가 필요합니다.' }); + } + try { + const subscription = await ClubSubscription.findOne({ + where: { clubId, status: 'active' }, + include: [{ + model: SubscriptionPlan, + include: [{ model: Feature, through: { attributes: ['status'] } }] + }] + }); + if (!subscription) { + return res.status(404).json({ message: '활성화된 구독 정보가 없습니다.' }); + } + res.json({ + planName: subscription.SubscriptionPlan.name, + planId: subscription.SubscriptionPlan.id, + status: subscription.status, + startDate: subscription.startDate, + endDate: subscription.expiryDate + }); + } catch (error) { + console.error('Error in getCurrentSubscription:', error); + res.status(500).json({ message: '구독 정보 조회 중 오류가 발생했습니다.' }); + } +}; + +// 클럽의 구독 결제 내역 반환 +exports.getSubscriptionPayments = async (req, res) => { + const { clubId } = req.body; + if (!clubId) { + return res.status(400).json({ message: '클럽 ID가 필요합니다.' }); + } + try { + const payments = await ClubSubscription.findAll({ + where: { clubId }, + include: [{ model: SubscriptionPlan }], + order: [['createdAt', 'DESC']] + }); + res.json(payments.map(payment => ({ + id: payment.id, + paymentDate: payment.createdAt, + planName: payment.SubscriptionPlan?.name || '', + amount: payment.SubscriptionPlan?.price || 0, + status: payment.status + }))); + } catch (error) { + console.error('Error in getSubscriptionPayments:', error); + res.status(500).json({ message: '결제 내역 조회 중 오류가 발생했습니다.' }); + } +}; + // 플랜별 구독 목록 조회 exports.getPlanSubscriptions = async (req, res) => { try { diff --git a/backend/routes/featureRoutes.js b/backend/routes/featureRoutes.js index 9d49c94..2f5ab7d 100644 --- a/backend/routes/featureRoutes.js +++ b/backend/routes/featureRoutes.js @@ -7,9 +7,9 @@ const { authenticateJWT } = require('../middleware/authMiddleware'); router.get('/', authenticateJWT, featureController.getFeatures); // 기능 구매 관련 API -router.get('/available', authenticateJWT, featureController.getAvailableFeatures); -router.get('/active', authenticateJWT, featureController.getActiveFeatures); -router.get('/payments', authenticateJWT, featureController.getFeaturePayments); +router.post('/available', authenticateJWT, featureController.getAvailableFeatures); +router.post('/active', authenticateJWT, featureController.getActiveFeatures); +router.post('/payments', authenticateJWT, featureController.getFeaturePayments); router.post('/purchase', authenticateJWT, featureController.purchaseFeature); module.exports = router; diff --git a/backend/routes/subscriptionRoutes.js b/backend/routes/subscriptionRoutes.js index 835cc27..8fe9e5f 100644 --- a/backend/routes/subscriptionRoutes.js +++ b/backend/routes/subscriptionRoutes.js @@ -16,4 +16,8 @@ router.get('/plans/:planId/subscriptions', authMiddleware, subscriptionControlle router.post('/subscribe', authMiddleware, subscriptionController.subscribeClub); router.get('/clubs/:clubId', authMiddleware, subscriptionController.getClubSubscription); +// 클럽 구독 정보 및 결제 내역 (POST, 클럽 기준) +router.post('/current', authMiddleware, subscriptionController.getCurrentSubscription); +router.post('/payments', authMiddleware, subscriptionController.getSubscriptionPayments); + module.exports = router; \ No newline at end of file diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js index 732e9f9..018f35d 100644 --- a/frontend/src/router/index.js +++ b/frontend/src/router/index.js @@ -112,7 +112,7 @@ const routes = [ component: ClubSubscriptionManagement, meta: { requiresAuth: true, - requiredRoles: ['모임장', '운영진'] + requiredRoles: ['admin', '모임장', '운영진'] } } ] @@ -169,7 +169,7 @@ router.beforeEach(async (to, from, next) => { } // 클럽 구독 관리 페이지에 접근하려는 경우, 권한 확인 - if (to.name === 'ClubSubscription' && (userClubRole !== '모임장' && userClubRole !== '운영진')) { + if (to.name === 'ClubSubscription' && (userClubRole !== 'admin' && userClubRole !== '모임장' && userClubRole !== '운영진')) { next({ name: 'ClubDashboard' }); return; } diff --git a/frontend/src/services/api.js b/frontend/src/services/api.js index 331675f..fcedce1 100644 --- a/frontend/src/services/api.js +++ b/frontend/src/services/api.js @@ -1,7 +1,8 @@ import axios from 'axios'; // 환경 변수에서 API URL을 가져오거나 기본값 사용 -const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3030'; +// const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3030'; +const API_URL = ''; // axios 인스턴스 생성 const apiClient = axios.create({ diff --git a/frontend/src/views/club/subscription/SubscriptionManagement.vue b/frontend/src/views/club/subscription/SubscriptionManagement.vue index cda8bbc..239c4d7 100644 --- a/frontend/src/views/club/subscription/SubscriptionManagement.vue +++ b/frontend/src/views/club/subscription/SubscriptionManagement.vue @@ -126,6 +126,8 @@ import { useRouter } from 'vue-router'; import apiClient from '@/services/api'; const router = useRouter(); +// 전역 clubId +const clubId = ref(localStorage.getItem('clubId')); const currentSubscription = ref(null); const plans = ref([]); const payments = ref([]); @@ -158,7 +160,7 @@ const isFeatureActive = (featureId) => { // 현재 구독 정보 로드 const loadCurrentSubscription = async () => { try { - const response = await apiClient.get('/api/subscriptions/current'); + const response = await apiClient.post('/api/subscriptions/current', { clubId: clubId.value }); currentSubscription.value = response.data; } catch (error) { console.error('구독 정보 로드 실패:', error); @@ -178,7 +180,7 @@ const loadPlans = async () => { // 결제 내역 로드 const loadPayments = async () => { try { - const response = await apiClient.get('/api/subscriptions/payments'); + const response = await apiClient.post('/api/subscriptions/payments', { clubId: clubId.value }); payments.value = response.data; } catch (error) { console.error('결제 내역 로드 실패:', error); @@ -188,7 +190,7 @@ const loadPayments = async () => { // 사용 가능한 기능 목록 로드 const loadAvailableFeatures = async () => { try { - const response = await apiClient.get('/api/features/available'); + const response = await apiClient.post('/api/features/available', { clubId: clubId.value }); availableFeatures.value = response.data.map(feature => ({ ...feature, selectedDuration: 1 @@ -201,7 +203,7 @@ const loadAvailableFeatures = async () => { // 활성화된 기능 목록 로드 const loadActiveFeatures = async () => { try { - const response = await apiClient.get('/api/features/active'); + const response = await apiClient.post('/api/features/active', { clubId: clubId.value }); activeFeatures.value = response.data; } catch (error) { console.error('활성화된 기능 로드 실패:', error); @@ -211,7 +213,7 @@ const loadActiveFeatures = async () => { // 기능 구매 내역 로드 const loadFeaturePayments = async () => { try { - const response = await apiClient.get('/api/features/payments'); + const response = await apiClient.post('/api/features/payments', { clubId: clubId.value }); featurePayments.value = response.data; } catch (error) { console.error('기능 구매 내역 로드 실패:', error);