Skip to content

Commit 5a7bb81

Browse files
teja-polasurya4419
authored andcommitted
feat(editor): add undo redo icons to editor - I204 (#212)
* fix(button): fix dark mode toggle click - I201 Signed-off-by: Dharma Teja <[email protected]> * fix(button): fix dark mode toggle click - I201 Signed-off-by: Dharma Teja <[email protected]> * fix(button): fix dark mode toggle click - I201 Signed-off-by: Dharma Teja <[email protected]> * update is checked Signed-off-by: Dharma Teja <[email protected]> * feat(editor): add undo redo icons to editor - I204 Signed-off-by: Dharma Teja <[email protected]> * feat(editor): add undo redo icons to editor - I204 Signed-off-by: Dharma Teja <[email protected]> * feat(editor): add undo redo icons to editor - I204 Signed-off-by: Dharma Teja <[email protected]> * feat(editor): add undo redo icons to editor - I204 Signed-off-by: Dharma Teja <[email protected]> * feat(editor): add undo redo icons to editor - I204 Signed-off-by: Dharma Teja <[email protected]> * feat(editor): add undo redo icons to editor - I204 Signed-off-by: Dharma Teja <[email protected]> --------- Signed-off-by: Dharma Teja <[email protected]>
1 parent 7c36913 commit 5a7bb81

File tree

5 files changed

+103
-77
lines changed

5 files changed

+103
-77
lines changed

src/AgreementHtml.tsx

+7-38
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
1+
12
import { LoadingOutlined } from "@ant-design/icons";
23
import { Spin } from "antd";
34
import useAppStore from "./store/store";
45
import FullScreenModal from "./components/FullScreenModal";
56

6-
function AgreementHtml({
7-
loading,
8-
isModal,
9-
}: {
10-
loading: boolean;
11-
isModal?: boolean;
12-
}) {
7+
function AgreementHtml({ loading, isModal }: { loading: any; isModal?: boolean }) {
138
const agreementHtml = useAppStore((state) => state.agreementHtml);
149
const backgroundColor = useAppStore((state) => state.backgroundColor);
1510
const textColor = useAppStore((state) => state.textColor);
@@ -35,49 +30,23 @@ function AgreementHtml({
3530
color: textColor,
3631
}}
3732
>
38-
<h2
39-
style={{
40-
flexGrow: 1,
41-
textAlign: "center",
42-
paddingLeft: "34px",
43-
color: textColor,
44-
}}
45-
>
33+
<h2 style={{ flexGrow: 1, textAlign: "center", paddingLeft: "34px", color: textColor }}>
4634
Preview Output
4735
</h2>
4836
{!isModal && <FullScreenModal />}
4937
</div>
5038
<p style={{ textAlign: "center", color: textColor }}>
51-
The result of merging the JSON data with the template. This is
52-
AgreementMark converted to HTML.
39+
The result of merging the JSON data with the template.
5340
</p>
5441
{loading ? (
55-
<div
56-
style={{
57-
flex: 1,
58-
display: "flex",
59-
justifyContent: "center",
60-
alignItems: "center",
61-
}}
62-
>
63-
<Spin
64-
indicator={
65-
<LoadingOutlined
66-
style={{ fontSize: 42, color: "#19c6c7" }}
67-
spin
68-
/>
69-
}
70-
/>
42+
<div style={{ flex: 1, display: "flex", justifyContent: "center", alignItems: "center" }}>
43+
<Spin indicator={<LoadingOutlined style={{ fontSize: 42, color: "#19c6c7" }} spin />} />
7144
</div>
7245
) : (
7346
<div
7447
className="agreement"
7548
dangerouslySetInnerHTML={{ __html: agreementHtml }}
76-
style={{
77-
flex: 1,
78-
color: textColor,
79-
backgroundColor: backgroundColor,
80-
}}
49+
style={{ flex: 1, color: textColor, backgroundColor: backgroundColor }}
8150
/>
8251
)}
8352
</div>

src/components/useUndoRedo.ts

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { useState } from 'react';
2+
function useUndoRedo<T>(initialValue: T, onChange?: (value: T) => void) {
3+
const [past, setPast] = useState<T[]>([]);
4+
const [present, setPresent] = useState<T>(initialValue);
5+
const [future, setFuture] = useState<T[]>([]);
6+
7+
const setValue = (newValue: T) => {
8+
setPast((prevPast) => [...prevPast, present]);
9+
setPresent(newValue);
10+
setFuture([]);
11+
if (onChange) onChange(newValue); // Ensure preview updates
12+
};
13+
14+
const undo = () => {
15+
if (past.length === 0) return;
16+
const previous = past[past.length - 1];
17+
setPast((prevPast) => prevPast.slice(0, -1));
18+
setFuture((prevFuture) => [present, ...prevFuture]);
19+
setPresent(previous);
20+
if (onChange) onChange(previous);
21+
};
22+
23+
const redo = () => {
24+
if (future.length === 0) return;
25+
const next = future[0];
26+
setFuture((prevFuture) => prevFuture.slice(1));
27+
setPast((prevPast) => [...prevPast, present]);
28+
setPresent(next);
29+
if (onChange) onChange(next);
30+
};
31+
32+
return { value: present, setValue, undo, redo };
33+
}
34+
35+
export default useUndoRedo;
+20-15
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import JSONEditor from "../JSONEditor";
22
import useAppStore from "../../store/store";
3+
import useUndoRedo from "../../components/useUndoRedo";
34
import { useCallback } from "react";
45
import { debounce } from "ts-debounce";
6+
import { FaUndo, FaRedo } from "react-icons/fa";
57

68
function AgreementData() {
7-
const editorAgreementData = useAppStore((state) => state.editorAgreementData);
8-
const setEditorAgreementData = useAppStore(
9-
(state) => state.setEditorAgreementData
10-
);
11-
const setData = useAppStore((state) => state.setData);
129
const textColor = useAppStore((state) => state.textColor);
10+
const setData = useAppStore((state) => state.setData);
11+
const { value, setValue, undo, redo } = useUndoRedo(
12+
useAppStore((state) => state.editorAgreementData),
13+
setData // Pass setData to update the preview when undo/redo happens
14+
);
1315

1416
const debouncedSetData = useCallback(
1517
debounce((value: string) => {
@@ -20,23 +22,26 @@ function AgreementData() {
2022

2123
const handleChange = (value: string | undefined) => {
2224
if (value !== undefined) {
23-
setEditorAgreementData(value); // Immediate state update
24-
debouncedSetData(value); // Debounced state update
25+
setValue(value);
26+
debouncedSetData(value);
2527
}
2628
};
2729

2830
return (
29-
<div className="column">
30-
<div className="tooltip">
31+
<div className="column" >
32+
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
3133
<h3 style={{ color: textColor }}>Data</h3>
32-
<span style={{ color: textColor }} className="tooltiptext">
33-
JSON data (an instance of the Concerto model) used to preview output
34-
from the template.
35-
</span>
34+
<div>
35+
<FaUndo onClick={undo} title="Undo" style={{ cursor: "pointer", color: textColor, marginRight: "8px" }} />
36+
<FaRedo onClick={redo} title="Redo" style={{ cursor: "pointer", color: textColor }} />
37+
</div>
3638
</div>
37-
<JSONEditor value={editorAgreementData} onChange={handleChange} />
39+
<p style={{ color: textColor }}>
40+
JSON data (an instance of the Concerto model) used to preview output from the template.
41+
</p>
42+
<JSONEditor value={value} onChange={handleChange} />
3843
</div>
3944
);
4045
}
4146

42-
export default AgreementData;
47+
export default AgreementData;
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,48 @@
11
import MarkdownEditor from "../MarkdownEditor";
22
import useAppStore from "../../store/store";
3+
import useUndoRedo from "../../components/useUndoRedo";
34
import { useCallback } from "react";
45
import { debounce } from "ts-debounce";
6+
import { FaUndo, FaRedo } from "react-icons/fa";
57

68
function TemplateMarkdown() {
7-
const editorValue = useAppStore((state) => state.editorValue);
8-
const setEditorValue = useAppStore((state) => state.setEditorValue);
9-
const setTemplateMarkdown = useAppStore((state) => state.setTemplateMarkdown);
10-
const backgroundColor = useAppStore((state) => state.backgroundColor);
119
const textColor = useAppStore((state) => state.textColor);
12-
10+
const backgroundColor = useAppStore((state) => state.backgroundColor);
11+
const setTemplateMarkdown = useAppStore((state) => state.setTemplateMarkdown);
12+
const { value, setValue, undo, redo } = useUndoRedo(
13+
useAppStore((state) => state.editorValue),
14+
setTemplateMarkdown // Ensures preview updates when undo/redo happens
15+
);
16+
1317
const debouncedSetTemplateMarkdown = useCallback(
1418
debounce((value: string) => {
1519
void setTemplateMarkdown(value);
1620
}, 500),
17-
[]
21+
[setTemplateMarkdown]
1822
);
1923

2024
const handleChange = (value: string | undefined) => {
2125
if (value !== undefined) {
22-
setEditorValue(value);
26+
setValue(value);
2327
debouncedSetTemplateMarkdown(value);
2428
}
2529
};
2630

2731
return (
28-
<div className="column" style={{ backgroundColor: backgroundColor }}>
29-
<h2 style={{ color: textColor }}>TemplateMark</h2>
32+
<div className="column" style={{ backgroundColor }}>
33+
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
34+
<h3 style={{ color: textColor }}>TemplateMark</h3>
35+
<div>
36+
<FaUndo onClick={undo} title="Undo" style={{ cursor: "pointer", color: textColor, marginRight: "8px" }} />
37+
<FaRedo onClick={redo} title="Redo" style={{ cursor: "pointer", color: textColor }} />
38+
</div>
39+
</div>
3040
<p style={{ color: textColor }}>
31-
A natural language template with embedded variables, conditional
32-
sections, and TypeScript code.
41+
A natural language template with embedded variables, conditional sections, and TypeScript code.
3342
</p>
34-
<MarkdownEditor value={editorValue} onChange={handleChange} />
43+
<MarkdownEditor value={value} onChange={handleChange} />
3544
</div>
3645
);
3746
}
3847

39-
export default TemplateMarkdown;
48+
export default TemplateMarkdown;
+19-11
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import ConcertoEditor from "../ConcertoEditor";
22
import useAppStore from "../../store/store";
3+
import useUndoRedo from "../../components/useUndoRedo";
34
import { useCallback } from "react";
45
import { debounce } from "ts-debounce";
6+
import { FaUndo, FaRedo } from "react-icons/fa";
57

68
function TemplateModel() {
7-
const editorModelCto = useAppStore((state) => state.editorModelCto);
8-
const setEditorModelCto = useAppStore((state) => state.setEditorModelCto);
9-
const setModelCto = useAppStore((state) => state.setModelCto);
109
const textColor = useAppStore((state) => state.textColor);
11-
10+
const setModelCto = useAppStore((state) => state.setModelCto);
11+
const { value, setValue, undo, redo } = useUndoRedo(
12+
useAppStore((state) => state.editorModelCto),
13+
setModelCto // Ensures errors and preview update when undo/redo happens
14+
);
15+
1216
const debouncedSetModelCto = useCallback(
1317
debounce((value: string) => {
1418
void setModelCto(value);
@@ -18,22 +22,26 @@ function TemplateModel() {
1822

1923
const handleChange = (value: string | undefined) => {
2024
if (value !== undefined) {
21-
setEditorModelCto(value);
25+
setValue(value);
2226
debouncedSetModelCto(value);
2327
}
2428
};
2529

2630
return (
2731
<div className="column">
28-
<div className="tooltip">
32+
<div className="tooltip" style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
2933
<h3 style={{ color: textColor }}>Concerto Model</h3>
30-
<span style={{ color: textColor }} className="tooltiptext">
31-
Defines the data model for the template and its logic.
32-
</span>
34+
<div>
35+
<FaUndo onClick={undo} title="Undo" style={{ cursor: "pointer", color: textColor, marginRight: "8px" }} />
36+
<FaRedo onClick={redo} title="Redo" style={{ cursor: "pointer", color: textColor }} />
37+
</div>
3338
</div>
34-
<ConcertoEditor value={editorModelCto} onChange={handleChange} />
39+
<span style={{ color: textColor }} className="tooltiptext">
40+
Defines the data model for the template and its logic.
41+
</span>
42+
<ConcertoEditor value={value} onChange={handleChange} />
3543
</div>
3644
);
3745
}
3846

39-
export default TemplateModel;
47+
export default TemplateModel;

0 commit comments

Comments
 (0)