78 lines
2.5 KiB
TypeScript
78 lines
2.5 KiB
TypeScript
"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>
|
||
);
|
||
}
|