'use client'; import { useState, useEffect } from 'react'; import { useParams, useRouter } from 'next/navigation'; import { Box, Container, Card, CardContent, Typography, Button, FormControlLabel, Checkbox, Dialog, DialogTitle, DialogContent, DialogActions, IconButton, Grid, Alert, CircularProgress, } from '@mui/material'; import { EventNote, Tune, Casino, Download, Refresh, Notifications, Add, Remove, Info, People, } from '@mui/icons-material'; import { drawWinners, getWinners, getParticipants } from '@/shared/api/participation.api'; import type { DrawWinnersResponse } from '@/shared/types/api.types'; // 디자인 시스템 색상 const colors = { pink: '#F472B6', purple: '#C084FC', purpleLight: '#E9D5FF', blue: '#60A5FA', mint: '#34D399', orange: '#FB923C', yellow: '#FBBF24', gray: { 900: '#1A1A1A', 700: '#4A4A4A', 500: '#9E9E9E', 300: '#D9D9D9', 100: '#F5F5F5', }, }; interface Winner { participantId: string; name: string; phoneNumber: string; rank: number; channel?: string; storeVisited: boolean; } export default function DrawPage() { const params = useParams(); const router = useRouter(); const eventId = params.eventId as string; // State const [winnerCount, setWinnerCount] = useState(5); const [storeBonus, setStoreBonus] = useState(false); const [isDrawing, setIsDrawing] = useState(false); const [showResults, setShowResults] = useState(false); const [winners, setWinners] = useState([]); const [animationText, setAnimationText] = useState('추첨 중...'); const [animationSubtext, setAnimationSubtext] = useState('난수 생성 중'); const [confirmDialogOpen, setConfirmDialogOpen] = useState(false); const [redrawDialogOpen, setRedrawDialogOpen] = useState(false); const [notifyDialogOpen, setNotifyDialogOpen] = useState(false); // API 관련 상태 const [totalParticipants, setTotalParticipants] = useState(0); const [eventName] = useState('이벤트'); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [drawResult, setDrawResult] = useState(null); // 초기 데이터 로드 useEffect(() => { const loadInitialData = async () => { try { setLoading(true); setError(null); // 참여자 총 수 조회 const participantsResponse = await getParticipants({ eventId, page: 0, size: 1, }); setTotalParticipants(participantsResponse.data.totalElements); // 기존 당첨자가 있는지 확인 try { const winnersResponse = await getWinners(eventId, 0, 100); if (winnersResponse.data.content.length > 0) { // 당첨자가 있으면 결과 화면 표시 const winnerList: Winner[] = winnersResponse.data.content.map((p) => ({ participantId: p.participantId, name: p.name, phoneNumber: p.phoneNumber, rank: 0, // rank는 순서대로 channel: p.channel, storeVisited: p.storeVisited, })); setWinners(winnerList); setShowResults(true); } } catch { // 당첨자가 없으면 무시 console.log('No winners yet'); } } catch (err) { console.error('Failed to load initial data:', err); setError('데이터를 불러오는데 실패했습니다.'); } finally { setLoading(false); } }; loadInitialData(); }, [eventId]); const handleDecrease = () => { if (winnerCount > 1) { setWinnerCount(winnerCount - 1); } }; const handleIncrease = () => { if (winnerCount < 100 && winnerCount < totalParticipants) { setWinnerCount(winnerCount + 1); } }; const handleStartDrawing = () => { setConfirmDialogOpen(true); }; const executeDrawing = async () => { setConfirmDialogOpen(false); setIsDrawing(true); setError(null); try { // Phase 1: 난수 생성 중 (1 second) setTimeout(() => { setAnimationText('당첨자 선정 중...'); setAnimationSubtext('공정한 추첨을 진행하고 있습니다'); }, 1000); // 실제 API 호출 const response = await drawWinners(eventId, winnerCount, storeBonus); setDrawResult(response.data); // Phase 2: 완료 (2 seconds) setTimeout(() => { setAnimationText('완료!'); setAnimationSubtext('추첨이 완료되었습니다'); }, 2000); // Phase 3: 당첨자 목록 변환 및 표시 setTimeout(() => { const winnerList: Winner[] = response.data.winners.map((w) => ({ participantId: w.participantId, name: w.name, phoneNumber: w.phoneNumber, rank: w.rank, storeVisited: false, // API 응답에 포함되지 않음 })); setWinners(winnerList); setIsDrawing(false); setShowResults(true); }, 3000); } catch (err) { console.error('Draw failed:', err); setIsDrawing(false); const errorMessage = err && typeof err === 'object' && 'response' in err ? (err as { response?: { data?: { message?: string } } }).response?.data?.message : undefined; setError(errorMessage || '추첨에 실패했습니다. 다시 시도해주세요.'); } }; const handleRedraw = async () => { setRedrawDialogOpen(false); setShowResults(false); setWinners([]); setTimeout(() => { executeDrawing(); }, 500); }; const handleNotify = () => { setNotifyDialogOpen(false); setTimeout(() => { alert('알림이 전송되었습니다'); }, 500); }; const handleDownload = () => { const now = new Date(); const dateStr = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')}_${String(now.getHours()).padStart(2, '0')}${String(now.getMinutes()).padStart(2, '0')}`; const filename = `당첨자목록_${eventName}_${dateStr}.xlsx`; alert(`${filename} 다운로드를 시작합니다`); }; const handleBackToEvents = () => { router.push('/events'); }; const getRankClass = (rank: number) => { if (rank === 1) return 'linear-gradient(135deg, #FFD700 0%, #FFA500 100%)'; if (rank === 2) return 'linear-gradient(135deg, #C0C0C0 0%, #A8A8A8 100%)'; if (rank === 3) return 'linear-gradient(135deg, #CD7F32 0%, #B87333 100%)'; return '#e0e0e0'; }; // 로딩 상태 if (loading) { return ( ); } return ( {/* 에러 메시지 */} {error && ( setError(null)}> {error} )} {/* Setup View (Before Drawing) */} {!showResults && ( <> {/* Page Header */} 🎲 당첨자 추첨 참여자 중에서 공정하게 당첨자를 선정하세요 {/* Event Info Summary Cards */} 이벤트명 {eventName} 총 참여자 {totalParticipants}명 {/* Drawing Settings */} 추첨 설정 당첨 인원 {winnerCount} setStoreBonus(e.target.checked)} sx={{ color: colors.purple, '&.Mui-checked': { color: colors.purple, }, }} /> } label={ 매장 방문 고객 가산점 (가중치: 1.5배) } sx={{ mb: 6 }} /> 추첨 방식 • 난수 기반 무작위 추첨 • 모든 추첨 과정은 자동 기록됩니다 {/* Drawing Start Button */} )} {/* Results View (After Drawing) */} {showResults && ( <> {/* Results Header */} 🎉 추첨 완료! 총 {totalParticipants}명 중 {winners.length}명 당첨 {drawResult && ( 추첨 일시: {new Date(drawResult.drawnAt).toLocaleString('ko-KR')} )} {/* Winner List */} 🏆 당첨자 목록 {winners.map((winner) => { return ( {winner.rank}위 참여자 ID: {winner.participantId} {winner.name} ({winner.phoneNumber}) {winner.channel && ( 참여: {winner.channel}{' '} {winner.storeVisited && storeBonus && '🌟'} )} ); })} {storeBonus && ( 🌟 매장 방문 고객 가산점 적용 )} {/* Action Buttons */} )} {/* Drawing Animation */} {/* 그라데이션 스피너 */} {animationText} {animationSubtext} {/* Confirm Dialog */} setConfirmDialogOpen(false)} maxWidth="xs" fullWidth PaperProps={{ sx: { borderRadius: 4 } }} > 추첨 확인 총 {totalParticipants}명 중 {winnerCount}명을 추첨하시겠습니까? {storeBonus && ( 매장 방문 고객에게 1.5배 가산점이 적용됩니다. )} {/* Redraw Dialog */} setRedrawDialogOpen(false)} maxWidth="xs" fullWidth PaperProps={{ sx: { borderRadius: 4 } }} > 재추첨 확인 재추첨 시 현재 당첨자 정보가 변경됩니다. 계속하시겠습니까? 이전 추첨 이력은 보관됩니다 {/* Notify Dialog */} setNotifyDialogOpen(false)} maxWidth="xs" fullWidth PaperProps={{ sx: { borderRadius: 4 } }} > 알림 전송 {winnerCount}명의 당첨자에게 SMS 알림을 전송하시겠습니까? 예상 비용: {winnerCount * 100}원 (100원/건) ); }