File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
'use client';
import { useActionState, useEffect, useRef, useState } from 'react';
import { FoxButton } from '@fox/core/components/fox-button';
import { FoxHelperText } from '@fox/core/components/fox-helper-text';
import { FoxInput } from '@fox/core/components/fox-input';
import { FoxModal } from '@fox/core/components/fox-modal';
import { FoxSelect } from '@fox/core/components/fox-select';
import { FoxTextArea } from '@fox/core/components/fox-text-area';
import { submitFormAction } from '@/app/_hooks/submit-form-action';
import { useFeedback } from '@/app/_hooks/use-feedback';
import {
formatInquiryTypeLabel,
formatOptionalValue,
type BoardPost,
} from '@/lib/domain/board-post';
import {
ANSWER_MAX_LENGTH,
INITIAL_INQUIRY_ANSWER_FORM_STATE,
} from '@/lib/domain/board-post-form';
import type { CommonCode } from '@/lib/domain/common-code';
import { saveInquiryAnswerAction } from '../../_actions';
import { BoardAttachmentField } from '../../_components/board-attachment-field';
import styles from './inquiry-answer-modal.module.scss';
interface InquiryAnswerModalProps {
post: BoardPost;
/** 공통코드 `BBS_ANS_CD` — 진행상태 선택지. */
answerStatuses: readonly CommonCode[];
onClose: () => void;
}
const STATUS_HELP_TEXT =
'답변완료 선택 시에만 FO(사용자 화면)에 답변 내용 노출, 목록에 답변일도 표시.';
/**
* 이슈: 기획의 "답변완료 시 앱푸쉬 전송"은 백엔드 푸시 분기가 빈 블록이라 동작하지 않는다.
* 이슈: 백엔드 첨부 필드가 `atchFileId` 하나뿐이라 질문 첨부와 답변 첨부가 같은 자리를 쓴다.
*/
export function InquiryAnswerModal({
post,
answerStatuses,
onClose,
}: InquiryAnswerModalProps) {
const { showToast } = useFeedback();
const formRef = useRef<HTMLFormElement>(null);
const [statusCode, setStatusCode] = useState(
post.answerStatusCode ?? answerStatuses[0]?.code ?? ''
);
const [state, formAction, isPending] = useActionState(
saveInquiryAnswerAction,
INITIAL_INQUIRY_ANSWER_FORM_STATE
);
useEffect(() => {
if (state.status === 'success') {
showToast({ variant: 'success', message: '답변을 저장했습니다.' });
onClose();
}
}, [state, showToast, onClose]);
const errors = state.status === 'error' ? (state.errors ?? {}) : {};
return (
<FoxModal
open
size="md"
title="1:1문의 상세 및 답변"
onClose={onClose}
actions={
<>
<FoxButton type="default" size="md" label="취소" onAction={onClose} />
<FoxButton
type="primary"
size="md"
label="저장"
loading={isPending}
onAction={() => formRef.current?.requestSubmit()}
/>
</>
}
>
<form
ref={formRef}
onSubmit={(event) => submitFormAction(event, formAction)}
className={styles.fields}
>
<input type="hidden" name="id" value={post.id} />
<div className={styles.field}>
<FoxInput
size="md"
label="질문유형"
value={post.typeName ?? formatInquiryTypeLabel(post.typeCode)}
readOnly
/>
</div>
<p className={styles.sectionTitle}>게시물의 항목 (조회 전용)</p>
<div className={styles.field}>
<div className={styles.pair}>
<FoxInput
size="md"
label="질문자명"
value={formatOptionalValue(post.authorName)}
readOnly
/>
<FoxInput
size="md"
label="작성일"
value={formatOptionalValue(post.createdAt)}
readOnly
/>
</div>
</div>
<div className={styles.field}>
<div className={styles.pair}>
<FoxInput
size="md"
label="이메일"
value={formatOptionalValue(post.authorEmail)}
readOnly
/>
<FoxInput
size="md"
label="전화번호"
value={formatOptionalValue(post.authorPhoneNumber)}
readOnly
/>
</div>
</div>
<div className={styles.field}>
<FoxTextArea
label="질문내용"
value={post.content}
readOnly
rows={4}
/>
</div>
<div className={styles.field}>
<FoxSelect
size="md"
label="진행상태"
requirement="required"
options={answerStatuses.map((status) => ({
value: status.code,
label: status.label,
}))}
value={statusCode}
onValueChange={setStatusCode}
error={Boolean(errors.answerStatusCode)}
hint={errors.answerStatusCode ?? STATUS_HELP_TEXT}
/>
<input type="hidden" name="answerStatusCode" value={statusCode} />
</div>
<div className={styles.field}>
<FoxTextArea
name="answerContent"
label="답변내용"
defaultValue={post.answerContent ?? ''}
maxLength={ANSWER_MAX_LENGTH}
counter
rows={4}
placeholder="답변 내용을 입력하세요."
invalid={Boolean(errors.answerContent)}
message={errors.answerContent}
/>
</div>
<div className={styles.field}>
<BoardAttachmentField
label="답변 첨부파일"
attachmentId={post.attachmentId}
/>
</div>
{state.status === 'error' && state.message && (
<FoxHelperText type="danger" message={state.message} />
)}
</form>
</FoxModal>
);
}