Files
react-editor-shopify/src/App.tsx
2026-05-05 13:51:10 -04:00

110 lines
3.6 KiB
TypeScript

import { useCallback, useMemo, useRef, useState } from "react";
import { App as ReactEditorApp, createUseEditor } from "@reacteditor/core";
import "@reacteditor/core/react-editor.css";
import createTailwindCdnPlugin from "@reacteditor/plugin-tailwind-cdn";
import { mediaPlugin } from "@reacteditor/plugin-media";
import "@reacteditor/plugin-media/styles.css";
import { aiPlugin } from "@reacteditor/plugin-ai";
import "@reacteditor/plugin-ai/styles.css";
import { createConfig } from "@/react-editor.config";
import { ShopifyProvider } from "@/contexts/shopify-context";
import { frontendAiMediaAdapter } from "@/services/media-adapter";
import { Loader } from "@/components/ui/loader";
import schemaJson from "../app.schema.json";
const AI_API_KEY = (import.meta.env.VITE_API_KEY as string | undefined) ?? "";
type Pages = Record<string, { root: any; content: any[] }>;
const useEditor = createUseEditor();
const SHOPIFY_DOMAIN =
(import.meta.env.VITE_SHOPIFY_DOMAIN as string | undefined) ?? "mock.shop";
const STOREFRONT_TOKEN =
(import.meta.env.VITE_SHOPIFY_STOREFRONT_ACCESS_TOKEN as
| string
| undefined) ?? "";
function readPathname() {
if (typeof window === "undefined") return "/";
const p = window.location.pathname;
return p === "" ? "/" : p;
}
export default function App() {
const pages = schemaJson as Pages;
const [currentPath, setCurrentPath] = useState<string>(readPathname);
const [isPublishing, setIsPublishing] = useState(false);
const latestDataRef = useRef<any>(null);
const handleChange = useCallback((data: any) => {
latestDataRef.current = data;
}, []);
const config = useMemo(
() =>
createConfig({
domain: SHOPIFY_DOMAIN,
token: STOREFRONT_TOKEN || null,
}),
[],
);
const handlePublish = useCallback((data: any, route?: string) => {
console.log(data);
setIsPublishing(true);
if (typeof window !== "undefined" && window.parent !== window) {
window.parent.postMessage(
{ type: "PUBLISH", data: { data, route } },
"*",
);
}
setTimeout(() => setIsPublishing(false), 1000);
}, []);
const plugins = useMemo(
() => [createTailwindCdnPlugin()],
[pages, currentPath, handlePublish],
);
return (
<div className="h-screen w-screen">
<ShopifyProvider domain={SHOPIFY_DOMAIN} token={STOREFRONT_TOKEN}>
<ReactEditorApp
config={config as any}
pages={pages as any}
currentPath={currentPath}
plugins={plugins}
iframe={{ enabled: true }}
ui={{ navBarVisible: false, leftSideBarVisible: false }}
onPublish={handlePublish}
onChange={handleChange}
overrides={{
headerActions: () => {
const appState = useEditor((s: any) => s.appState);
return (
<button
type="button"
disabled={isPublishing}
onClick={() => {
handlePublish(appState.data, currentPath);
}}
className="inline-flex items-center justify-center gap-2 rounded-md bg-black px-4 py-1.5 text-sm font-medium text-white hover:bg-gray-800 disabled:cursor-not-allowed disabled:opacity-60"
>
{isPublishing && <Loader size={14} />}
{isPublishing ? "Saving..." : "Save"}
</button>
);
},
}}
/>
</ShopifyProvider>
{isPublishing && (
<div className="fixed inset-0 z-[9999] flex items-center justify-center bg-black/30">
<Loader size={32} />
</div>
)}
</div>
);
}