@@ -5,6 +5,10 @@ import { Dialog, DialogPanel, DialogTitle, Transition, TransitionChild, Listbox,
55import { useTheme } from '@/contexts/ThemeContext' ;
66import { useConfig } from '@/contexts/ConfigContext' ;
77import { ChevronUpDownIcon , CheckIcon } from './icons/Icons' ;
8+ import { indexedDBService } from '@/utils/indexedDB' ;
9+ import { useDocuments } from '@/contexts/DocumentContext' ;
10+
11+ const isDev = process . env . NEXT_PUBLIC_NODE_ENV !== 'production' || process . env . NODE_ENV == null ;
812
913interface SettingsModalProps {
1014 isOpen : boolean ;
@@ -20,15 +24,41 @@ const themes = [
2024export function SettingsModal ( { isOpen, setIsOpen } : SettingsModalProps ) {
2125 const { theme, setTheme } = useTheme ( ) ;
2226 const { apiKey, baseUrl, updateConfig } = useConfig ( ) ;
27+ const { refreshPDFs, refreshEPUBs } = useDocuments ( ) ;
2328 const [ localApiKey , setLocalApiKey ] = useState ( apiKey ) ;
2429 const [ localBaseUrl , setLocalBaseUrl ] = useState ( baseUrl ) ;
30+ const [ isSyncing , setIsSyncing ] = useState ( false ) ;
31+ const [ isLoading , setIsLoading ] = useState ( false ) ;
2532 const selectedTheme = themes . find ( t => t . id === theme ) || themes [ 0 ] ;
2633
2734 useEffect ( ( ) => {
2835 setLocalApiKey ( apiKey ) ;
2936 setLocalBaseUrl ( baseUrl ) ;
3037 } , [ apiKey , baseUrl ] ) ;
3138
39+ const handleSync = async ( ) => {
40+ try {
41+ setIsSyncing ( true ) ;
42+ await indexedDBService . syncToServer ( ) ;
43+ } catch ( error ) {
44+ console . error ( 'Sync failed:' , error ) ;
45+ } finally {
46+ setIsSyncing ( false ) ;
47+ }
48+ } ;
49+
50+ const handleLoad = async ( ) => {
51+ try {
52+ setIsLoading ( true ) ;
53+ await indexedDBService . loadFromServer ( ) ;
54+ await Promise . all ( [ refreshPDFs ( ) , refreshEPUBs ( ) ] ) ;
55+ } catch ( error ) {
56+ console . error ( 'Load failed:' , error ) ;
57+ } finally {
58+ setIsLoading ( false ) ;
59+ }
60+ } ;
61+
3262 return (
3363 < Transition appear show = { isOpen } as = { Fragment } >
3464 < Dialog as = "div" className = "relative z-50" onClose = { ( ) => setIsOpen ( false ) } >
@@ -130,6 +160,38 @@ export function SettingsModal({ isOpen, setIsOpen }: SettingsModalProps) {
130160 className = "w-full rounded-lg bg-background py-2 px-3 text-foreground shadow-sm focus:outline-none focus:ring-2 focus:ring-accent"
131161 />
132162 </ div >
163+
164+ { isDev && < div className = "space-y-2" >
165+ < label className = "block text-sm font-medium text-foreground" > Document Sync</ label >
166+ < div className = "flex items-center justify-between" >
167+ < div className = "space-y-2" >
168+ < div className = "flex gap-2" >
169+ < button
170+ onClick = { handleSync }
171+ disabled = { isSyncing || isLoading }
172+ className = "inline-flex justify-center rounded-lg bg-background px-4 py-2 text-sm
173+ font-medium text-foreground hover:bg-background/90 focus:outline-none
174+ focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
175+ transform transition-transform duration-200 ease-in-out hover:scale-[1.04] hover:text-accent
176+ disabled:opacity-50"
177+ >
178+ { isSyncing ? 'Saving...' : 'Save to Server' }
179+ </ button >
180+ < button
181+ onClick = { handleLoad }
182+ disabled = { isSyncing || isLoading }
183+ className = "inline-flex justify-center rounded-lg bg-background px-4 py-2 text-sm
184+ font-medium text-foreground hover:bg-background/90 focus:outline-none
185+ focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
186+ transform transition-transform duration-200 ease-in-out hover:scale-[1.04] hover:text-accent
187+ disabled:opacity-50"
188+ >
189+ { isLoading ? 'Loading...' : 'Load from Server' }
190+ </ button >
191+ </ div >
192+ </ div >
193+ </ div >
194+ </ div > }
133195 </ div >
134196 </ div >
135197
0 commit comments