story-research-zapwall/components/ArticleEditorForm.tsx
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

129 lines
3.4 KiB
TypeScript

import React from 'react'
import type { ArticleDraft } from '@/lib/articlePublisher'
import { ArticleField } from './ArticleField'
import { ArticleFormButtons } from './ArticleFormButtons'
import { CategorySelect } from './CategorySelect'
interface ArticleEditorFormProps {
draft: ArticleDraft
onDraftChange: (draft: ArticleDraft) => void
onSubmit: (e: React.FormEvent) => void
loading: boolean
error: string | null
onCancel?: () => void
}
function CategoryField({
value,
onChange,
}: {
value: ArticleDraft['category']
onChange: (value: ArticleDraft['category']) => void
}) {
return (
<CategorySelect
id="category"
label="Catégorie"
value={value}
onChange={onChange}
required
helpText="Sélectionnez la catégorie de votre article"
/>
)
}
function ErrorAlert({ error }: { error: string | null }) {
if (!error) {
return null
}
return (
<div className="bg-red-50 border border-red-200 rounded-lg p-3">
<p className="text-sm text-red-800">{error}</p>
</div>
)
}
const ArticleFieldsLeft = ({
draft,
onDraftChange,
}: {
draft: ArticleDraft
onDraftChange: (draft: ArticleDraft) => void
}) => (
<div className="space-y-4">
<CategoryField value={draft.category} onChange={(value) => onDraftChange({ ...draft, category: value })} />
<ArticleField
id="title"
label="Titre"
value={draft.title}
onChange={(value) => onDraftChange({ ...draft, title: value as string })}
required
placeholder="Entrez le titre de l'article"
/>
<ArticleField
id="preview"
label="Aperçu (Public)"
value={draft.preview}
onChange={(value) => onDraftChange({ ...draft, preview: value as string })}
required
type="textarea"
rows={4}
placeholder="Cet aperçu sera visible par tous gratuitement"
helpText="Ce contenu sera visible par tous"
/>
</div>
)
const ArticleFieldsRight = ({
draft,
onDraftChange,
}: {
draft: ArticleDraft
onDraftChange: (draft: ArticleDraft) => void
}) => (
<div className="space-y-4">
<ArticleField
id="content"
label="Contenu complet (Privé)"
value={draft.content}
onChange={(value) => onDraftChange({ ...draft, content: value as string })}
required
type="textarea"
rows={8}
placeholder="Ce contenu sera chiffré et envoyé aux lecteurs qui paient"
helpText="Ce contenu sera chiffré et envoyé comme message privé après paiement"
/>
<ArticleField
id="zapAmount"
label="Prix (sats)"
value={draft.zapAmount}
onChange={(value) => onDraftChange({ ...draft, zapAmount: value as number })}
required
type="number"
min={1}
helpText="Montant en satoshis pour débloquer le contenu complet"
/>
</div>
)
export function ArticleEditorForm({
draft,
onDraftChange,
onSubmit,
loading,
error,
onCancel,
}: ArticleEditorFormProps) {
return (
<form onSubmit={onSubmit} className="border rounded-lg p-6 bg-white space-y-4">
<h2 className="text-2xl font-bold mb-4">Publier un nouvel article</h2>
<div className="space-y-4">
<ArticleFieldsLeft draft={draft} onDraftChange={onDraftChange} />
<ArticleFieldsRight draft={draft} onDraftChange={onDraftChange} />
</div>
<ErrorAlert error={error} />
<ArticleFormButtons loading={loading} onCancel={onCancel} />
</form>
)
}