전체 코드, 구조 검토 - P1-6 코드 수정 진행

This commit is contained in:
2026-07-04 15:40:33 +09:00
parent 41a246ad7b
commit 2231ac4bfe
5 changed files with 93 additions and 72 deletions
+2 -2
View File
@@ -40,12 +40,12 @@ export const PATCH = withApiHandler<{ id: string }>(
id: maestroExtensionID,
duration: Date.now() - t0,
});
void sendExtensionDoneEmail(
const emailSent = await sendExtensionDoneEmail(
result.maestroName,
result.maestroEmail,
formatDate(result.availableActivateDateTime)
);
return NextResponse.json({ ok: true, availableActivateDateTime: result.availableActivateDateTime });
return NextResponse.json({ ok: true, availableActivateDateTime: result.availableActivateDateTime, emailSent });
}
await cancelExtensionRequest(maestroExtensionID);
+2 -2
View File
@@ -40,7 +40,7 @@ export const PATCH = withApiHandler<{ id: string }>(
id: maestroUpgradeID,
duration: Date.now() - t0,
});
void sendUpgradeDoneEmail(
const emailSent = await sendUpgradeDoneEmail(
result.maestroName,
result.maestroEmail,
result.registeredActivateStatus,
@@ -48,7 +48,7 @@ export const PATCH = withApiHandler<{ id: string }>(
result.requestedAccountType,
formatDate(result.availableActivateDateTime)
);
return NextResponse.json({ ok: true, availableActivateDateTime: result.availableActivateDateTime });
return NextResponse.json({ ok: true, availableActivateDateTime: result.availableActivateDateTime, emailSent });
}
await rejectUpgradeRequest(maestroUpgradeID);
@@ -108,19 +108,16 @@ function ExtensionRequestActions({
const router = useRouter();
const [isPending, startTransition] = useTransition();
const [errorMessage, setErrorMessage] = useState("");
const [emailWarning, setEmailWarning] = useState(false);
const isRequested = request.status === REQUEST_STATUSES.REQUESTED;
if (!isRequested) {
if (!isRequested && !emailWarning) {
return <span className="text-xs text-muted-foreground"> </span>;
}
async function submitAction(action: "approve" | "cancel") {
const actionLabel = action === "approve" ? "승인" : "취소";
const confirmed = window.confirm(
`${request.maestroName} 연장 신청을 ${actionLabel}하시겠습니까?`
);
if (!confirmed) {
if (!window.confirm(`${request.maestroName} 연장 신청을 ${actionLabel}하시겠습니까?`)) {
return;
}
@@ -136,14 +133,19 @@ function ExtensionRequestActions({
}
);
if (!response.ok) {
const body = (await response.json().catch(() => null)) as {
message?: string;
emailSent?: boolean;
} | null;
if (!response.ok) {
throw new Error(body?.message ?? "연장 신청 처리에 실패했습니다.");
}
if (action === "approve" && body?.emailSent === false) {
setEmailWarning(true);
}
startTransition(() => {
router.refresh();
});
@@ -158,6 +160,7 @@ function ExtensionRequestActions({
return (
<div className="space-y-2">
{isRequested ? (
<div className="flex items-center gap-2">
<Button
disabled={isPending}
@@ -179,6 +182,14 @@ function ExtensionRequestActions({
</Button>
</div>
) : (
<span className="text-xs text-muted-foreground"> </span>
)}
{emailWarning ? (
<p className="max-w-56 text-xs text-amber-600 dark:text-amber-400">
</p>
) : null}
{errorMessage ? (
<p className="max-w-56 text-xs text-destructive">{errorMessage}</p>
) : null}
@@ -113,19 +113,16 @@ function UpgradeRequestActions({
const router = useRouter();
const [isPending, startTransition] = useTransition();
const [errorMessage, setErrorMessage] = useState("");
const [emailWarning, setEmailWarning] = useState(false);
const isRequested = request.status === REQUEST_STATUSES.REQUESTED;
if (!isRequested) {
if (!isRequested && !emailWarning) {
return <span className="text-xs text-muted-foreground"> </span>;
}
async function submitAction(action: "approve" | "reject") {
const actionLabel = action === "approve" ? "승인" : "거절";
const confirmed = window.confirm(
`${request.maestroName} 업그레이드 신청을 ${actionLabel}하시겠습니까?`
);
if (!confirmed) {
if (!window.confirm(`${request.maestroName} 업그레이드 신청을 ${actionLabel}하시겠습니까?`)) {
return;
}
@@ -141,14 +138,17 @@ function UpgradeRequestActions({
}
);
if (!response.ok) {
const body = (await response.json().catch(() => null)) as {
message?: string;
emailSent?: boolean;
} | null;
throw new Error(
body?.message ?? "업그레이드 신청 처리에 실패했습니다."
);
if (!response.ok) {
throw new Error(body?.message ?? "업그레이드 신청 처리에 실패했습니다.");
}
if (action === "approve" && body?.emailSent === false) {
setEmailWarning(true);
}
startTransition(() => {
@@ -165,6 +165,7 @@ function UpgradeRequestActions({
return (
<div className="space-y-2">
{isRequested ? (
<div className="flex items-center gap-2">
<Button
disabled={isPending}
@@ -186,6 +187,14 @@ function UpgradeRequestActions({
</Button>
</div>
) : (
<span className="text-xs text-muted-foreground"> </span>
)}
{emailWarning ? (
<p className="max-w-56 text-xs text-amber-600 dark:text-amber-400">
</p>
) : null}
{errorMessage ? (
<p className="max-w-56 text-xs text-destructive">{errorMessage}</p>
) : null}
+4 -3
View File
@@ -168,9 +168,10 @@
- P1-5: `request_extension_maestro` / `request_upgrade_maestro` 로그 추가
- P1-7: 관리자 대행 등록 시 입금 메일 미발송 — 의도 확인, AGENTS.md에 명시
- P2-10: 신청 시점 스냅샷 유지 — 변경 없음
3. **Step 3 (P1-6 이메일 + 검증)**
- emailSent 응답 + UI 경고, stage에서 연장/업그레이드(체험→유료, 유료→유료) 메일 실측
(phase11 잔여 항목 겸)
3. **Step 3 (P1-6 이메일 + 검증) ✅ 완료 (2026-07-04)**
- API route 2곳: `void sendXxxDoneEmail``await emailSent`, 응답에 `emailSent: boolean` 포함
- 테이블 UI 2곳: 응답 body를 단일 파싱으로 통일, 승인 성공 후 `emailSent === false`이면 인라인 경고 표시 (`router.refresh()` 후에도 client state 유지됨)
- stage 실측(체험→유료, 유료→유료 메일 검증)은 별도 수동 테스트 항목으로 남김
4. **Step 4 (P2 일괄)**
- 소규모 항목 묶음 처리 후 AGENTS.md / phase 문서 갱신