181 lines
4.8 KiB
TypeScript
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)
|
|
}
|
|
}
|