전체 코드, 구조 검토 - P1-6 코드 수정 진행
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 문서 갱신
|
||||
|
||||
|
||||
Reference in New Issue
Block a user