Files
hanarang-dashboard/frontend/components/admin/ConfirmModal.tsx
narang-ai 033c142c0e feat(sprint-004): admin features + API auth guard
Sprint 003 non-blocking 처리:
- API Key Guard (passport-http-bearer) + AuthModule
- Helmet 적용 (main.ts)
- SisterNamePipe - name 파라미터 Controller 검증
- lib/sisters.ts - formatLastSeen/sisterEmojis/sisterDisplayNames 공통 추출

Sprint 004 본문:
- TASK-012: POST /api/admin/sisters/:name/{restart,reset} (ApiKeyGuard 적용)
- TASK-013: GET/PUT /api/admin/harness/:name/:file (허용 파일 allowlist)
- TASK-015: GET /api/admin/logs/:name
- 관리자 전 API @UseGuards(ApiKeyGuard)
- TASK-014: /admin 자매 관리 (재시작/리셋 + ConfirmModal)
- TASK-014: /admin/harness 하네스 편집 (CodeEditor + 파일트리)
- TASK-015: /admin/logs 로그 뷰어 (LogTerminal + 검색/에러필터)
- /admin/repos 저장소 목록
- AdminLayout (API Key 로컬스토리지 저장)
- 테스트 22/22 pass, FE 11 routes build 성공
2026-04-04 12:11:06 +09:00

116 lines
2.4 KiB
TypeScript

'use client';
import React from 'react';
import styled from 'styled-components';
import { theme } from '@/styles/theme';
interface ConfirmModalProps {
title: string;
message: string;
confirmLabel?: string;
danger?: boolean;
onConfirm: () => void;
onCancel: () => void;
}
const Overlay = styled.div`
position: fixed;
inset: 0;
background: rgba(0,0,0,0.6);
z-index: 300;
display: flex;
align-items: center;
justify-content: center;
`;
const Modal = styled.div`
background: #161b22;
border: 1px solid ${theme.colors.border};
border-radius: 12px;
padding: 28px;
min-width: 320px;
max-width: 480px;
box-shadow: 0 20px 60px rgba(0,0,0,0.6);
`;
const Title = styled.h2`
font-size: 16px;
font-weight: 700;
color: ${theme.colors.textPrimary};
margin-bottom: 10px;
`;
const Message = styled.p`
font-size: 14px;
color: ${theme.colors.textSecondary};
line-height: 1.6;
margin-bottom: 24px;
`;
const Buttons = styled.div`
display: flex;
gap: 10px;
justify-content: flex-end;
`;
const Btn = styled.button<{ $danger?: boolean; $primary?: boolean }>`
padding: 8px 18px;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
border: 1px solid;
transition: all 0.15s;
${({ $danger }) =>
$danger &&
`
background: rgba(255,23,68,0.12);
border-color: rgba(255,23,68,0.4);
color: #FF1744;
&:hover { background: rgba(255,23,68,0.2); }
`}
${({ $primary }) =>
$primary &&
`
background: rgba(88,166,255,0.12);
border-color: rgba(88,166,255,0.4);
color: #58A6FF;
&:hover { background: rgba(88,166,255,0.2); }
`}
${({ $danger, $primary }) =>
!$danger && !$primary &&
`
background: transparent;
border-color: rgba(240,246,252,0.15);
color: #8B949E;
&:hover { background: rgba(240,246,252,0.06); color: #E6EDF3; }
`}
`;
export default function ConfirmModal({
title,
message,
confirmLabel = '확인',
danger,
onConfirm,
onCancel,
}: ConfirmModalProps) {
return (
<Overlay onClick={onCancel}>
<Modal onClick={(e) => e.stopPropagation()}>
<Title>{title}</Title>
<Message>{message}</Message>
<Buttons>
<Btn onClick={onCancel}></Btn>
<Btn $danger={danger} $primary={!danger} onClick={onConfirm}>
{confirmLabel}
</Btn>
</Buttons>
</Modal>
</Overlay>
);
}