-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement auto save feature (#112)
chore(test): remove save button click in enterSettings to test auto save chore: add Gitlocalize in readme
- Loading branch information
Showing
13 changed files
with
437 additions
and
126 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import debounce from 'lodash.debounce'; | ||
|
||
import { useEffect, useRef } from 'react'; | ||
|
||
const AUTO_SAVE_DEBOUNCE_MS = 700; | ||
const REFRESH_SAVE_TIME_MS = 20_000; | ||
|
||
export interface DebouncedFunction { | ||
(): void; | ||
cancel(): void; | ||
} | ||
|
||
type UseAutoSaveType = { | ||
updateSaveTimeToNow: () => void; | ||
debounceSaveSetting: ({ | ||
settingKey, | ||
saveCallBack, | ||
}: { | ||
settingKey: string; | ||
saveCallBack: () => void; | ||
}) => void; | ||
}; | ||
|
||
type UseAutoSaveProps = { | ||
onRefreshLastSaved?: (lastTime: Date) => void; | ||
}; | ||
|
||
export const useAutoSave = ({ | ||
onRefreshLastSaved, | ||
}: UseAutoSaveProps): UseAutoSaveType => { | ||
const lastSavedTime = useRef<Date>(); | ||
|
||
// This map is used to manage the auto save of each setting. | ||
const autoSaveDebounceMap = useRef(new Map<string, DebouncedFunction>()); | ||
|
||
// This useEffect is used to refresh the last saved time periodically. | ||
useEffect(() => { | ||
const interval = setInterval(() => { | ||
const lastTime = lastSavedTime.current; | ||
if (lastTime) { | ||
onRefreshLastSaved?.(lastTime); | ||
} | ||
}, REFRESH_SAVE_TIME_MS); | ||
return () => clearInterval(interval); | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [lastSavedTime.current]); | ||
|
||
const debounceSaveSetting = ({ | ||
settingKey, | ||
saveCallBack, | ||
}: { | ||
settingKey: string; | ||
saveCallBack: () => void; | ||
}): void => { | ||
autoSaveDebounceMap.current.get(settingKey)?.cancel(); | ||
const newDebounce = debounce(() => saveCallBack(), AUTO_SAVE_DEBOUNCE_MS); | ||
autoSaveDebounceMap.current.set(settingKey, newDebounce); | ||
newDebounce(); | ||
}; | ||
|
||
const updateSaveTimeToNow = (): void => { | ||
lastSavedTime.current = new Date(); | ||
}; | ||
|
||
return { | ||
debounceSaveSetting, | ||
updateSaveTimeToNow, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { useEffect, useState } from 'react'; | ||
|
||
// This effect allows to detect when the client is offline. | ||
export const useOnlineStatus = (): boolean => { | ||
const [online, setOnline] = useState( | ||
typeof window !== 'undefined' ? window.navigator.onLine : true, | ||
); | ||
|
||
useEffect(() => { | ||
const handleStatusChange = (): void => { | ||
setOnline(navigator.onLine); | ||
}; | ||
|
||
window.addEventListener('online', handleStatusChange); | ||
window.addEventListener('offline', handleStatusChange); | ||
|
||
return () => { | ||
window.removeEventListener('online', handleStatusChange); | ||
window.removeEventListener('offline', handleStatusChange); | ||
}; | ||
}, []); | ||
|
||
return online; | ||
}; |
Oops, something went wrong.