Skip to content

Commit 0be3e75

Browse files
authored
Merge pull request #674 from Lemoncode/dev
restore mobile temp restriction and fix on modal annoying leave dialog
2 parents 7d2bc7e + 50cc694 commit 0be3e75

6 files changed

Lines changed: 58 additions & 25 deletions

File tree

editor.html

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,5 @@
3737
<body>
3838
<div id="root"></div>
3939
<script type="module" src="/src/main.tsx"></script>
40-
<script>
41-
window.onbeforeunload = function () {
42-
return 'You are about to leave this page. All progress in QuickMock will be lost. Are you sure you want to proceed?';
43-
};
44-
</script>
4540
</body>
4641
</html>

index.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,8 @@ <h1>
357357
</p>
358358
</div>
359359
</div>
360-
<a href="editor.html" class="link">Launch QuickMock</a>
360+
<a href="editor.html" class="link hide-mobile">START DESIGN</a>
361+
<p class="mobile-text mobile-only">Now, only available on desktop.</p>
361362
</div>
362363
</main>
363364
</body>

src/core/providers/canvas/canvas.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ export interface CanvasContextModel {
124124
updateColorSlot: (color: string, index: number) => void;
125125
dropRef: React.MutableRefObject<HTMLDivElement | null>;
126126
setDropRef: (dropRef: React.MutableRefObject<HTMLDivElement | null>) => void;
127+
setIsDirty: (dirty: boolean) => void;
127128
loadSampleDocument: boolean;
128129
setLoadSampleDocument: React.Dispatch<React.SetStateAction<boolean>>;
129130
}

src/core/providers/canvas/canvas.provider.tsx

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,34 @@ export const CanvasProvider: React.FC<Props> = props => {
5151
addSnapshot
5252
);
5353

54-
const selectionInfo = useSelection(document, setDocument);
54+
const [isDirty, setIsDirty] = React.useState(false);
55+
56+
const setDocumentAndMarkDirtyState = (
57+
updater: DocumentModel | ((prev: DocumentModel) => DocumentModel),
58+
isDirty = true
59+
) => {
60+
setDocument(updater);
61+
setIsDirty(isDirty);
62+
};
63+
64+
const selectionInfo = useSelection(
65+
document,
66+
setDocument,
67+
setDocumentAndMarkDirtyState
68+
);
69+
70+
React.useEffect(() => {
71+
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
72+
if (isDirty) {
73+
e.preventDefault();
74+
}
75+
};
76+
window.addEventListener('beforeunload', handleBeforeUnload);
77+
return () => window.removeEventListener('beforeunload', handleBeforeUnload);
78+
}, [isDirty]);
5579

5680
const addNewPage = () => {
57-
setDocument(lastDocument =>
81+
setDocumentAndMarkDirtyState(lastDocument =>
5882
produce(lastDocument, draft => {
5983
const newActiveIndex = draft.pages.length;
6084
draft.pages.push({
@@ -76,7 +100,7 @@ export const CanvasProvider: React.FC<Props> = props => {
76100
}
77101
);
78102

79-
setDocument(lastDocument =>
103+
setDocumentAndMarkDirtyState(lastDocument =>
80104
produce(lastDocument, draft => {
81105
const newPage = {
82106
id: uuidv4(),
@@ -96,7 +120,7 @@ export const CanvasProvider: React.FC<Props> = props => {
96120
? document.pages[pageIndex + 1].id // If it's not the last page, select the next one
97121
: document.pages[pageIndex - 1].id; // Otherwise, select the previous one
98122

99-
setDocument(lastDocument =>
123+
setDocumentAndMarkDirtyState(lastDocument =>
100124
produce(lastDocument, draft => {
101125
draft.pages = draft.pages.filter(
102126
currentPage => document.pages[pageIndex].id !== currentPage.id
@@ -119,7 +143,7 @@ export const CanvasProvider: React.FC<Props> = props => {
119143
selectionInfo.clearSelection();
120144
selectionInfo.shapeRefs.current = {};
121145

122-
setDocument(lastDocument =>
146+
setDocumentAndMarkDirtyState(lastDocument =>
123147
produce(lastDocument, draft => {
124148
const pageIndex = draft.pages.findIndex(page => page.id === pageId);
125149
if (pageIndex !== -1) {
@@ -130,15 +154,15 @@ export const CanvasProvider: React.FC<Props> = props => {
130154
};
131155

132156
const editPageTitle = (pageIndex: number, newName: string) => {
133-
setDocument(lastDocument =>
157+
setDocumentAndMarkDirtyState(lastDocument =>
134158
produce(lastDocument, draft => {
135159
draft.pages[pageIndex].name = newName;
136160
})
137161
);
138162
};
139163

140164
const swapPages = (id1: string, id2: string) => {
141-
setDocument(lastDocument =>
165+
setDocumentAndMarkDirtyState(lastDocument =>
142166
produce(lastDocument, draft => {
143167
const index1 = draft.pages.findIndex(page => page.id === id1);
144168
const index2 = draft.pages.findIndex(page => page.id === id2);
@@ -159,7 +183,7 @@ export const CanvasProvider: React.FC<Props> = props => {
159183
});
160184

161185
if (isPageIndexValid(document)) {
162-
setDocument(lastDocument =>
186+
setDocumentAndMarkDirtyState(lastDocument =>
163187
produce(lastDocument, draft => {
164188
draft.pages[lastDocument.activePageIndex].shapes.push(...newShapes);
165189
})
@@ -198,13 +222,13 @@ export const CanvasProvider: React.FC<Props> = props => {
198222
);
199223

200224
const createNewFullDocument = () => {
201-
setDocument(createDefaultDocumentModel());
225+
setDocumentAndMarkDirtyState(createDefaultDocumentModel(), false);
202226
setFileName('');
203227
};
204228

205229
const deleteSelectedShapes = () => {
206230
if (isPageIndexValid(document)) {
207-
setDocument(lastDocument =>
231+
setDocumentAndMarkDirtyState(lastDocument =>
208232
produce(lastDocument, draft => {
209233
draft.pages[lastDocument.activePageIndex].shapes =
210234
removeShapesFromList(
@@ -230,7 +254,7 @@ export const CanvasProvider: React.FC<Props> = props => {
230254

231255
const newShape = createShape({ x, y }, type, otherProps);
232256

233-
setDocument(lastDocument =>
257+
setDocumentAndMarkDirtyState(lastDocument =>
234258
produce(lastDocument, draft => {
235259
draft.pages[lastDocument.activePageIndex].shapes.push(newShape);
236260
})
@@ -260,7 +284,7 @@ export const CanvasProvider: React.FC<Props> = props => {
260284
});
261285
});
262286
} else {
263-
setDocument(fullDocument => {
287+
setDocumentAndMarkDirtyState(fullDocument => {
264288
return produce(fullDocument, draft => {
265289
draft.pages[document.activePageIndex].shapes = draft.pages[
266290
document.activePageIndex
@@ -274,7 +298,7 @@ export const CanvasProvider: React.FC<Props> = props => {
274298

275299
const updateShapePosition = (id: string, { x, y }: Coord) => {
276300
if (isPageIndexValid(document)) {
277-
setDocument(fullDocument => {
301+
setDocumentAndMarkDirtyState(fullDocument => {
278302
return produce(fullDocument, draft => {
279303
draft.pages[document.activePageIndex].shapes = draft.pages[
280304
document.activePageIndex
@@ -307,6 +331,7 @@ export const CanvasProvider: React.FC<Props> = props => {
307331
};
308332

309333
const loadDocument = (document: DocumentModel) => {
334+
setDocumentAndMarkDirtyState(document, false);
310335
loadSampleDocument && setLoadSampleDocument(false);
311336
setDocument(document);
312337
setHowManyLoadedDocuments(numberOfDocuments => numberOfDocuments + 1);
@@ -373,6 +398,7 @@ export const CanvasProvider: React.FC<Props> = props => {
373398
updateColorSlot,
374399
dropRef,
375400
setDropRef,
401+
setIsDirty,
376402
loadSampleDocument,
377403
setLoadSampleDocument,
378404
}}

src/core/providers/canvas/use-selection.hook.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ import { produce } from 'immer';
88

99
export const useSelection = (
1010
document: DocumentModel,
11-
setDocument: React.Dispatch<React.SetStateAction<DocumentModel>>
11+
setDocument: React.Dispatch<React.SetStateAction<DocumentModel>>,
12+
setDocumentAndMarkDirtyState: (
13+
updater: DocumentModel | ((prev: DocumentModel) => DocumentModel),
14+
isDirty?: boolean
15+
) => void
1216
): SelectionInfo => {
1317
const transformerRef = useRef<Konva.Transformer>(null);
1418
const shapeRefs = useRef<ShapeRefs>({});
@@ -165,7 +169,7 @@ export const useSelection = (
165169
}
166170

167171
const selectedShapeId = selectedShapesIds[0];
168-
setDocument(prevDocument =>
172+
setDocumentAndMarkDirtyState(prevDocument =>
169173
produce(prevDocument, draft => {
170174
draft.pages[prevDocument.activePageIndex].shapes = draft.pages[
171175
prevDocument.activePageIndex
@@ -181,7 +185,7 @@ export const useSelection = (
181185
key: K,
182186
value: OtherProps[K]
183187
) => {
184-
setDocument(prevDocument =>
188+
setDocumentAndMarkDirtyState(prevDocument =>
185189
produce(prevDocument, draft => {
186190
draft.pages[prevDocument.activePageIndex].shapes = draft.pages[
187191
prevDocument.activePageIndex
@@ -198,7 +202,7 @@ export const useSelection = (
198202
key: K,
199203
value: OtherProps[K]
200204
) => {
201-
setDocument(prevDocument =>
205+
setDocumentAndMarkDirtyState(prevDocument =>
202206
produce(prevDocument, draft => {
203207
draft.pages[prevDocument.activePageIndex].shapes = draft.pages[
204208
prevDocument.activePageIndex
@@ -225,7 +229,6 @@ export const useSelection = (
225229
if (selectedShapesIds.length === 1) {
226230
const selectedShapeId = selectedShapesIds[0];
227231
updateOtherPropsOnSelectedSingleShape(selectedShapeId, key, value);
228-
229232
return;
230233
}
231234

src/pods/toolbar/components/save-button/save-button.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,20 @@ import { SaveIcon } from '@/common/components/icons/save-icon.component';
22
import classes from '@/pods/toolbar/toolbar.pod.module.css';
33
import { ToolbarButton } from '../toolbar-button';
44
import { useLocalDisk } from '@/core/local-disk';
5+
import { useCanvasContext } from '@/core/providers';
56

67
export const SaveButton: React.FC = () => {
78
const { handleSave } = useLocalDisk();
9+
const { setIsDirty } = useCanvasContext();
10+
11+
const handleSaveLocal = () => {
12+
handleSave();
13+
setIsDirty(false);
14+
};
815

916
return (
1017
<ToolbarButton
11-
onClick={handleSave}
18+
onClick={handleSaveLocal}
1219
className={classes.button}
1320
icon={<SaveIcon />}
1421
label="Save"

0 commit comments

Comments
 (0)