// 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 .
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 & PostApi
export interface ChannelStore extends ReactiveBlogStore, ChannelApi {
editId: string
readonly editChannel: BlogChannel | undefined;
}
export interface ContentStore extends ReactiveBlogStore, ContentApi {
}
export interface BlogAdminState{
content: ContentStore
posts: PostStore
channels: ChannelStore
uploadProgress: number;
waitForEditor(): Promise;
queryState:{
sort: SortType;
search: string;
pageSize: number;
}
}
declare module 'pinia' {
export interface PiniaCustomProperties extends BlogAdminState {
}
}
export const cmnextAdminPlugin = (router: ReturnType, ckEditorUrl: string, pageSize: MaybeRef): PiniaPlugin => {
return ({ store }: PiniaPluginContext): BlogAdminState => {
//setup filter search query
const search = useRouteQuery(QueryType.Filter, '', { mode: 'replace', router });
//Get sort order query
const sort = useRouteQuery(QueryType.Sort, SortType.CreatedTime, { mode: 'replace', router });
const uploadProgress = ref(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 => {
await loadPromise;
}
}
return (): Promise => Promise.resolve()
}
const blogContext = createBlogContext({
axios,
channelUrl: '/blog/channels',
postUrl: '/blog/posts',
contentUrl: '/blog/content',
})
const channels = (() => {
//Create channel api
const api = createReactiveBlogApi(
useChannels(blogContext),
{
query: QueryType.Channel,
channelId: undefined,
router,
sort,
search,
pageSize
}
)
//route query for the selected channel
const editId = useRouteQuery(QueryType.ChannelEdit, '', { mode: 'push', router });
//Compute the selected items from their ids
const editChannel = computed(() => find(api.all.value, c => isEqual(c.id, editId.value)))
return{
...api,
editId,
editChannel
}
})()
const getContentStore = (): ContentStore => {
//Create post api
return createReactiveBlogApi(
useContent(blogContext, channels.selectedId),
{
query: QueryType.Content,
channelId: toRef(channels.selectedId),
router,
sort,
search,
pageSize
},
)
}
const getPostStore = (): PostStore => {
//Create post api
return createReactiveBlogApi(
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
}
}
}
}