From e8ea659c0bff386200fc1cfa1d7c8c328692cf1f Mon Sep 17 00:00:00 2001 From: cherry2250 Date: Mon, 27 Oct 2025 14:26:39 +0900 Subject: [PATCH 1/8] =?UTF-8?q?UI=20=EA=B0=9C=EC=84=A0:=20=EA=B0=84?= =?UTF-8?q?=EA=B2=A9=20=ED=99=95=EB=8C=80,=20=EC=B0=A8=ED=8A=B8=20?= =?UTF-8?q?=EC=83=89=EC=83=81=20=EB=B3=80=EA=B2=BD,=20=EC=9D=B4=EB=B2=A4?= =?UTF-8?q?=ED=8A=B8=20=EB=AA=A9=EB=A1=9D=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 전체 간격(spacing) 2배 증가 및 컨테이너 패딩 확대 - 기본 폰트 크기 14px→16px 증가 - 채널별 성과 차트 색상을 조화로운 색상으로 변경 (#F472B6, #60A5FA, #FB923C) - 이벤트 목록 페이지에 통계 요약 카드 추가 (전체/진행중/참여자/평균ROI) - 진행중인 이벤트에 진행률 바 추가 - 이벤트 상태 배지 추가 (마감임박/인기/높은ROI/신규) - 상품 및 참여방법에 아이콘 추가 - 이벤트 카드 레이아웃 개선: 참여자/ROI 정보를 오른쪽 하단으로 재배치 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- package-lock.json | 25 +- package.json | 5 +- src/app/(main)/analytics/page.tsx | 484 +++++++++++++++++++------- src/app/(main)/events/page.tsx | 558 +++++++++++++++++++++++++----- src/app/(main)/page.tsx | 72 ++-- src/styles/globals.css | 24 +- 6 files changed, 914 insertions(+), 254 deletions(-) diff --git a/package-lock.json b/package-lock.json index ad38b77..9644766 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,11 +18,11 @@ "@use-funnel/browser": "^0.0.12", "@use-funnel/next": "^0.0.12", "axios": "^1.7.7", - "chart.js": "^4.4.6", + "chart.js": "^4.5.1", "dayjs": "^1.11.13", "next": "^14.2.15", "react": "^18.3.1", - "react-chartjs-2": "^5.2.0", + "react-chartjs-2": "^5.3.0", "react-dom": "^18.3.1", "react-hook-form": "^7.53.0", "zod": "^3.23.8", @@ -30,6 +30,7 @@ }, "devDependencies": { "@playwright/test": "^1.48.0", + "@types/chart.js": "^2.9.41", "@types/node": "^22.7.5", "@types/react": "^18.3.11", "@types/react-dom": "^18.3.0", @@ -1215,6 +1216,16 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/chart.js": { + "version": "2.9.41", + "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.41.tgz", + "integrity": "sha512-3dvkDvueckY83UyUXtJMalYoH6faOLkWQoaTlJgB4Djde3oORmNP0Jw85HtzTuXyliUHcdp704s0mZFQKio/KQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "moment": "^2.10.2" + } + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -4684,6 +4695,16 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", diff --git a/package.json b/package.json index eca31d7..b4463e4 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,11 @@ "@use-funnel/browser": "^0.0.12", "@use-funnel/next": "^0.0.12", "axios": "^1.7.7", - "chart.js": "^4.4.6", + "chart.js": "^4.5.1", "dayjs": "^1.11.13", "next": "^14.2.15", "react": "^18.3.1", - "react-chartjs-2": "^5.2.0", + "react-chartjs-2": "^5.3.0", "react-dom": "^18.3.1", "react-hook-form": "^7.53.0", "zod": "^3.23.8", @@ -32,6 +32,7 @@ }, "devDependencies": { "@playwright/test": "^1.48.0", + "@types/chart.js": "^2.9.41", "@types/node": "^22.7.5", "@types/react": "^18.3.11", "@types/react-dom": "^18.3.0", diff --git a/src/app/(main)/analytics/page.tsx b/src/app/(main)/analytics/page.tsx index c2fc0ff..a94244f 100644 --- a/src/app/(main)/analytics/page.tsx +++ b/src/app/(main)/analytics/page.tsx @@ -10,12 +10,41 @@ import { Grid, } from '@mui/material'; import { - PieChart, - ShowChart, + PieChart as PieChartIcon, + ShowChart as ShowChartIcon, Payments, People, } from '@mui/icons-material'; +import { + Chart as ChartJS, + ArcElement, + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + Legend, +} from 'chart.js'; +import { Pie, Line } from 'react-chartjs-2'; import Header from '@/shared/ui/Header'; +import { + cardStyles, + colors, + responsiveText, +} from '@/shared/lib/button-styles'; + +// Chart.js 등록 +ChartJS.register( + ArcElement, + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + Legend +); // Mock 데이터 const mockAnalyticsData = { @@ -28,9 +57,9 @@ const mockAnalyticsData = { targetRoi: 300, }, channelPerformance: [ - { channel: '우리동네TV', participants: 58, percentage: 45, color: '#E31E24' }, - { channel: '링고비즈', participants: 38, percentage: 30, color: '#0066FF' }, - { channel: 'SNS', participants: 32, percentage: 25, color: '#FFB800' }, + { channel: '우리동네TV', participants: 58, percentage: 45, color: '#F472B6' }, + { channel: '링고비즈', participants: 38, percentage: 30, color: '#60A5FA' }, + { channel: 'SNS', participants: 32, percentage: 25, color: '#FB923C' }, ], timePerformance: { peakTime: '오후 2-4시', @@ -98,18 +127,25 @@ export default function AnalyticsPage() { return ( <>
- - + + {/* Title with Real-time Indicator */} - + 📊 요약 (실시간) @@ -118,7 +154,7 @@ export default function AnalyticsPage() { width: 8, height: 8, borderRadius: '50%', - bgcolor: 'success.main', + bgcolor: colors.mint, animation: 'pulse 2s infinite', '@keyframes pulse': { '0%, 100%': { opacity: 1 }, @@ -126,39 +162,75 @@ export default function AnalyticsPage() { }, }} /> - + {updateText} {/* Summary KPI Cards */} - + - - - + + + 참여자 수 - - {summary.participants}명 + + {summary.participants} - + ↑ {summary.participantsDelta}명 (오늘) - - - + + + 총 비용 - - {Math.floor(summary.totalCost / 10000)}만원 + + {Math.floor(summary.totalCost / 10000)}만 - + 경품 {Math.floor(roiDetail.prizeCost / 10000)}만 + 채널{' '} {Math.floor(roiDetail.channelCost / 10000)}만 @@ -166,31 +238,67 @@ export default function AnalyticsPage() { - - - + + + 예상 수익 - - {Math.floor(summary.expectedRevenue / 10000)}만원 + + {Math.floor(summary.expectedRevenue / 10000)}만 - - 매출증가 {Math.floor(roiDetail.salesIncrease / 10000)}만 + LTV{' '} + + 매출 {Math.floor(roiDetail.salesIncrease / 10000)}만 + LTV{' '} {Math.floor(roiDetail.newCustomerLTV / 10000)}만 - - - + + + 투자대비수익률 - + {summary.roi}% - + 목표 {summary.targetRoi}% 달성 @@ -199,39 +307,76 @@ export default function AnalyticsPage() { {/* Charts Grid */} - + {/* Channel Performance */} - - - - - + + + + + + + 채널별 성과 - {/* Chart Placeholder */} + {/* Pie Chart */} - - donut_large - - - 파이 차트 - + item.channel), + datasets: [ + { + data: channelPerformance.map((item) => item.participants), + backgroundColor: channelPerformance.map((item) => item.color), + borderColor: '#fff', + borderWidth: 2, + }, + ], + }} + options={{ + responsive: true, + maintainAspectRatio: true, + plugins: { + legend: { + display: false, + }, + tooltip: { + callbacks: { + label: function (context) { + const label = context.label || ''; + const value = context.parsed || 0; + const total = context.dataset.data.reduce((a: number, b: number) => a + b, 0); + const percentage = ((value / total) * 100).toFixed(1); + return `${label}: ${value}명 (${percentage}%)`; + }, + }, + }, + }, + }} + /> {/* Legend */} @@ -250,9 +395,11 @@ export default function AnalyticsPage() { bgcolor: item.color, }} /> - {item.channel} + + {item.channel} + - + {item.percentage}% ({item.participants}명) @@ -264,44 +411,113 @@ export default function AnalyticsPage() { {/* Time Trend */} - - - - - + + + + + + + 시간대별 참여 추이 - {/* Chart Placeholder */} + {/* Line Chart */} - - trending_up - - - 라인 차트 - + {/* Stats */} - + 피크 시간: {timePerformance.peakTime} ({timePerformance.peakParticipants}명) - + 평균 시간당: {timePerformance.avgPerHour}명 @@ -311,37 +527,49 @@ export default function AnalyticsPage() { {/* ROI Detail & Participant Profile */} - + {/* ROI Detail */} - - - - - + + + + + + + 투자대비수익률 상세 - + - + 총 비용: {Math.floor(roiDetail.totalCost / 10000)}만원 - + - + • 경품 비용 - + {Math.floor(roiDetail.prizeCost / 10000)}만원 - + • 채널 비용 - + {Math.floor(roiDetail.channelCost / 10000)}만원 @@ -349,23 +577,23 @@ export default function AnalyticsPage() { - + 예상 수익: {Math.floor(roiDetail.expectedRevenue / 10000)}만원 - + - + • 매출 증가 - + {Math.floor(roiDetail.salesIncrease / 10000)}만원 - + • 신규 고객 LTV - + {Math.floor(roiDetail.newCustomerLTV / 10000)}만원 @@ -373,26 +601,26 @@ export default function AnalyticsPage() { - + 투자대비수익률 - + (수익 - 비용) ÷ 비용 × 100 - + ({Math.floor(roiDetail.expectedRevenue / 10000)}만 -{' '} {Math.floor(roiDetail.totalCost / 10000)}만) ÷{' '} {Math.floor(roiDetail.totalCost / 10000)}만 × 100 - + = {summary.roi}% @@ -404,33 +632,45 @@ export default function AnalyticsPage() { {/* Participant Profile */} - - - - - + + + + + + + 참여자 프로필 {/* Age Distribution */} - + 연령별 {participantProfile.age.map((item) => ( - + {item.label} @@ -438,11 +678,11 @@ export default function AnalyticsPage() { sx={{ width: `${item.percentage}%`, height: '100%', - bgcolor: 'info.main', + background: `linear-gradient(135deg, ${colors.blue} 0%, ${colors.blueLight} 100%)`, display: 'flex', alignItems: 'center', justifyContent: 'flex-end', - pr: 1, + pr: 1.5, }} > - + 성별 {participantProfile.gender.map((item) => ( - + {item.label} @@ -484,11 +724,11 @@ export default function AnalyticsPage() { sx={{ width: `${item.percentage}%`, height: '100%', - bgcolor: 'error.main', + background: `linear-gradient(135deg, ${colors.pink} 0%, ${colors.pinkLight} 100%)`, display: 'flex', alignItems: 'center', justifyContent: 'flex-end', - pr: 1, + pr: 1.5, }} > { + const getStatusStyle = (status: string) => { switch (status) { case 'active': - return 'success'; + return { + bgcolor: colors.mint, + color: 'white', + }; case 'scheduled': - return 'info'; + return { + bgcolor: colors.blue, + color: 'white', + }; case 'ended': - return 'default'; + return { + bgcolor: colors.gray[300], + color: colors.gray[700], + }; default: - return 'default'; + return { + bgcolor: colors.gray[200], + color: colors.gray[600], + }; } }; @@ -140,13 +193,149 @@ export default function EventsPage() { } }; + const getMethodIcon = (method: string) => { + switch (method) { + case '전화번호 입력': + return ; + case 'SNS 팔로우': + return ; + case '구매 인증': + return ; + case '이메일 등록': + return ; + default: + return ; + } + }; + + const calculateProgress = (event: typeof mockEvents[0]) => { + if (event.status !== 'active') return 0; + const total = new Date(event.endDate).getTime() - new Date(event.startDate).getTime(); + const elapsed = Date.now() - new Date(event.startDate).getTime(); + return Math.min(Math.max((elapsed / total) * 100, 0), 100); + }; + + // 통계 계산 + const stats = { + total: mockEvents.length, + active: mockEvents.filter((e) => e.status === 'active').length, + totalParticipants: mockEvents.reduce((sum, e) => sum + e.participants, 0), + avgROI: Math.round( + mockEvents.filter((e) => e.roi > 0).reduce((sum, e) => sum + e.roi, 0) / + mockEvents.filter((e) => e.roi > 0).length + ), + }; + return ( <>
- - + + + {/* Summary Statistics */} + + + + + + + {stats.total} + + + 전체 이벤트 + + + + + + + + + + {stats.active} + + + 진행중 + + + + + + + + + + {stats.totalParticipants} + + + 총 참여자 + + + + + + + + + + {stats.avgROI}% + + + 평균 ROI + + + + + + {/* Search Section */} - + - + ), }} sx={{ '& .MuiOutlinedInput-root': { - borderRadius: 2, + borderRadius: 3, + bgcolor: 'white', + '& fieldset': { + borderColor: colors.gray[200], + }, + '&:hover fieldset': { + borderColor: colors.gray[300], + }, + '&.Mui-focused fieldset': { + borderColor: colors.purple, + }, }, }} /> {/* Filters */} - - - + + + 상태 setSortBy(e.target.value as SortBy)} size="small" + sx={{ + borderRadius: 2, + bgcolor: 'white', + '& .MuiOutlinedInput-notchedOutline': { + borderColor: colors.gray[200], + }, + '&:hover .MuiOutlinedInput-notchedOutline': { + borderColor: colors.gray[300], + }, + '&.Mui-focused .MuiOutlinedInput-notchedOutline': { + borderColor: colors.purple, + }, + }} > 최신순 참여자순 @@ -222,89 +460,234 @@ export default function EventsPage() { {/* Event List */} - + {pageEvents.length === 0 ? ( - - - event_busy - - - 검색 결과가 없습니다 - - + + + + + event_busy + + + + 검색 결과가 없습니다 + + + 다른 검색 조건으로 다시 시도해보세요 + + + ) : ( - + {pageEvents.map((event) => ( handleEventClick(event.id)} > - - {/* Header */} - - - {event.title} - - + {/* Header with Badges */} + + + + {event.title} + + + {getStatusText(event.status)} + {event.status === 'active' ? ` | D-${event.daysLeft}` : event.status === 'scheduled' ? ` | D+${event.daysLeft}` - : '' - }`} - color={getStatusColor(event.status) as any} - size="small" - sx={{ fontWeight: 600 }} - /> + : ''} + + + + {/* Status Badges */} + + {event.isUrgent && ( + } + label="마감임박" + size="small" + sx={{ + bgcolor: '#FEF3C7', + color: '#92400E', + fontWeight: 600, + fontSize: '0.75rem', + '& .MuiChip-icon': { color: '#92400E' }, + }} + /> + )} + {event.isPopular && ( + } + label="인기" + size="small" + sx={{ + bgcolor: '#FEE2E2', + color: '#991B1B', + fontWeight: 600, + fontSize: '0.75rem', + '& .MuiChip-icon': { color: '#991B1B' }, + }} + /> + )} + {event.isHighROI && ( + } + label="높은 ROI" + size="small" + sx={{ + bgcolor: '#DCFCE7', + color: '#166534', + fontWeight: 600, + fontSize: '0.75rem', + '& .MuiChip-icon': { color: '#166534' }, + }} + /> + )} + {event.isNew && ( + } + label="신규" + size="small" + sx={{ + bgcolor: '#DBEAFE', + color: '#1E40AF', + fontWeight: 600, + fontSize: '0.75rem', + '& .MuiChip-icon': { color: '#1E40AF' }, + }} + /> + )} + - {/* Stats */} - - - - - 참여 + {/* Progress Bar for Active Events */} + {event.status === 'active' && ( + + + + 이벤트 진행률 - - {event.participants}명 + + {Math.round(calculateProgress(event))}% - - + + + )} + + {/* Event Info and Stats Container */} + + {/* Left: Event Info */} + + + + + + {event.prize} + + + + {getMethodIcon(event.method)} + + {event.method} + + + + + {/* Date */} + + 📅 + + {event.startDate} ~ {event.endDate} + + + + + {/* Right: Stats */} + - - 투자대비수익률 + + 참여자 - + + {event.participants.toLocaleString()} + + 명 + + + {event.targetParticipants > 0 && ( + + 목표: {event.targetParticipants}명 ({Math.round((event.participants / event.targetParticipants) * 100)}%) + + )} + + + + ROI + + = 400 ? colors.mint : event.roi >= 200 ? colors.orange : colors.gray[500] }}> {event.roi}% - - - - {/* Date */} - - {event.startDate} ~ {event.endDate} - + + ))} @@ -314,13 +697,28 @@ export default function EventsPage() { {/* Pagination */} {totalPages > 1 && ( - + setCurrentPage(page)} - color="primary" size="large" + sx={{ + '& .MuiPaginationItem-root': { + color: colors.gray[700], + fontWeight: 600, + '&.Mui-selected': { + background: `linear-gradient(135deg, ${colors.purple} 0%, ${colors.blue} 100%)`, + color: 'white', + '&:hover': { + background: `linear-gradient(135deg, ${colors.purpleLight} 0%, ${colors.blueLight} 100%)`, + }, + }, + '&:hover': { + bgcolor: colors.gray[100], + }, + }, + }} /> )} diff --git a/src/app/(main)/page.tsx b/src/app/(main)/page.tsx index 61de739..6dbac59 100644 --- a/src/app/(main)/page.tsx +++ b/src/app/(main)/page.tsx @@ -88,14 +88,14 @@ export default function HomePage() { minHeight: '100vh', }} > - + {/* Welcome Section */} - + 안녕하세요, {mockUser.name}님! 👋 @@ -106,7 +106,7 @@ export default function HomePage() { {/* KPI Cards */} - + - + @@ -145,7 +145,7 @@ export default function HomePage() { {activeEvents.length} @@ -161,7 +161,7 @@ export default function HomePage() { borderColor: 'transparent', }} > - + @@ -190,7 +190,7 @@ export default function HomePage() { {totalParticipants.toLocaleString()} @@ -206,7 +206,7 @@ export default function HomePage() { borderColor: 'transparent', }} > - + @@ -235,7 +235,7 @@ export default function HomePage() { {avgROI}% @@ -245,11 +245,11 @@ export default function HomePage() { {/* Quick Actions */} - - + + 빠른 시작 - + - + - + 새 이벤트 @@ -289,7 +289,7 @@ export default function HomePage() { }} onClick={handleViewAnalytics} > - + - + 성과분석 @@ -316,9 +316,9 @@ export default function HomePage() { {/* Active Events */} - + 진행 중인 이벤트 @@ -372,7 +372,7 @@ export default function HomePage() { ) : ( - + {activeEvents.map((event) => ( handleEventClick(event.id)} > - + @@ -411,11 +411,11 @@ export default function HomePage() { 📅 @@ -423,7 +423,7 @@ export default function HomePage() { {event.startDate} ~ {event.endDate} - + {/* Recent Activity */} - - + + 최근 활동 - + {mockActivities.map((activity, index) => ( 0 ? 3.5 : 0, - mt: index > 0 ? 3.5 : 0, + gap: 4, + pt: index > 0 ? 6 : 0, + mt: index > 0 ? 6 : 0, borderTop: index > 0 ? 1 : 0, borderColor: colors.gray[200], }} diff --git a/src/styles/globals.css b/src/styles/globals.css index 3054163..eb797cc 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -24,13 +24,13 @@ --color-error: #D32F2F; --color-info: #0288D1; - /* Spacing (4px Grid) */ - --spacing-xs: 4px; - --spacing-s: 8px; - --spacing-m: 16px; - --spacing-l: 24px; - --spacing-xl: 32px; - --spacing-2xl: 48px; + /* Spacing (4px Grid) - Doubled values */ + --spacing-xs: 8px; + --spacing-s: 16px; + --spacing-m: 32px; + --spacing-l: 48px; + --spacing-xl: 64px; + --spacing-2xl: 96px; /* Border Radius */ --border-radius-sm: 4px; @@ -73,8 +73,8 @@ body { padding: 0; font-family: "Pretendard", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica Neue", system-ui, sans-serif; - font-size: 14px; - line-height: 1.5; + font-size: 16px; + line-height: 1.6; color: var(--color-gray-900); background-color: var(--color-gray-50); min-height: 100%; @@ -149,18 +149,18 @@ button { width: 100%; max-width: 1200px; margin: 0 auto; - padding: 0 20px; + padding: 0 40px; } @media (min-width: 768px) { .container { - padding: 0 40px; + padding: 0 80px; } } @media (min-width: 1024px) { .container { - padding: 0 80px; + padding: 0 120px; } } From de7726ffad2acb76ec442c276fbcda048753e647 Mon Sep 17 00:00:00 2001 From: cherry2250 Date: Mon, 27 Oct 2025 14:40:05 +0900 Subject: [PATCH 2/8] =?UTF-8?q?=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=94=94=EC=9E=90?= =?UTF-8?q?=EC=9D=B8=20=EA=B0=9C=EC=84=A0=20=EB=B0=8F=20=EC=B0=A8=ED=8A=B8?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 전체 간격 2배 이상 확대하여 다른 페이지와 디자인 통일 - 실제 Chart.js 라이브러리로 3개 차트 구현 - 참여 추이 차트 (Line): 7일/30일/전체 기간 선택 가능 - 채널별 참여자 차트 (Bar): 우리동네TV, 링고비즈, SNS - ROI 추이 차트 (Line): 주차별 ROI 성장 추이 - 상태 배지 추가 (AI 추천, 마감임박, 인기, 높은 ROI, 신규) - 진행중인 이벤트에 진행률 바 추가 - KPI 카드에 그라데이션 배경 적용 및 목표 달성률 표시 - 이벤트 정보 섹션 디자인 개선 (아이콘 색상, 간격 확대) - Quick Actions 카드 hover 효과 개선 - 최근 참여자 아바타 디자인 개선 - 실시간 업데이트 인디케이터에 pulse 애니메이션 추가 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/app/(main)/events/[eventId]/page.tsx | 688 +++++++++++++++++------ 1 file changed, 525 insertions(+), 163 deletions(-) diff --git a/src/app/(main)/events/[eventId]/page.tsx b/src/app/(main)/events/[eventId]/page.tsx index 6d718dc..578ecd4 100644 --- a/src/app/(main)/events/[eventId]/page.tsx +++ b/src/app/(main)/events/[eventId]/page.tsx @@ -15,6 +15,7 @@ import { Menu, MenuItem, Divider, + LinearProgress, } from '@mui/material'; import { MoreVert, @@ -23,13 +24,63 @@ import { TrendingUp, Share, CardGiftcard, - HowToReg, AttachMoney, People, Edit, Download, Person, + Phone, + Email, + ShoppingCart, + Warning, + LocalFireDepartment, + Star, + NewReleases, } from '@mui/icons-material'; +import { Line, Bar } from 'react-chartjs-2'; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + PointElement, + LineElement, + BarElement, + Title, + Tooltip, + Legend, + Filler, +} from 'chart.js'; + +// Chart.js 등록 +ChartJS.register( + CategoryScale, + LinearScale, + PointElement, + LineElement, + BarElement, + Title, + Tooltip, + Legend, + Filler +); + +// 디자인 시스템 색상 +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', + }, +}; // Mock 데이터 const mockEventData = { @@ -41,12 +92,17 @@ const mockEventData = { prize: '커피 쿠폰', method: 'SNS 팔로우', cost: 250000, - channels: ['홈페이지', '카카오톡', 'Instagram'], + channels: ['우리동네TV', '링고비즈', 'SNS'], participants: 128, views: 456, roi: 450, conversion: 28, + targetParticipants: 200, isAIRecommended: true, + isUrgent: false, + isPopular: true, + isHighROI: true, + isNew: false, }; const recentParticipants = [ @@ -57,6 +113,86 @@ const recentParticipants = [ { name: '정*희', phone: '010-****-7890', time: '2시간 전' }, ]; +// 차트 데이터 생성 함수 +const generateParticipationTrendData = (period: '7d' | '30d' | 'all') => { + const labels = + period === '7d' + ? ['1/20', '1/21', '1/22', '1/23', '1/24', '1/25', '1/26'] + : period === '30d' + ? Array.from({ length: 30 }, (_, i) => `1/${i + 1}`) + : Array.from({ length: 31 }, (_, i) => `1/${i + 1}`); + + const data = + period === '7d' + ? [12, 19, 15, 25, 22, 30, 28] + : period === '30d' + ? Array.from({ length: 30 }, () => Math.floor(Math.random() * 30) + 10) + : Array.from({ length: 31 }, () => Math.floor(Math.random() * 30) + 10); + + return { + labels, + datasets: [ + { + label: '일별 참여자', + data, + borderColor: colors.blue, + backgroundColor: `${colors.blue}40`, + fill: true, + tension: 0.4, + }, + ], + }; +}; + +const channelPerformanceData = { + labels: ['우리동네TV', '링고비즈', 'SNS'], + datasets: [ + { + label: '참여자 수', + data: [58, 38, 32], + backgroundColor: [colors.pink, colors.blue, colors.orange], + borderRadius: 8, + }, + ], +}; + +const roiTrendData = { + labels: ['1주차', '2주차', '3주차', '4주차'], + datasets: [ + { + label: 'ROI (%)', + data: [150, 280, 380, 450], + borderColor: colors.mint, + backgroundColor: `${colors.mint}40`, + fill: true, + tension: 0.4, + }, + ], +}; + +// 헬퍼 함수 +const getMethodIcon = (method: string) => { + switch (method) { + case '전화번호 입력': + return ; + case 'SNS 팔로우': + return ; + case '구매 인증': + return ; + case '이메일 등록': + return ; + default: + return ; + } +}; + +const calculateProgress = (event: typeof mockEventData) => { + if (event.status !== 'active') return 0; + const total = new Date(event.endDate).getTime() - new Date(event.startDate).getTime(); + const elapsed = Date.now() - new Date(event.startDate).getTime(); + return Math.min(Math.max((elapsed / total) * 100, 0), 100); +}; + export default function EventDetailPage() { const router = useRouter(); const params = useParams(); @@ -119,11 +255,11 @@ export default function EventDetailPage() { return ( - + {/* Event Header */} - - - + + + {event.title} @@ -131,13 +267,13 @@ export default function EventDetailPage() { - 이벤트 수정 + 이벤트 수정 - 공유하기 + 공유하기 - 데이터 다운로드 + 데이터 다운로드 @@ -146,35 +282,99 @@ export default function EventDetailPage() { - - + + {event.isAIRecommended && ( + + )} + {event.isUrgent && ( } + label="마감임박" + size="medium" + sx={{ bgcolor: '#FEF3C7', color: '#92400E' }} + /> + )} + {event.isPopular && ( + } + label="인기" + size="medium" + sx={{ bgcolor: '#FEE2E2', color: '#991B1B' }} + /> + )} + {event.isHighROI && ( + } + label="높은 ROI" + size="medium" + sx={{ bgcolor: '#DCFCE7', color: '#166534' }} + /> + )} + {event.isNew && ( + } + label="신규" + size="medium" + sx={{ bgcolor: '#DBEAFE', color: '#1E40AF' }} /> )} - - {event.startDate} ~ {event.endDate} + + 📅 {event.startDate} ~ {event.endDate} + + {/* 진행률 바 (진행중인 이벤트만) */} + {event.status === 'active' && ( + + + + 이벤트 진행률 + + + {Math.round(calculateProgress(event))}% + + + + + )} {/* Real-time KPIs */} - - - + + + 실시간 현황 - + @@ -183,56 +383,86 @@ export default function EventDetailPage() { - + - - - - + + + + 참여자 - + {event.participants}명 + + 목표: {event.targetParticipants}명 ( + {Math.round((event.participants / event.targetParticipants) * 100)}%) + - - - - + + + + 조회수 - + {event.views} - - - - + + + + ROI - + {event.roi}% - - - - conversion_path - - + + + + 전환율 - + {event.conversion}% @@ -241,112 +471,236 @@ export default function EventDetailPage() { - {/* Chart Section */} - - - 참여 추이 + {/* Chart Section - 참여 추이 */} + + + 📈 참여 추이 - - - + + + - - - show_chart - - - 참여자 추이 차트 - + + + {/* Chart Section - 채널별 성과 & ROI 추이 */} + + + + 📊 채널별 참여자 + + + + + + + + + + + + + 💰 ROI 추이 + + + + + + + + + + + {/* Event Details */} - - - 이벤트 정보 + + + 🎯 이벤트 정보 - - - - - - - 경품 - - {event.prize} - - - - - - - - - - 참여 방법 - - {event.method} - - - - - - - - - - 예상 비용 - - {event.cost.toLocaleString()}원 - - - - - - - + + + + + 경품 + + + {event.prize} + + + + + + + + {getMethodIcon(event.method)} + + + 참여 방법 + + + {event.method} + + + + + + + + + + + 예상 비용 + + + {event.cost.toLocaleString()}원 + + + + + + + + + + 배포 채널 - + {event.channels.map((channel) => ( - + ))} @@ -356,29 +710,31 @@ export default function EventDetailPage() { {/* Quick Actions */} - - - 빠른 작업 + + + ⚡ 빠른 작업 - + router.push(`/events/${eventId}/participants`)} > - - - 참여자 목록 + + + + 참여자 목록 + @@ -387,18 +743,20 @@ export default function EventDetailPage() { elevation={0} sx={{ cursor: 'pointer', - borderRadius: 3, - boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)', + borderRadius: 4, + boxShadow: '0 2px 8px rgba(0, 0, 0, 0.08)', transition: 'all 0.2s', '&:hover': { boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)', - transform: 'translateY(-2px)', + transform: 'translateY(-4px)', }, }} > - - - 이벤트 수정 + + + + 이벤트 수정 + @@ -407,18 +765,20 @@ export default function EventDetailPage() { elevation={0} sx={{ cursor: 'pointer', - borderRadius: 3, - boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)', + borderRadius: 4, + boxShadow: '0 2px 8px rgba(0, 0, 0, 0.08)', transition: 'all 0.2s', '&:hover': { boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)', - transform: 'translateY(-2px)', + transform: 'translateY(-4px)', }, }} > - - - 공유하기 + + + + 공유하기 + @@ -427,18 +787,20 @@ export default function EventDetailPage() { elevation={0} sx={{ cursor: 'pointer', - borderRadius: 3, - boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)', + borderRadius: 4, + boxShadow: '0 2px 8px rgba(0, 0, 0, 0.08)', transition: 'all 0.2s', '&:hover': { boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)', - transform: 'translateY(-2px)', + transform: 'translateY(-4px)', }, }} > - - - 데이터 다운 + + + + 데이터 다운 + @@ -446,51 +808,51 @@ export default function EventDetailPage() { {/* Recent Participants */} - - - - 최근 참여자 + + + + 👥 최근 참여자 - - + + {recentParticipants.map((participant, index) => ( - {index > 0 && } + {index > 0 && } - + - + - + {participant.name} - + {participant.phone} - + {participant.time} From 28f0ebde33c1f71df2d65eb348a405c6c346f746 Mon Sep 17 00:00:00 2001 From: cherry2250 Date: Mon, 27 Oct 2025 14:56:43 +0900 Subject: [PATCH 3/8] =?UTF-8?q?=EC=B6=94=EC=B2=A8=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EA=B0=9C=EC=84=A0=20?= =?UTF-8?q?=EB=B0=8F=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 페이지 헤더 및 요약 카드 추가 (이벤트명, 참여자 수) - 추첨 설정 카드 간격 2배 확대 및 버튼 크기 증가 - 추첨 이력 섹션 간격 확대 및 카드 디자인 개선 - 당첨자 목록 카드 디자인 개선 (순위 배지 크기 증가, 간격 확대) - 모든 액션 버튼에 그라데이션 배경 적용 - 모든 다이얼로그 컴포넌트 간격 및 디자인 통일 - 애니메이션 다이얼로그 크기 증가 - 미사용 import 제거 (EmojiEvents) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/app/(main)/events/[eventId]/draw/page.tsx | 553 +++++++++++++----- .../events/[eventId]/participants/page.tsx | 461 +++++++++++---- 2 files changed, 770 insertions(+), 244 deletions(-) diff --git a/src/app/(main)/events/[eventId]/draw/page.tsx b/src/app/(main)/events/[eventId]/draw/page.tsx index cf0dc62..4f10d86 100644 --- a/src/app/(main)/events/[eventId]/draw/page.tsx +++ b/src/app/(main)/events/[eventId]/draw/page.tsx @@ -29,8 +29,27 @@ import { Add, Remove, Info, + People, } from '@mui/icons-material'; +// 디자인 시스템 색상 +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', + }, +}; + // Mock 데이터 const mockEventData = { name: '신규고객 유치 이벤트', @@ -163,55 +182,77 @@ export default function DrawPage() { }; return ( - - + + {/* Setup View (Before Drawing) */} {!showResults && ( <> - {/* Event Info */} - - - - - - 이벤트 정보 - - - - - 이벤트명 - - {mockEventData.name} - - - - 총 참여자 - - - {mockEventData.totalParticipants}명 - - - - - 추첨 상태 - - 추첨 전 - - - + {/* Page Header */} + + + 🎲 당첨자 추첨 + + + 참여자 중에서 공정하게 당첨자를 선정하세요 + + + + {/* Event Info Summary Cards */} + + + + + + + 이벤트명 + + + {mockEventData.name} + + + + + + + + + + 총 참여자 + + + {mockEventData.totalParticipants}명 + + + + + {/* Drawing Settings */} - - - - - + + + + + 추첨 설정 - - + + 당첨 인원 - + - + {winnerCount} - + @@ -255,21 +307,42 @@ export default function DrawPage() { setStoreBonus(e.target.checked)} + sx={{ + color: colors.purple, + '&.Mui-checked': { + color: colors.purple, + }, + }} /> } - label="매장 방문 고객 가산점 (가중치: 1.5배)" - sx={{ mb: 3 }} + label={ + + 매장 방문 고객 가산점 (가중치: 1.5배) + + } + sx={{ mb: 6 }} /> - - - - + + + + 추첨 방식 - • 난수 기반 무작위 추첨 - • 모든 추첨 과정은 자동 기록됩니다 + + • 난수 기반 무작위 추첨 + + + • 모든 추첨 과정은 자동 기록됩니다 + @@ -279,45 +352,75 @@ export default function DrawPage() { fullWidth variant="contained" size="large" - startIcon={} + startIcon={} onClick={handleStartDrawing} - sx={{ mb: 3, py: 1.5, borderRadius: 2, fontWeight: 700, fontSize: '1rem' }} + sx={{ + mb: 10, + py: 3, + borderRadius: 4, + fontWeight: 700, + fontSize: '1.25rem', + background: `linear-gradient(135deg, ${colors.pink} 0%, ${colors.purple} 100%)`, + boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)', + '&:hover': { + background: `linear-gradient(135deg, ${colors.pink} 0%, ${colors.purple} 100%)`, + boxShadow: '0 6px 16px rgba(0, 0, 0, 0.2)', + transform: 'translateY(-2px)', + }, + }} > 추첨 시작 {/* Drawing History */} - - 📜 추첨 이력 (최근 3건) + + 📜 추첨 이력 {mockDrawingHistory.length === 0 ? ( - - - + + + + 추첨 이력이 없습니다 ) : ( - + {mockDrawingHistory.slice(0, 3).map((history, index) => ( - - + + - + {history.date} {history.isRedraw && '(재추첨)'} - + 당첨자 {history.winnerCount}명 @@ -335,51 +438,59 @@ export default function DrawPage() { {showResults && ( <> {/* Results Header */} - - + + 🎉 추첨 완료! - + 총 {mockEventData.totalParticipants}명 중 {winnerCount}명 당첨 {/* Winner List */} - - + + 🏆 당첨자 목록 - + {winners.map((winner, index) => { const rank = index + 1; return ( - - - + + + {rank}위 - + 응모번호: #{winner.id} - + {winner.name} ({winner.phone}) - + 참여: {winner.channel}{' '} {winner.hasBonus && storeBonus && '🌟'} @@ -391,14 +502,18 @@ export default function DrawPage() { })} {storeBonus && ( - + 🌟 매장 방문 고객 가산점 적용 )} {/* Action Buttons */} - + @@ -418,7 +542,16 @@ export default function DrawPage() { size="large" startIcon={} onClick={() => setRedrawDialogOpen(true)} - sx={{ borderRadius: 2 }} + sx={{ + borderRadius: 3, + py: 3, + fontSize: '1rem', + fontWeight: 600, + borderWidth: 2, + '&:hover': { + borderWidth: 2, + }, + }} > 재추첨 @@ -431,7 +564,18 @@ export default function DrawPage() { size="large" startIcon={} onClick={() => setNotifyDialogOpen(true)} - sx={{ mb: 2, py: 1.5, borderRadius: 2, fontWeight: 700, fontSize: '1rem' }} + sx={{ + mb: 4, + py: 3, + borderRadius: 3, + fontWeight: 700, + fontSize: '1rem', + background: `linear-gradient(135deg, ${colors.purple} 0%, ${colors.pink} 100%)`, + '&:hover': { + background: `linear-gradient(135deg, ${colors.purple} 0%, ${colors.pink} 100%)`, + opacity: 0.9, + }, + }} > 당첨자에게 알림 전송 @@ -441,7 +585,12 @@ export default function DrawPage() { variant="text" size="large" onClick={handleBackToEvents} - sx={{ borderRadius: 2 }} + sx={{ + borderRadius: 3, + py: 3, + fontSize: '1rem', + fontWeight: 600, + }} > 이벤트 목록으로 @@ -457,14 +606,15 @@ export default function DrawPage() { sx: { bgcolor: 'rgba(0, 0, 0, 0.9)', color: 'white', + borderRadius: 4, }, }} > - + - + {animationText} - + {animationSubtext} {/* Confirm Dialog */} - setConfirmDialogOpen(false)} maxWidth="xs" fullWidth> - 추첨 확인 - - + setConfirmDialogOpen(false)} + maxWidth="xs" + fullWidth + PaperProps={{ sx: { borderRadius: 4 } }} + > + + 추첨 확인 + + + 총 {mockEventData.totalParticipants}명 중 {winnerCount}명을 추첨하시겠습니까? - - - + {/* Redraw Dialog */} - setRedrawDialogOpen(false)} maxWidth="xs" fullWidth> - 재추첨 확인 - - + setRedrawDialogOpen(false)} + maxWidth="xs" + fullWidth + PaperProps={{ sx: { borderRadius: 4 } }} + > + + 재추첨 확인 + + + 재추첨 시 현재 당첨자 정보가 변경됩니다. - + 계속하시겠습니까? - + 이전 추첨 이력은 보관됩니다 - - - + {/* Notify Dialog */} - setNotifyDialogOpen(false)} maxWidth="xs" fullWidth> - 알림 전송 - - + setNotifyDialogOpen(false)} + maxWidth="xs" + fullWidth + PaperProps={{ sx: { borderRadius: 4 } }} + > + + 알림 전송 + + + {winnerCount}명의 당첨자에게 SMS 알림을 전송하시겠습니까? - + 예상 비용: {winnerCount * 100}원 (100원/건) - - - + {/* History Detail Dialog */} - setHistoryDetailOpen(false)} maxWidth="xs" fullWidth> - 추첨 이력 상세 - + setHistoryDetailOpen(false)} + maxWidth="xs" + fullWidth + PaperProps={{ sx: { borderRadius: 4 } }} + > + + 추첨 이력 상세 + + {selectedHistory && ( - - + + 추첨 일시: {selectedHistory.date} - + 당첨 인원: {selectedHistory.winnerCount}명 - + 재추첨 여부: {selectedHistory.isRedraw ? '예' : '아니오'} - + ※ 당첨자 정보는 개인정보 보호를 위해 마스킹 처리됩니다 )} - - diff --git a/src/app/(main)/events/[eventId]/participants/page.tsx b/src/app/(main)/events/[eventId]/participants/page.tsx index 3caf968..c2236cf 100644 --- a/src/app/(main)/events/[eventId]/participants/page.tsx +++ b/src/app/(main)/events/[eventId]/participants/page.tsx @@ -21,14 +21,37 @@ import { DialogTitle, DialogContent, DialogActions, + Grid, } from '@mui/material'; import { Search, FilterList, Casino, Download, + People, + TrendingUp, + Person, + AccessTime, } from '@mui/icons-material'; +// 디자인 시스템 색상 +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', + }, +}; + // Mock 데이터 const mockParticipants = [ { @@ -150,11 +173,117 @@ export default function ParticipantsPage() { alert('엑셀 다운로드 기능은 추후 구현됩니다'); }; + // 통계 계산 + const stats = { + total: mockParticipants.length, + waiting: mockParticipants.filter((p) => p.status === 'waiting').length, + winner: mockParticipants.filter((p) => p.status === 'winner').length, + channelDistribution: { + uriTV: mockParticipants.filter((p) => p.channelType === 'uriTV').length, + ringoBiz: mockParticipants.filter((p) => p.channelType === 'ringoBiz').length, + sns: mockParticipants.filter((p) => p.channelType === 'sns').length, + }, + }; + return ( - + + {/* Page Header */} + + + 👥 참여자 목록 + + + 이벤트에 참여한 사용자들의 정보를 확인하고 관리하세요 + + + + {/* Statistics Cards */} + + + + + + + 전체 참여자 + + + {stats.total}명 + + + + + + + + + + 대기중 + + + {stats.waiting}명 + + + + + + + + + + 당첨자 + + + {stats.winner}명 + + + + + + + + + + 당첨률 + + + {stats.total > 0 ? Math.round((stats.winner / stats.total) * 100) : 0}% + + + + + + {/* Search Section */} - + {/* Filters */} - - - - + + + + 참여 경로 - + 상태 - 음식점 - 카페/베이커리 - 소매/편의점 - 미용/뷰티 - 헬스/피트니스 - 학원/교육 - 서비스업 - 기타 - - {businessErrors.businessType && ( - - {businessErrors.businessType.message} - + + ( + )} - - )} - /> - - ( - - )} - /> - - ( - - )} - /> - - - {/* 비밀번호 변경 */} - - - 비밀번호 변경 - + ( + { + const formatted = formatPhoneNumber(e.target.value); + field.onChange(formatted); + }} + error={!!basicErrors.phone} + helperText={basicErrors.phone?.message} + /> + )} + /> - - ( - ( + + )} + /> + + + + + {/* 매장 정보 */} + + + + 매장 정보 + + + + ( + + )} + /> + + ( + + 업종 + + {businessErrors.businessType && ( + + {businessErrors.businessType.message} + + )} + + )} + /> + + ( + + )} + /> + + ( + + )} + /> + + + + + {/* 비밀번호 변경 */} + + + + 비밀번호 변경 + + + + ( + + setShowCurrentPassword(!showCurrentPassword)} + edge="end" + > + {showCurrentPassword ? : } + + + ), + }} + /> + )} + /> + + ( + + setShowNewPassword(!showNewPassword)} + edge="end" + > + {showNewPassword ? : } + + + ), + }} + /> + )} + /> + + ( + + setShowConfirmPassword(!showConfirmPassword)} + edge="end" + > + {showConfirmPassword ? : } + + + ), + }} + /> + )} + /> + + + + + + {/* 액션 버튼 */} + + - - - {/* 액션 버튼 */} - - - - + {/* 저장 완료 다이얼로그 */} - setSuccessDialogOpen(false)}> + setSuccessDialogOpen(false)} + PaperProps={{ + sx: { + borderRadius: 4, + minWidth: 300, + }, + }} + > - + 저장 완료 - + 프로필 정보가 업데이트되었습니다. @@ -496,8 +536,15 @@ export default function ProfilePage() { }} sx={{ minWidth: 120, - py: { xs: 1.25, sm: 1.5 }, - ...getGradientButtonStyle('success'), + py: 2, + borderRadius: 2, + fontSize: '1rem', + fontWeight: 700, + background: `linear-gradient(135deg, ${colors.purple} 0%, ${colors.pink} 100%)`, + '&:hover': { + background: `linear-gradient(135deg, ${colors.purple} 0%, ${colors.pink} 100%)`, + opacity: 0.9, + }, }} > 확인 @@ -506,29 +553,51 @@ export default function ProfilePage() { {/* 로그아웃 확인 다이얼로그 */} - setLogoutDialogOpen(false)}> - 로그아웃 + setLogoutDialogOpen(false)} + PaperProps={{ + sx: { + borderRadius: 4, + minWidth: 300, + }, + }} + > + 로그아웃 - + 로그아웃 하시겠습니까? - + - + ); } From f2d533df09f75fd5d7a48e1b4a36b922478a263d Mon Sep 17 00:00:00 2001 From: cherry2250 Date: Mon, 27 Oct 2025 16:18:46 +0900 Subject: [PATCH 8/8] =?UTF-8?q?ContentEditStep=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EB=94=94=EC=9E=90=EC=9D=B8=20=ED=86=B5=EC=9D=BC=20?= =?UTF-8?q?=EB=B0=8F=20=EC=B9=B4=EB=93=9C=20=ED=81=AC=EA=B8=B0=20=EB=8F=99?= =?UTF-8?q?=EC=9D=BC=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 공통 디자인 시스템에 맞춰 ContentEditStep 페이지를 리디자인하고 미리보기/편집 카드의 높이를 동일하게 조정했습니다. 주요 변경사항: - cardStyles, colors, responsiveText 공통 디자인 시스템 적용 - 페이지 배경: colors.gray[50] - 양쪽 카드에 height: '100%' 추가하여 크기 동일화 - 카드 패딩: p: { xs: 6, sm: 8 }로 통일 - Grid spacing: 6으로 증가 - 헤더 및 섹션 여백 통일 (mb: 10, mb: 6) - 미리보기 아이콘 크기 64px, 색상 purple 적용 - Edit 아이콘 색상 purple 적용 - TextField rows 4로 증가 (참여안내 입력 공간 확대) - 버튼 상단 여백 mt: 10으로 증가 반응형 타이포그래피 적용: - 헤더: responsiveText.h3 - 섹션 제목: responsiveText.h4 - 본문 텍스트: responsiveText.body1, body2 --- .../events/create/steps/ContentEditStep.tsx | 109 ++++++++---------- 1 file changed, 47 insertions(+), 62 deletions(-) diff --git a/src/app/(main)/events/create/steps/ContentEditStep.tsx b/src/app/(main)/events/create/steps/ContentEditStep.tsx index e8d122a..5f8f659 100644 --- a/src/app/(main)/events/create/steps/ContentEditStep.tsx +++ b/src/app/(main)/events/create/steps/ContentEditStep.tsx @@ -11,24 +11,7 @@ import { IconButton, } from '@mui/material'; import { ArrowBack, Edit } from '@mui/icons-material'; - -// 디자인 시스템 색상 -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', - }, -}; +import { cardStyles, colors, responsiveText } from '@/shared/lib/button-styles'; interface ContentEditStepProps { initialTitle: string; @@ -57,71 +40,73 @@ export default function ContentEditStep({ }; return ( - - + + {/* Header */} - - + + - + 콘텐츠 편집 - + {/* Preview Section */} - + 미리보기 - - - - celebration - - - {title || '제목을 입력하세요'} - - - {prize || '경품을 입력하세요'} - - - {guide || '참여 안내를 입력하세요'} - - + + + + + celebration + + + {title || '제목을 입력하세요'} + + + {prize || '경품을 입력하세요'} + + + {guide || '참여 안내를 입력하세요'} + + + {/* Edit Section */} - + 편집 - - - - - + + + + + 텍스트 편집 - + setGuide(e.target.value)} multiline - rows={3} + rows={4} inputProps={{ maxLength: 100 }} helperText={`${guide.length}/100자`} /> @@ -163,7 +148,7 @@ export default function ContentEditStep({ {/* Action Buttons */} - +