'use client'; import { useActionState, useEffect, useRef, useState } from 'react'; import { FoxButton } from '@fox/core/components/fox-button'; import { FoxFileUpload } from '@fox/core/components/fox-file-upload'; import { FoxFormLabel } from '@fox/core/components/fox-form-label'; 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 { FoxToggleSwitch } from '@fox/core/components/fox-toggle-switch'; import { submitFormAction } from '@/app/_hooks/submit-form-action'; import { useFeedback } from '@/app/_hooks/use-feedback'; import type { CommonCode } from '@/lib/domain/common-code'; import { BOARD_CATEGORY_OPTIONS, INQUIRY_TYPE_OPTIONS, type BoardPost, type BoardType, } from '@/lib/domain/board-post'; import { CONTENT_MAX_LENGTH, INITIAL_BOARD_POST_FORM_STATE, TITLE_MAX_LENGTH, } from '@/lib/domain/board-post-form'; import { createBoardPostAction, updateBoardPostAction } from '../_actions'; import styles from './board-post-form.module.scss'; interface BoardPostFormModalProps { boardType: BoardType; mode: 'create' | 'edit'; post?: BoardPost; /** 공통코드 `BBS_FAQ_CD` — FAQ의 유형 선택지. 다른 게시판에서는 쓰이지 않는다. */ faqTypes?: readonly CommonCode[]; onClose: () => void; } const BOARD_TITLES: Record = { notice: '공지사항', inquiry: '1:1문의', faq: 'FAQ', }; const STATIC_TYPE_OPTIONS: Partial< Record > = { inquiry: INQUIRY_TYPE_OPTIONS, }; export function BoardPostFormModal({ boardType, mode, post, faqTypes = [], onClose, }: BoardPostFormModalProps) { const isCreate = mode === 'create'; const { showToast } = useFeedback(); const formRef = useRef(null); const [state, formAction, isPending] = useActionState( isCreate ? createBoardPostAction : updateBoardPostAction, INITIAL_BOARD_POST_FORM_STATE ); const [categoryCode, setCategoryCode] = useState( post?.categoryCode || BOARD_CATEGORY_OPTIONS[0].value ); const [typeCode, setTypeCode] = useState(post?.typeCode ?? ''); const [isPinned, setIsPinned] = useState(post?.isPinned ?? false); const [isVisible, setIsVisible] = useState(post?.isVisible ?? true); const [isPushEnabled, setIsPushEnabled] = useState(post?.isPushEnabled ?? false); useEffect(() => { if (state.status === 'success') { showToast({ variant: 'success', message: isCreate ? '게시물을 등록했습니다.' : '게시물을 수정했습니다.', }); onClose(); } }, [state, showToast, onClose, isCreate]); const errors = state.status === 'error' ? (state.errors ?? {}) : {}; const typeOptions = boardType === 'faq' ? faqTypes.map((code) => ({ value: code.code, label: code.label })) : STATIC_TYPE_OPTIONS[boardType]; const hasNoticeOnlyFields = boardType === 'notice'; return ( formRef.current?.requestSubmit()} /> } >
submitFormAction(event, formAction)} className={styles.fields} > {!isCreate && post && }
({ value: option.value, label: option.label, }))} value={categoryCode} onValueChange={setCategoryCode} error={Boolean(errors.categoryCode)} hint={errors.categoryCode} />
{typeOptions && typeOptions.length > 0 && (
({ value: option.value, label: option.label, }))} value={typeCode} onValueChange={setTypeCode} placeholder="유형을 선택하세요." error={Boolean(errors.typeCode)} hint={errors.typeCode} />
)}
{hasNoticeOnlyFields && (
상단고정
)} {hasNoticeOnlyFields && (
게시기간
{(errors.startDate ?? errors.endDate) && ( )}
)}
사용여부
{hasNoticeOnlyFields && (
앱푸쉬 설정
)} {state.status === 'error' && state.message && ( )}
); }