1- import { useEffect , useState } from "react" ;
1+ import { useEffect , useState , useCallback } from "react" ;
22import {
33 Tooltip ,
44 TooltipContent ,
@@ -16,8 +16,7 @@ import { ExcalidrawImperativeAPI } from "@excalidraw/excalidraw/types/types";
1616import { useQuery , useMutation } from "@tanstack/react-query" ;
1717import { RefreshCcw } from "lucide-react" ;
1818import { getDrawData , setDrawData } from "@/db/draw" ;
19- import { drawDataStore } from "@/stores/drawDataStore" ; // Adjust the import path as needed
20- import { queryClient } from "@/main" ;
19+ import { drawDataStore } from "@/stores/drawDataStore" ;
2120
2221type PageProps = {
2322 id : string ;
@@ -27,6 +26,7 @@ export default function Page({ id }: PageProps) {
2726 const [ excalidrawAPI , setExcalidrawAPI ] =
2827 useState < ExcalidrawImperativeAPI | null > ( null ) ;
2928 const [ name , setName ] = useState ( "" ) ;
29+ const [ isSaving , setIsSaving ] = useState ( false ) ;
3030 const { theme } = useTheme ( ) ;
3131
3232 const { data, isLoading } = useQuery ( {
@@ -40,16 +40,18 @@ export default function Page({ id }: PageProps) {
4040 name : string ;
4141 } ) => setDrawData ( id , data . elements , data . name ) ,
4242 onSuccess : ( ) => {
43- queryClient . invalidateQueries ( { queryKey : [ "page" , id ] } ) ;
44- toast ( "Your page has been saved to the server!" ) ;
43+ setIsSaving ( false ) ;
4544 } ,
4645 onError : ( error : Error ) => {
46+ setIsSaving ( false ) ;
4747 toast ( "An error occurred while saving to the server" , {
4848 description : error . message ,
4949 } ) ;
5050 } ,
5151 } ) ;
5252
53+ const { mutate } = mutation ;
54+
5355 async function updateScene ( ) {
5456 if ( data ?. data && excalidrawAPI ) {
5557 const elements = data . data [ 0 ] . page_elements . elements ;
@@ -58,37 +60,55 @@ export default function Page({ id }: PageProps) {
5860 appState : { theme : theme } ,
5961 } ) ;
6062 setName ( data . data [ 0 ] . name ) ;
61- toast ( "Scene updated" ) ;
6263 }
6364 if ( data ?. error ) {
6465 toast ( "An error occurred" , { description : data . error . message } ) ;
6566 }
6667 }
6768
68- async function setSceneData ( ) {
69+ const setSceneData = useCallback ( async ( ) => {
6970 if ( excalidrawAPI ) {
7071 const scene = excalidrawAPI . getSceneElements ( ) ;
7172 const updatedAt = new Date ( ) . toISOString ( ) ;
7273
73- // Save locally first
74- drawDataStore . getState ( ) . setPageData ( id , scene , updatedAt , name ) ;
75- toast ( "Your page has been saved locally!" ) ;
74+ const existingData = drawDataStore . getState ( ) . getPageData ( id ) ;
7675
77- // Then push to API
78- mutation . mutate ( {
79- elements : scene as NonDeletedExcalidrawElement [ ] ,
80- name,
81- } ) ;
76+ if ( JSON . stringify ( existingData ?. elements ) !== JSON . stringify ( scene ) ) {
77+ setIsSaving ( true ) ;
78+ // Save locally first
79+ drawDataStore . getState ( ) . setPageData ( id , scene , updatedAt , name ) ;
80+
81+ // Then push to API
82+ mutate (
83+ {
84+ elements : scene as NonDeletedExcalidrawElement [ ] ,
85+ name,
86+ } ,
87+ {
88+ onSettled ( ) {
89+ setIsSaving ( false ) ;
90+ } ,
91+ } ,
92+ ) ;
93+ }
8294 }
83- }
95+ } , [ excalidrawAPI , id , name , mutate ] ) ;
8496
8597 useEffect ( ( ) => {
8698 if ( ! isLoading && data ?. data && excalidrawAPI ) {
87- setTimeout ( updateScene , 10 ) ;
99+ setTimeout ( updateScene , 1000 ) ;
88100 }
89101 // eslint-disable-next-line react-hooks/exhaustive-deps
90102 } , [ isLoading , data , excalidrawAPI ] ) ;
91103
104+ useEffect ( ( ) => {
105+ const interval = setInterval ( ( ) => {
106+ setSceneData ( ) ;
107+ } , 3000 ) ;
108+
109+ return ( ) => clearInterval ( interval ) ;
110+ } , [ setSceneData ] ) ;
111+
92112 useEffect ( ( ) => {
93113 // Load data from local storage if available
94114 const localData = drawDataStore . getState ( ) . getPageData ( id ) ;
@@ -98,7 +118,6 @@ export default function Page({ id }: PageProps) {
98118 appState : { theme : theme } ,
99119 } ) ;
100120 setName ( localData . name ) ;
101- toast ( "Loaded data from local storage" ) ;
102121 }
103122 } , [ id , excalidrawAPI , theme ] ) ;
104123
@@ -116,20 +135,26 @@ export default function Page({ id }: PageProps) {
116135 < Input
117136 onChange = { ( e ) => setName ( e . target . value ) }
118137 value = { name }
119- className = "w-40"
138+ className = "h-9 w-40"
139+ placeholder = "Page Title"
120140 />
121- < Button variant = "secondary" onClick = { setSceneData } >
122- Save
141+ < Button
142+ variant = "secondary"
143+ onClick = { setSceneData }
144+ disabled = { isSaving }
145+ size = "sm"
146+ >
147+ { isSaving ? "Saving..." : "Save" }
123148 </ Button >
124149 < TooltipProvider >
125150 < Tooltip >
126151 < TooltipTrigger asChild >
127152 < Button
128153 variant = "secondary"
129- size = "icon "
154+ size = "sm "
130155 onClick = { updateScene }
131156 >
132- < RefreshCcw className = "h-5 w-5 " />
157+ < RefreshCcw className = "h-4 w-4 " />
133158 </ Button >
134159 </ TooltipTrigger >
135160 < TooltipContent >
0 commit comments