diff --git a/components/KeyManagementManager.tsx b/components/KeyManagementManager.tsx index e28244a..2c7c99a 100644 --- a/components/KeyManagementManager.tsx +++ b/components/KeyManagementManager.tsx @@ -11,6 +11,8 @@ interface PublicKeys { } export function KeyManagementManager(): React.ReactElement { + console.log('[KeyManagementManager] Component rendered') + const [publicKeys, setPublicKeys] = useState(null) const [accountExists, setAccountExists] = useState(false) const [loading, setLoading] = useState(true) @@ -253,7 +255,10 @@ export function KeyManagementManager(): React.ReactElement { )} {/* Sync Progress Bar - Always show if connected, even if publicKeys not loaded yet */} - + {(() => { + console.log('[KeyManagementManager] Rendering SyncProgressBar') + return + })()} {!publicKeys && !accountExists && (
diff --git a/components/SyncProgressBar.tsx b/components/SyncProgressBar.tsx index 4bac335..946353b 100644 --- a/components/SyncProgressBar.tsx +++ b/components/SyncProgressBar.tsx @@ -7,6 +7,8 @@ import { objectCache } from '@/lib/objectCache' import { t } from '@/lib/i18n' export function SyncProgressBar(): React.ReactElement | null { + console.log('[SyncProgressBar] Component function called') + const [syncProgress, setSyncProgress] = useState(null) const [isSyncing, setIsSyncing] = useState(false) const [lastSyncDate, setLastSyncDate] = useState(null) diff --git a/components/UnlockAccountModal.tsx b/components/UnlockAccountModal.tsx index 880b763..9597464 100644 --- a/components/UnlockAccountModal.tsx +++ b/components/UnlockAccountModal.tsx @@ -38,24 +38,24 @@ function WordInputWithAutocomplete({ } }, [value]) - const handleChange = (e: React.ChangeEvent): void => { - const newValue = e.target.value.trim().toLowerCase() + const handleChange = (event: React.ChangeEvent): void => { + const newValue = event.target.value.trim().toLowerCase() onChange(newValue) } - const handleKeyDown = (e: React.KeyboardEvent): void => { - if (e.key === 'ArrowDown') { - e.preventDefault() + const handleKeyDown = (event: React.KeyboardEvent): void => { + if (event.key === 'ArrowDown') { + event.preventDefault() setSelectedIndex((prev) => (prev < suggestions.length - 1 ? prev + 1 : prev)) - } else if (e.key === 'ArrowUp') { - e.preventDefault() + } else if (event.key === 'ArrowUp') { + event.preventDefault() setSelectedIndex((prev) => (prev > 0 ? prev - 1 : -1)) - } else if (e.key === 'Enter' && selectedIndex >= 0 && suggestions[selectedIndex]) { - e.preventDefault() + } else if (event.key === 'Enter' && selectedIndex >= 0 && suggestions[selectedIndex]) { + event.preventDefault() onChange(suggestions[selectedIndex] ?? '') setShowSuggestions(false) inputRef.current?.blur() - } else if (e.key === 'Escape') { + } else if (event.key === 'Escape') { setShowSuggestions(false) inputRef.current?.blur() } @@ -244,8 +244,8 @@ export function UnlockAccountModal({ onSuccess, onClose }: UnlockAccountModalPro await nostrAuthService.unlockAccount(words) onSuccess() onClose() - } catch (e) { - setError(e instanceof Error ? e.message : 'Échec du déverrouillage. Vérifiez vos mots-clés.') + } catch (unlockError) { + setError(unlockError instanceof Error ? unlockError.message : 'Échec du déverrouillage. Vérifiez vos mots-clés.') } finally { setLoading(false) } diff --git a/lib/alby.ts b/lib/alby.ts index 31c6619..d21161e 100644 --- a/lib/alby.ts +++ b/lib/alby.ts @@ -90,8 +90,8 @@ export class AlbyService { amount: request.amount, expiresAt: Math.floor(Date.now() / 1000) + (request.expiry ?? 3600), } - } catch (error) { - const err = error instanceof Error ? error : new Error(String(error)) + } catch (invoiceError) { + const err = invoiceError instanceof Error ? invoiceError : new Error(String(invoiceError)) console.error('Alby createInvoice error:', err) throw new Error(`Failed to create invoice: ${err.message}`) } @@ -117,8 +117,8 @@ export class AlbyService { try { const response = await webln.sendPayment(invoice) return { preimage: response.preimage } - } catch (error) { - const err = error instanceof Error ? error : new Error(String(error)) + } catch (paymentError) { + const err = paymentError instanceof Error ? paymentError : new Error(String(paymentError)) console.error('Alby sendPayment error:', err) throw new Error(`Failed to send payment: ${err.message}`) } diff --git a/lib/purchaseQueries.ts b/lib/purchaseQueries.ts index 88acc71..2cae1ef 100644 --- a/lib/purchaseQueries.ts +++ b/lib/purchaseQueries.ts @@ -86,13 +86,13 @@ export async function getPurchaseById(purchaseId: string, timeoutMs: number = 50 } sub.on('event', async (event: Event): Promise => { - const parsed = await parsePurchaseFromEvent(event) - if (parsed?.id === purchaseId) { + const purchaseParsed = await parsePurchaseFromEvent(event) + if (purchaseParsed?.id === purchaseId) { // Cache the parsed purchase - if (parsed.hash) { - await objectCache.set('purchase', parsed.hash, event, parsed, 0, false, parsed.index) + if (purchaseParsed.hash) { + await objectCache.set('purchase', purchaseParsed.hash, event, purchaseParsed, 0, false, purchaseParsed.index) } - done(parsed) + done(purchaseParsed) } }) @@ -128,13 +128,13 @@ export function getPurchasesForArticle(articleId: string, timeoutMs: number = 50 } sub.on('event', async (event: Event): Promise => { - const parsed = await parsePurchaseFromEvent(event) - if (parsed?.articleId === articleId) { + const purchaseParsed = await parsePurchaseFromEvent(event) + if (purchaseParsed?.articleId === articleId) { // Cache the parsed purchase - if (parsed.hash) { - await objectCache.set('purchase', parsed.hash, event, parsed, 0, false, parsed.index) + if (purchaseParsed.hash) { + await objectCache.set('purchase', purchaseParsed.hash, event, purchaseParsed, 0, false, purchaseParsed.index) } - results.push(parsed) + results.push(purchaseParsed) } }) diff --git a/lib/reviewTipQueries.ts b/lib/reviewTipQueries.ts index 5cf3e6a..8098263 100644 --- a/lib/reviewTipQueries.ts +++ b/lib/reviewTipQueries.ts @@ -93,13 +93,13 @@ export async function getReviewTipById(reviewTipId: string, timeoutMs: number = } sub.on('event', async (event: Event): Promise => { - const parsed = await parseReviewTipFromEvent(event) - if (parsed?.id === reviewTipId) { + const reviewTipParsed = await parseReviewTipFromEvent(event) + if (reviewTipParsed?.id === reviewTipId) { // Cache the parsed review tip - if (parsed.hash) { - await objectCache.set('review_tip', parsed.hash, event, parsed, 0, false, parsed.index) + if (reviewTipParsed.hash) { + await objectCache.set('review_tip', reviewTipParsed.hash, event, reviewTipParsed, 0, false, reviewTipParsed.index ?? 0) } - done(parsed) + done(reviewTipParsed) } }) diff --git a/lib/sponsoringQueries.ts b/lib/sponsoringQueries.ts index 99a7b06..1d853f4 100644 --- a/lib/sponsoringQueries.ts +++ b/lib/sponsoringQueries.ts @@ -93,13 +93,13 @@ export async function getSponsoringById(sponsoringId: string, timeoutMs: number } sub.on('event', async (event: Event) => { - const parsed = await parseSponsoringFromEvent(event) - if (parsed?.id === sponsoringId) { + const sponsoringParsed = await parseSponsoringFromEvent(event) + if (sponsoringParsed?.id === sponsoringId) { // Cache the parsed sponsoring - if (parsed.hash) { - await objectCache.set('sponsoring', parsed.hash, event, parsed, 0, false, parsed.index) + if (sponsoringParsed.hash) { + await objectCache.set('sponsoring', sponsoringParsed.hash, event, sponsoringParsed, 0, false, sponsoringParsed.index ?? 0) } - done(parsed) + done(sponsoringParsed) } }) @@ -135,13 +135,13 @@ export function getSponsoringByAuthor(authorPubkey: string, timeoutMs: number = } sub.on('event', async (event: Event): Promise => { - const parsed = await parseSponsoringFromEvent(event) - if (parsed?.authorPubkey === authorPubkey) { + const sponsoringParsed = await parseSponsoringFromEvent(event) + if (sponsoringParsed?.authorPubkey === authorPubkey) { // Cache the parsed sponsoring - if (parsed.hash) { - await objectCache.set('sponsoring', parsed.hash, event, parsed, 0, false, parsed.index) + if (sponsoringParsed.hash) { + await objectCache.set('sponsoring', sponsoringParsed.hash, event, sponsoringParsed, 0, false, sponsoringParsed.index ?? 0) } - results.push(parsed) + results.push(sponsoringParsed) } }) diff --git a/pages/_app.tsx b/pages/_app.tsx index a80069a..3d11932 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -3,6 +3,9 @@ import type { AppProps } from 'next/app' import { useI18n } from '@/hooks/useI18n' import React from 'react' import { platformSyncService } from '@/lib/platformSync' +import { nostrAuthService } from '@/lib/nostrAuth' +import { syncUserContentToCache } from '@/lib/userContentSync' +import { getLastSyncDate, getCurrentTimestamp } from '@/lib/syncStorage' function I18nProvider({ children }: { children: React.ReactNode }): React.ReactElement { // Get saved locale from localStorage or default to French @@ -64,6 +67,58 @@ export default function App({ Component, pageProps }: AppProps): React.ReactElem } }, []) + // Start user content sync on app mount if connected + React.useEffect(() => { + let syncInProgress = false + + const startUserSync = async (): Promise => { + if (syncInProgress) { + return + } + + const state = nostrAuthService.getState() + if (!state.connected || !state.pubkey) { + return + } + + // Check if already recently synced (within last hour) + const storedLastSyncDate = await getLastSyncDate() + const currentTimestamp = getCurrentTimestamp() + const isRecentlySynced = storedLastSyncDate >= currentTimestamp - 3600 + + if (isRecentlySynced) { + console.log('[App] User content already synced recently, skipping') + return + } + + syncInProgress = true + console.log('[App] Starting user content sync...') + + try { + await syncUserContentToCache(state.pubkey) + console.log('[App] User content sync completed') + } catch (error) { + console.error('[App] Error during user content sync:', error) + } finally { + syncInProgress = false + } + } + + // Try to start sync immediately + void startUserSync() + + // Also listen to connection changes to sync when user connects + const unsubscribe = nostrAuthService.subscribe((state) => { + if (state.connected && state.pubkey && !syncInProgress) { + void startUserSync() + } + }) + + return () => { + unsubscribe() + } + }, []) + return (