2023-04-26 02:37:29 +00:00
|
|
|
import type { JSX } from 'solid-js'
|
2023-05-07 15:15:30 +00:00
|
|
|
import { Accessor, createContext, createSignal, useContext } from 'solid-js'
|
2023-05-04 19:57:02 +00:00
|
|
|
import { createStore, SetStoreFunction } from 'solid-js/store'
|
2023-05-07 15:15:30 +00:00
|
|
|
import { Topic } from '../graphql/types.gen'
|
2023-05-05 20:05:50 +00:00
|
|
|
import { apiClient } from '../utils/apiClient'
|
|
|
|
import { useLocalize } from './localize'
|
|
|
|
import { useSnackbar } from './snackbar'
|
2023-04-26 02:37:29 +00:00
|
|
|
|
|
|
|
type WordCounter = {
|
|
|
|
characters: number
|
|
|
|
words: number
|
|
|
|
}
|
|
|
|
|
2023-05-04 19:57:02 +00:00
|
|
|
type ShoutForm = {
|
2023-05-07 15:15:30 +00:00
|
|
|
shoutId: number
|
2023-05-04 19:57:02 +00:00
|
|
|
slug: string
|
|
|
|
title: string
|
|
|
|
subtitle: string
|
|
|
|
selectedTopics: Topic[]
|
|
|
|
mainTopic: string
|
|
|
|
body: string
|
|
|
|
coverImageUrl: string
|
|
|
|
}
|
|
|
|
|
2023-04-26 02:37:29 +00:00
|
|
|
type EditorContextType = {
|
|
|
|
isEditorPanelVisible: Accessor<boolean>
|
|
|
|
wordCounter: Accessor<WordCounter>
|
2023-05-04 19:57:02 +00:00
|
|
|
form: ShoutForm
|
2023-05-05 20:05:50 +00:00
|
|
|
formErrors: Partial<ShoutForm>
|
2023-04-26 02:37:29 +00:00
|
|
|
actions: {
|
2023-05-05 20:05:50 +00:00
|
|
|
saveShout: () => Promise<boolean>
|
|
|
|
publishShout: () => Promise<boolean>
|
2023-04-26 02:37:29 +00:00
|
|
|
toggleEditorPanel: () => void
|
|
|
|
countWords: (value: WordCounter) => void
|
2023-05-04 19:57:02 +00:00
|
|
|
setForm: SetStoreFunction<ShoutForm>
|
2023-05-05 20:05:50 +00:00
|
|
|
setFormErrors: SetStoreFunction<Partial<ShoutForm>>
|
2023-04-26 02:37:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const EditorContext = createContext<EditorContextType>()
|
|
|
|
|
|
|
|
export function useEditorContext() {
|
|
|
|
return useContext(EditorContext)
|
|
|
|
}
|
|
|
|
|
|
|
|
export const EditorProvider = (props: { children: JSX.Element }) => {
|
2023-05-05 20:05:50 +00:00
|
|
|
const { t } = useLocalize()
|
|
|
|
const {
|
|
|
|
actions: { showSnackbar }
|
|
|
|
} = useSnackbar()
|
|
|
|
|
2023-05-03 16:13:48 +00:00
|
|
|
const [isEditorPanelVisible, setIsEditorPanelVisible] = createSignal<boolean>(false)
|
2023-05-04 19:57:02 +00:00
|
|
|
|
|
|
|
const [form, setForm] = createStore<ShoutForm>(null)
|
2023-05-05 20:05:50 +00:00
|
|
|
const [formErrors, setFormErrors] = createStore<Partial<ShoutForm>>(null)
|
2023-05-04 19:57:02 +00:00
|
|
|
|
2023-04-26 02:37:29 +00:00
|
|
|
const [wordCounter, setWordCounter] = createSignal<WordCounter>({
|
|
|
|
characters: 0,
|
|
|
|
words: 0
|
|
|
|
})
|
2023-05-05 20:05:50 +00:00
|
|
|
|
2023-05-03 16:13:48 +00:00
|
|
|
const toggleEditorPanel = () => setIsEditorPanelVisible((value) => !value)
|
2023-04-26 02:37:29 +00:00
|
|
|
const countWords = (value) => setWordCounter(value)
|
2023-05-05 20:05:50 +00:00
|
|
|
|
|
|
|
const saveShout = async () => {
|
|
|
|
if (!form.title) {
|
|
|
|
setFormErrors('title', t('Required'))
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
await apiClient.updateArticle({
|
2023-05-07 15:15:30 +00:00
|
|
|
shoutId: form.shoutId,
|
|
|
|
shoutInput: {
|
2023-05-05 20:05:50 +00:00
|
|
|
body: form.body,
|
|
|
|
topics: form.selectedTopics.map((topic) => topic.slug),
|
|
|
|
// authors?: InputMaybe<Array<InputMaybe<Scalars['String']>>>
|
|
|
|
// community?: InputMaybe<Scalars['Int']>
|
|
|
|
mainTopic: form.selectedTopics[0]?.slug || 'society',
|
|
|
|
slug: form.slug,
|
|
|
|
subtitle: form.subtitle,
|
2023-05-07 19:33:20 +00:00
|
|
|
title: form.title,
|
|
|
|
cover: form.coverImageUrl
|
2023-05-05 20:05:50 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
return true
|
|
|
|
} catch (error) {
|
|
|
|
console.error(error)
|
|
|
|
showSnackbar({ type: 'error', body: t('Error') })
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const publishShout = async () => {
|
|
|
|
try {
|
|
|
|
await apiClient.publishShout({
|
|
|
|
slug: form.slug,
|
|
|
|
shoutInput: {
|
|
|
|
body: form.body,
|
|
|
|
topics: form.selectedTopics.map((topic) => topic.slug),
|
|
|
|
// authors?: InputMaybe<Array<InputMaybe<Scalars['String']>>>
|
|
|
|
// community?: InputMaybe<Scalars['Int']>
|
|
|
|
mainTopic: form.selectedTopics[0]?.slug || '',
|
|
|
|
slug: form.slug,
|
|
|
|
subtitle: form.subtitle,
|
|
|
|
title: form.title
|
|
|
|
}
|
|
|
|
})
|
|
|
|
return true
|
|
|
|
} catch {
|
|
|
|
showSnackbar({ type: 'error', body: t('Error') })
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-26 02:37:29 +00:00
|
|
|
const actions = {
|
2023-05-05 20:05:50 +00:00
|
|
|
saveShout,
|
|
|
|
publishShout,
|
2023-04-26 02:37:29 +00:00
|
|
|
toggleEditorPanel,
|
2023-05-04 19:57:02 +00:00
|
|
|
countWords,
|
2023-05-05 20:05:50 +00:00
|
|
|
setForm,
|
|
|
|
setFormErrors
|
2023-04-26 02:37:29 +00:00
|
|
|
}
|
|
|
|
|
2023-05-05 20:05:50 +00:00
|
|
|
const value: EditorContextType = { actions, form, formErrors, isEditorPanelVisible, wordCounter }
|
2023-04-26 02:37:29 +00:00
|
|
|
|
|
|
|
return <EditorContext.Provider value={value}>{props.children}</EditorContext.Provider>
|
|
|
|
}
|