[RAPID-micro] 메일 계정 등록 폼 필드별 유효성 검사 에러 표시 추가
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -129,6 +129,7 @@ export default function ImapMailPage() {
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [saveError, setSaveError] = useState<string | null>(null);
|
||||
const [formErrors, setFormErrors] = useState<Partial<Record<'displayName' | 'email' | 'host' | 'username' | 'password', string>>>({});
|
||||
|
||||
// New states
|
||||
const [folders, setFolders] = useState<MailFolder[]>([]);
|
||||
@@ -432,6 +433,7 @@ export default function ImapMailPage() {
|
||||
setTestResult(null);
|
||||
setShowPassword(false);
|
||||
setHostPopoverOpen(false);
|
||||
setFormErrors({});
|
||||
setShowDialog(true);
|
||||
}
|
||||
|
||||
@@ -461,6 +463,14 @@ export default function ImapMailPage() {
|
||||
}
|
||||
|
||||
async function handleSave() {
|
||||
const errors: typeof formErrors = {};
|
||||
if (!form.displayName.trim()) errors.displayName = "표시 이름을 입력하세요.";
|
||||
if (!form.email.trim()) errors.email = "이메일 주소를 입력하세요.";
|
||||
if (!form.host.trim()) errors.host = "IMAP 호스트를 입력하세요.";
|
||||
if (!form.username.trim()) errors.username = "사용자명을 입력하세요.";
|
||||
if (!editingAccount && !form.password.trim()) errors.password = "비밀번호를 입력하세요.";
|
||||
if (Object.keys(errors).length > 0) { setFormErrors(errors); return; }
|
||||
setFormErrors({});
|
||||
setSaving(true);
|
||||
setSaveError(null);
|
||||
try {
|
||||
@@ -914,18 +924,22 @@ export default function ImapMailPage() {
|
||||
<Label className="text-xs">표시 이름</Label>
|
||||
<Input
|
||||
value={form.displayName}
|
||||
onChange={(e) => setForm((p) => ({ ...p, displayName: e.target.value }))}
|
||||
onChange={(e) => { setForm((p) => ({ ...p, displayName: e.target.value })); setFormErrors((p) => ({ ...p, displayName: undefined })); }}
|
||||
placeholder="내 Gmail"
|
||||
className={formErrors.displayName ? "border-destructive" : ""}
|
||||
/>
|
||||
{formErrors.displayName && <p className="text-xs text-destructive">{formErrors.displayName}</p>}
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs">이메일 주소</Label>
|
||||
<Input
|
||||
type="email"
|
||||
value={form.email}
|
||||
onChange={(e) => setForm((p) => ({ ...p, email: e.target.value, username: e.target.value }))}
|
||||
onChange={(e) => { setForm((p) => ({ ...p, email: e.target.value, username: e.target.value })); setFormErrors((p) => ({ ...p, email: undefined })); }}
|
||||
placeholder="user@example.com"
|
||||
className={formErrors.email ? "border-destructive" : ""}
|
||||
/>
|
||||
{formErrors.email && <p className="text-xs text-destructive">{formErrors.email}</p>}
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div className="space-y-1">
|
||||
@@ -944,7 +958,7 @@ export default function ImapMailPage() {
|
||||
<CommandInput
|
||||
placeholder="호스트 직접 입력..."
|
||||
value={form.host}
|
||||
onValueChange={(v) => setForm((p) => ({ ...p, host: v }))}
|
||||
onValueChange={(v) => { setForm((p) => ({ ...p, host: v })); setFormErrors((p) => ({ ...p, host: undefined })); }}
|
||||
/>
|
||||
<CommandList>
|
||||
<CommandEmpty>직접 입력한 값을 사용합니다</CommandEmpty>
|
||||
@@ -970,6 +984,7 @@ export default function ImapMailPage() {
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
{formErrors.host && <p className="text-xs text-destructive">{formErrors.host}</p>}
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs">포트</Label>
|
||||
@@ -988,9 +1003,11 @@ export default function ImapMailPage() {
|
||||
<Label className="text-xs">사용자명</Label>
|
||||
<Input
|
||||
value={form.username}
|
||||
onChange={(e) => setForm((p) => ({ ...p, username: e.target.value }))}
|
||||
onChange={(e) => { setForm((p) => ({ ...p, username: e.target.value })); setFormErrors((p) => ({ ...p, username: undefined })); }}
|
||||
placeholder="user@example.com"
|
||||
className={formErrors.username ? "border-destructive" : ""}
|
||||
/>
|
||||
{formErrors.username && <p className="text-xs text-destructive">{formErrors.username}</p>}
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs">비밀번호 {editingAccount && "(변경 시에만 입력)"}</Label>
|
||||
@@ -998,10 +1015,10 @@ export default function ImapMailPage() {
|
||||
<Input
|
||||
type={showPassword ? "text" : "password"}
|
||||
value={form.password}
|
||||
onChange={(e) => setForm((p) => ({ ...p, password: e.target.value }))}
|
||||
onChange={(e) => { setForm((p) => ({ ...p, password: e.target.value })); setFormErrors((p) => ({ ...p, password: undefined })); }}
|
||||
onKeyDown={(e) => { if (e.key === "Enter") handleSave(); }}
|
||||
placeholder="••••••••"
|
||||
className="pr-9"
|
||||
className={`pr-9 ${formErrors.password ? "border-destructive" : ""}`}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
@@ -1011,6 +1028,7 @@ export default function ImapMailPage() {
|
||||
{showPassword ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
|
||||
</button>
|
||||
</div>
|
||||
{formErrors.password && <p className="text-xs text-destructive">{formErrors.password}</p>}
|
||||
</div>
|
||||
{editingAccount && (
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user