You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

132 lines
4.1 KiB
TypeScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// frontend/components/automation/NewView.tsx — auto.jsx NewView 이식 (자연어 → 규칙)
"use client";
import { useEffect, useRef, useState } from "react";
import { Icon } from "@/components/Icon";
import type { ParsePreview } from "@/lib/types";
import { AU_CAT, AU_TONE, Flow } from "./Flow";
// 원본 auto-data.js examples 입력 문장(고정 골든 — 칩 표시·정확 일치 트리거)
const EXAMPLE_TEXTS = [
"출장 전날엔 저녁 일정 비워줘",
"뉴스레터는 모아서 저녁에 보여줘",
"운동을 3일 거르면 산책 잡아줘",
];
export function NewView({
parse,
onCreate,
}: {
parse: (text: string) => Promise<ParsePreview>;
onCreate: (p: ParsePreview) => void;
}) {
const [text, setText] = useState("");
const [preview, setPreview] = useState<ParsePreview | null>(null);
const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
useEffect(() => {
const t = text.trim();
if (!t) {
setPreview(null);
return;
}
if (timer.current) clearTimeout(timer.current);
timer.current = setTimeout(async () => {
try {
const pr = await parse(t);
setPreview(pr.matched ? pr : null);
} catch {
setPreview(null);
}
}, 300);
return () => {
if (timer.current) clearTimeout(timer.current);
};
}, [text, parse]);
const match = preview?.matched ? preview : null;
return (
<div className="board">
<section className="card sp2 hero">
<span className="hero-spark">
<Icon name="zap" />
</span>
<p className="brief">
<b> </b> . ·· .
</p>
<div className="cmd">
<Icon name="pen" />
<input
value={text}
onChange={(e) => setText(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter" && match) onCreate(match);
}}
placeholder="예: 출장 전날엔 저녁 일정 비워줘"
aria-label="새 규칙 문장"
autoFocus
/>
<button
className="send"
disabled={!match}
onClick={() => match && onCreate(match)}
aria-label="규칙 만들기"
>
<Icon name="arrow" />
</button>
</div>
<div className="chips">
{EXAMPLE_TEXTS.map((t) => (
<button key={t} className="chip" onClick={() => setText(t)}>
<Icon name="spark" />
{t}
</button>
))}
</div>
</section>
{/* 미리보기 */}
<section className="card sp2">
<div className="ch">
<div className="ico">
<Icon name="spark" />
</div>
<div className="htext">
<h3></h3>
<div className="sub">
{match ? "아리가 이렇게 이해했어요" : "문장을 적으면 여기에 규칙이 그려져요"}
</div>
</div>
{match && (
<span className="rl-cat" style={{ background: AU_TONE[match.cat] }}>
{AU_CAT[match.cat]}
</span>
)}
</div>
{match ? (
<>
<div className="nv-name">{match.name}</div>
<Flow p={match.parse} />
<button className="rb-make-btn" onClick={() => onCreate(match)}>
<Icon name="plus" />
</button>
<div className="nv-hint">
<Icon name="shield" /> .
</div>
</>
) : (
<div className="nv-empty">
<span className="nv-empty-ic">
<Icon name="zap" />
</span>
<p>
. <b> </b>
.
</p>
</div>
)}
</section>
</div>
);
}