129 lines
4.5 KiB
TypeScript
129 lines
4.5 KiB
TypeScript
import { useState, useEffect, useCallback } from "react";
|
|
import { toast } from "sonner";
|
|
import { translate } from "@/i18n";
|
|
import { useLayouts } from "./useLayouts";
|
|
import { Database } from "@/integrations/supabase/types";
|
|
|
|
type Layout = Database['public']['Tables']['layouts']['Row'];
|
|
|
|
const SNIPPET_TYPE = 'widget-snippet';
|
|
|
|
export interface WidgetSnippetData {
|
|
widgetId: string;
|
|
props?: Record<string, any>;
|
|
}
|
|
|
|
export function useWidgetSnippets() {
|
|
const [snippets, setSnippets] = useState<Layout[]>([]);
|
|
const [loading, setLoading] = useState(false);
|
|
const { getLayouts, createLayout, updateLayout, deleteLayout } = useLayouts();
|
|
|
|
const loadSnippets = useCallback(async () => {
|
|
setLoading(true);
|
|
try {
|
|
const { data, error } = await getLayouts({ type: SNIPPET_TYPE });
|
|
if (error) throw error;
|
|
setSnippets(data || []);
|
|
} catch (e) {
|
|
console.error("Failed to load widget snippets", e);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, [getLayouts]);
|
|
|
|
useEffect(() => {
|
|
loadSnippets();
|
|
}, []);
|
|
|
|
const saveSnippet = useCallback(async (name: string, widgetData: WidgetSnippetData) => {
|
|
try {
|
|
const { data, error } = await createLayout({
|
|
name,
|
|
layout_json: widgetData as any,
|
|
type: SNIPPET_TYPE,
|
|
visibility: 'private',
|
|
meta: { sourceWidgetType: widgetData.widgetId },
|
|
});
|
|
if (error) throw error;
|
|
toast.success(translate("Widget saved"));
|
|
await loadSnippets();
|
|
return data;
|
|
} catch (e) {
|
|
console.error("Failed to save widget snippet", e);
|
|
toast.error(translate("Failed to save widget"));
|
|
return null;
|
|
}
|
|
}, [createLayout, loadSnippets]);
|
|
|
|
const updateSnippetName = useCallback(async (id: string, name: string) => {
|
|
try {
|
|
const { error } = await updateLayout(id, { name });
|
|
if (error) throw error;
|
|
toast.success(translate("Widget renamed"));
|
|
await loadSnippets();
|
|
} catch (e) {
|
|
console.error("Failed to rename widget snippet", e);
|
|
toast.error(translate("Failed to rename widget"));
|
|
}
|
|
}, [updateLayout, loadSnippets]);
|
|
|
|
const updateSnippetData = useCallback(async (id: string, widgetData: WidgetSnippetData) => {
|
|
try {
|
|
const { error } = await updateLayout(id, {
|
|
layout_json: widgetData as any,
|
|
meta: { sourceWidgetType: widgetData.widgetId },
|
|
});
|
|
if (error) throw error;
|
|
toast.success(translate("Widget updated"));
|
|
await loadSnippets();
|
|
} catch (e) {
|
|
console.error("Failed to update widget snippet", e);
|
|
toast.error(translate("Failed to update widget"));
|
|
}
|
|
}, [updateLayout, loadSnippets]);
|
|
|
|
const cloneSnippet = useCallback(async (snippet: Layout) => {
|
|
const snippetData = snippet.layout_json as unknown as WidgetSnippetData;
|
|
try {
|
|
const { data, error } = await createLayout({
|
|
name: `${snippet.name} (copy)`,
|
|
layout_json: snippetData as any,
|
|
type: SNIPPET_TYPE,
|
|
visibility: 'private',
|
|
meta: snippet.meta || { sourceWidgetType: snippetData?.widgetId },
|
|
});
|
|
if (error) throw error;
|
|
toast.success(translate("Widget cloned"));
|
|
await loadSnippets();
|
|
return data;
|
|
} catch (e) {
|
|
console.error("Failed to clone widget snippet", e);
|
|
toast.error(translate("Failed to clone widget"));
|
|
return null;
|
|
}
|
|
}, [createLayout, loadSnippets]);
|
|
|
|
const removeSnippet = useCallback(async (id: string) => {
|
|
try {
|
|
const { error } = await deleteLayout(id);
|
|
if (error) throw error;
|
|
toast.success(translate("Widget deleted"));
|
|
await loadSnippets();
|
|
} catch (e) {
|
|
console.error("Failed to delete widget snippet", e);
|
|
toast.error(translate("Failed to delete widget"));
|
|
}
|
|
}, [deleteLayout, loadSnippets]);
|
|
|
|
return {
|
|
snippets,
|
|
loading,
|
|
loadSnippets,
|
|
saveSnippet,
|
|
updateSnippetName,
|
|
updateSnippetData,
|
|
cloneSnippet,
|
|
removeSnippet,
|
|
};
|
|
}
|