2026-01-06 20:59:59 +01:00

105 lines
3.5 KiB
TypeScript

import type { Page } from '@/types/nostr'
import { t } from '@/lib/i18n'
import { useNostrAuth } from '@/hooks/useNostrAuth'
import { useEffect, useState } from 'react'
import { objectCache } from '@/lib/objectCache'
interface ArticlePagesProps {
pages: Page[]
articleId: string
}
export function ArticlePages({ pages, articleId }: ArticlePagesProps): React.ReactElement | null {
const { pubkey } = useNostrAuth()
const [hasPurchased, setHasPurchased] = useState(false)
useEffect(() => {
const checkPurchase = async (): Promise<void> => {
if (!pubkey || !articleId) {
setHasPurchased(false)
return
}
try {
// Check if user has purchased this article from cache
const purchases = await objectCache.getAll('purchase')
const userPurchases = purchases.filter((p) => {
if (typeof p !== 'object' || p === null) {
return false
}
const purchase = p as { payerPubkey?: string; articleId?: string }
return purchase.payerPubkey === pubkey && purchase.articleId === articleId
})
setHasPurchased(userPurchases.length > 0)
} catch (error) {
console.error('Error checking purchase status:', error)
setHasPurchased(false)
}
}
void checkPurchase()
}, [pubkey, articleId])
if (!pages || pages.length === 0) {
return null
}
// If user hasn't purchased, show locked message
if (!hasPurchased) {
return (
<div className="space-y-6 mt-6">
<h3 className="text-xl font-semibold text-neon-cyan">{t('article.pages.title')}</h3>
<div className="border border-neon-cyan/30 rounded-lg p-6 bg-cyber-dark text-center">
<p className="text-cyber-accent mb-2">{t('article.pages.locked.title')}</p>
<p className="text-sm text-cyber-accent/70">{t('article.pages.locked.message', { count: pages.length })}</p>
</div>
</div>
)
}
// User has purchased, show all pages
return (
<div className="space-y-6 mt-6">
<h3 className="text-xl font-semibold text-neon-cyan">{t('article.pages.title')}</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{pages.map((page) => (
<PageDisplay key={page.number} page={page} />
))}
</div>
</div>
)
}
function PageDisplay({ page }: { page: Page }): React.ReactElement {
return (
<div className="border border-neon-cyan/30 rounded-lg p-4 bg-cyber-dark">
<div className="flex items-center justify-between mb-2">
<h4 className="font-semibold text-neon-cyan">
{t('page.number', { number: page.number })}
</h4>
<span className="text-xs text-cyber-accent/70">{t(`page.type.${page.type}`)}</span>
</div>
{page.type === 'markdown' ? (
<div className="prose prose-invert max-w-none text-cyber-accent whitespace-pre-wrap">
{page.content || <span className="text-cyber-accent/50">{t('page.markdown.empty')}</span>}
</div>
) : (
<div className="space-y-2">
{page.content ? (
<img
src={page.content}
alt={t('page.image.alt', { number: page.number })}
className="max-w-full h-auto rounded border border-neon-cyan/20"
/>
) : (
<div className="text-center py-8 text-cyber-accent/50 border border-dashed border-neon-cyan/20 rounded">
{t('page.image.empty')}
</div>
)}
</div>
)}
</div>
)
}