lint fix wip
This commit is contained in:
parent
b7d65a55c7
commit
e97d2b32cc
@ -5,7 +5,7 @@ export function AuthorMnemonicIcons({ value, getMnemonicIcons }: { value: string
|
|||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-1 flex-shrink-0">
|
<div className="flex items-center gap-1 flex-shrink-0">
|
||||||
{getMnemonicIcons(value).map((icon, idx) => (
|
{getMnemonicIcons(value).map((icon, idx) => (
|
||||||
<span key={idx} className="text-sm" title={`Mnemonic icon ${idx + 1}`}>
|
<span key={`mnemonic-icon-${idx}-${icon}`} className="text-sm" title={`Mnemonic icon ${idx + 1}`}>
|
||||||
{icon}
|
{icon}
|
||||||
</span>
|
</span>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -47,7 +47,7 @@ export function AuthorOption({
|
|||||||
<span className="flex-1 truncate text-cyber-accent">{displayName}</span>
|
<span className="flex-1 truncate text-cyber-accent">{displayName}</span>
|
||||||
<div className="flex items-center gap-1 flex-shrink-0">
|
<div className="flex items-center gap-1 flex-shrink-0">
|
||||||
{mnemonicIcons.map((icon, idx) => (
|
{mnemonicIcons.map((icon, idx) => (
|
||||||
<span key={idx} className="text-sm" title={`Mnemonic icon ${idx + 1}`}>
|
<span key={`mnemonic-icon-${idx}-${icon}`} className="text-sm" title={`Mnemonic icon ${idx + 1}`}>
|
||||||
{icon}
|
{icon}
|
||||||
</span>
|
</span>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -224,11 +224,15 @@ function PresentationForm({
|
|||||||
disabled={loading ?? deleting}
|
disabled={loading ?? deleting}
|
||||||
className="w-full px-4 py-2 bg-neon-cyan/20 hover:bg-neon-cyan/30 text-neon-cyan rounded-lg font-medium transition-all border border-neon-cyan/50 hover:shadow-glow-cyan disabled:opacity-50 disabled:cursor-not-allowed"
|
className="w-full px-4 py-2 bg-neon-cyan/20 hover:bg-neon-cyan/30 text-neon-cyan rounded-lg font-medium transition-all border border-neon-cyan/50 hover:shadow-glow-cyan disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
>
|
>
|
||||||
{loading ?? deleting
|
{(() => {
|
||||||
? t('publish.publishing')
|
if (loading ?? deleting) {
|
||||||
: hasExistingPresentation === true
|
return t('publish.publishing')
|
||||||
? t('presentation.update.button')
|
}
|
||||||
: t('publish.button')}
|
if (hasExistingPresentation === true) {
|
||||||
|
return t('presentation.update.button')
|
||||||
|
}
|
||||||
|
return t('publish.button')
|
||||||
|
})()}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{hasExistingPresentation && (
|
{hasExistingPresentation && (
|
||||||
@ -279,7 +283,7 @@ function useAuthorPresentationState(pubkey: string | null, existingAuthorName?:
|
|||||||
if (existingAuthorName && existingAuthorName !== draft.authorName && !existingPresentation) {
|
if (existingAuthorName && existingAuthorName !== draft.authorName && !existingPresentation) {
|
||||||
setDraft((prev) => ({ ...prev, authorName: existingAuthorName }))
|
setDraft((prev) => ({ ...prev, authorName: existingAuthorName }))
|
||||||
}
|
}
|
||||||
}, [existingAuthorName, existingPresentation])
|
}, [existingAuthorName, existingPresentation, draft.authorName])
|
||||||
|
|
||||||
const handleSubmit = useCallback(
|
const handleSubmit = useCallback(
|
||||||
async (e: FormEvent<HTMLFormElement>) => {
|
async (e: FormEvent<HTMLFormElement>) => {
|
||||||
|
|||||||
@ -25,7 +25,7 @@ export function RecoveryPhraseDisplay({
|
|||||||
<div className="grid grid-cols-2 gap-4 mb-4">
|
<div className="grid grid-cols-2 gap-4 mb-4">
|
||||||
{recoveryPhrase.map((word, index) => (
|
{recoveryPhrase.map((word, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={`recovery-word-${index}-${word}`}
|
||||||
className="bg-cyber-dark border border-neon-cyan/30 rounded-lg p-3 text-center font-mono text-lg"
|
className="bg-cyber-dark border border-neon-cyan/30 rounded-lg p-3 text-center font-mono text-lg"
|
||||||
>
|
>
|
||||||
<span className="text-cyber-accent/70 text-sm mr-2">{index + 1}.</span>
|
<span className="text-cyber-accent/70 text-sm mr-2">{index + 1}.</span>
|
||||||
|
|||||||
@ -53,21 +53,35 @@ export function SyncStatus(): React.ReactElement | null {
|
|||||||
setProgress(newProgress)
|
setProgress(newProgress)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Check current progress immediately
|
||||||
|
const currentProgress = syncProgressManager.getProgress()
|
||||||
|
if (currentProgress) {
|
||||||
|
setProgress(currentProgress)
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
if (!progress || progress.completed) {
|
// Show indicator if we have progress and it's not completed
|
||||||
|
if (!progress) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Always show indicator during sync, even if completed is false (means sync is in progress)
|
||||||
|
if (progress.completed) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const relayName = progress.currentRelay ? getRelayDisplayName(progress.currentRelay) : null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-2 ml-2" title={progress.currentRelay ? getRelayDisplayName(progress.currentRelay) : t('settings.sync.connecting')}>
|
<div className="flex items-center gap-2 ml-2" title={relayName ?? t('settings.sync.connecting')}>
|
||||||
<SyncIcon />
|
<SyncIcon />
|
||||||
{progress.currentRelay ? (
|
{relayName ? (
|
||||||
<span className="text-neon-cyan text-xs font-mono max-w-[200px] truncate">
|
<span className="text-neon-cyan text-xs font-mono max-w-[200px] truncate">
|
||||||
{getRelayDisplayName(progress.currentRelay)}
|
{relayName}
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<span className="text-cyber-accent/70 text-xs italic">
|
<span className="text-cyber-accent/70 text-xs italic">
|
||||||
|
|||||||
@ -102,15 +102,19 @@ function HomeContent({
|
|||||||
<ArticleFiltersComponent filters={filters} onFiltersChange={setFilters} articles={allArticles} />
|
<ArticleFiltersComponent filters={filters} onFiltersChange={setFilters} articles={allArticles} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isInitialLoad ? (
|
{(() => {
|
||||||
|
if (isInitialLoad) {
|
||||||
|
return (
|
||||||
<div className="text-center py-12">
|
<div className="text-center py-12">
|
||||||
<p className="text-cyber-accent/70">{t('common.loading')}</p>
|
<p className="text-cyber-accent/70">{t('common.loading')}</p>
|
||||||
</div>
|
</div>
|
||||||
) : shouldShowAuthors ? (
|
)
|
||||||
<AuthorsList {...authorsListProps} />
|
}
|
||||||
) : (
|
if (shouldShowAuthors) {
|
||||||
<ArticlesList {...articlesListProps} />
|
return <AuthorsList {...authorsListProps} />
|
||||||
)}
|
}
|
||||||
|
return <ArticlesList {...articlesListProps} />
|
||||||
|
})()}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -382,7 +382,7 @@ export function KeyManagementManager(): React.ReactElement {
|
|||||||
<div className="grid grid-cols-2 gap-4 mb-4">
|
<div className="grid grid-cols-2 gap-4 mb-4">
|
||||||
{recoveryPhrase.map((word, index) => (
|
{recoveryPhrase.map((word, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={`recovery-word-${index}-${word}`}
|
||||||
className="bg-cyber-dark border border-neon-cyan/30 rounded-lg p-3 text-center font-mono text-lg"
|
className="bg-cyber-dark border border-neon-cyan/30 rounded-lg p-3 text-center font-mono text-lg"
|
||||||
>
|
>
|
||||||
<span className="text-cyber-accent/70 text-sm mr-2">{index + 1}.</span>
|
<span className="text-cyber-accent/70 text-sm mr-2">{index + 1}.</span>
|
||||||
|
|||||||
@ -129,7 +129,7 @@ function WordInputs({
|
|||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
{words.map((word, index) => (
|
{words.map((word, index) => (
|
||||||
<WordInputWithAutocomplete
|
<WordInputWithAutocomplete
|
||||||
key={index}
|
key={`word-input-${index}-${word}`}
|
||||||
index={index}
|
index={index}
|
||||||
value={word}
|
value={word}
|
||||||
onChange={(value) => onWordChange(index, value)}
|
onChange={(value) => onWordChange(index, value)}
|
||||||
|
|||||||
@ -193,6 +193,8 @@ export function getPurchasesByPayer(payerPubkey: string, timeoutMs: number = 500
|
|||||||
sub.on('eose', (): void => {
|
sub.on('eose', (): void => {
|
||||||
void done()
|
void done()
|
||||||
})
|
})
|
||||||
setTimeout(() => done(), timeoutMs).unref?.()
|
setTimeout((): void => {
|
||||||
|
void done()
|
||||||
|
}, timeoutMs).unref?.()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -154,7 +154,9 @@ export function getReviewTipsForArticle(articleId: string, timeoutMs: number = 5
|
|||||||
sub.on('eose', (): void => {
|
sub.on('eose', (): void => {
|
||||||
void done()
|
void done()
|
||||||
})
|
})
|
||||||
setTimeout(() => done(), timeoutMs).unref?.()
|
setTimeout((): void => {
|
||||||
|
void done()
|
||||||
|
}, timeoutMs).unref?.()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,6 +200,8 @@ export function getReviewTipsForReview(reviewId: string, timeoutMs: number = 500
|
|||||||
sub.on('eose', (): void => {
|
sub.on('eose', (): void => {
|
||||||
void done()
|
void done()
|
||||||
})
|
})
|
||||||
setTimeout(() => done(), timeoutMs).unref?.()
|
setTimeout((): void => {
|
||||||
|
void done()
|
||||||
|
}, timeoutMs).unref?.()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -154,6 +154,8 @@ export function getSponsoringByAuthor(authorPubkey: string, timeoutMs: number =
|
|||||||
sub.on('eose', (): void => {
|
sub.on('eose', (): void => {
|
||||||
void done()
|
void done()
|
||||||
})
|
})
|
||||||
setTimeout(() => done(), timeoutMs).unref?.()
|
setTimeout((): void => {
|
||||||
|
void done()
|
||||||
|
}, timeoutMs).unref?.()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import { getLatestVersion } from './versionManager'
|
|||||||
import { buildTagFilter } from './nostrTagSystemFilter'
|
import { buildTagFilter } from './nostrTagSystemFilter'
|
||||||
import { getPrimaryRelaySync } from './config'
|
import { getPrimaryRelaySync } from './config'
|
||||||
import { tryWithRelayRotation } from './relayRotation'
|
import { tryWithRelayRotation } from './relayRotation'
|
||||||
import { PLATFORM_SERVICE, MIN_EVENT_DATE } from './platformConfig'
|
import { PLATFORM_SERVICE } from './platformConfig'
|
||||||
import { parseObjectId } from './urlGenerator'
|
import { parseObjectId } from './urlGenerator'
|
||||||
import type { SimplePoolWithSub } from '@/types/nostr-tools-extended'
|
import type { SimplePoolWithSub } from '@/types/nostr-tools-extended'
|
||||||
|
|
||||||
@ -24,6 +24,9 @@ async function fetchAndCachePublications(
|
|||||||
pool: SimplePoolWithSub,
|
pool: SimplePoolWithSub,
|
||||||
authorPubkey: string
|
authorPubkey: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
const { getLastSyncDate } = await import('./syncStorage')
|
||||||
|
const lastSyncDate = await getLastSyncDate()
|
||||||
|
|
||||||
const filters = [
|
const filters = [
|
||||||
{
|
{
|
||||||
...buildTagFilter({
|
...buildTagFilter({
|
||||||
@ -31,7 +34,7 @@ async function fetchAndCachePublications(
|
|||||||
authorPubkey,
|
authorPubkey,
|
||||||
service: PLATFORM_SERVICE,
|
service: PLATFORM_SERVICE,
|
||||||
}),
|
}),
|
||||||
since: MIN_EVENT_DATE,
|
since: lastSyncDate,
|
||||||
limit: 1000, // Get all publications
|
limit: 1000, // Get all publications
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -148,6 +151,9 @@ async function fetchAndCacheSeries(
|
|||||||
pool: SimplePoolWithSub,
|
pool: SimplePoolWithSub,
|
||||||
authorPubkey: string
|
authorPubkey: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
const { getLastSyncDate } = await import('./syncStorage')
|
||||||
|
const lastSyncDate = await getLastSyncDate()
|
||||||
|
|
||||||
// Fetch all events for series to cache them properly
|
// Fetch all events for series to cache them properly
|
||||||
const filters = [
|
const filters = [
|
||||||
{
|
{
|
||||||
@ -156,7 +162,7 @@ async function fetchAndCacheSeries(
|
|||||||
authorPubkey,
|
authorPubkey,
|
||||||
service: PLATFORM_SERVICE,
|
service: PLATFORM_SERVICE,
|
||||||
}),
|
}),
|
||||||
since: MIN_EVENT_DATE,
|
since: lastSyncDate,
|
||||||
limit: 1000, // Get all series events
|
limit: 1000, // Get all series events
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -278,12 +284,15 @@ async function fetchAndCachePurchases(
|
|||||||
pool: SimplePoolWithSub,
|
pool: SimplePoolWithSub,
|
||||||
payerPubkey: string
|
payerPubkey: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
const { getLastSyncDate } = await import('./syncStorage')
|
||||||
|
const lastSyncDate = await getLastSyncDate()
|
||||||
|
|
||||||
const filters = [
|
const filters = [
|
||||||
{
|
{
|
||||||
kinds: [9735], // Zap receipt
|
kinds: [9735], // Zap receipt
|
||||||
authors: [payerPubkey],
|
authors: [payerPubkey],
|
||||||
'#kind_type': ['purchase'],
|
'#kind_type': ['purchase'],
|
||||||
since: MIN_EVENT_DATE,
|
since: lastSyncDate,
|
||||||
limit: 1000,
|
limit: 1000,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -376,12 +385,15 @@ async function fetchAndCacheSponsoring(
|
|||||||
pool: SimplePoolWithSub,
|
pool: SimplePoolWithSub,
|
||||||
authorPubkey: string
|
authorPubkey: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
const { getLastSyncDate } = await import('./syncStorage')
|
||||||
|
const lastSyncDate = await getLastSyncDate()
|
||||||
|
|
||||||
const filters = [
|
const filters = [
|
||||||
{
|
{
|
||||||
kinds: [9735], // Zap receipt
|
kinds: [9735], // Zap receipt
|
||||||
'#p': [authorPubkey],
|
'#p': [authorPubkey],
|
||||||
'#kind_type': ['sponsoring'],
|
'#kind_type': ['sponsoring'],
|
||||||
since: MIN_EVENT_DATE,
|
since: lastSyncDate,
|
||||||
limit: 1000,
|
limit: 1000,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -474,12 +486,15 @@ async function fetchAndCacheReviewTips(
|
|||||||
pool: SimplePoolWithSub,
|
pool: SimplePoolWithSub,
|
||||||
authorPubkey: string
|
authorPubkey: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
const { getLastSyncDate } = await import('./syncStorage')
|
||||||
|
const lastSyncDate = await getLastSyncDate()
|
||||||
|
|
||||||
const filters = [
|
const filters = [
|
||||||
{
|
{
|
||||||
kinds: [9735], // Zap receipt
|
kinds: [9735], // Zap receipt
|
||||||
'#p': [authorPubkey],
|
'#p': [authorPubkey],
|
||||||
'#kind_type': ['review_tip'],
|
'#kind_type': ['review_tip'],
|
||||||
since: MIN_EVENT_DATE,
|
since: lastSyncDate,
|
||||||
limit: 1000,
|
limit: 1000,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -579,6 +594,9 @@ async function fetchAndCachePaymentNotes(
|
|||||||
pool: SimplePoolWithSub,
|
pool: SimplePoolWithSub,
|
||||||
userPubkey: string
|
userPubkey: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
const { getLastSyncDate } = await import('./syncStorage')
|
||||||
|
const lastSyncDate = await getLastSyncDate()
|
||||||
|
|
||||||
// Payment notes are kind 1 with type='payment'
|
// Payment notes are kind 1 with type='payment'
|
||||||
// They can be: as payer (authors) or as recipient (#recipient tag)
|
// They can be: as payer (authors) or as recipient (#recipient tag)
|
||||||
const filters = [
|
const filters = [
|
||||||
@ -587,7 +605,7 @@ async function fetchAndCachePaymentNotes(
|
|||||||
authors: [userPubkey],
|
authors: [userPubkey],
|
||||||
'#payment': [''],
|
'#payment': [''],
|
||||||
'#service': [PLATFORM_SERVICE],
|
'#service': [PLATFORM_SERVICE],
|
||||||
since: MIN_EVENT_DATE,
|
since: lastSyncDate,
|
||||||
limit: 1000,
|
limit: 1000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -595,7 +613,7 @@ async function fetchAndCachePaymentNotes(
|
|||||||
'#recipient': [userPubkey],
|
'#recipient': [userPubkey],
|
||||||
'#payment': [''],
|
'#payment': [''],
|
||||||
'#service': [PLATFORM_SERVICE],
|
'#service': [PLATFORM_SERVICE],
|
||||||
since: MIN_EVENT_DATE,
|
since: lastSyncDate,
|
||||||
limit: 1000,
|
limit: 1000,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import React from 'react'
|
|||||||
import { platformSyncService } from '@/lib/platformSync'
|
import { platformSyncService } from '@/lib/platformSync'
|
||||||
import { nostrAuthService } from '@/lib/nostrAuth'
|
import { nostrAuthService } from '@/lib/nostrAuth'
|
||||||
import { syncUserContentToCache } from '@/lib/userContentSync'
|
import { syncUserContentToCache } from '@/lib/userContentSync'
|
||||||
import { getLastSyncDate, getCurrentTimestamp } from '@/lib/syncStorage'
|
|
||||||
import { syncProgressManager } from '@/lib/syncProgressManager'
|
import { syncProgressManager } from '@/lib/syncProgressManager'
|
||||||
import { relaySessionManager } from '@/lib/relaySessionManager'
|
import { relaySessionManager } from '@/lib/relaySessionManager'
|
||||||
|
|
||||||
@ -74,27 +73,20 @@ export default function App({ Component, pageProps }: AppProps): React.ReactElem
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
// Start user content sync on app mount if connected
|
// Start user content sync on app mount and on each page navigation if connected
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
let syncInProgress = false
|
let syncInProgress = false
|
||||||
|
|
||||||
const startUserSync = async (): Promise<void> => {
|
const startUserSync = async (): Promise<void> => {
|
||||||
if (syncInProgress) {
|
if (syncInProgress) {
|
||||||
|
console.log('[App] Sync already in progress, skipping')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = nostrAuthService.getState()
|
const state = nostrAuthService.getState()
|
||||||
|
console.log('[App] Checking connection state:', { connected: state.connected, hasPubkey: Boolean(state.pubkey) })
|
||||||
if (!state.connected || !state.pubkey) {
|
if (!state.connected || !state.pubkey) {
|
||||||
return
|
console.log('[App] Not connected or no pubkey, skipping sync')
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +113,16 @@ export default function App({ Component, pageProps }: AppProps): React.ReactElem
|
|||||||
// Try to start sync immediately
|
// Try to start sync immediately
|
||||||
void startUserSync()
|
void startUserSync()
|
||||||
|
|
||||||
// Also listen to connection changes to sync when user connects
|
// Also listen to connection changes and route changes to sync when user connects or navigates
|
||||||
|
const router = require('next/router').default
|
||||||
|
const handleRouteChange = (): void => {
|
||||||
|
if (!syncInProgress) {
|
||||||
|
void startUserSync()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
router.events?.on('routeChangeComplete', handleRouteChange)
|
||||||
|
|
||||||
const unsubscribe = nostrAuthService.subscribe((state) => {
|
const unsubscribe = nostrAuthService.subscribe((state) => {
|
||||||
if (state.connected && state.pubkey && !syncInProgress) {
|
if (state.connected && state.pubkey && !syncInProgress) {
|
||||||
void startUserSync()
|
void startUserSync()
|
||||||
@ -129,6 +130,7 @@ export default function App({ Component, pageProps }: AppProps): React.ReactElem
|
|||||||
})
|
})
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
router.events?.off('routeChangeComplete', handleRouteChange)
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user