Files
startover/apps/web/src/app/stores/new/actions.ts
T
chpark df7857a8ef
Deploy Startover / deploy (push) Failing after 0s
feat: 블로그·정보 페이지 추가 및 매매정보 도메인 확장
AdSense 승인을 위한 콘텐츠 인프라와 점포라인형 매매 정보 모델을 도입.

- 업종 분류 확장: 7개 대분류(휴게음식점/일반음식점/주류점/오락스포츠/판매업/서비스업/기타업종) 하위 소분류
- StoreSale 모델 추가: 월매출·월수익·창업비용·매물설명·입지특징·매매사유
- 매장 검색 카드 재설계(대표 사진 + 권리금 + 월수익), 등록/상세 페이지 매매정보 섹션
- 블로그 시스템: 17개 포스트(폐업/창업/지원금/인테리어), /blog, /blog/[slug]
- 정보 페이지: /about, /terms, /privacy, /faq, /contact
- SEO: sitemap.ts, robots.ts, 페이지별 메타데이터, Article·FAQ JSON-LD, OG 태그
- 주소 라벨 도로명 주소 → 주소

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 10:52:21 +09:00

146 lines
5.4 KiB
TypeScript

'use server';
import { redirect } from 'next/navigation';
import { createPrismaClient } from '@startover/database';
import { auth } from '@/lib/auth';
import { createStoreDraftService } from '@/services/store-service';
import type { CreateStoreDraftInput } from '@startover/domain';
export type StoreFormState = {
error?: string;
fieldValues?: {
listingTitle?: string;
regionClusterCode?: string;
industryMajorCode?: string;
industryLeafCode?: string;
roadAddress?: string;
depositAmount?: string;
monthlyRentAmount?: string;
premiumAmount?: string;
remainingLeaseMonths?: string;
monthlySalesAmount?: string;
monthlyProfitAmount?: string;
startupCostAmount?: string;
listingDescription?: string;
locationHighlight?: string;
saleReason?: string;
exclusiveAreaSqm?: string;
floorLevel?: string;
kitchenEquipmentSummary?: string;
};
};
export async function createStoreDraftAction(
_prevState: StoreFormState,
formData: FormData,
): Promise<StoreFormState> {
const listingTitle = (formData.get('listingTitle') as string | null)?.trim() ?? '';
const regionClusterCode = (formData.get('regionClusterCode') as string | null) ?? '';
const industryMajorCode = (formData.get('industryMajorCode') as string | null) ?? '';
const industryLeafCode = (formData.get('industryLeafCode') as string | null) ?? '';
const roadAddress = (formData.get('roadAddress') as string | null)?.trim() ?? '';
const depositAmount = formData.get('depositAmount') as string | null;
const monthlyRentAmount = formData.get('monthlyRentAmount') as string | null;
const premiumAmount = formData.get('premiumAmount') as string | null;
const remainingLeaseMonths = formData.get('remainingLeaseMonths') as string | null;
const monthlySalesAmount = formData.get('monthlySalesAmount') as string | null;
const monthlyProfitAmount = formData.get('monthlyProfitAmount') as string | null;
const startupCostAmount = formData.get('startupCostAmount') as string | null;
const listingDescription =
(formData.get('listingDescription') as string | null)?.trim() ?? '';
const locationHighlight =
(formData.get('locationHighlight') as string | null)?.trim() ?? '';
const saleReason = (formData.get('saleReason') as string | null)?.trim() ?? '';
const exclusiveAreaSqm = formData.get('exclusiveAreaSqm') as string | null;
const floorLevel = formData.get('floorLevel') as string | null;
const kitchenEquipmentSummary =
(formData.get('kitchenEquipmentSummary') as string | null)?.trim() ?? '';
const fieldValues = {
listingTitle,
regionClusterCode,
industryMajorCode,
industryLeafCode,
roadAddress,
depositAmount: depositAmount ?? undefined,
monthlyRentAmount: monthlyRentAmount ?? undefined,
premiumAmount: premiumAmount ?? undefined,
remainingLeaseMonths: remainingLeaseMonths ?? undefined,
monthlySalesAmount: monthlySalesAmount ?? undefined,
monthlyProfitAmount: monthlyProfitAmount ?? undefined,
startupCostAmount: startupCostAmount ?? undefined,
listingDescription,
locationHighlight,
saleReason,
exclusiveAreaSqm: exclusiveAreaSqm ?? undefined,
floorLevel: floorLevel ?? undefined,
kitchenEquipmentSummary,
};
const session = await auth();
if (!session?.user?.dbId) {
return { error: '로그인이 필요합니다.', fieldValues };
}
const hasSale =
premiumAmount ||
monthlySalesAmount ||
monthlyProfitAmount ||
startupCostAmount ||
listingDescription ||
locationHighlight ||
saleReason;
const input: CreateStoreDraftInput = {
ownerUserId: session.user.dbId,
listingTitle,
industryLeafCode,
regionClusterCode,
roadAddress,
...(depositAmount || monthlyRentAmount || premiumAmount || remainingLeaseMonths
? {
lease: {
depositAmount: depositAmount ? Number(depositAmount) : 0,
monthlyRentAmount: monthlyRentAmount ? Number(monthlyRentAmount) : 0,
premiumAmount: premiumAmount ? Number(premiumAmount) : 0,
remainingLeaseMonths: remainingLeaseMonths
? parseInt(remainingLeaseMonths, 10)
: undefined,
},
}
: {}),
...(hasSale
? {
sale: {
premiumAmount: premiumAmount ? Number(premiumAmount) : undefined,
monthlySalesAmount: monthlySalesAmount ? Number(monthlySalesAmount) : undefined,
monthlyProfitAmount: monthlyProfitAmount ? Number(monthlyProfitAmount) : undefined,
startupCostAmount: startupCostAmount ? Number(startupCostAmount) : undefined,
listingDescription: listingDescription || undefined,
locationHighlight: locationHighlight || undefined,
saleReason: saleReason || undefined,
},
}
: {}),
...(exclusiveAreaSqm || floorLevel || kitchenEquipmentSummary
? {
facility: {
exclusiveAreaSqm: exclusiveAreaSqm ? Number(exclusiveAreaSqm) : 0,
seatCount: 0,
floorLevel: floorLevel ? parseInt(floorLevel, 10) : undefined,
kitchenEquipmentSummary: kitchenEquipmentSummary || undefined,
},
}
: {}),
};
const prisma = createPrismaClient();
const result = await createStoreDraftService(prisma, input);
if (!result.ok) {
return { error: result.error.message, fieldValues };
}
redirect(`/stores/${result.value.publicId}`);
}