Nicolas Cantu 3000872dbc refactoring
- **Motivations :** Assurer passage du lint strict et clarifier la logique paiements/publications.

- **Root causes :** Fonctions trop longues, promesses non gérées et typages WebLN/Nostr incomplets.

- **Correctifs :** Refactor PaymentModal (handlers void), extraction helpers articlePublisher, simplification polling sponsoring/zap, corrections curly et awaits.

- **Evolutions :** Nouveau module articlePublisherHelpers pour présentation/aiguillage contenu privé.

- **Page affectées :** components/PaymentModal.tsx, lib/articlePublisher.ts, lib/articlePublisherHelpers.ts, lib/paymentPolling.ts, lib/sponsoring.ts, lib/nostrZapVerification.ts et dépendances liées.
2025-12-22 17:56:00 +01:00

121 lines
3.6 KiB
TypeScript

import { useEffect, useState, useCallback } from 'react'
import { getAlbyService } from '@/lib/alby'
interface AlbyInstallerProps {
onInstalled?: () => void
}
function InfoIcon() {
return (
<svg
className="h-5 w-5 text-blue-400"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fillRule="evenodd"
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"
clipRule="evenodd"
/>
</svg>
)
}
function InstallerActions({ onInstalled, markInstalled }: { onInstalled?: () => void; markInstalled: () => void }) {
const connect = useCallback(() => {
const alby = getAlbyService()
void alby.enable().then(() => {
markInstalled()
onInstalled?.()
})
}, [markInstalled, onInstalled])
return (
<div className="mt-4">
<div className="flex flex-col sm:flex-row gap-2">
<a
href="https://getalby.com/"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center justify-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
Install Alby
</a>
<button
onClick={() => {
void connect()
}}
className="inline-flex items-center justify-center px-4 py-2 border border-blue-300 text-sm font-medium rounded-md text-blue-700 bg-white hover:bg-blue-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
Already installed? Connect
</button>
</div>
</div>
)
}
function InstallerBody({ onInstalled, markInstalled }: { onInstalled?: () => void; markInstalled: () => void }) {
return (
<div className="ml-3 flex-1">
<h3 className="text-sm font-medium text-blue-800">Alby Extension Required</h3>
<div className="mt-2 text-sm text-blue-700">
<p>To make Lightning payments, please install the Alby browser extension.</p>
</div>
<InstallerActions onInstalled={onInstalled} markInstalled={markInstalled} />
<div className="mt-3 text-xs text-blue-600">
<p>Alby is a Lightning wallet that enables instant Bitcoin payments in your browser.</p>
</div>
</div>
)
}
function useAlbyStatus(onInstalled?: () => void) {
const [isInstalled, setIsInstalled] = useState(false)
const [isChecking, setIsChecking] = useState(true)
useEffect(() => {
const checkAlby = () => {
try {
const alby = getAlbyService()
const installed = alby.isEnabled()
setIsInstalled(installed)
if (installed) {
onInstalled?.()
}
} catch (e) {
console.error('Error checking Alby:', e)
setIsInstalled(false)
} finally {
setIsChecking(false)
}
}
checkAlby()
}, [onInstalled])
const markInstalled = () => {
setIsInstalled(true)
}
return { isInstalled, isChecking, markInstalled }
}
export function AlbyInstaller({ onInstalled }: AlbyInstallerProps) {
const { isInstalled, isChecking, markInstalled } = useAlbyStatus(onInstalled)
if (isChecking || isInstalled) {
return null
}
return (
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4 mb-4">
<div className="flex items-start">
<div className="flex-shrink-0">
<InfoIcon />
</div>
<InstallerBody onInstalled={onInstalled} markInstalled={markInstalled} />
</div>
</div>
)
}