fix: 매장 등록 폼 검증 실패 시 입력값 보존

서버 검증 에러 발생 시 fieldValues를 반환하고
각 입력 필드에 defaultValue로 바인딩하여 사용자 입력 유지
This commit is contained in:
Johngreen
2026-03-09 07:40:11 +09:00
parent cfcb694a01
commit 12f142ac74
2 changed files with 44 additions and 6 deletions
+33 -6
View File
@@ -8,17 +8,25 @@ import type { CreateStoreDraftInput } from '@startover/domain';
export type StoreFormState = {
error?: string;
fieldValues?: {
listingTitle?: string;
regionClusterCode?: string;
industryLeafCode?: string;
roadAddress?: string;
depositAmount?: string;
monthlyRentAmount?: string;
premiumAmount?: string;
remainingLeaseMonths?: string;
exclusiveAreaSqm?: string;
floorLevel?: string;
kitchenEquipmentSummary?: string;
};
};
export async function createStoreDraftAction(
_prevState: StoreFormState,
formData: FormData,
): Promise<StoreFormState> {
const session = await auth();
if (!session?.user?.dbId) {
return { error: '로그인이 필요합니다.' };
}
const listingTitle = (formData.get('listingTitle') as string | null)?.trim() ?? '';
const regionClusterCode = (formData.get('regionClusterCode') as string | null) ?? '';
const industryLeafCode = (formData.get('industryLeafCode') as string | null) ?? '';
@@ -32,6 +40,25 @@ export async function createStoreDraftAction(
const kitchenEquipmentSummary =
(formData.get('kitchenEquipmentSummary') as string | null)?.trim() ?? '';
const fieldValues = {
listingTitle,
regionClusterCode,
industryLeafCode,
roadAddress,
depositAmount: depositAmount ?? undefined,
monthlyRentAmount: monthlyRentAmount ?? undefined,
premiumAmount: premiumAmount ?? undefined,
remainingLeaseMonths: remainingLeaseMonths ?? undefined,
exclusiveAreaSqm: exclusiveAreaSqm ?? undefined,
floorLevel: floorLevel ?? undefined,
kitchenEquipmentSummary,
};
const session = await auth();
if (!session?.user?.dbId) {
return { error: '로그인이 필요합니다.', fieldValues };
}
const input: CreateStoreDraftInput = {
ownerUserId: session.user.dbId,
listingTitle,
@@ -66,7 +93,7 @@ export async function createStoreDraftAction(
const result = await createStoreDraftService(prisma, input);
if (!result.ok) {
return { error: result.error.message };
return { error: result.error.message, fieldValues };
}
redirect(`/stores/${result.value.publicId}`);
+11
View File
@@ -40,6 +40,7 @@ export default function NewStorePage() {
name="listingTitle"
placeholder="예: 강남역 카페 양도"
required
defaultValue={state.fieldValues?.listingTitle}
className="mt-1 w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 focus:outline-none"
/>
</div>
@@ -49,6 +50,7 @@ export default function NewStorePage() {
<select
name="regionClusterCode"
required
defaultValue={state.fieldValues?.regionClusterCode}
className="mt-1 w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
>
<option value=""> </option>
@@ -61,6 +63,7 @@ export default function NewStorePage() {
<select
name="industryLeafCode"
required
defaultValue={state.fieldValues?.industryLeafCode}
className="mt-1 w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
>
<option value=""> </option>
@@ -78,6 +81,7 @@ export default function NewStorePage() {
name="roadAddress"
placeholder="예: 서울시 강남구 테헤란로 123"
required
defaultValue={state.fieldValues?.roadAddress}
className="mt-1 w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 focus:outline-none"
/>
</div>
@@ -95,6 +99,7 @@ export default function NewStorePage() {
type="number"
name="depositAmount"
placeholder="50000000"
defaultValue={state.fieldValues?.depositAmount}
className="mt-1 w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 focus:outline-none"
/>
</div>
@@ -104,6 +109,7 @@ export default function NewStorePage() {
type="number"
name="monthlyRentAmount"
placeholder="3000000"
defaultValue={state.fieldValues?.monthlyRentAmount}
className="mt-1 w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 focus:outline-none"
/>
</div>
@@ -115,6 +121,7 @@ export default function NewStorePage() {
type="number"
name="premiumAmount"
placeholder="30000000"
defaultValue={state.fieldValues?.premiumAmount}
className="mt-1 w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 focus:outline-none"
/>
</div>
@@ -126,6 +133,7 @@ export default function NewStorePage() {
type="number"
name="remainingLeaseMonths"
placeholder="18"
defaultValue={state.fieldValues?.remainingLeaseMonths}
className="mt-1 w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 focus:outline-none"
/>
</div>
@@ -145,6 +153,7 @@ export default function NewStorePage() {
name="exclusiveAreaSqm"
placeholder="82.6"
step="0.01"
defaultValue={state.fieldValues?.exclusiveAreaSqm}
className="mt-1 w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 focus:outline-none"
/>
</div>
@@ -154,6 +163,7 @@ export default function NewStorePage() {
type="number"
name="floorLevel"
placeholder="1"
defaultValue={state.fieldValues?.floorLevel}
className="mt-1 w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 focus:outline-none"
/>
</div>
@@ -164,6 +174,7 @@ export default function NewStorePage() {
rows={3}
name="kitchenEquipmentSummary"
placeholder="주방 시설, 인테리어 상태, 포함 장비 등을 자유롭게 작성해주세요"
defaultValue={state.fieldValues?.kitchenEquipmentSummary}
className="mt-1 w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 focus:outline-none"
/>
</div>