Files
webflash/platform/frontend/src/pages/Dashboard/Index.jsx
root bdef4b7ae0 feat: add ESP32 DIY platform Phase 1 (marketplace scaffold)
- Docker Compose with Postgres, Redis, MinIO, backend, frontend (port 3200/3201)
- Prisma schema: User, Project, ProjectFile, Product, Order, FlashToken, Review, AuditLog
- Backend: JWT auth, project CRUD + file upload (MinIO + sharp WebP), admin approval flow
- Frontend: React + Vite SPA with auth, project/shop browse, seller dashboard, admin panel
- Admin: pending approval queue, user management, audit log viewer, stats dashboard
- Audit logging middleware for legal compliance
- Admin init script: createAdmin.js
- Full design document in PLATFORM_DESIGN.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 06:05:46 +09:00

76 lines
3.1 KiB
JavaScript

import { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import { useAuth } from '../../hooks/useAuth';
import api from '../../api/client';
const STATUS_BADGE = {
draft: <span className="badge badge-draft">임시저장</span>,
pending: <span className="badge badge-pending">검토 대기</span>,
approved: <span className="badge badge-approved">승인됨</span>,
rejected: <span className="badge badge-rejected">반려됨</span>,
suspended: <span className="badge badge-suspended">정지됨</span>,
};
export default function Dashboard() {
const { user } = useAuth();
const [projects, setProjects] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
api.get('/projects/my/list')
.then(r => setProjects(r.data))
.catch(() => {})
.finally(() => setLoading(false));
}, []);
return (
<div className="container page">
<div className="flex items-center justify-between" style={{ marginBottom: 24 }}>
<div>
<h2 style={{ fontSize: 22 }}> 대시보드</h2>
<p className="text-muted" style={{ marginTop: 4 }}>안녕하세요, {user?.nickname}</p>
</div>
<Link to="/dashboard/projects/new" className="btn btn-primary">+ 프로젝트</Link>
</div>
<div style={{ display: 'flex', gap: 12, marginBottom: 16 }}>
<Link to="/dashboard/projects/new" className="btn btn-outline btn-sm">프로젝트 등록</Link>
<Link to="/dashboard/orders" className="btn btn-outline btn-sm">구매 내역</Link>
<Link to="/dashboard/sales" className="btn btn-outline btn-sm">판매 내역</Link>
</div>
<h3 style={{ marginBottom: 16 }}> 프로젝트</h3>
{loading ? <div className="spinner" /> : (
projects.length === 0 ? (
<div className="card text-center" style={{ padding: 48 }}>
<p className="text-muted">등록한 프로젝트가 없습니다.</p>
<Link to="/dashboard/projects/new" className="btn btn-primary" style={{ marginTop: 16 }}> 프로젝트 등록</Link>
</div>
) : (
<div className="table-wrap">
<table>
<thead>
<tr><th>제목</th><th></th><th></th><th></th><th></th><th></th></tr>
</thead>
<tbody>
{projects.map(p => (
<tr key={p.id}>
<td>{p.title}</td>
<td>{STATUS_BADGE[p.status] || p.status}</td>
<td>{p.product ? `${p.product.price.toLocaleString()}` : '-'}</td>
<td>{p.product?.totalSales ?? '-'}</td>
<td className="text-muted">{new Date(p.createdAt).toLocaleDateString('ko-KR')}</td>
<td>
<Link to={`/dashboard/projects/${p.id}`} className="btn btn-outline btn-sm">관리</Link>
</td>
</tr>
))}
</tbody>
</table>
</div>
)
)}
</div>
);
}