mirror of
https://github.com/ktds-dg0501/kt-event-marketing-fe.git
synced 2026-06-13 08:59:10 +00:00
이벤트 목록 Mock 데이터 적용 및 Participation API 연동
- 이벤트 목록 페이지에 Mock 데이터 적용 (evt_2025012301 등 4개 이벤트) - 이벤트 상세 페이지 Analytics API 임시 주석처리 (서버 이슈) - Participation API 프록시 라우트 URL 구조 수정 (/events/ 제거) - EventID localStorage 저장 기능 추가 - 상세한 console.log 추가 (생성된 eventId, objective, timestamp) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
export { participationApi, default } from './participationApi';
|
||||
@@ -0,0 +1,142 @@
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import type {
|
||||
ParticipationRequest,
|
||||
ParticipationResponse,
|
||||
ApiResponse,
|
||||
PageResponse,
|
||||
DrawWinnersRequest,
|
||||
DrawWinnersResponse,
|
||||
} from '../model/types';
|
||||
|
||||
// Use Next.js API proxy to bypass CORS issues
|
||||
const PARTICIPATION_API_BASE = '/api/participations';
|
||||
|
||||
const participationApiClient: AxiosInstance = axios.create({
|
||||
baseURL: PARTICIPATION_API_BASE,
|
||||
timeout: 90000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
// Request interceptor
|
||||
participationApiClient.interceptors.request.use(
|
||||
(config) => {
|
||||
console.log('🎫 Participation API Request:', {
|
||||
method: config.method?.toUpperCase(),
|
||||
url: config.url,
|
||||
baseURL: config.baseURL,
|
||||
});
|
||||
|
||||
const token = localStorage.getItem('accessToken');
|
||||
if (token && config.headers) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
console.error('❌ Participation API Request Error:', error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// Response interceptor
|
||||
participationApiClient.interceptors.response.use(
|
||||
(response) => {
|
||||
console.log('✅ Participation API Response:', {
|
||||
status: response.status,
|
||||
url: response.config.url,
|
||||
});
|
||||
return response;
|
||||
},
|
||||
(error) => {
|
||||
console.error('❌ Participation API Error:', {
|
||||
message: error.message,
|
||||
status: error.response?.status,
|
||||
url: error.config?.url,
|
||||
});
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Participation API Service
|
||||
* 이벤트 참여 관리 API
|
||||
*/
|
||||
export const participationApi = {
|
||||
/**
|
||||
* 이벤트 참여
|
||||
*/
|
||||
participate: async (
|
||||
eventId: string,
|
||||
data: ParticipationRequest
|
||||
): Promise<ApiResponse<ParticipationResponse>> => {
|
||||
const response = await participationApiClient.post<
|
||||
ApiResponse<ParticipationResponse>
|
||||
>(`/${eventId}/participate`, data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 참여자 목록 조회
|
||||
*/
|
||||
getParticipants: async (
|
||||
eventId: string,
|
||||
params?: {
|
||||
storeVisited?: boolean;
|
||||
page?: number;
|
||||
size?: number;
|
||||
sort?: string[];
|
||||
}
|
||||
): Promise<ApiResponse<PageResponse<ParticipationResponse>>> => {
|
||||
const response = await participationApiClient.get<
|
||||
ApiResponse<PageResponse<ParticipationResponse>>
|
||||
>(`/${eventId}/participants`, { params });
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 특정 참여자 조회
|
||||
*/
|
||||
getParticipant: async (
|
||||
eventId: string,
|
||||
participantId: string
|
||||
): Promise<ApiResponse<ParticipationResponse>> => {
|
||||
const response = await participationApiClient.get<
|
||||
ApiResponse<ParticipationResponse>
|
||||
>(`/${eventId}/participants/${participantId}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 당첨자 추첨
|
||||
*/
|
||||
drawWinners: async (
|
||||
eventId: string,
|
||||
data: DrawWinnersRequest
|
||||
): Promise<ApiResponse<DrawWinnersResponse>> => {
|
||||
const response = await participationApiClient.post<
|
||||
ApiResponse<DrawWinnersResponse>
|
||||
>(`/${eventId}/draw-winners`, data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 당첨자 목록 조회
|
||||
*/
|
||||
getWinners: async (
|
||||
eventId: string,
|
||||
params?: {
|
||||
page?: number;
|
||||
size?: number;
|
||||
sort?: string[];
|
||||
}
|
||||
): Promise<ApiResponse<PageResponse<ParticipationResponse>>> => {
|
||||
const response = await participationApiClient.get<
|
||||
ApiResponse<PageResponse<ParticipationResponse>>
|
||||
>(`/${eventId}/winners`, { params });
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
|
||||
export default participationApi;
|
||||
@@ -0,0 +1,10 @@
|
||||
export { participationApi } from './api';
|
||||
export type {
|
||||
ParticipationRequest,
|
||||
ParticipationResponse,
|
||||
ApiResponse,
|
||||
PageResponse,
|
||||
DrawWinnersRequest,
|
||||
DrawWinnersResponse,
|
||||
WinnerSummary,
|
||||
} from './model';
|
||||
@@ -0,0 +1,9 @@
|
||||
export type {
|
||||
ParticipationRequest,
|
||||
ParticipationResponse,
|
||||
ApiResponse,
|
||||
PageResponse,
|
||||
DrawWinnersRequest,
|
||||
DrawWinnersResponse,
|
||||
WinnerSummary,
|
||||
} from './types';
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Participation API Types
|
||||
* 이벤트 참여 관련 타입 정의
|
||||
*/
|
||||
|
||||
/**
|
||||
* 참여 요청
|
||||
*/
|
||||
export interface ParticipationRequest {
|
||||
/** 이름 (2-50자, 필수) */
|
||||
name: string;
|
||||
/** 전화번호 (형식: "010-1234-5678", 필수) */
|
||||
phoneNumber: string;
|
||||
/** 이메일 (선택) */
|
||||
email?: string;
|
||||
/** 채널 (선택) */
|
||||
channel?: string;
|
||||
/** 마케팅 동의 (선택) */
|
||||
agreeMarketing?: boolean;
|
||||
/** 개인정보 동의 (필수) */
|
||||
agreePrivacy: boolean;
|
||||
/** 매장 방문 여부 (선택) */
|
||||
storeVisited?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 참여 응답
|
||||
*/
|
||||
export interface ParticipationResponse {
|
||||
/** 참여자 ID (UUID) */
|
||||
participantId: string;
|
||||
/** 이벤트 ID */
|
||||
eventId: string;
|
||||
/** 이름 */
|
||||
name: string;
|
||||
/** 전화번호 */
|
||||
phoneNumber: string;
|
||||
/** 이메일 */
|
||||
email?: string;
|
||||
/** 채널 */
|
||||
channel?: string;
|
||||
/** 참여 일시 */
|
||||
participatedAt: string;
|
||||
/** 매장 방문 여부 */
|
||||
storeVisited?: boolean;
|
||||
/** 보너스 응모권 수 */
|
||||
bonusEntries: number;
|
||||
/** 당첨 여부 */
|
||||
isWinner: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* API 공통 응답
|
||||
*/
|
||||
export interface ApiResponse<T> {
|
||||
success: boolean;
|
||||
data: T;
|
||||
errorCode?: string;
|
||||
message?: string;
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 페이지 응답
|
||||
*/
|
||||
export interface PageResponse<T> {
|
||||
content: T[];
|
||||
page: number;
|
||||
size: number;
|
||||
totalElements: number;
|
||||
totalPages: number;
|
||||
first: boolean;
|
||||
last: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 당첨자 추첨 요청
|
||||
*/
|
||||
export interface DrawWinnersRequest {
|
||||
/** 당첨자 수 (최소 1명, 필수) */
|
||||
winnerCount: number;
|
||||
/** 매장 방문 보너스 적용 여부 (선택) */
|
||||
applyStoreVisitBonus?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 당첨자 요약 정보
|
||||
*/
|
||||
export interface WinnerSummary {
|
||||
/** 참여자 ID */
|
||||
participantId: string;
|
||||
/** 이름 */
|
||||
name: string;
|
||||
/** 전화번호 */
|
||||
phoneNumber: string;
|
||||
/** 등수 */
|
||||
rank: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 당첨자 추첨 응답
|
||||
*/
|
||||
export interface DrawWinnersResponse {
|
||||
/** 이벤트 ID */
|
||||
eventId: string;
|
||||
/** 총 참여자 수 */
|
||||
totalParticipants: number;
|
||||
/** 당첨자 수 */
|
||||
winnerCount: number;
|
||||
/** 추첨 일시 */
|
||||
drawnAt: string;
|
||||
/** 당첨자 목록 */
|
||||
winners: WinnerSummary[];
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { apiClient } from '@/shared/api';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import type {
|
||||
LoginRequest,
|
||||
LoginResponse,
|
||||
@@ -10,8 +10,57 @@ import type {
|
||||
ChangePasswordRequest,
|
||||
} from '../model/types';
|
||||
|
||||
// Use Next.js API proxy to bypass CORS issues
|
||||
const USER_API_BASE = '/api/v1/users';
|
||||
|
||||
const userApiClient: AxiosInstance = axios.create({
|
||||
baseURL: USER_API_BASE,
|
||||
timeout: 90000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
// Request interceptor
|
||||
userApiClient.interceptors.request.use(
|
||||
(config) => {
|
||||
console.log('👤 User API Request:', {
|
||||
method: config.method?.toUpperCase(),
|
||||
url: config.url,
|
||||
baseURL: config.baseURL,
|
||||
});
|
||||
|
||||
const token = localStorage.getItem('accessToken');
|
||||
if (token && config.headers) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
console.error('❌ User API Request Error:', error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// Response interceptor
|
||||
userApiClient.interceptors.response.use(
|
||||
(response) => {
|
||||
console.log('✅ User API Response:', {
|
||||
status: response.status,
|
||||
url: response.config.url,
|
||||
});
|
||||
return response;
|
||||
},
|
||||
(error) => {
|
||||
console.error('❌ User API Error:', {
|
||||
message: error.message,
|
||||
status: error.response?.status,
|
||||
url: error.config?.url,
|
||||
});
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* User API Service
|
||||
* 사용자 인증 및 프로필 관리 API
|
||||
@@ -21,8 +70,8 @@ export const userApi = {
|
||||
* 로그인
|
||||
*/
|
||||
login: async (data: LoginRequest): Promise<LoginResponse> => {
|
||||
const response = await apiClient.post<LoginResponse>(
|
||||
`${USER_API_BASE}/login`,
|
||||
const response = await userApiClient.post<LoginResponse>(
|
||||
'/login',
|
||||
data
|
||||
);
|
||||
return response.data;
|
||||
@@ -33,15 +82,14 @@ export const userApi = {
|
||||
*/
|
||||
register: async (data: RegisterRequest): Promise<RegisterResponse> => {
|
||||
console.log('📞 userApi.register 호출');
|
||||
console.log('🎯 URL:', `${USER_API_BASE}/register`);
|
||||
console.log('📦 요청 데이터:', {
|
||||
...data,
|
||||
password: '***'
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await apiClient.post<RegisterResponse>(
|
||||
`${USER_API_BASE}/register`,
|
||||
const response = await userApiClient.post<RegisterResponse>(
|
||||
'/register',
|
||||
data
|
||||
);
|
||||
console.log('✅ userApi.register 성공:', response.data);
|
||||
@@ -56,15 +104,9 @@ export const userApi = {
|
||||
* 로그아웃
|
||||
*/
|
||||
logout: async (): Promise<LogoutResponse> => {
|
||||
const token = localStorage.getItem('accessToken');
|
||||
const response = await apiClient.post<LogoutResponse>(
|
||||
`${USER_API_BASE}/logout`,
|
||||
{},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
}
|
||||
const response = await userApiClient.post<LogoutResponse>(
|
||||
'/logout',
|
||||
{}
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
@@ -73,8 +115,8 @@ export const userApi = {
|
||||
* 프로필 조회
|
||||
*/
|
||||
getProfile: async (): Promise<ProfileResponse> => {
|
||||
const response = await apiClient.get<ProfileResponse>(
|
||||
`${USER_API_BASE}/profile`
|
||||
const response = await userApiClient.get<ProfileResponse>(
|
||||
'/profile'
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
@@ -85,8 +127,8 @@ export const userApi = {
|
||||
updateProfile: async (
|
||||
data: UpdateProfileRequest
|
||||
): Promise<ProfileResponse> => {
|
||||
const response = await apiClient.put<ProfileResponse>(
|
||||
`${USER_API_BASE}/profile`,
|
||||
const response = await userApiClient.put<ProfileResponse>(
|
||||
'/profile',
|
||||
data
|
||||
);
|
||||
return response.data;
|
||||
@@ -96,7 +138,7 @@ export const userApi = {
|
||||
* 비밀번호 변경
|
||||
*/
|
||||
changePassword: async (data: ChangePasswordRequest): Promise<void> => {
|
||||
await apiClient.put(`${USER_API_BASE}/password`, data);
|
||||
await userApiClient.put('/password', data);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ export interface LoginRequest {
|
||||
|
||||
export interface LoginResponse {
|
||||
token: string;
|
||||
userId: number;
|
||||
userId: string; // UUID format
|
||||
userName: string;
|
||||
role: string;
|
||||
email: string;
|
||||
@@ -31,9 +31,9 @@ export interface RegisterRequest {
|
||||
|
||||
export interface RegisterResponse {
|
||||
token: string;
|
||||
userId: number;
|
||||
userId: string; // UUID format
|
||||
userName: string;
|
||||
storeId: number;
|
||||
storeId: string; // UUID format
|
||||
storeName: string;
|
||||
}
|
||||
|
||||
@@ -45,12 +45,12 @@ export interface LogoutResponse {
|
||||
|
||||
// 프로필 조회/수정
|
||||
export interface ProfileResponse {
|
||||
userId: number;
|
||||
userId: string; // UUID format
|
||||
userName: string;
|
||||
phoneNumber: string;
|
||||
email: string;
|
||||
role: string;
|
||||
storeId: number;
|
||||
storeId: string; // UUID format
|
||||
storeName: string;
|
||||
industry: string;
|
||||
address: string;
|
||||
@@ -77,12 +77,12 @@ export interface ChangePasswordRequest {
|
||||
|
||||
// User 상태
|
||||
export interface User {
|
||||
userId: number;
|
||||
userId: string; // UUID format
|
||||
userName: string;
|
||||
email: string;
|
||||
role: string;
|
||||
phoneNumber?: string;
|
||||
storeId?: number;
|
||||
storeId?: string; // UUID format
|
||||
storeName?: string;
|
||||
industry?: string;
|
||||
address?: string;
|
||||
|
||||
Reference in New Issue
Block a user