feat(ai-character): 댓글과 팬톡 운영 기능 구현
This commit is contained in:
47
src/features/fan-talks/components/FanTalkReplyForm.tsx
Normal file
47
src/features/fan-talks/components/FanTalkReplyForm.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
import { useRef, useState } from "react";
|
||||
|
||||
import { focusFirstInvalidControl } from "@/shared/lib/focus-first-invalid-control";
|
||||
|
||||
export function FanTalkReplyForm({ content, errorMessage, isSaving, onChange, onSubmit, submitLabel = "답변 등록" }: { readonly content: string; readonly errorMessage: string | null; readonly isSaving: boolean; readonly onChange: (content: string) => void; readonly onSubmit: () => void; readonly submitLabel?: string }) {
|
||||
const errorId = "fan-talk-reply-error";
|
||||
const formRef = useRef<HTMLFormElement>(null);
|
||||
const [contentErrorMessage, setContentErrorMessage] = useState<string | null>(null);
|
||||
const visibleErrorMessage = contentErrorMessage ?? errorMessage;
|
||||
|
||||
function submit() {
|
||||
if (content.trim().length === 0) {
|
||||
setContentErrorMessage("답변 내용을 입력해 주세요.");
|
||||
queueMicrotask(() => focusFirstInvalidControl(formRef.current));
|
||||
return;
|
||||
}
|
||||
|
||||
setContentErrorMessage(null);
|
||||
onSubmit();
|
||||
}
|
||||
|
||||
return (
|
||||
<form
|
||||
className="flex flex-col gap-3"
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
submit();
|
||||
}}
|
||||
ref={formRef}
|
||||
>
|
||||
<label className="flex flex-col gap-2 text-sm font-semibold">
|
||||
답변 내용
|
||||
<textarea aria-describedby={visibleErrorMessage === null ? undefined : errorId} aria-invalid={visibleErrorMessage === null ? undefined : true} className="min-h-32 rounded-md border border-input bg-card px-3 py-2 text-base font-normal text-foreground" onChange={(event) => {
|
||||
const nextContent = event.currentTarget.value;
|
||||
if (nextContent.trim().length > 0) {
|
||||
setContentErrorMessage(null);
|
||||
}
|
||||
onChange(nextContent);
|
||||
}} value={content} />
|
||||
</label>
|
||||
{visibleErrorMessage === null ? null : <p aria-label="답변 내용 오류" className="rounded-md border border-destructive bg-card p-3 text-sm font-semibold text-destructive" id={errorId} role="alert">{visibleErrorMessage}</p>}
|
||||
<button className="w-fit rounded-md border border-input bg-primary px-4 py-2 font-semibold text-primary-foreground hover:bg-[var(--button-bg-hover)] active:bg-[var(--button-bg-active)] disabled:opacity-60" disabled={isSaving} type="submit">
|
||||
{submitLabel}
|
||||
</button>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user