// Screens 5: 신고·차단·안전센터, 인증·수상 내역 관리, 기관 관리자 대시보드, 운영자 콘솔
const A5 = window.MajorAtoms;
const D5 = window.MajorLinkData;
const D5b = window.MajorLinkData2;
const Lc5 = window.lucideReact || {};
const { useState: useS5 } = React;
const BORDER5 = '#E4E4E7';
const MUTE5 = '#475569';
const FAINT5 = '#94A3B8';
function TextInput5(props) {
return ;
}
function SummaryCard5({ n, l }) {
return (
);
}
function BarRow5({ name, count, max }) {
return (
);
}
// ============================== ScreenSafety ==============================
const REPORT_REASONS = ['스팸 · 광고성 내용', '사기 · 허위 정보', '무단 노쇼 (연락 없이 불참)', '부적절한 언어 · 행동', '기타'];
function ScreenSafety({ device, animKey }) {
const isM = device === 'mobile';
const [reports, setReports] = useS5(() => D5b.REPORTS.map(r => ({ ...r })));
const [blocked, setBlocked] = useS5(() => [...D5b.BLOCKED_USERS]);
const [targetId, setTargetId] = useS5(D5.APPLICANTS[7].id);
const [reason, setReason] = useS5('');
const [detail, setDetail] = useS5('');
const submit = () => {
if (!reason) return;
const id = 'rp' + Date.now();
setReports(rs => [{ id, applicantId: targetId, reason, detail, status: 'reviewing', createdAt: '방금' }, ...rs]);
setReason(''); setDetail('');
setTimeout(() => setReports(rs => rs.map(r => r.id === id ? { ...r, status: 'resolved' } : r)), 3000);
};
return (
허위 신고가 확인되면 계정 제재로 이어질 수 있어요
{reports.map(r => {
const a = D5.APPLICANTS.find(x => x.id === r.applicantId);
return (
{a.name} · {r.reason}
{r.createdAt}
{r.status === 'resolved' ? '처리완료' : '검토중'}
);
})}
{blocked.length === 0 ? (
차단한 사용자가 없어요
) : blocked.map(id => {
const a = D5.APPLICANTS.find(x => x.id === id);
return (
{a.name}
);
})}
);
}
// ============================== ScreenVerifications ==============================
const VKIND_ICON = { edu: '🎓', award: '🏆' };
const VSTATUS_TONE = { approved: 'lime', ai_checking: 'amber', rejected: 'rose' };
const VSTATUS_LABEL = { approved: '승인됨', ai_checking: 'AI 검증중', rejected: '반려됨' };
function ScreenVerifications({ device, animKey }) {
const isM = device === 'mobile';
const [list, setList] = useS5(() => D5b.MY_VERIFICATIONS.map(v => ({ ...v })));
const [adding, setAdding] = useS5(false);
const [title, setTitle] = useS5('');
const addVerification = () => {
if (!title.trim()) return;
const id = 'new' + Date.now();
setList(l => [{ id, kind: 'award', title: title.trim(), sub: 'AI가 진위를 확인하는 중이에요', status: 'ai_checking', method: 'ai' }, ...l]);
setTitle(''); setAdding(false);
setTimeout(() => setList(l => l.map(v => v.id === id ? { ...v, status: 'approved', sub: '🤖 AI 자동 승인됨' } : v)), 2500);
};
const approved = list.filter(v => v.status === 'approved');
return (
setAdding(a => !a)} className="text-[11.5px] font-semibold rounded-lg border px-2.5 py-1" style={{ borderColor: BORDER5, color: '#4F46E5' }}>+ 새 인증 추가
}>
{adding && (
setTitle(e.target.value)} onKeyDown={e => e.key === 'Enter' && addVerification()} />
)}
{list.map(v => (
{VKIND_ICON[v.kind]}
{VSTATUS_LABEL[v.status]}
))}
수상 및 인증
{approved.map(v => (
✓
{v.title}
))}
AI가 진위를 확인해 통과시킨 인증만 포트폴리오 하단에 자동으로 노출돼요. AI 검증중·반려된 항목은 노출되지 않아요.
);
}
// ============================== ScreenOrg ==============================
function ScreenOrg({ device, animKey }) {
const isM = device === 'mobile';
const [sortBy, setSortBy] = useS5('dday');
const projects = [...D5.PROJECTS].sort((a, b) => sortBy === 'dday' ? a.dday - b.dday : b.id - a.id);
const maxDept = Math.max(...D5b.ORG_DEPT_STATS.map(d => d.count));
return (
기관 관리자 대시보드
{D5b.ORG_INFO.name}
{D5b.ORG_DEPT_STATS.map(d => )}
{[['dday', '마감임박순'], ['id', '최신순']].map(([k, l]) => (
))}
}>
{projects.map(p => (
{p.title}
{p.leader}
{p.filled}/{p.total}명
D-{p.dday}
))}
);
}
// ============================== ScreenAdmin ==============================
function ScreenAdmin({ device, animKey }) {
const isM = device === 'mobile';
const [queue, setQueue] = useS5(() => D5b.ADMIN_QUEUE.map(q => ({ ...q })));
const resolve = (id) => setQueue(q => q.filter(x => x.id !== id));
return (
서비스 운영자 콘솔
{queue.length === 0 ? (
처리할 신고가 없어요 🎉
) : (
{queue.map(q => (
{q.from} → {q.to} · {q.reason}
))}
)}
{D5b.ADMIN_PAYMENTS.map((p, i) => (
{p.date}
{p.user}
{p.plan}
{p.amount.toLocaleString()}원
))}
);
}
window.MajorScreens5 = { ScreenSafety, ScreenVerifications, ScreenOrg, ScreenAdmin };