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 { 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 { FoxRadio } from '@fox/core/components/fox-radio';
import { FoxRadioGroup } from '@fox/core/components/fox-radio-group';
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 {
DESCRIPTION_MAX_LENGTH,
INITIAL_POINT_STANDARD_FORM_STATE,
} from '@/lib/domain/point-standard-form';
import type { PointStandard } from '@/lib/domain/point-standard';
import { updatePointStandardAction } from '../_actions';
import styles from './point-standard-form.module.scss';
interface PointStandardFormModalProps {
standard: PointStandard;
onClose: () => void;
}
export function PointStandardFormModal({
standard,
onClose,
}: PointStandardFormModalProps) {
const { showToast } = useFeedback();
const formRef = useRef<HTMLFormElement>(null);
const [state, formAction, isPending] = useActionState(
updatePointStandardAction,
INITIAL_POINT_STANDARD_FORM_STATE
);
const [isDuplicable, setIsDuplicable] = useState(standard.isDuplicable);
const [isActive, setIsActive] = useState(standard.isActive);
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="수정"
onClose={onClose}
actions={
<>
<FoxButton type="default" size="md" label="취소" onAction={onClose} />
<FoxButton
type="primary"
size="md"
label={isPending ? '저장 중...' : '수정'}
disabled={isPending}
onAction={() => formRef.current?.requestSubmit()}
/>
</>
}
>
<form
ref={formRef}
onSubmit={(event) => submitFormAction(event, formAction)}
className={styles.fields}
>
<p className={styles.required}>* 는 필수 항목입니다.</p>
<input type="hidden" name="id" value={standard.id} />
{/* 화면에서는 읽기 전용이지만 백엔드 UPDATE가 EVENT_CD를 덮어써서 그대로 돌려보낸다. */}
<input type="hidden" name="eventCode" value={standard.eventCode} />
<div className={styles.field}>
{/* 기획 ① 이벤트행은 수정불가(Read Only). 값은 hidden id가 갖는다. */}
<FoxInput
size="md"
label="이벤트"
requirement="required"
value={standard.eventCode}
readOnly
state="view"
/>
</div>
<div className={styles.field}>
<FoxFormLabel as="span" requirement="required">
포인트
</FoxFormLabel>
<div className={styles.numberRow}>
<div className={styles.numberField}>
<FoxInput
size="md"
name="point"
type="number"
inputMode="numeric"
min={0}
aria-label="포인트"
defaultValue={String(standard.point)}
invalid={Boolean(errors.point)}
/>
</div>
<span className={styles.numberNote}>포인트</span>
</div>
{errors.point && <FoxHelperText type="danger" message={errors.point} />}
</div>
<div className={styles.field}>
<FoxFormLabel as="span" requirement="required">
제한포인트
</FoxFormLabel>
<div className={styles.numberRow}>
<div className={styles.numberField}>
<FoxInput
size="md"
name="limitPoint"
type="number"
inputMode="numeric"
min={0}
aria-label="제한포인트"
defaultValue={String(standard.limitPoint)}
invalid={Boolean(errors.limitPoint)}
/>
</div>
<span className={styles.numberNote}>
'0' 일경우 일 누적 포인트에 대한 제한이 없습니다.
</span>
</div>
{errors.limitPoint && (
<FoxHelperText type="danger" message={errors.limitPoint} />
)}
</div>
<div className={styles.field}>
<FoxFormLabel as="span">중복 여부</FoxFormLabel>
<FoxRadioGroup name="isDuplicable" size="md" label="중복 여부">
<FoxRadio
value="Y"
label="중복 가능"
checked={isDuplicable}
onChange={() => setIsDuplicable(true)}
/>
<FoxRadio
value="N"
label="중복 불가"
checked={!isDuplicable}
onChange={() => setIsDuplicable(false)}
/>
</FoxRadioGroup>
</div>
<div className={styles.field}>
<FoxTextArea
name="description"
label="이벤트 설명"
requirement="required"
defaultValue={standard.description}
placeholder="이벤트 설명을 입력하세요."
rows={4}
counter
maxLength={DESCRIPTION_MAX_LENGTH}
invalid={Boolean(errors.description)}
message={errors.description}
/>
</div>
<div className={styles.field}>
<FoxFormLabel as="span">사용여부</FoxFormLabel>
<FoxRadioGroup name="isActive" size="md" label="사용여부">
<FoxRadio
value="Y"
label="사용"
checked={isActive}
onChange={() => setIsActive(true)}
/>
<FoxRadio
value="N"
label="사용안함"
checked={!isActive}
onChange={() => setIsActive(false)}
/>
</FoxRadioGroup>
</div>
{state.status === 'error' && state.message && (
<FoxHelperText type="danger" message={state.message} />
)}
</form>
</FoxModal>
);
}