109 lines
3.7 KiB
TypeScript
109 lines
3.7 KiB
TypeScript
import React, { useState } from "react";
|
||
import { motion, AnimatePresence } from "framer-motion";
|
||
import type { ChartType } from "../types";
|
||
|
||
interface AddWidgetModalProps {
|
||
isOpen: boolean;
|
||
onAdd: (data: { type: ChartType; title: string; dataKey: string }) => void;
|
||
onClose: () => void;
|
||
}
|
||
|
||
export const AddWidgetModal: React.FC<AddWidgetModalProps> = ({
|
||
isOpen,
|
||
onAdd,
|
||
onClose,
|
||
}) => {
|
||
const [type, setType] = useState<ChartType>("line");
|
||
const [title, setTitle] = useState("");
|
||
const [dataKey, setDataKey] = useState("requests");
|
||
|
||
const handleAdd = () => {
|
||
if (!title.trim()) return;
|
||
onAdd({ type, title: title.trim(), dataKey });
|
||
setTitle("");
|
||
setType("line");
|
||
setDataKey("requests");
|
||
onClose();
|
||
};
|
||
|
||
return (
|
||
<AnimatePresence>
|
||
{isOpen && (
|
||
<motion.div
|
||
initial={{ opacity: 0 }}
|
||
animate={{ opacity: 1 }}
|
||
exit={{ opacity: 0 }}
|
||
className="fixed inset-0 bg-black/50 flex items-center justify-center z-50"
|
||
onClick={onClose}
|
||
>
|
||
<motion.div
|
||
initial={{ scale: 0.95, opacity: 0 }}
|
||
animate={{ scale: 1, opacity: 1 }}
|
||
exit={{ scale: 0.95, opacity: 0 }}
|
||
className="bg-secondary rounded-xl shadow-large border border-primary w-80 p-3"
|
||
onClick={(e) => e.stopPropagation()}
|
||
>
|
||
<h3 className="text-xs font-semibold text-primary mb-3">
|
||
Добавить график
|
||
</h3>
|
||
|
||
<div className="space-y-2">
|
||
<div>
|
||
<label className="block text-[10px] text-secondary mb-1">
|
||
Тип
|
||
</label>
|
||
<div className="flex gap-1">
|
||
{(["line", "bar", "area", "pie"] as ChartType[]).map((t) => (
|
||
<button
|
||
key={t}
|
||
onClick={() => setType(t)}
|
||
className={`px-2 py-0.5 rounded text-[10px] transition-colors cursor-pointer ${
|
||
type === t
|
||
? "bg-accent-primary text-white"
|
||
: "bg-tertiary text-secondary hover:bg-tertiary/70"
|
||
}`}
|
||
>
|
||
{t === "line" && "📈"}
|
||
{t === "bar" && "📊"}
|
||
{t === "area" && "📉"}
|
||
{t === "pie" && "🥧"}
|
||
</button>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block text-[10px] text-secondary mb-1">
|
||
Название
|
||
</label>
|
||
<input
|
||
type="text"
|
||
value={title}
|
||
onChange={(e) => setTitle(e.target.value)}
|
||
placeholder="Название"
|
||
className="w-full px-2 py-1 text-[11px] bg-tertiary border border-primary rounded text-primary focus:outline-none focus:border-accent-primary"
|
||
/>
|
||
</div>
|
||
|
||
<div className="flex gap-1 pt-2">
|
||
<button
|
||
onClick={handleAdd}
|
||
className="flex-1 px-2 py-1 bg-accent-primary text-white rounded text-[10px] hover:bg-accent-hover transition-colors cursor-pointer"
|
||
>
|
||
Добавить
|
||
</button>
|
||
<button
|
||
onClick={onClose}
|
||
className="px-2 py-1 bg-tertiary text-secondary rounded text-[10px] hover:bg-secondary transition-colors cursor-pointer"
|
||
>
|
||
Отмена
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</motion.div>
|
||
</motion.div>
|
||
)}
|
||
</AnimatePresence>
|
||
);
|
||
};
|