w-funnel/src/components/admin/builder/BuilderTopBar.tsx
2025-09-25 18:04:52 +02:00

78 lines
2.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useId, useRef } from "react";
import { Button } from "@/components/ui/button";
import { serializeBuilderState, deserializeFunnelDefinition } from "@/lib/admin/builder/utils";
import { useBuilderDispatch, useBuilderState } from "@/lib/admin/builder/context";
import type { BuilderState } from "@/lib/admin/builder/context";
interface BuilderTopBarProps {
onNew: () => void;
onExport: (json: string) => void;
onLoadError?: (message: string) => void;
}
export function BuilderTopBar({ onNew, onExport, onLoadError }: BuilderTopBarProps) {
const dispatch = useBuilderDispatch();
const state = useBuilderState();
const fileInputId = useId();
const fileInputRef = useRef<HTMLInputElement | null>(null);
const handleExport = () => {
const json = JSON.stringify(serializeBuilderState(state), null, 2);
onExport(json);
};
const handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (!file) {
return;
}
try {
const text = await file.text();
const parsed = JSON.parse(text);
const builderState = deserializeFunnelDefinition(parsed);
dispatch({ type: "reset", payload: builderState as BuilderState });
} catch (error) {
onLoadError?.(error instanceof Error ? error.message : "Не удалось загрузить JSON");
} finally {
if (fileInputRef.current) {
fileInputRef.current.value = "";
}
}
};
return (
<div className="flex items-center justify-between px-6 py-4">
<div className="flex flex-col gap-1">
<h1 className="text-xl font-semibold">Funnel Builder</h1>
<p className="text-sm text-muted-foreground">
Соберите воронку, редактируйте экраны и экспортируйте JSON для рантайма.
</p>
</div>
<div className="flex items-center gap-3">
<Button variant="ghost" onClick={onNew}>
Создать заново
</Button>
<Button
variant="outline"
onClick={() => fileInputRef.current?.click()}
>
Загрузить JSON
</Button>
<input
ref={fileInputRef}
id={fileInputId}
type="file"
accept="application/json"
className="hidden"
onChange={handleFileChange}
/>
<Button onClick={handleExport}>Export JSON</Button>
</div>
</div>
);
}