diff --git a/src/components/useUndoRedo.ts b/src/components/useUndoRedo.ts index e144f5e4..3b618765 100644 --- a/src/components/useUndoRedo.ts +++ b/src/components/useUndoRedo.ts @@ -1,22 +1,16 @@ +import { useState } from 'react'; -import { useState,useEffect } from 'react'; - -function useUndoRedo(initialValue: T, onChange?: (value: T) => void) { +function useUndoRedo(initialValue: T, onChange?: (value: T) => void, onSync?: (value: T) => Promise) { const [past, setPast] = useState([]); const [present, setPresent] = useState(initialValue); const [future, setFuture] = useState([]); - useEffect(() => { - setPresent(initialValue); - setPast([]); - setFuture([]); - }, [initialValue]); - const setValue = (newValue: T) => { setPast((prevPast) => [...prevPast, present]); setPresent(newValue); setFuture([]); - if (onChange) onChange(newValue); // Sync with store + if (onChange) onChange(newValue); // Update editor state + if (onSync) onSync(newValue); // Sync to main state and rebuild }; const undo = () => { @@ -25,7 +19,8 @@ function useUndoRedo(initialValue: T, onChange?: (value: T) => void) { setPast((prevPast) => prevPast.slice(0, -1)); setFuture((prevFuture) => [present, ...prevFuture]); setPresent(previous); - if (onChange) onChange(previous); + if (onChange) onChange(previous); // Update editor state + if (onSync) onSync(previous); // Sync to main state and rebuild }; const redo = () => { @@ -34,7 +29,8 @@ function useUndoRedo(initialValue: T, onChange?: (value: T) => void) { setFuture((prevFuture) => prevFuture.slice(1)); setPast((prevPast) => [...prevPast, present]); setPresent(next); - if (onChange) onChange(next); + if (onChange) onChange(next); // Update editor state + if (onSync) onSync(next); // Sync to main state and rebuild }; return { value: present, setValue, undo, redo }; diff --git a/src/editors/editorsContainer/AgreementData.tsx b/src/editors/editorsContainer/AgreementData.tsx index 10685874..74d6059b 100644 --- a/src/editors/editorsContainer/AgreementData.tsx +++ b/src/editors/editorsContainer/AgreementData.tsx @@ -1,25 +1,29 @@ import JSONEditor from "../JSONEditor"; import useAppStore from "../../store/store"; import useUndoRedo from "../../components/useUndoRedo"; + import { FaUndo, FaRedo } from "react-icons/fa"; function AgreementData() { const textColor = useAppStore((state) => state.textColor); + const editorAgreementData = useAppStore((state) => state.editorAgreementData); + const setEditorAgreementData = useAppStore((state) => state.setEditorAgreementData); const setData = useAppStore((state) => state.setData); const { value, setValue, undo, redo } = useUndoRedo( - useAppStore((state) => state.data), - setData + editorAgreementData, + setEditorAgreementData, + setData // Sync to main state and rebuild ); const handleChange = (value: string | undefined) => { if (value !== undefined) { - setValue(value); + setValue(value); // Update editor state and sync setData(value); } }; return ( -
+

Data

@@ -28,7 +32,7 @@ function AgreementData() {

- JSON data (an instance of the Concerto model) used to preview output from the template. + JSON data (an instance of the Concerto model) used to preview output from the template.

diff --git a/src/editors/editorsContainer/TemplateMarkdown.tsx b/src/editors/editorsContainer/TemplateMarkdown.tsx index 1a58bce1..28e91af6 100644 --- a/src/editors/editorsContainer/TemplateMarkdown.tsx +++ b/src/editors/editorsContainer/TemplateMarkdown.tsx @@ -6,16 +6,19 @@ import { FaUndo, FaRedo } from "react-icons/fa"; function TemplateMarkdown() { const textColor = useAppStore((state) => state.textColor); const backgroundColor = useAppStore((state) => state.backgroundColor); + const editorValue = useAppStore((state) => state.editorValue); + const setEditorValue = useAppStore((state) => state.setEditorValue); const setTemplateMarkdown = useAppStore((state) => state.setTemplateMarkdown); const { value, setValue, undo, redo } = useUndoRedo( - useAppStore((state) => state.templateMarkdown), - setTemplateMarkdown + editorValue, + setEditorValue, + setTemplateMarkdown // Sync to main state and rebuild ); const handleChange = (value: string | undefined) => { if (value !== undefined) { - setValue(value); - setTemplateMarkdown(value); + setValue(value); // Update editor state and sync + setTemplateMarkdown(value); } }; diff --git a/src/editors/editorsContainer/TemplateModel.tsx b/src/editors/editorsContainer/TemplateModel.tsx index 436c82f6..ca4f0fc8 100644 --- a/src/editors/editorsContainer/TemplateModel.tsx +++ b/src/editors/editorsContainer/TemplateModel.tsx @@ -1,19 +1,23 @@ import ConcertoEditor from "../ConcertoEditor"; import useAppStore from "../../store/store"; import useUndoRedo from "../../components/useUndoRedo"; + import { FaUndo, FaRedo } from "react-icons/fa"; function TemplateModel() { const textColor = useAppStore((state) => state.textColor); + const editorModelCto = useAppStore((state) => state.editorModelCto); + const setEditorModelCto = useAppStore((state) => state.setEditorModelCto); const setModelCto = useAppStore((state) => state.setModelCto); const { value, setValue, undo, redo } = useUndoRedo( - useAppStore((state) => state.modelCto), - setModelCto + editorModelCto, + setEditorModelCto, + setModelCto // Sync to main state and rebuild ); - + const handleChange = (value: string | undefined) => { if (value !== undefined) { - setValue(value); + setValue(value); // Update editor state and sync setModelCto(value); } }; diff --git a/src/store/store.ts b/src/store/store.ts index fce7fd32..52d697f3 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -12,8 +12,11 @@ import { compress, decompress } from "../utils/compression/compression"; interface AppState { templateMarkdown: string; + editorValue: string; modelCto: string; + editorModelCto: string; data: string; + editorAgreementData: string; agreementHtml: string; error: string | undefined; samples: Array; @@ -21,8 +24,11 @@ interface AppState { backgroundColor: string; textColor: string; setTemplateMarkdown: (template: string) => Promise; + setEditorValue: (value: string) => void; setModelCto: (model: string) => Promise; + setEditorModelCto: (value: string) => void; setData: (data: string) => Promise; + setEditorAgreementData: (value: string) => void; rebuild: () => Promise; init: () => Promise; loadSample: (name: string) => Promise; @@ -70,8 +76,11 @@ const useAppStore = create()( textColor: '#121212', sampleName: playground.NAME, templateMarkdown: playground.TEMPLATE, + editorValue: playground.TEMPLATE, modelCto: playground.MODEL, + editorModelCto: playground.MODEL, data: JSON.stringify(playground.DATA, null, 2), + editorAgreementData: JSON.stringify(playground.DATA, null, 2), agreementHtml: "", error: undefined, samples: SAMPLES, @@ -92,8 +101,11 @@ const useAppStore = create()( agreementHtml: undefined, error: undefined, templateMarkdown: sample.TEMPLATE, + editorValue: sample.TEMPLATE, modelCto: sample.MODEL, + editorModelCto: sample.MODEL, data: JSON.stringify(sample.DATA, null, 2), + editorAgreementData: JSON.stringify(sample.DATA, null, 2), })); await get().rebuild(); } @@ -102,58 +114,61 @@ const useAppStore = create()( const { templateMarkdown, modelCto, data } = get(); try { const result = await rebuildDeBounce(templateMarkdown, modelCto, data); - set(() => ({ agreementHtml: result, error: undefined })); + set(() => ({ agreementHtml: result, error: undefined })); // Clear error on success } catch (error: any) { set(() => ({ error: formatError(error) })); } }, setTemplateMarkdown: async (template: string) => { + set(() => ({ templateMarkdown: template })); const { modelCto, data } = get(); try { const result = await rebuildDeBounce(template, modelCto, data); - set(() => ({ - templateMarkdown: template, - agreementHtml: result, - error: undefined, - })); + set(() => ({ agreementHtml: result, error: undefined })); // Clear error on success } catch (error: any) { set(() => ({ error: formatError(error) })); } }, + setEditorValue: (value: string) => { + set(() => ({ editorValue: value })); + }, setModelCto: async (model: string) => { + set(() => ({ modelCto: model })); const { templateMarkdown, data } = get(); try { const result = await rebuildDeBounce(templateMarkdown, model, data); - set(() => ({ - modelCto: model, - agreementHtml: result, - error: undefined, - })); + set(() => ({ agreementHtml: result, error: undefined })); // Clear error on success } catch (error: any) { set(() => ({ error: formatError(error) })); } }, + setEditorModelCto: (value: string) => { + set(() => ({ editorModelCto: value })); + }, setData: async (data: string) => { + set(() => ({ data })); try { const result = await rebuildDeBounce( get().templateMarkdown, get().modelCto, data ); - set(() => ({ agreementHtml: result, error: undefined, data })); + set(() => ({ agreementHtml: result, error: undefined })); // Clear error on success } catch (error: any) { set(() => ({ error: formatError(error) })); } }, + setEditorAgreementData: (value: string) => { + set(() => ({ editorAgreementData: value })); + }, generateShareableLink: () => { const state = get(); - const dataToShare = { + const compressedData = compress({ templateMarkdown: state.templateMarkdown, modelCto: state.modelCto, data: state.data, agreementHtml: state.agreementHtml, - }; - const compressedData = compress(dataToShare); + }); return `${window.location.origin}?data=${compressedData}`; }, loadFromLink: async (compressedData: string) => { @@ -164,8 +179,11 @@ const useAppStore = create()( } set(() => ({ templateMarkdown, + editorValue: templateMarkdown, modelCto, + editorModelCto: modelCto, data, + editorAgreementData: data, agreementHtml, error: undefined, })); @@ -189,6 +207,7 @@ const useAppStore = create()( ) ); + export default useAppStore; function formatError(error: any): string {