8.7 제휴문의: 접수 폼/관리자 승인 워크플로우/알림 o

This commit is contained in:
koreacomp5
2025-10-09 17:43:24 +09:00
parent 9fb4b0c783
commit 66a68c2bfa
7 changed files with 85 additions and 2 deletions

View File

@@ -0,0 +1,14 @@
-- CreateTable
CREATE TABLE "partner_inquiries" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"contact" TEXT NOT NULL,
"category" TEXT,
"message" TEXT NOT NULL,
"status" TEXT NOT NULL DEFAULT 'pending',
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"approvedAt" DATETIME
);
-- CreateIndex
CREATE INDEX "partner_inquiries_status_createdAt_idx" ON "partner_inquiries"("status", "createdAt");

View File

@@ -631,3 +631,18 @@ model Partner {
@@index([category])
@@map("partners")
}
// 제휴 문의
model PartnerInquiry {
id String @id @default(cuid())
name String
contact String
category String?
message String
status String @default("pending") // pending/approved/rejected
createdAt DateTime @default(now())
approvedAt DateTime?
@@index([status, createdAt])
@@map("partner_inquiries")
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 706 KiB

After

Width:  |  Height:  |  Size: 727 KiB

View File

@@ -0,0 +1,10 @@
import { NextResponse } from "next/server";
import prisma from "@/lib/prisma";
export async function POST(_: Request, context: { params: Promise<{ id: string }> }) {
const { id } = await context.params;
const updated = await prisma.partnerInquiry.update({ where: { id }, data: { status: "approved", approvedAt: new Date() } });
return NextResponse.json({ inquiry: updated });
}

View File

@@ -0,0 +1,20 @@
import { NextResponse } from "next/server";
import prisma from "@/lib/prisma";
import { z } from "zod";
const schema = z.object({ name: z.string().min(1), contact: z.string().min(1), category: z.string().optional(), message: z.string().min(1) });
export async function POST(req: Request) {
const body = await req.json().catch(() => ({}));
const parsed = schema.safeParse(body);
if (!parsed.success) return NextResponse.json({ error: parsed.error.flatten() }, { status: 400 });
const created = await prisma.partnerInquiry.create({ data: parsed.data });
return NextResponse.json({ inquiry: created }, { status: 201 });
}
export async function GET() {
const items = await prisma.partnerInquiry.findMany({ orderBy: { createdAt: "desc" } });
return NextResponse.json({ inquiries: items });
}

View File

@@ -0,0 +1,24 @@
"use client";
import { useState } from "react";
export default function PartnerInquiryPage() {
const [form, setForm] = useState({ name: "", contact: "", category: "", message: "" });
const [done, setDone] = useState(false);
async function submit() {
const r = await fetch("/api/partner-inquiries", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(form) });
setDone(r.ok);
}
if (done) return <div>. .</div>;
return (
<div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
<h1> </h1>
<input placeholder="업체명" value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })} />
<input placeholder="연락처/이메일" value={form.contact} onChange={(e) => setForm({ ...form, contact: e.target.value })} />
<input placeholder="카테고리(선택)" value={form.category} onChange={(e) => setForm({ ...form, category: e.target.value })} />
<textarea placeholder="문의 내용" value={form.message} onChange={(e) => setForm({ ...form, message: e.target.value })} rows={8} />
<button onClick={submit}></button>
</div>
);
}

View File

@@ -58,7 +58,7 @@
8.4 무료쿠폰: 쿠폰 등록/재고/사용 처리/만료/1인 제한/로그 o
8.5 월간집계: 월별 지표 산출 배치/차트/다운로드(CSV) o
8.6 주변 제휴업체: 위치 기반 목록/지도/필터(거리/카테고리) o
8.7 제휴문의: 접수 폼/관리자 승인 워크플로우/알림
8.7 제휴문의: 접수 폼/관리자 승인 워크플로우/알림 o
8.8 제휴업소 요청: 요청 생성/승인/상태 관리/이력
[에디터/업로드]