diff options
author | vnugent <public@vaughnnugent.com> | 2023-12-16 02:40:03 -0500 |
---|---|---|
committer | vnugent <public@vaughnnugent.com> | 2023-12-16 02:40:03 -0500 |
commit | 0d25abab798c005266a1c0b4eeba957d232d4328 (patch) | |
tree | 427bd36e33fcd4960e3a2bc7d73b77dc7779b214 /front-end/src/store/cmnextAdminPlugin.ts | |
parent | 4b8ae76132d2342f40cec703b3d5145ea075c451 (diff) |
move blog admin state to pinia store plugin
Diffstat (limited to 'front-end/src/store/cmnextAdminPlugin.ts')
-rw-r--r-- | front-end/src/store/cmnextAdminPlugin.ts | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/front-end/src/store/cmnextAdminPlugin.ts b/front-end/src/store/cmnextAdminPlugin.ts new file mode 100644 index 0000000..a4741ab --- /dev/null +++ b/front-end/src/store/cmnextAdminPlugin.ts @@ -0,0 +1,176 @@ +// Copyright (C) 2023 Vaughn Nugent +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. + +import 'pinia' +import { MaybeRef, Ref, computed, ref, toRef } from 'vue'; +import { PiniaPluginContext, PiniaPlugin } from 'pinia' +import { find, isEqual } from 'lodash-es'; +import { useRouter } from 'vue-router'; +import { useContent, ContentApi, ContentMeta, + PostMeta, PostApi, BlogChannel, ChannelApi, usePosts, useChannels, + createBlogContext +} from '@vnuge/cmnext-admin'; +import { useRouteQuery } from '@vueuse/router'; +import { useAxios } from '@vnuge/vnlib.browser'; +import { useScriptTag } from '@vueuse/core'; +import { type ReactiveBlogStore, createReactiveBlogApi, QueryType, SortType } from './sharedTypes'; +import { AxiosProgressEvent } from 'axios'; + +export type PostStore = ReactiveBlogStore<PostMeta> & PostApi + +export interface ChannelStore extends ReactiveBlogStore<BlogChannel>, ChannelApi { + editId: string + readonly editChannel: BlogChannel | undefined; +} + +export interface ContentStore extends ReactiveBlogStore<ContentMeta>, ContentApi { +} + +export interface BlogAdminState{ + content: ContentStore + posts: PostStore + channels: ChannelStore + uploadProgress: number; + waitForEditor(): Promise<void>; + queryState:{ + sort: SortType; + search: string; + pageSize: number; + } +} + +declare module 'pinia' { + export interface PiniaCustomProperties extends BlogAdminState { + } +} + +export const cmnextAdminPlugin = (router: ReturnType<typeof useRouter>, ckEditorUrl: string, pageSize: MaybeRef<number>): PiniaPlugin => { + + return ({ store }: PiniaPluginContext): BlogAdminState => { + + //setup filter search query + const search = useRouteQuery<string>(QueryType.Filter, '', { mode: 'replace', router }); + + //Get sort order query + const sort = useRouteQuery<SortType>(QueryType.Sort, SortType.CreatedTime, { mode: 'replace', router }); + + const uploadProgress = ref<number>(0) + + const axios = useAxios({ + onUploadProgress: (e: AxiosProgressEvent) => { + uploadProgress.value = Math.round((e.loaded * 100) / e.total!) + }, + //Set to 60 second timeout + timeout: 60 * 1000 + }) + + const initCkEditor = () => { + //Setup cke editor + if ('CKEDITOR' in window === false) { + //Load scripts + const ckEditorTag = useScriptTag(ckEditorUrl) + //Store the wait result on the window for the editor script to wait + const loadPromise = ckEditorTag.load(true); + + return async (): Promise<void> => { + await loadPromise; + } + } + return (): Promise<void> => Promise.resolve() + } + + const blogContext = createBlogContext({ + axios, + channelUrl: '/blog/channels', + postUrl: '/blog/posts', + contentUrl: '/blog/content', + }) + + const channels = (() => { + + //Create channel api + const api = createReactiveBlogApi<BlogChannel, ChannelApi>( + useChannels(blogContext), + { + query: QueryType.Channel, + channelId: undefined, + router, + sort, + search, + pageSize + } + ) + + //route query for the selected channel + const editId = useRouteQuery<string>(QueryType.ChannelEdit, '', { mode: 'push', router }); + + //Compute the selected items from their ids + const editChannel = computed<BlogChannel | undefined>(() => find(api.all.value, c => isEqual(c.id, editId.value))) + + return{ + ...api, + editId, + editChannel + } + })() + + const getContentStore = (): ContentStore => { + //Create post api + return createReactiveBlogApi<ContentMeta, ContentApi>( + useContent(blogContext, channels.selectedId), + { + query: QueryType.Content, + channelId: toRef(channels.selectedId), + router, + sort, + search, + pageSize + }, + ) + } + + const getPostStore = (): PostStore => { + + //Create post api + return createReactiveBlogApi<PostMeta, PostApi>( + usePosts(blogContext, channels.selectedId), + { + query: QueryType.Post, + channelId: toRef(channels.selectedId), + router, + sort, + search, + pageSize + } + ) + } + + //Load the editor script + const waitForEditor = initCkEditor() + + return { + content: getContentStore(), + posts: getPostStore(), + channels, + uploadProgress, + waitForEditor, + queryState: { + sort, + search, + pageSize + } + } + } +}
\ No newline at end of file |