story-research-zapwall/components/ArticleEditorFormFieldsLeft.tsx
2026-01-08 23:04:56 +01:00

181 lines
4.8 KiB
TypeScript

import React from 'react'
import type { ArticleDraft } from '@/lib/articlePublisher'
import type { ArticleCategory } from '@/types/nostr'
import { ArticleField } from './ArticleField'
import { CategorySelect } from './CategorySelect'
import { t } from '@/lib/i18n'
interface ArticleFieldsLeftProps {
draft: ArticleDraft
onDraftChange: (draft: ArticleDraft) => void
seriesOptions?: { id: string; title: string }[] | undefined
onSelectSeries?: ((seriesId: string | undefined) => void) | undefined
}
export function ArticleFieldsLeft({
draft,
onDraftChange,
seriesOptions,
onSelectSeries,
}: ArticleFieldsLeftProps): React.ReactElement {
return (
<div className="space-y-4">
<CategoryField
value={draft.category}
onChange={buildCategoryChangeHandler({ draft, onDraftChange })}
/>
{seriesOptions && (
<SeriesSelect
draft={draft}
onDraftChange={onDraftChange}
seriesOptions={seriesOptions}
onSelectSeries={onSelectSeries}
/>
)}
<ArticleTitleField draft={draft} onDraftChange={onDraftChange} />
<ArticlePreviewField draft={draft} onDraftChange={onDraftChange} />
</div>
)
}
interface CategoryFieldProps {
value: ArticleDraft['category']
onChange: (value: ArticleCategory | undefined) => void
}
function CategoryField({ value, onChange }: CategoryFieldProps): React.ReactElement {
return (
<CategorySelect
id="category"
label={t('article.editor.category')}
{...(value ? { value } : {})}
onChange={onChange}
required
helpText={t('article.editor.category.help')}
/>
)
}
interface BuildCategoryChangeHandlerParams {
draft: ArticleDraft
onDraftChange: (draft: ArticleDraft) => void
}
function buildCategoryChangeHandler(
params: BuildCategoryChangeHandlerParams
): (value: ArticleCategory | undefined) => void {
return (value): void => {
if (value !== 'science-fiction' && value !== 'scientific-research' && value !== undefined) {
return
}
if (value) {
params.onDraftChange({ ...params.draft, category: value })
return
}
const { category: _category, ...rest } = params.draft
params.onDraftChange(rest)
}
}
function ArticleTitleField({
draft,
onDraftChange,
}: {
draft: ArticleDraft
onDraftChange: (draft: ArticleDraft) => void
}): React.ReactElement {
return (
<ArticleField
id="title"
label={t('article.title')}
value={draft.title}
onChange={(value) => onDraftChange({ ...draft, title: value as string })}
required
placeholder={t('article.editor.title.placeholder')}
/>
)
}
function ArticlePreviewField({
draft,
onDraftChange,
}: {
draft: ArticleDraft
onDraftChange: (draft: ArticleDraft) => void
}): React.ReactElement {
return (
<ArticleField
id="preview"
label={t('article.editor.preview.label')}
value={draft.preview}
onChange={(value) => onDraftChange({ ...draft, preview: value as string })}
required
type="textarea"
rows={4}
placeholder={t('article.editor.preview.placeholder')}
helpText={t('article.editor.preview.help')}
/>
)
}
function SeriesSelect({
draft,
onDraftChange,
seriesOptions,
onSelectSeries,
}: {
draft: ArticleDraft
onDraftChange: (draft: ArticleDraft) => void
seriesOptions: { id: string; title: string }[]
onSelectSeries?: ((seriesId: string | undefined) => void) | undefined
}): React.ReactElement {
const handleChange = buildSeriesChangeHandler({ draft, onDraftChange, onSelectSeries })
return (
<div>
<label htmlFor="series" className="block text-sm font-medium text-gray-700">
{t('article.editor.series.label')}
</label>
<select
id="series"
className="mt-1 block w-full border-gray-300 rounded-md shadow-sm"
value={draft.seriesId ?? ''}
onChange={handleChange}
>
<option value="">{t('article.editor.series.none')}</option>
{seriesOptions.map((s) => (
<option key={s.id} value={s.id}>
{s.title}
</option>
))}
</select>
</div>
)
}
interface BuildSeriesChangeHandlerParams {
draft: ArticleDraft
onDraftChange: (draft: ArticleDraft) => void
onSelectSeries?: ((seriesId: string | undefined) => void) | undefined
}
function buildSeriesChangeHandler(
params: BuildSeriesChangeHandlerParams
): (e: React.ChangeEvent<HTMLSelectElement>) => void {
return (e): void => {
const value = e.target.value === '' ? undefined : e.target.value
if (value) {
params.onDraftChange({ ...params.draft, seriesId: value })
params.onSelectSeries?.(value)
return
}
const { seriesId: _seriesId, ...rest } = params.draft
params.onDraftChange(rest)
params.onSelectSeries?.(undefined)
}
}