diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 637bc0e0..5d9b89ff 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -271,5 +271,6 @@ "topics": "topics", "user already exist": "user already exists", "view": "view", - "zine": "zine" + "zine": "zine", + "Required": "Required" } diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json index 8ea0c002..0d00d8eb 100644 --- a/public/locales/ru/translation.json +++ b/public/locales/ru/translation.json @@ -292,5 +292,6 @@ "topics": "темы", "user already exist": "пользователь уже существует", "view": "просмотр", - "zine": "журнал" + "zine": "журнал", + "Required": "Поле обязательно для заполнения" } diff --git a/src/components/App.tsx b/src/components/App.tsx index 11c1356d..06aa4241 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -96,13 +96,13 @@ export const App = (props: PageProps) => { return ( - - - + + + - - - + + + ) } diff --git a/src/components/Editor/Editor.tsx b/src/components/Editor/Editor.tsx index f4faeb6f..18f59bb1 100644 --- a/src/components/Editor/Editor.tsx +++ b/src/components/Editor/Editor.tsx @@ -26,7 +26,6 @@ import { CustomImage } from './extensions/CustomImage' import { Figure } from './extensions/Figure' import { Paragraph } from '@tiptap/extension-paragraph' import Focus from '@tiptap/extension-focus' -import { TrailingNode } from './extensions/TrailingNode' import * as Y from 'yjs' import { CollaborationCursor } from '@tiptap/extension-collaboration-cursor' import { Collaboration } from '@tiptap/extension-collaboration' @@ -41,6 +40,7 @@ import { ImageBubbleMenu } from './ImageBubbleMenu' import { EditorFloatingMenu } from './EditorFloatingMenu' import { useEditorContext } from '../../context/editor' import { isTextSelection } from '@tiptap/core' +import type { Doc } from 'yjs/dist/src/utils/Doc' import './Prosemirror.scss' type EditorProps = { @@ -49,7 +49,7 @@ type EditorProps = { onChange: (text: string) => void } -const yDoc = new Y.Doc() +const yDocs: Record = {} const persisters: Record = {} const providers: Record = {} @@ -59,17 +59,20 @@ export const Editor = (props: EditorProps) => { const docName = `shout-${props.shoutId}` + if (!yDocs[docName]) { + yDocs[docName] = new Y.Doc() + } + if (!providers[docName]) { providers[docName] = new HocuspocusProvider({ url: 'wss://hocuspocus.discours.io', - // url: 'ws://localhost:4242', name: docName, - document: yDoc + document: yDocs[docName] }) } if (!persisters[docName]) { - persisters[docName] = new IndexeddbPersistence(docName, yDoc) + persisters[docName] = new IndexeddbPersistence(docName, yDocs[docName]) } const editorElRef: { @@ -123,7 +126,7 @@ export const Editor = (props: EditorProps) => { OrderedList, ListItem, Collaboration.configure({ - document: yDoc + document: yDocs[docName] }), CollaborationCursor.configure({ provider: providers[docName], @@ -145,7 +148,6 @@ export const Editor = (props: EditorProps) => { } }), Figure, - TrailingNode, Embed, CharacterCount, BubbleMenu.configure({ diff --git a/src/components/Editor/EditorFloatingMenu/EditorFloatingMenu.module.scss b/src/components/Editor/EditorFloatingMenu/EditorFloatingMenu.module.scss index 0e677cbb..30f4f763 100644 --- a/src/components/Editor/EditorFloatingMenu/EditorFloatingMenu.module.scss +++ b/src/components/Editor/EditorFloatingMenu/EditorFloatingMenu.module.scss @@ -15,9 +15,9 @@ .menuHolder { background: #fff; - left: 40px; + left: 24px; position: absolute; - top: -0.4rem; + top: -2px; min-width: 64vw; } } diff --git a/src/components/Editor/EditorFloatingMenu/EditorFloatingMenu.tsx b/src/components/Editor/EditorFloatingMenu/EditorFloatingMenu.tsx index 43ea8501..d74c637d 100644 --- a/src/components/Editor/EditorFloatingMenu/EditorFloatingMenu.tsx +++ b/src/components/Editor/EditorFloatingMenu/EditorFloatingMenu.tsx @@ -10,6 +10,7 @@ import { Menu } from './Menu' import type { MenuItem } from './Menu/Menu' import { showModal } from '../../../stores/ui' import { UploadModalContent } from '../UploadModal' +import { useOutsideClickHandler } from '../../../utils/useOutsideClickHandler' type FloatingMenuProps = { editor: Editor @@ -57,6 +58,17 @@ export const EditorFloatingMenu = (props: FloatingMenuProps) => { setMenuOpen(false) } + const menuRef: { current: HTMLDivElement } = { current: null } + + useOutsideClickHandler({ + containerRef: menuRef, + handler: () => { + if (menuOpen()) { + setMenuOpen(false) + } + } + }) + return ( <>
@@ -69,7 +81,7 @@ export const EditorFloatingMenu = (props: FloatingMenuProps) => { -
+
(menuRef.current = el)}> setSelectedMenuItem(value)} /> diff --git a/src/components/Editor/extensions/TrailingNode.tsx b/src/components/Editor/extensions/TrailingNode.tsx deleted file mode 100644 index fa399c79..00000000 --- a/src/components/Editor/extensions/TrailingNode.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { Extension } from '@tiptap/core' -import { Plugin, PluginKey } from '@tiptap/pm/state' - -function nodeEqualsType({ types, node }) { - return (Array.isArray(types) && types.includes(node.type)) || node.type === types -} - -/** - * Extension based on: - * - https://github.com/ueberdosis/tiptap/blob/v1/packages/tiptap-extensions/src/extensions/TrailingNode.js - * - https://github.com/remirror/remirror/blob/e0f1bec4a1e8073ce8f5500d62193e52321155b9/packages/prosemirror-trailing-node/src/trailing-node-plugin.ts - */ - -export interface TrailingNodeOptions { - node: string - notAfter: string[] -} - -export const TrailingNode = Extension.create({ - name: 'trailingNode', - - addOptions() { - return { - node: 'paragraph', - notAfter: ['paragraph'] - } - }, - - addProseMirrorPlugins() { - const plugin = new PluginKey(this.name) - const disabledNodes = Object.entries(this.editor.schema.nodes) - .map(([, value]) => value) - .filter((node) => this.options.notAfter.includes(node.name)) - - return [ - new Plugin({ - key: plugin, - appendTransaction: (_, __, state) => { - const { doc, tr, schema } = state - const shouldInsertNodeAtEnd = plugin.getState(state) - const endPosition = doc.content.size - const type = schema.nodes[this.options.node] - - if (!shouldInsertNodeAtEnd) { - return - } - - return tr.insert(endPosition, type.create()) - }, - state: { - init: (_, state) => { - const lastNode = state.tr.doc.lastChild - - return !nodeEqualsType({ node: lastNode, types: disabledNodes }) - }, - apply: (tr, value) => { - if (!tr.docChanged) { - return value - } - - const lastNode = tr.doc.lastChild - - return !nodeEqualsType({ node: lastNode, types: disabledNodes }) - } - } - }) - ] - } -}) diff --git a/src/components/Nav/HeaderAuth.tsx b/src/components/Nav/HeaderAuth.tsx index b5a49ac4..09643c8d 100644 --- a/src/components/Nav/HeaderAuth.tsx +++ b/src/components/Nav/HeaderAuth.tsx @@ -11,9 +11,10 @@ import { showModal, useWarningsStore } from '../../stores/ui' import { ShowOnlyOnClient } from '../_shared/ShowOnlyOnClient' import { useSession } from '../../context/session' import { useLocalize } from '../../context/localize' -import { getPagePath } from '@nanostores/router' +import { getPagePath, openPage } from '@nanostores/router' import { Button } from '../_shared/Button' import { useEditorContext } from '../../context/editor' +import { apiClient } from '../../utils/apiClient' type HeaderAuthProps = { setIsProfilePopupVisible: (value: boolean) => void @@ -28,7 +29,7 @@ export const HeaderAuth = (props: HeaderAuthProps) => { const { session, isSessionLoaded, isAuthenticated } = useSession() const { - actions: { toggleEditorPanel } + actions: { toggleEditorPanel, saveShout, publishShout } } = useEditorContext() const toggleWarnings = () => setVisibleWarnings(!visibleWarnings()) @@ -50,12 +51,19 @@ export const HeaderAuth = (props: HeaderAuthProps) => { const showNotifications = createMemo(() => isAuthenticated() && !isEditorPage()) const showSaveButton = createMemo(() => isAuthenticated() && isEditorPage()) const showCreatePostButton = createMemo(() => isAuthenticated() && !isEditorPage()) - const showAuthenticatedControls = createMemo(() => isAuthenticated() && isEditorPage()) + const showAuthenticatedControls = createMemo(() => isAuthenticated()) const handleBurgerButtonClick = () => { toggleEditorPanel() } + const handleSaveButtonClick = async () => { + const result = await saveShout() + if (result) { + openPage(router, 'drafts') + } + } + return ( @@ -90,6 +98,7 @@ export const HeaderAuth = (props: HeaderAuthProps) => { } variant={'outline'} + onClick={handleSaveButtonClick} />
diff --git a/src/components/Nav/ProfilePopup.tsx b/src/components/Nav/ProfilePopup.tsx index f20d988d..023cd931 100644 --- a/src/components/Nav/ProfilePopup.tsx +++ b/src/components/Nav/ProfilePopup.tsx @@ -23,7 +23,7 @@ export const ProfilePopup = (props: ProfilePopupProps) => { {t('Profile')}
  • - {t('Drafts')} + {t('Drafts')}
  • {t('Subscriptions')} diff --git a/src/components/Views/Edit.module.scss b/src/components/Views/Edit.module.scss index 46648131..cfd06498 100644 --- a/src/components/Views/Edit.module.scss +++ b/src/components/Views/Edit.module.scss @@ -132,8 +132,9 @@ } .scrollTopButtonLabel { - display: none; @include font-size(1.4rem); + + display: none; font-weight: bold; left: 100%; padding-left: 0.5em; @@ -141,3 +142,14 @@ top: 50%; transform: translateY(-50%); } + +.inputContainer { + position: relative; + + .validationError { + position: absolute; + top: 100%; + font-size: small; + color: #f00; + } +} diff --git a/src/components/Views/Edit.tsx b/src/components/Views/Edit.tsx index 7eabdc3d..1eadc8a1 100644 --- a/src/components/Views/Edit.tsx +++ b/src/components/Views/Edit.tsx @@ -6,9 +6,7 @@ import { Title } from '@solidjs/meta' import type { Shout, Topic } from '../../graphql/types.gen' import { apiClient } from '../../utils/apiClient' import { TopicSelect } from '../Editor/TopicSelect/TopicSelect' -import { router, useRouter } from '../../stores/router' -import { openPage } from '@nanostores/router' -import { translit } from '../../utils/ru2en' +import { useRouter } from '../../stores/router' import { Editor } from '../Editor/Editor' import { Panel } from '../Editor/Panel' import { useEditorContext } from '../../context/editor' @@ -26,16 +24,18 @@ export const EditView = (props: EditViewProps) => { const { form, - actions: { setForm } + formErrors, + actions: { setForm, setFormErrors } } = useEditorContext() const [isSlugChanged, setIsSlugChanged] = createSignal(false) setForm({ + shoutId: props.shout.id, slug: props.shout.slug, title: props.shout.title, subtitle: props.shout.subtitle, - selectedTopics: props.shout.topics, + selectedTopics: props.shout.topics || [], mainTopic: props.shout.mainTopic, body: props.shout.body, coverImageUrl: props.shout.cover @@ -46,22 +46,18 @@ export const EditView = (props: EditViewProps) => { setTopics(allTopics) }) - const handleFormSubmit = async (e) => { - e.preventDefault() - - const article = await apiClient.publishDraft() - - openPage(router, 'article', { slug: article.slug }) - } - const handleTitleInputChange = (e) => { const title = e.currentTarget.value setForm('title', title) - if (!isSlugChanged()) { - const slug = translit(title).replaceAll(' ', '-') - setForm('slug', slug) + if (title) { + setFormErrors('title', '') } + + // if (!isSlugChanged()) { + // const slug = translit(title).replaceAll(' ', '-') + // setForm('slug', slug) + // } } const handleSlugInputChange = (e) => { @@ -89,8 +85,7 @@ export const EditView = (props: EditViewProps) => {
    {t('Write an article')} - -
    +
    @@ -99,21 +94,28 @@ export const EditView = (props: EditViewProps) => { [styles.visible]: page().route === 'edit' })} > - +
    + + +
    {formErrors.title}
    +
    +
    setForm('subtitle', e.currentTarget.value)} diff --git a/src/context/editor.tsx b/src/context/editor.tsx index 9b3072ff..d3c4595f 100644 --- a/src/context/editor.tsx +++ b/src/context/editor.tsx @@ -2,6 +2,9 @@ import type { JSX } from 'solid-js' import { Accessor, createContext, createSignal, useContext } from 'solid-js' import { createStore, SetStoreFunction } from 'solid-js/store' import { Topic } from '../graphql/types.gen' +import { apiClient } from '../utils/apiClient' +import { useLocalize } from './localize' +import { useSnackbar } from './snackbar' type WordCounter = { characters: number @@ -9,6 +12,7 @@ type WordCounter = { } type ShoutForm = { + shoutId: number slug: string title: string subtitle: string @@ -22,10 +26,14 @@ type EditorContextType = { isEditorPanelVisible: Accessor wordCounter: Accessor form: ShoutForm + formErrors: Partial actions: { + saveShout: () => Promise + publishShout: () => Promise toggleEditorPanel: () => void countWords: (value: WordCounter) => void setForm: SetStoreFunction + setFormErrors: SetStoreFunction> } } @@ -36,23 +44,84 @@ export function useEditorContext() { } export const EditorProvider = (props: { children: JSX.Element }) => { + const { t } = useLocalize() + const { + actions: { showSnackbar } + } = useSnackbar() + const [isEditorPanelVisible, setIsEditorPanelVisible] = createSignal(false) const [form, setForm] = createStore(null) + const [formErrors, setFormErrors] = createStore>(null) const [wordCounter, setWordCounter] = createSignal({ characters: 0, words: 0 }) + const toggleEditorPanel = () => setIsEditorPanelVisible((value) => !value) const countWords = (value) => setWordCounter(value) - const actions = { - toggleEditorPanel, - countWords, - setForm + + const saveShout = async () => { + if (!form.title) { + setFormErrors('title', t('Required')) + return false + } + + try { + await apiClient.updateArticle({ + shoutId: form.shoutId, + shoutInput: { + body: form.body, + topics: form.selectedTopics.map((topic) => topic.slug), + // authors?: InputMaybe>> + // community?: InputMaybe + mainTopic: form.selectedTopics[0]?.slug || 'society', + slug: form.slug, + subtitle: form.subtitle, + title: form.title + } + }) + return true + } catch (error) { + console.error(error) + showSnackbar({ type: 'error', body: t('Error') }) + return false + } } - const value: EditorContextType = { actions, form, isEditorPanelVisible, wordCounter } + const publishShout = async () => { + try { + await apiClient.publishShout({ + slug: form.slug, + shoutInput: { + body: form.body, + topics: form.selectedTopics.map((topic) => topic.slug), + // authors?: InputMaybe>> + // community?: InputMaybe + 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 + } + } + + const actions = { + saveShout, + publishShout, + toggleEditorPanel, + countWords, + setForm, + setFormErrors + } + + const value: EditorContextType = { actions, form, formErrors, isEditorPanelVisible, wordCounter } return {props.children} } diff --git a/src/graphql/mutation/article-destroy.ts b/src/graphql/mutation/article-destroy.ts index 607a5a5c..918b4451 100644 --- a/src/graphql/mutation/article-destroy.ts +++ b/src/graphql/mutation/article-destroy.ts @@ -1,8 +1,8 @@ import { gql } from '@urql/core' export default gql` - mutation DeleteShoutMutation($shout: String!) { - deleteShout(slug: $shout) { + mutation DeleteShoutMutation($shoutId: Int!) { + deleteShout(shout_id: $shoutId) { error } } diff --git a/src/graphql/mutation/article-publish.ts b/src/graphql/mutation/article-publish.ts index 582c9086..dd1bc126 100644 --- a/src/graphql/mutation/article-publish.ts +++ b/src/graphql/mutation/article-publish.ts @@ -1,8 +1,8 @@ import { gql } from '@urql/core' export default gql` - mutation UpdateShoutMutation($slug: String!) { - publishShout(slug: $slug) { + mutation PublishShoutMutation($shoutId: Int!, $shoutInput: ShoutInput) { + publishShout(shout_id: $shoutId, shout_input: $shoutInput) { error shout { id diff --git a/src/graphql/mutation/article-update.ts b/src/graphql/mutation/article-update.ts index 3da0ef20..38756226 100644 --- a/src/graphql/mutation/article-update.ts +++ b/src/graphql/mutation/article-update.ts @@ -1,8 +1,8 @@ import { gql } from '@urql/core' export default gql` - mutation UpdateShoutMutation($slug: String!, $shout: ShoutInput!) { - updateShout(slug: $slug, inp: $shout) { + mutation UpdateShoutMutation($shoutId: Int!, $shoutInput: ShoutInput!) { + updateShout(shout_id: $shoutId, shout_input: $shoutInput) { error shout { id diff --git a/src/graphql/mutation/shout-publish.ts b/src/graphql/mutation/shout-publish.ts new file mode 100644 index 00000000..41c7b8f6 --- /dev/null +++ b/src/graphql/mutation/shout-publish.ts @@ -0,0 +1,16 @@ +import { gql } from '@urql/core' + +export default gql` + mutation PublishShoutMutation($slug: String!, $shout: ShoutInput!) { + publishShout(slug: $slug, inp: $shout) { + error + shout { + id + slug + title + subtitle + body + } + } + } +` diff --git a/src/graphql/query/articles-load-by.ts b/src/graphql/query/articles-load-by.ts index f7c7b541..e40bee3f 100644 --- a/src/graphql/query/articles-load-by.ts +++ b/src/graphql/query/articles-load-by.ts @@ -12,7 +12,7 @@ export default gql` # community mainTopic topics { - # id + id title body slug diff --git a/src/graphql/query/article-drafts-load-by.ts b/src/graphql/query/drafts-load.ts similarity index 75% rename from src/graphql/query/article-drafts-load-by.ts rename to src/graphql/query/drafts-load.ts index 59610321..d3d22ef3 100644 --- a/src/graphql/query/article-drafts-load-by.ts +++ b/src/graphql/query/drafts-load.ts @@ -1,8 +1,8 @@ import { gql } from '@urql/core' export default gql` - query LoadDraftsQuery($options: LoadShoutsOptions) { - loadDrafts(options: $options) { + query LoadDraftsQuery { + loadDrafts { id title subtitle @@ -12,7 +12,7 @@ export default gql` # community mainTopic topics { - # id + id title body slug @@ -30,6 +30,12 @@ export default gql` } createdAt publishedAt + stat { + viewed + reacted + rating + commented + } } } ` diff --git a/src/graphql/types.gen.ts b/src/graphql/types.gen.ts index 34eef2e0..d671c00c 100644 --- a/src/graphql/types.gen.ts +++ b/src/graphql/types.gen.ts @@ -228,7 +228,7 @@ export type MutationDeleteReactionArgs = { } export type MutationDeleteShoutArgs = { - slug: Scalars['String'] + shout_id: Scalars['Int'] } export type MutationDestroyTopicArgs = { @@ -246,8 +246,8 @@ export type MutationMarkAsReadArgs = { } export type MutationPublishShoutArgs = { - inp: ShoutInput - slug: Scalars['String'] + shout_id: Scalars['Int'] + shout_input?: InputMaybe } export type MutationRateUserArgs = { @@ -292,8 +292,8 @@ export type MutationUpdateReactionArgs = { } export type MutationUpdateShoutArgs = { - inp: ShoutInput - slug: Scalars['String'] + shout_id: Scalars['Int'] + shout_input: ShoutInput } export type MutationUpdateTopicArgs = { @@ -340,7 +340,6 @@ export type Query = { loadShouts: Array> markdownBody: Scalars['String'] myFeed?: Maybe>> - publishShout: Array> searchMessages: Result searchRecipients: Result signIn: AuthResult @@ -377,10 +376,6 @@ export type QueryLoadChatsArgs = { offset?: InputMaybe } -export type QueryLoadDraftsArgs = { - options?: InputMaybe -} - export type QueryLoadMessagesByArgs = { by: MessagesBy limit?: InputMaybe @@ -414,10 +409,6 @@ export type QueryMyFeedArgs = { options?: InputMaybe } -export type QueryPublishShoutArgs = { - slug: Scalars['String'] -} - export type QuerySearchMessagesArgs = { by: MessagesBy limit?: InputMaybe diff --git a/src/pages/allAuthors.page.tsx b/src/pages/allAuthors.page.tsx index 8a2fb1c3..83825fc6 100644 --- a/src/pages/allAuthors.page.tsx +++ b/src/pages/allAuthors.page.tsx @@ -4,10 +4,14 @@ import type { PageProps } from './types' import { createSignal, onMount, Show } from 'solid-js' import { loadAllAuthors } from '../stores/zine/authors' import { Loading } from '../components/_shared/Loading' +import { Title } from '@solidjs/meta' +import { useLocalize } from '../context/localize' export const AllAuthorsPage = (props: PageProps) => { const [isLoaded, setIsLoaded] = createSignal(Boolean(props.allAuthors)) + const { t } = useLocalize() + onMount(async () => { if (isLoaded()) { return @@ -19,6 +23,7 @@ export const AllAuthorsPage = (props: PageProps) => { return ( + {t('Authors')} }> diff --git a/src/pages/drafts.page.tsx b/src/pages/drafts.page.tsx index 1279ff0b..af2abe23 100644 --- a/src/pages/drafts.page.tsx +++ b/src/pages/drafts.page.tsx @@ -3,6 +3,8 @@ import { PageLayout } from '../components/_shared/PageLayout' import { useSession } from '../context/session' import { Shout } from '../graphql/types.gen' import { apiClient } from '../utils/apiClient' +import { getPagePath } from '@nanostores/router' +import { router } from '../stores/router' export const DraftsPage = () => { const { isAuthenticated, isSessionLoaded, user } = useSession() @@ -10,22 +12,28 @@ export const DraftsPage = () => { const [drafts, setDrafts] = createSignal([]) onMount(async () => { - const loadedDrafts = await apiClient.getShouts({ - filters: { - author: user().slug, - visibility: 'owner' - }, - limit: 9999 - }) + const loadedDrafts = await apiClient.getDrafts() setDrafts(loadedDrafts) }) return ( - - {(draft) =>
    {draft.title}
    }
    -
    +
    +
    +
    + + + {(draft) => ( + + )} + + +
    +
    +
    ) diff --git a/src/utils/apiClient.ts b/src/utils/apiClient.ts index aaf2dbed..153e4d2d 100644 --- a/src/utils/apiClient.ts +++ b/src/utils/apiClient.ts @@ -46,11 +46,13 @@ import createChat from '../graphql/mutation/create-chat' import reactionsLoadBy from '../graphql/query/reactions-load-by' import authorsLoadBy from '../graphql/query/authors-load-by' import shoutsLoadBy from '../graphql/query/articles-load-by' +import draftsLoad from '../graphql/query/drafts-load' import shoutLoad from '../graphql/query/article-load' import loadRecipients from '../graphql/query/chat-recipients' import createMessage from '../graphql/mutation/create-chat-message' import updateProfile from '../graphql/mutation/update-profile' import updateArticle from '../graphql/mutation/article-update' +import publishShout from '../graphql/mutation/shout-publish' type ApiErrorCode = | 'unknown' @@ -246,41 +248,29 @@ export const apiClient = { console.debug('[createArticle]:', response.data) return response.data.createShout.shout }, - updateArticle: async ({ slug, article }: { slug: string; article: ShoutInput }): Promise => { - const response = await privateGraphQLClient - .mutation(updateArticle, { slug, shout: article }) - .toPromise() + updateArticle: async ({ + shoutId, + shoutInput + }: { + shoutId: number + shoutInput: ShoutInput + }): Promise => { + const response = await privateGraphQLClient.mutation(updateArticle, { shoutId, shoutInput }).toPromise() console.debug('[updateArticle]:', response.data) - return response.data.updateArticle.shout + return response.data.updateShout.shout }, - publishDraft: async (): Promise => { - console.log('publishDraft') - return { - authors: undefined, - body: '', - community: '', - cover: '', - createdAt: undefined, - deletedAt: undefined, - deletedBy: undefined, - id: 0, - lang: '', - layout: '', - mainTopic: '', - media: '', - publishedAt: undefined, - slug: '', - stat: undefined, - subtitle: '', - title: '', - topics: undefined, - updatedAt: undefined, - updatedBy: undefined, - versionOf: '', - visibility: '' - } + publishShout: async ({ slug, shoutInput }: { slug: string; shoutInput: ShoutInput }): Promise => { + const response = await privateGraphQLClient + .mutation(publishShout, { slug, shout: shoutInput }) + .toPromise() + console.debug('[publishShout]:', response) + return response.data.publishShout.shout + }, + getDrafts: async (): Promise => { + const response = await privateGraphQLClient.query(draftsLoad, {}).toPromise() + console.debug('[getDrafts]:', response) + return response.data.loadDrafts }, - createReaction: async (input: ReactionInput) => { const response = await privateGraphQLClient.mutation(reactionCreate, { reaction: input }).toPromise() console.debug('[createReaction]:', response)