From c1442886cff757a5368d4937b026dcd96dc2b367 Mon Sep 17 00:00:00 2001 From: Nicolas Cantu Date: Tue, 6 Jan 2026 17:45:45 +0100 Subject: [PATCH] lint fix wip --- components/AuthorPresentationEditor.tsx | 2 +- components/Nip95ConfigManager.tsx | 140 ++++++++++++++++++++---- components/ProfileView.tsx | 2 +- components/SyncProgressBar.tsx | 122 ++++++++++++++++++--- components/UnlockAccountModal.tsx | 2 +- hooks/useArticles.ts | 123 ++++++++++++--------- lib/articlePublisher.ts | 8 +- lib/articleQueries.ts | 12 +- lib/automaticTransfer.ts | 2 +- lib/config.ts | 10 +- lib/mempoolSpaceConfirmation.ts | 6 +- lib/nostrEventParsing.ts | 57 ++++++---- lib/nostrSubscription.ts | 8 +- lib/paymentNotes.ts | 27 ++++- lib/reviewRewardInvoice.ts | 2 +- lib/sponsoringPayment.ts | 4 +- lib/userContentSync.ts | 14 ++- public/locales/en.txt | 4 +- public/locales/fr.txt | 4 +- 19 files changed, 397 insertions(+), 152 deletions(-) diff --git a/components/AuthorPresentationEditor.tsx b/components/AuthorPresentationEditor.tsx index 9713a53..588af21 100644 --- a/components/AuthorPresentationEditor.tsx +++ b/components/AuthorPresentationEditor.tsx @@ -226,7 +226,7 @@ function PresentationForm({ > {loading ?? deleting ? t('publish.publishing') - : hasExistingPresentation + : hasExistingPresentation === true ? t('presentation.update.button') : t('publish.button')} diff --git a/components/Nip95ConfigManager.tsx b/components/Nip95ConfigManager.tsx index e0fb015..4bedcf1 100644 --- a/components/Nip95ConfigManager.tsx +++ b/components/Nip95ConfigManager.tsx @@ -15,6 +15,8 @@ export function Nip95ConfigManager({ onConfigChange }: Nip95ConfigManagerProps): const [editingId, setEditingId] = useState(null) const [newUrl, setNewUrl] = useState('') const [showAddForm, setShowAddForm] = useState(false) + const [draggedId, setDraggedId] = useState(null) + const [dragOverId, setDragOverId] = useState(null) useEffect(() => { void loadApis() @@ -47,18 +49,95 @@ export function Nip95ConfigManager({ onConfigChange }: Nip95ConfigManagerProps): } } - async function handleUpdatePriority(id: string, priority: number): Promise { + async function handleUpdatePriorities(newOrder: Nip95Config[]): Promise { try { - await configStorage.updateNip95Api(id, { priority }) + // Update priorities based on new order (priority = index + 1, lower number = higher priority) + const updatePromises = newOrder.map((api, index) => { + const newPriority = index + 1 + if (api.priority !== newPriority) { + return configStorage.updateNip95Api(api.id, { priority: newPriority }) + } + return Promise.resolve() + }) + + await Promise.all(updatePromises) await loadApis() onConfigChange?.() } catch (e) { const errorMessage = e instanceof Error ? e.message : t('settings.nip95.error.priorityFailed') setError(errorMessage) - console.error('Error updating priority:', e) + console.error('Error updating priorities:', e) } } + function handleDragStart(e: React.DragEvent, id: string): void { + setDraggedId(id) + e.dataTransfer.effectAllowed = 'move' + e.dataTransfer.setData('text/plain', id) + } + + function handleDragOver(e: React.DragEvent, id: string): void { + e.preventDefault() + e.dataTransfer.dropEffect = 'move' + setDragOverId(id) + } + + function handleDragLeave(): void { + setDragOverId(null) + } + + function handleDrop(e: React.DragEvent, targetId: string): void { + e.preventDefault() + setDragOverId(null) + + if (!draggedId || draggedId === targetId) { + setDraggedId(null) + return + } + + const draggedIndex = apis.findIndex((api) => api.id === draggedId) + const targetIndex = apis.findIndex((api) => api.id === targetId) + + if (draggedIndex === -1 || targetIndex === -1) { + setDraggedId(null) + return + } + + // Reorder the array + const newApis = [...apis] + const removed = newApis[draggedIndex] + if (!removed) { + setDraggedId(null) + return + } + newApis.splice(draggedIndex, 1) + newApis.splice(targetIndex, 0, removed) + + setApis(newApis) + setDraggedId(null) + + // Update priorities based on new order + void handleUpdatePriorities(newApis) + } + + function DragHandle(): React.ReactElement { + return ( +
+ + + + + + + + + + + +
+ ) + } + async function handleUpdateUrl(id: string, url: string): Promise { try { await configStorage.updateNip95Api(id, { url }) @@ -186,13 +265,40 @@ export function Nip95ConfigManager({ onConfigChange }: Nip95ConfigManagerProps): {t('settings.nip95.empty')} ) : ( - apis.map((api) => ( + apis.map((api, index) => (
{ + handleDragOver(e, api.id) + }} + onDragLeave={handleDragLeave} + onDrop={(e) => { + handleDrop(e, api.id) + }} + className={`bg-cyber-dark border rounded p-4 space-y-3 transition-all ${ + draggedId === api.id + ? 'opacity-50 border-neon-cyan' + : dragOverId === api.id + ? 'border-neon-green shadow-lg' + : 'border-neon-cyan/30' + }`} >
-
+
+
{ + handleDragStart(e, api.id) + e.stopPropagation() + }} + onMouseDown={(e) => { + e.stopPropagation() + }} + > + +
+
{editingId === api.id ? (
)} +
-
- +
+ + {t('settings.nip95.list.priorityLabel', { priority: index + 1, id: api.id })} +
)) diff --git a/components/ProfileView.tsx b/components/ProfileView.tsx index a59cfbc..b93f96f 100644 --- a/components/ProfileView.tsx +++ b/components/ProfileView.tsx @@ -78,7 +78,7 @@ function ProfileHeaderSection({ {loadingProfile ? ( - ) : profile ? ( + ) : profile !== null && profile !== undefined ? ( ) : null} diff --git a/components/SyncProgressBar.tsx b/components/SyncProgressBar.tsx index 9f95ee3..369274a 100644 --- a/components/SyncProgressBar.tsx +++ b/components/SyncProgressBar.tsx @@ -1,8 +1,9 @@ import { useState, useEffect } from 'react' import { nostrAuthService } from '@/lib/nostrAuth' import { syncUserContentToCache, type SyncProgress } from '@/lib/userContentSync' -import { getLastSyncDate, getCurrentTimestamp, calculateDaysBetween } from '@/lib/syncStorage' +import { getLastSyncDate, setLastSyncDate as setLastSyncDateStorage, getCurrentTimestamp, calculateDaysBetween } from '@/lib/syncStorage' import { MIN_EVENT_DATE } from '@/lib/platformConfig' +import { objectCache } from '@/lib/objectCache' import { t } from '@/lib/i18n' export function SyncProgressBar(): React.ReactElement | null { @@ -10,6 +11,9 @@ export function SyncProgressBar(): React.ReactElement | null { const [isSyncing, setIsSyncing] = useState(false) const [lastSyncDate, setLastSyncDate] = useState(null) const [totalDays, setTotalDays] = useState(0) + const [isInitialized, setIsInitialized] = useState(false) + const [connectionState, setConnectionState] = useState<{ connected: boolean; pubkey: string | null }>({ connected: false, pubkey: null }) + const [error, setError] = useState(null) async function loadSyncStatus(): Promise { try { @@ -30,10 +34,64 @@ export function SyncProgressBar(): React.ReactElement | null { } useEffect(() => { - void loadSyncStatus() + // Check connection state + const checkConnection = (): void => { + const state = nostrAuthService.getState() + setConnectionState({ connected: state.connected ?? false, pubkey: state.pubkey ?? null }) + setIsInitialized(true) + } + + // Initial check + checkConnection() + + // Listen to connection changes + const unsubscribe = nostrAuthService.subscribe((state) => { + setConnectionState({ connected: state.connected ?? false, pubkey: state.pubkey ?? null }) + }) + + return () => { + unsubscribe() + } }, []) - async function startSync(): Promise { + useEffect(() => { + if (!isInitialized || !connectionState.connected || !connectionState.pubkey) { + return + } + + void (async () => { + await loadSyncStatus() + + // Auto-start sync if not recently synced + const storedLastSyncDate = await getLastSyncDate() + const currentTimestamp = getCurrentTimestamp() + const isRecentlySynced = storedLastSyncDate >= currentTimestamp - 3600 + + // Only auto-start if not recently synced + if (!isRecentlySynced && !isSyncing && connectionState.pubkey) { + setIsSyncing(true) + setSyncProgress({ currentStep: 0, totalSteps: 6, completed: false }) + + try { + await syncUserContentToCache(connectionState.pubkey, (progress) => { + setSyncProgress(progress) + if (progress.completed) { + setIsSyncing(false) + void loadSyncStatus() + } + }) + // Check if sync completed successfully (if it didn't, isSyncing should still be false) + setIsSyncing(false) + } catch (error) { + console.error('Error during auto-sync:', error) + setIsSyncing(false) + setError(error instanceof Error ? error.message : 'Erreur de synchronisation') + } + } + })() + }, [isInitialized, connectionState.connected, connectionState.pubkey]) + + async function resynchronize(): Promise { try { const state = nostrAuthService.getState() if (!state.connected || !state.pubkey) { @@ -43,22 +101,41 @@ export function SyncProgressBar(): React.ReactElement | null { setIsSyncing(true) setSyncProgress({ currentStep: 0, totalSteps: 6, completed: false }) - await syncUserContentToCache(state.pubkey, (progress) => { - setSyncProgress(progress) - if (progress.completed) { - setIsSyncing(false) - void loadSyncStatus() - } - }) + // Clear cache for user content (but keep other data) + await Promise.all([ + objectCache.clear('author'), + objectCache.clear('series'), + objectCache.clear('publication'), + objectCache.clear('review'), + objectCache.clear('purchase'), + objectCache.clear('sponsoring'), + objectCache.clear('review_tip'), + ]) + + // Reset last sync date to force full resync + await setLastSyncDateStorage(MIN_EVENT_DATE) + + // Reload sync status + await loadSyncStatus() + + // Start full resynchronization + if (state.pubkey !== null) { + await syncUserContentToCache(state.pubkey, (progress) => { + setSyncProgress(progress) + if (progress.completed) { + setIsSyncing(false) + void loadSyncStatus() + } + }) + } } catch (error) { - console.error('Error starting sync:', error) + console.error('Error resynchronizing:', error) setIsSyncing(false) } } - // Don't show if not connected - const state = nostrAuthService.getState() - if (!state.connected || !state.pubkey) { + // Don't show if not initialized or not connected + if (!isInitialized || !connectionState.connected || !connectionState.pubkey) { return null } @@ -87,6 +164,19 @@ export function SyncProgressBar(): React.ReactElement | null { return (
+ {error && ( +
+ {error} + +
+ )}

{t('settings.sync.title')} @@ -94,11 +184,11 @@ export function SyncProgressBar(): React.ReactElement | null { {!isSyncing && ( )}

diff --git a/components/UnlockAccountModal.tsx b/components/UnlockAccountModal.tsx index 209e0a3..880b763 100644 --- a/components/UnlockAccountModal.tsx +++ b/components/UnlockAccountModal.tsx @@ -160,7 +160,7 @@ function useUnlockAccount(words: string[], setWords: (words: string[]) => void, setWords(pastedWords.map((w) => w.toLowerCase())) setError(null) } - } catch (_e) { + } catch { // Ignore clipboard errors } } diff --git a/hooks/useArticles.ts b/hooks/useArticles.ts index e3df55c..791f6bf 100644 --- a/hooks/useArticles.ts +++ b/hooks/useArticles.ts @@ -24,7 +24,7 @@ export function useArticles(searchQuery: string = '', filters: ArticleFilters | setError(null) // Load authors from cache first - const loadAuthorsFromCache = async (): Promise => { + const loadAuthorsFromCache = async (): Promise => { try { const cachedAuthors = await objectCache.getAll('author') const authors = cachedAuthors as Article[] @@ -40,69 +40,90 @@ export function useArticles(searchQuery: string = '', filters: ArticleFilters | return merged }) setLoading(false) - } - // Calculate totalSponsoring asynchronously from cache (non-blocking) - // Only update authors that don't have totalSponsoring yet - const authorsNeedingSponsoring = authors.filter( - (author) => author.isPresentation && author.pubkey && author.totalSponsoring === undefined - ) - - if (authorsNeedingSponsoring.length > 0) { - // Load sponsoring from cache in parallel (fast, no network) - const sponsoringPromises = authorsNeedingSponsoring.map(async (author) => { - if (author.pubkey) { - const totalSponsoring = await getAuthorSponsoring(author.pubkey, true) - return { authorId: author.id, totalSponsoring } - } - return null - }) - - const sponsoringResults = await Promise.all(sponsoringPromises) - - // Update articles with sponsoring amounts - setArticles((prev) => - prev.map((article) => { - const sponsoringResult = sponsoringResults.find((r) => r?.authorId === article.id) - if (sponsoringResult && article.isPresentation) { - return { ...article, totalSponsoring: sponsoringResult.totalSponsoring } - } - return article - }) + // Calculate totalSponsoring asynchronously from cache (non-blocking) + // Only update authors that don't have totalSponsoring yet + const authorsNeedingSponsoring = authors.filter( + (author) => author.isPresentation && author.pubkey && author.totalSponsoring === undefined ) + + if (authorsNeedingSponsoring.length > 0) { + // Load sponsoring from cache in parallel (fast, no network) + const sponsoringPromises = authorsNeedingSponsoring.map(async (author) => { + if (author.pubkey) { + const totalSponsoring = await getAuthorSponsoring(author.pubkey, true) + return { authorId: author.id, totalSponsoring } + } + return null + }) + + const sponsoringResults = await Promise.all(sponsoringPromises) + + // Update articles with sponsoring amounts + setArticles((prev) => + prev.map((article) => { + const sponsoringResult = sponsoringResults.find((r) => r?.authorId === article.id) + if (sponsoringResult && article.isPresentation) { + return { ...article, totalSponsoring: sponsoringResult.totalSponsoring } + } + return article + }) + ) + } + + return true } + + // Cache is empty - stop loading immediately, no network requests needed + setLoading(false) + hasArticlesRef.current = false + return false } catch (error) { console.error('Error loading authors from cache:', error) + setLoading(false) + return false } } - void loadAuthorsFromCache() + let unsubscribe: (() => void) | null = null + let timeout: NodeJS.Timeout | null = null - const unsubscribe = nostrService.subscribeToArticles( - (article) => { - setArticles((prev) => { - if (prev.some((a) => a.id === article.id)) { - return prev + void loadAuthorsFromCache().then((hasCachedAuthors) => { + // Only subscribe to network if cache is empty (to fetch new content) + // If cache has authors, we can skip network subscription for faster load + if (!hasCachedAuthors) { + unsubscribe = nostrService.subscribeToArticles( + (article) => { + setArticles((prev) => { + if (prev.some((a) => a.id === article.id)) { + return prev + } + const next = [article, ...prev].sort((a, b) => b.createdAt - a.createdAt) + hasArticlesRef.current = next.length > 0 + return next + }) + setLoading(false) + }, + 50 + ) + + // Shorter timeout if cache is empty (5 seconds instead of 10) + timeout = setTimeout(() => { + setLoading(false) + if (!hasArticlesRef.current) { + setError(t('common.error.noContent')) } - const next = [article, ...prev].sort((a, b) => b.createdAt - a.createdAt) - hasArticlesRef.current = next.length > 0 - return next - }) - setLoading(false) - }, - 50 - ) - - const timeout = setTimeout(() => { - setLoading(false) - if (!hasArticlesRef.current) { - setError(t('common.error.noContent')) + }, 5000) } - }, 10000) + }) return () => { - unsubscribe() - clearTimeout(timeout) + if (unsubscribe) { + unsubscribe() + } + if (timeout) { + clearTimeout(timeout) + } } }, []) diff --git a/lib/articlePublisher.ts b/lib/articlePublisher.ts index e7d1841..1e31d4c 100644 --- a/lib/articlePublisher.ts +++ b/lib/articlePublisher.ts @@ -63,7 +63,8 @@ export class ArticlePublisher { try { const validation = await this.validatePublishRequest(draft, authorPubkey, authorPrivateKey) if (!validation.success) { - return buildFailure(validation.error) + const { error } = validation + return buildFailure(error) } const presentation = await this.getAuthorPresentation(authorPubkey) @@ -188,8 +189,9 @@ export class ArticlePublisher { const parsed = parsePresentationEvent(publishedEvent) if (parsed) { const tags = extractTagsFromEvent(publishedEvent) - if (tags.id) { - await objectCache.set('author', tags.id, publishedEvent, parsed, tags.version, tags.hidden) + const { id: tagId, version: tagVersion, hidden: tagHidden } = tags + if (tagId) { + await objectCache.set('author', tagId, publishedEvent, parsed, tagVersion ?? 0, tagHidden ?? false) } } diff --git a/lib/articleQueries.ts b/lib/articleQueries.ts index 7d2d473..5ff64d6 100644 --- a/lib/articleQueries.ts +++ b/lib/articleQueries.ts @@ -44,11 +44,13 @@ export function getArticlesBySeries(seriesId: string, timeoutMs: number = 5000, resolve(results) } - sub.on('event', async (event: Event): Promise => { - const parsed = await parseArticleFromEvent(event) - if (parsed) { - results.push(parsed) - } + sub.on('event', (event: Event): void => { + void (async (): Promise => { + const parsed = await parseArticleFromEvent(event) + if (parsed) { + results.push(parsed) + } + })() }) sub.on('eose', (): void => { diff --git a/lib/automaticTransfer.ts b/lib/automaticTransfer.ts index 6946f57..2d0177f 100644 --- a/lib/automaticTransfer.ts +++ b/lib/automaticTransfer.ts @@ -31,7 +31,7 @@ export class AutomaticTransferService { platformCommission, timestamp: new Date().toISOString(), } - console.log(`Automatic transfer required${type === 'review' ? ' for review' : ''}`, logData) + console.warn(`Automatic transfer required${type === 'review' ? ' for review' : ''}`, logData) } private buildTransferError(error: unknown, recipient: string, amount: number = 0): TransferResult { diff --git a/lib/config.ts b/lib/config.ts index 3b4e208..1ad71ce 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -16,7 +16,7 @@ export async function getPrimaryRelay(): Promise { } try { - return await configStorage.getPrimaryRelay() + return configStorage.getPrimaryRelay() } catch (error) { console.error('Error getting primary relay from IndexedDB:', error) return getPrimaryRelaySync() @@ -33,7 +33,7 @@ export async function getEnabledRelays(): Promise { } try { - return await configStorage.getEnabledRelays() + return configStorage.getEnabledRelays() } catch (error) { console.error('Error getting enabled relays from IndexedDB:', error) return [getPrimaryRelaySync()] @@ -50,7 +50,7 @@ export async function getPrimaryNip95Api(): Promise { } try { - return await configStorage.getPrimaryNip95Api() + return configStorage.getPrimaryNip95Api() } catch (error) { console.error('Error getting primary NIP-95 API from IndexedDB:', error) return getPrimaryNip95ApiSync() @@ -67,7 +67,7 @@ export async function getEnabledNip95Apis(): Promise { } try { - return await configStorage.getEnabledNip95Apis() + return configStorage.getEnabledNip95Apis() } catch (error) { console.error('Error getting enabled NIP-95 APIs from IndexedDB:', error) return [getPrimaryNip95ApiSync()] @@ -84,7 +84,7 @@ export async function getPlatformLightningAddress(): Promise { } try { - return await configStorage.getPlatformLightningAddress() + return configStorage.getPlatformLightningAddress() } catch (error) { console.error('Error getting platform Lightning address from IndexedDB:', error) return getPlatformLightningAddressSync() diff --git a/lib/mempoolSpaceConfirmation.ts b/lib/mempoolSpaceConfirmation.ts index 0810db8..36270b8 100644 --- a/lib/mempoolSpaceConfirmation.ts +++ b/lib/mempoolSpaceConfirmation.ts @@ -53,9 +53,9 @@ export async function waitForConfirmation( const startTime = Date.now() return new Promise((resolve) => { - const checkConfirmation = async (): Promise => { - await checkTransactionStatus(txid, startTime, timeout, interval, resolve, checkConfirmation) + const checkConfirmation = (): void => { + void checkTransactionStatus(txid, startTime, timeout, interval, resolve, checkConfirmation) } - void checkConfirmation() + checkConfirmation() }) } diff --git a/lib/nostrEventParsing.ts b/lib/nostrEventParsing.ts index e4ccbc0..75abbe7 100644 --- a/lib/nostrEventParsing.ts +++ b/lib/nostrEventParsing.ts @@ -17,7 +17,7 @@ export async function parseArticleFromEvent(event: Event): Promise
return null } // Map category from new system to old system - const category = tags.category === 'sciencefiction' ? 'science-fiction' : tags.category === 'research' ? 'scientific-research' : 'science-fiction' + let category: 'science-fiction' | 'scientific-research' = 'science-fiction' + if (tags.category === 'sciencefiction') { + category = 'science-fiction' + } else if (tags.category === 'research') { + category = 'scientific-research' + } // Extract hash, version, index from id tag or parse it let hash: string @@ -44,10 +49,11 @@ export async function parseSeriesFromEvent(event: Event): Promise if (tags.id) { const parsed = parseObjectId(tags.id) - if (parsed.hash) { - hash = parsed.hash - version = parsed.version ?? version - index = parsed.index ?? index + const { hash: parsedHash, version: parsedVersion, index: parsedIndex } = parsed + if (parsedHash) { + hash = parsedHash + version = parsedVersion ?? version + index = parsedIndex ?? index } else { // If id is just a hash, use it directly hash = tags.id @@ -109,10 +115,11 @@ export async function parseReviewFromEvent(event: Event): Promise if (tags.id) { const parsed = parseObjectId(tags.id) - if (parsed.hash) { - hash = parsed.hash - version = parsed.version ?? version - index = parsed.index ?? index + const { hash: parsedHash, version: parsedVersion, index: parsedIndex } = parsed + if (parsedHash) { + hash = parsedHash + version = parsedVersion ?? version + index = parsedIndex ?? index } else { // If id is just a hash, use it directly hash = tags.id @@ -207,8 +214,9 @@ async function buildArticle(event: Event, tags: ReturnType tag[0] === 'json')?.[1] if (jsonTag) { const metadata = JSON.parse(jsonTag) as { pages?: Page[] } - if (metadata.pages && Array.isArray(metadata.pages)) { - pages = metadata.pages + const { pages: metadataPages } = metadata + if (metadataPages && Array.isArray(metadataPages)) { + pages = metadataPages } } } catch (e) { @@ -229,7 +237,7 @@ async function buildArticle(event: Event, tags: ReturnType 0 ? { pages } : {}), - ...(tags.type === 'publication' ? { kindType: 'article' as KindType } : tags.type === 'author' ? { kindType: 'article' as KindType } : {}), + ...(tags.type === 'publication' || tags.type === 'author' ? { kindType: 'article' as KindType } : {}), } } @@ -255,9 +263,10 @@ export async function parsePurchaseFromEvent(event: Event): Promise( resolve(value) } - sub.on('event', async (event: Event): Promise => { - const result = await parser(event) - resolveOnce(result) + sub.on('event', (event: Event): void => { + void (async (): Promise => { + const result = await parser(event) + resolveOnce(result) + })() }) sub.on('eose', (): void => { resolveOnce(null) diff --git a/lib/paymentNotes.ts b/lib/paymentNotes.ts index 505d004..3453215 100644 --- a/lib/paymentNotes.ts +++ b/lib/paymentNotes.ts @@ -20,7 +20,12 @@ export async function publishPurchaseNote(params: { seriesId?: string payerPrivateKey: string }): Promise { - const category = params.category === 'science-fiction' ? 'sciencefiction' : params.category === 'scientific-research' ? 'research' : 'sciencefiction' + let category: 'sciencefiction' | 'research' = 'sciencefiction' + if (params.category === 'science-fiction') { + category = 'sciencefiction' + } else if (params.category === 'scientific-research') { + category = 'research' + } const purchaseData = { payerPubkey: params.payerPubkey, @@ -71,7 +76,7 @@ export async function publishPurchaseNote(params: { } nostrService.setPrivateKey(params.payerPrivateKey) - return await nostrService.publishEvent(eventTemplate) + return nostrService.publishEvent(eventTemplate) } /** @@ -92,7 +97,12 @@ export async function publishReviewTipNote(params: { text?: string payerPrivateKey: string }): Promise { - const category = params.category === 'science-fiction' ? 'sciencefiction' : params.category === 'scientific-research' ? 'research' : 'sciencefiction' + let category: 'sciencefiction' | 'research' = 'sciencefiction' + if (params.category === 'science-fiction') { + category = 'sciencefiction' + } else if (params.category === 'scientific-research') { + category = 'research' + } const tipData = { payerPubkey: params.payerPubkey, @@ -152,7 +162,7 @@ export async function publishReviewTipNote(params: { } nostrService.setPrivateKey(params.payerPrivateKey) - return await nostrService.publishEvent(eventTemplate) + return nostrService.publishEvent(eventTemplate) } /** @@ -171,7 +181,12 @@ export async function publishSponsoringNote(params: { transactionId?: string // Bitcoin transaction ID for mainnet payments payerPrivateKey: string }): Promise { - const category = params.category === 'science-fiction' ? 'sciencefiction' : params.category === 'scientific-research' ? 'research' : 'sciencefiction' + let category: 'sciencefiction' | 'research' = 'sciencefiction' + if (params.category === 'science-fiction') { + category = 'sciencefiction' + } else if (params.category === 'scientific-research') { + category = 'research' + } const sponsoringData = { payerPubkey: params.payerPubkey, @@ -234,5 +249,5 @@ export async function publishSponsoringNote(params: { } nostrService.setPrivateKey(params.payerPrivateKey) - return await nostrService.publishEvent(eventTemplate) + return nostrService.publishEvent(eventTemplate) } diff --git a/lib/reviewRewardInvoice.ts b/lib/reviewRewardInvoice.ts index bfa54b5..e965479 100644 --- a/lib/reviewRewardInvoice.ts +++ b/lib/reviewRewardInvoice.ts @@ -5,7 +5,7 @@ export async function createReviewInvoice(split: { total: number; reviewer: numb const alby = getAlbyService() await alby.enable() - return await alby.createInvoice({ + return alby.createInvoice({ amount: split.total, description: `Review reward: ${request.reviewId} (${split.reviewer} sats to reviewer, ${split.platform} sats commission)`, expiry: 3600, // 1 hour diff --git a/lib/sponsoringPayment.ts b/lib/sponsoringPayment.ts index 9ed118a..9c2c7af 100644 --- a/lib/sponsoringPayment.ts +++ b/lib/sponsoringPayment.ts @@ -76,7 +76,7 @@ export class SponsoringPaymentService { authorPubkey: string, authorMainnetAddress: string ): Promise { - return await verifySponsoringPayment(transactionId, authorPubkey, authorMainnetAddress) + return verifySponsoringPayment(transactionId, authorPubkey, authorMainnetAddress) } /** @@ -88,7 +88,7 @@ export class SponsoringPaymentService { authorMainnetAddress: string, authorPrivateKey: string ): Promise { - return await trackSponsoringPayment(transactionId, authorPubkey, authorMainnetAddress, authorPrivateKey) + return trackSponsoringPayment(transactionId, authorPubkey, authorMainnetAddress, authorPrivateKey) } } diff --git a/lib/userContentSync.ts b/lib/userContentSync.ts index 5eea6e1..03dc452 100644 --- a/lib/userContentSync.ts +++ b/lib/userContentSync.ts @@ -408,8 +408,9 @@ export async function syncUserContentToCache( try { const pool = nostrService.getPool() if (!pool) { - console.warn('Pool not initialized, cannot sync user content') - return + const errorMsg = 'Pool not initialized, cannot sync user content' + console.warn(errorMsg) + throw new Error(errorMsg) } const poolWithSub = pool as unknown as SimplePoolWithSub @@ -428,6 +429,7 @@ export async function syncUserContentToCache( let currentStep = 0 // Fetch and cache author profile (already caches itself) + console.log('[Sync] Step 1/6: Fetching author profile...') await fetchAuthorPresentationFromPool(poolWithSub, userPubkey) currentStep++ if (onProgress) { @@ -435,6 +437,7 @@ export async function syncUserContentToCache( } // Fetch and cache all series + console.log('[Sync] Step 2/6: Fetching series...') await fetchAndCacheSeries(poolWithSub, userPubkey) currentStep++ if (onProgress) { @@ -442,6 +445,7 @@ export async function syncUserContentToCache( } // Fetch and cache all publications + console.log('[Sync] Step 3/6: Fetching publications...') await fetchAndCachePublications(poolWithSub, userPubkey) currentStep++ if (onProgress) { @@ -449,6 +453,7 @@ export async function syncUserContentToCache( } // Fetch and cache all purchases (as payer) + console.log('[Sync] Step 4/6: Fetching purchases...') await fetchAndCachePurchases(poolWithSub, userPubkey) currentStep++ if (onProgress) { @@ -456,6 +461,7 @@ export async function syncUserContentToCache( } // Fetch and cache all sponsoring (as author) + console.log('[Sync] Step 5/6: Fetching sponsoring...') await fetchAndCacheSponsoring(poolWithSub, userPubkey) currentStep++ if (onProgress) { @@ -463,6 +469,7 @@ export async function syncUserContentToCache( } // Fetch and cache all review tips (as author) + console.log('[Sync] Step 6/6: Fetching review tips...') await fetchAndCacheReviewTips(poolWithSub, userPubkey) currentStep++ if (onProgress) { @@ -471,8 +478,9 @@ export async function syncUserContentToCache( // Store the current timestamp as last sync date await setLastSyncDate(currentTimestamp) + console.log('[Sync] Synchronization completed successfully') } catch (error) { console.error('Error syncing user content to cache:', error) - // Don't throw - this is a background operation + throw error // Re-throw to allow UI to handle it } } diff --git a/public/locales/en.txt b/public/locales/en.txt index c869efe..779c876 100644 --- a/public/locales/en.txt +++ b/public/locales/en.txt @@ -237,7 +237,7 @@ settings.keyManagement.recovery.copied=✓ Copied! settings.keyManagement.recovery.newNpub=Your new public key (npub) settings.keyManagement.recovery.done=Done settings.sync.title=Notes Synchronization -settings.sync.start=Start Synchronization +settings.sync.resync=Resynchronize settings.sync.daysRange=From {{startDate}} to {{endDate}} ({{days}} days) settings.sync.progress=Step {{current}} of {{total}} settings.sync.completed=Everything is synchronized @@ -269,7 +269,7 @@ settings.nip95.list.cancel=Cancel settings.nip95.list.remove=Remove settings.nip95.remove.confirm=Are you sure you want to remove this endpoint? settings.nip95.empty=No endpoints configured -settings.nip95.list.priorityLabel=Priority: {{priority}} | ID: {{id}} +settings.nip95.list.priorityLabel=Priority {{priority}} (ID: {{id}}) settings.nip95.list.editUrl=Click to edit URL settings.nip95.note.title=Note: settings.nip95.note.priority=Endpoints are tried in priority order (lower number = higher priority). Only enabled endpoints will be used for uploads. diff --git a/public/locales/fr.txt b/public/locales/fr.txt index 4cb2ed9..7edb4c6 100644 --- a/public/locales/fr.txt +++ b/public/locales/fr.txt @@ -237,7 +237,7 @@ settings.keyManagement.recovery.copied=✓ Copié ! settings.keyManagement.recovery.newNpub=Votre nouvelle clé publique (npub) settings.keyManagement.recovery.done=Terminé settings.sync.title=Synchronisation des notes -settings.sync.start=Démarrer la synchronisation +settings.sync.resync=Resynchroniser settings.sync.daysRange=Du {{startDate}} au {{endDate}} ({{days}} jours) settings.sync.progress=Étape {{current}} sur {{total}} settings.sync.completed=Tout est synchronisé @@ -274,7 +274,7 @@ settings.nip95.list.cancel=Annuler settings.nip95.list.remove=Supprimer settings.nip95.remove.confirm=Êtes-vous sûr de vouloir supprimer cet endpoint ? settings.nip95.empty=Aucun endpoint configuré -settings.nip95.list.priorityLabel=Priorité: {{priority}} | ID: {{id}} +settings.nip95.list.priorityLabel=Priorité {{priority}} (ID: {{id}}) settings.nip95.list.editUrl=Cliquer pour modifier l'URL settings.nip95.note.title=Note : settings.nip95.note.priority=Les endpoints sont essayés dans l'ordre de priorité (nombre plus bas = priorité plus haute). Seuls les endpoints activés seront utilisés pour les uploads.