195 lines
6.9 KiB
TypeScript
195 lines
6.9 KiB
TypeScript
import { useRef, useState } from 'react'
|
|
import {
|
|
Form,
|
|
useActionData,
|
|
useLoaderData,
|
|
useNavigation
|
|
} from 'react-router-dom'
|
|
import {
|
|
CheckboxFieldUncontrolled,
|
|
InputFieldUncontrolled,
|
|
InputFieldWithImageUpload
|
|
} from '../../components/Inputs'
|
|
import { ProfileSection } from '../../components/ProfileSection'
|
|
import { useAppSelector } from '../../hooks'
|
|
import { BlogFormErrors, BlogPageLoaderResult } from 'types'
|
|
import '../../styles/innerPage.css'
|
|
import '../../styles/styles.css'
|
|
import '../../styles/write.css'
|
|
import { LoadingSpinner } from 'components/LoadingSpinner'
|
|
import { AlertPopup } from 'components/AlertPopup'
|
|
import { Editor, EditorRef } from 'components/Markdown/Editor'
|
|
import { InputError } from 'components/Inputs/Error'
|
|
|
|
export const WritePage = () => {
|
|
const userState = useAppSelector((state) => state.user)
|
|
const data = useLoaderData() as BlogPageLoaderResult
|
|
const formErrors = useActionData() as BlogFormErrors
|
|
const navigation = useNavigation()
|
|
|
|
const blog = data?.blog
|
|
const title = data?.blog ? 'Edit blog post' : 'Submit a blog post'
|
|
const [content, setContent] = useState(blog?.content || '')
|
|
const [featuredImageUrl, setfeaturedImageUrl] = useState(blog?.image || '')
|
|
|
|
const formRef = useRef<HTMLFormElement>(null)
|
|
const editorRef = useRef<EditorRef>(null)
|
|
|
|
const [showConfirmPopup, setShowConfirmPopup] = useState<boolean>(false)
|
|
const handleReset = () => {
|
|
setShowConfirmPopup(true)
|
|
}
|
|
const handleResetConfirm = (confirm: boolean) => {
|
|
setShowConfirmPopup(false)
|
|
|
|
// Cancel if not confirmed
|
|
if (!confirm) return
|
|
|
|
// Reset editor
|
|
if (blog?.content) {
|
|
editorRef.current?.setMarkdown(blog?.content)
|
|
}
|
|
|
|
formRef.current?.reset()
|
|
}
|
|
|
|
return (
|
|
<div className='InnerBodyMain'>
|
|
<div className='ContainerMain'>
|
|
<div className='IBMSecMainGroup IBMSecMainGroupAlt'>
|
|
<div className='IBMSMSplitMain'>
|
|
<div className='IBMSMSplitMainBigSide'>
|
|
<div className='IBMSMTitleMain'>
|
|
<h2 className='IBMSMTitleMainHeading'>{title}</h2>
|
|
</div>
|
|
{navigation.state === 'loading' && (
|
|
<LoadingSpinner desc='Loading..' />
|
|
)}
|
|
{navigation.state === 'submitting' && (
|
|
<LoadingSpinner desc='Publishing blog to relays' />
|
|
)}
|
|
<Form
|
|
ref={formRef}
|
|
className='IBMSMSMBS_Write'
|
|
method={blog ? 'put' : 'post'}
|
|
>
|
|
<InputFieldUncontrolled
|
|
label='Title'
|
|
name='title'
|
|
defaultValue={blog?.title}
|
|
error={formErrors?.title}
|
|
/>
|
|
<div className='inputLabelWrapperMain'>
|
|
<label className='form-label labelMain'>Content</label>
|
|
<div className='inputMain'>
|
|
<Editor
|
|
ref={editorRef}
|
|
markdown={content}
|
|
onChange={(md) => {
|
|
setContent(md)
|
|
}}
|
|
/>
|
|
</div>
|
|
{typeof formErrors?.content !== 'undefined' && (
|
|
<InputError message={formErrors?.content} />
|
|
)}
|
|
{/* encode to keep the markdown formatting */}
|
|
<input
|
|
name='content'
|
|
hidden
|
|
value={encodeURIComponent(content)}
|
|
readOnly
|
|
/>
|
|
</div>
|
|
<InputFieldWithImageUpload
|
|
label='Featured Image URL'
|
|
inputMode='url'
|
|
placeholder='Image URL'
|
|
name='featuredImageUrl'
|
|
value={featuredImageUrl}
|
|
error={formErrors?.image}
|
|
onInputChange={(_, value) => setfeaturedImageUrl(value)}
|
|
/>
|
|
<InputFieldUncontrolled
|
|
label='Summary'
|
|
name='summary'
|
|
type='textarea'
|
|
defaultValue={blog?.summary}
|
|
error={formErrors?.summary}
|
|
/>
|
|
<InputFieldUncontrolled
|
|
label='Tags'
|
|
description='Separate each tag with a comma. (Example: tag1, tag2, tag3)'
|
|
placeholder='Tags'
|
|
name='tags'
|
|
defaultValue={blog?.tTags?.join(', ')}
|
|
error={formErrors?.tags}
|
|
/>
|
|
<CheckboxFieldUncontrolled
|
|
label='This post is not safe for work (NSFW)'
|
|
name='nsfw'
|
|
defaultChecked={blog?.nsfw}
|
|
/>
|
|
{typeof blog?.dTag !== 'undefined' && (
|
|
<input name='dTag' hidden value={blog.dTag} readOnly />
|
|
)}
|
|
{typeof blog?.rTag !== 'undefined' && (
|
|
<input name='rTag' hidden value={blog.rTag} readOnly />
|
|
)}
|
|
{typeof blog?.published_at !== 'undefined' && (
|
|
<input
|
|
name='published_at'
|
|
hidden
|
|
value={blog.published_at}
|
|
readOnly
|
|
/>
|
|
)}
|
|
<div className='IBMSMSMBS_WriteAction'>
|
|
<button
|
|
className='btn btnMain'
|
|
type='button'
|
|
onClick={handleReset}
|
|
disabled={
|
|
navigation.state === 'loading' ||
|
|
navigation.state === 'submitting'
|
|
}
|
|
>
|
|
{blog ? 'Reset' : 'Clear fields'}
|
|
</button>
|
|
<button
|
|
className='btn btnMain'
|
|
type='submit'
|
|
disabled={
|
|
navigation.state === 'loading' ||
|
|
navigation.state === 'submitting'
|
|
}
|
|
>
|
|
{navigation.state === 'submitting'
|
|
? 'Publishing...'
|
|
: 'Publish'}
|
|
</button>
|
|
</div>
|
|
{showConfirmPopup && (
|
|
<AlertPopup
|
|
handleConfirm={handleResetConfirm}
|
|
handleClose={() => setShowConfirmPopup(false)}
|
|
header={'Are you sure?'}
|
|
label={
|
|
blog
|
|
? `Are you sure you want to clear all changes?`
|
|
: `Are you sure you want to clear all field data?`
|
|
}
|
|
/>
|
|
)}
|
|
</Form>
|
|
</div>
|
|
{userState.auth && userState.user?.pubkey && (
|
|
<ProfileSection pubkey={userState.user.pubkey as string} />
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|