Commit e7853353 authored by Matija Obreza's avatar Matija Obreza
Browse files

Merge branch '158-cms-admin-activity-posts' into 'master'

Resolve "CMS Admin: Activity posts"

Closes #158

See merge request genesys-pgr/genesys-ui!168
parents 96b98dec 3690ee2b
...@@ -84,6 +84,7 @@ ...@@ -84,6 +84,7 @@
"itemEditorWarn": "Don't use the ItemsEditor for more than 100 items!", "itemEditorWarn": "Don't use the ItemsEditor for more than 100 items!",
"lastModified": "Last modified", "lastModified": "Last modified",
"lastUpdated": "Last updated", "lastUpdated": "Last updated",
"lastUpdatedBy": "Last updated by {{who}}",
"modified": "Modified", "modified": "Modified",
"name": "Name", "name": "Name",
"newVersionAvailable": "New version available", "newVersionAvailable": "New version available",
......
...@@ -254,6 +254,8 @@ ...@@ -254,6 +254,8 @@
"oAuthClients": "OAuth clients", "oAuthClients": "OAuth clients",
"requests": "Requests", "requests": "Requests",
"content": "CMS", "content": "CMS",
"activityPosts": "Activity posts",
"articles": "Articles",
"vocabulary": "Vocabulary", "vocabulary": "Vocabulary",
"fileRepository": "File repository", "fileRepository": "File repository",
"cluster": "Cluster", "cluster": "Cluster",
...@@ -528,6 +530,10 @@ ...@@ -528,6 +530,10 @@
"slug": "Slug", "slug": "Slug",
"lang": "Language", "lang": "Language",
"isTemplate": "Is template" "isTemplate": "Is template"
},
"activityPostForm": {
"content": "Content",
"title": "Title"
} }
}, },
"f": { "f": {
...@@ -543,8 +549,13 @@ ...@@ -543,8 +549,13 @@
"title": "Browse articles", "title": "Browse articles",
"create": "Create new article" "create": "Create new article"
}, },
"browseActivityPost": {
"title": "Browse activity posts",
"create": "Create new activity post"
},
"edit": { "edit": {
"articleSaved": "Article saved", "articleSaved": "Article saved",
"activityPostSaved": "Activity post saved",
"transifex": { "transifex": {
"fetch": "Fetch translations", "fetch": "Fetch translations",
"fetchStarted": "Fetch started", "fetchStarted": "Fetch started",
...@@ -578,11 +589,17 @@ ...@@ -578,11 +589,17 @@
"c": { "c": {
"documentationSection": { "documentationSection": {
"toc": "Table of contents" "toc": "Table of contents"
},
"activityPostSection": {
"shareArticle": "Share this article",
"tweet": "Tweet!",
"shareLinkedin": "Share on LinkedIn"
} }
} }
}, },
"common": { "common": {
"articleList": "Article list" "articleList": "Article list",
"activityPostList": "Activity post list"
} }
} }
......
...@@ -2,10 +2,12 @@ ...@@ -2,10 +2,12 @@
import { showSnackbar } from 'actions/snackbar'; import { showSnackbar } from 'actions/snackbar';
import navigateTo from 'actions/navigation'; import navigateTo from 'actions/navigation';
// constants // constants
import { ADMIN_APPEND_ARTICLES, ADMIN_RECEIVE_ARTICLE, ADMIN_RECEIVE_ARTICLES, ADMIN_LOADING_ARTICLE } from 'cms/constants'; import { ADMIN_APPEND_ARTICLES, ADMIN_RECEIVE_ARTICLE, ADMIN_RECEIVE_ARTICLES, ADMIN_LOADING_ARTICLE, ADMIN_APPEND_ACTIVITY_POSTS, ADMIN_RECEIVE_ACTIVITY_POSTS, ADMIN_RECEIVE_ACTIVITY_POST, ADMIN_LOADING_ACTIVITY_POST } from 'cms/constants';
// model // model
import Article from 'model/cms/Article'; import Article from 'model/cms/Article';
import ArticleFilter from 'model/cms/ArticleFilter'; import ArticleFilter from 'model/cms/ArticleFilter';
import ActivityPost from 'model/cms/ActivityPost';
import ActivityPostFilter from 'model/cms/ActivityPostFilter';
import Page from 'model/Page'; import Page from 'model/Page';
import FilteredPage, { IPageRequest } from 'model/FilteredPage'; import FilteredPage, { IPageRequest } from 'model/FilteredPage';
// service // service
...@@ -32,6 +34,28 @@ const loadingArticle = (slug: string) => ({ ...@@ -32,6 +34,28 @@ const loadingArticle = (slug: string) => ({
payload: {slug}, payload: {slug},
}); });
const receiveActivityPosts = (paged: FilteredPage<ActivityPost>, error = null) => ({
type: ADMIN_RECEIVE_ACTIVITY_POSTS,
payload: { paged, error },
});
const appendActivityPosts = (paged: FilteredPage<ActivityPost>, error = null) => ({
type: ADMIN_APPEND_ACTIVITY_POSTS,
payload: { paged, error },
});
const receiveActivityPost = (id: number, activityPost: ActivityPost) => ({
type: ADMIN_RECEIVE_ACTIVITY_POST,
payload: {id, activityPost},
});
const loadingActivityPost = (id: number) => ({
type: ADMIN_LOADING_ACTIVITY_POST,
payload: {id},
});
export const loadArticle = (locale: string, slug: string, targetId: number, clazz: string) => (dispatch) => { export const loadArticle = (locale: string, slug: string, targetId: number, clazz: string) => (dispatch) => {
dispatch(loadingArticle(slug)); dispatch(loadingArticle(slug));
if (!targetId || !clazz) { if (!targetId || !clazz) {
...@@ -55,6 +79,10 @@ export const updateRoute = (paged: FilteredPage<Article>) => (dispatch) => { ...@@ -55,6 +79,10 @@ export const updateRoute = (paged: FilteredPage<Article>) => (dispatch) => {
dispatch(navigateTo(paged.filterCode ? `/admin/content/${paged.filterCode}` : '/admin/content')); dispatch(navigateTo(paged.filterCode ? `/admin/content/${paged.filterCode}` : '/admin/content'));
}; };
export const activityPostUpdateRoute = (paged: FilteredPage<ActivityPost>) => (dispatch) => {
dispatch(navigateTo(paged.filterCode ? `/admin/content/activity-post/${paged.filterCode}` : '/admin/content/activity-post'));
};
export const applyFilters = (filters: ArticleFilter, page: IPageRequest = { page: 0 }) => (dispatch) => { export const applyFilters = (filters: ArticleFilter, page: IPageRequest = { page: 0 }) => (dispatch) => {
console.log('Applying new filter', filters); console.log('Applying new filter', filters);
dispatch(showSnackbar('Applying filters...')); dispatch(showSnackbar('Applying filters...'));
...@@ -70,6 +98,21 @@ export const applyFilters = (filters: ArticleFilter, page: IPageRequest = { page ...@@ -70,6 +98,21 @@ export const applyFilters = (filters: ArticleFilter, page: IPageRequest = { page
}); });
}; };
export const activityPostApplyFilters = (filters: ActivityPostFilter, page: IPageRequest = { page: 0 }) => (dispatch) => {
console.log('Applying new filter', filters);
dispatch(showSnackbar('Applying filters...'));
return CmsService.listActivityPosts(filters, page)
.then((paged) => {
dispatch(receiveActivityPosts(paged));
dispatch(activityPostUpdateRoute(paged));
dispatch(showSnackbar(`Filters applied.`));
}).catch((error) => {
console.log(`API error`, error);
dispatch(receiveArticles(null, error));
dispatch(showSnackbar(`API error: ${error.statusText}`));
});
};
export const loadMoreArticles = (paged?: FilteredPage<Article>) => (dispatch) => { export const loadMoreArticles = (paged?: FilteredPage<Article>) => (dispatch) => {
return CmsService.listArticles(paged && paged.filterCode, Page.nextPage(paged)) return CmsService.listArticles(paged && paged.filterCode, Page.nextPage(paged))
.then((paged) => { .then((paged) => {
...@@ -85,6 +128,43 @@ export const loadMoreArticles = (paged?: FilteredPage<Article>) => (dispatch) => ...@@ -85,6 +128,43 @@ export const loadMoreArticles = (paged?: FilteredPage<Article>) => (dispatch) =>
}); });
}; };
export const loadMoreActivityPosts = (paged?: FilteredPage<ActivityPost>) => (dispatch) => {
return CmsService.listActivityPosts(paged && paged.filterCode, Page.nextPage(paged))
.then((paged) => {
if (paged.number === 0) {
dispatch(receiveActivityPosts(paged));
} else {
dispatch(appendActivityPosts(paged));
}
dispatch(activityPostUpdateRoute(paged));
}).catch((error) => {
console.log(`API error`, error);
dispatch(receiveArticles(null, error));
});
};
export const loadActivityPost = (id: number) => (dispatch) => {
dispatch(loadingActivityPost(id));
return CmsService.getActivityPost(id)
.then((activityPost) => dispatch(receiveActivityPost(id, activityPost)));
};
export const createOrUpdateActivityPost = (activityPost: ActivityPost) => (dispatch) => {
const createOrUpdate = activityPost.id ? CmsService.updateActivityPost : CmsService.createActivityPost;
return createOrUpdate(activityPost)
.then((saved) => {
dispatch(receiveActivityPost(saved.id, saved));
dispatch(showSnackbar('cms.admin.p.edit.activityPostSaved'));
dispatch(navigateTo(`/admin/content/activity-post/${saved.id}/edit`));
}).catch((error) => dispatch(showSnackbar(error.statusText)));
};
export const deleteActivityPost = (id: number) => (dispatch) => {
return CmsService.deleteActivityPost(id)
.then(() => dispatch(navigateTo('/admin/content/activity-post')));
};
export const createGlobalArticle = (article: Article) => (dispatch) => { export const createGlobalArticle = (article: Article) => (dispatch) => {
article = { article = {
body: '<p></p>', body: '<p></p>',
......
// constants // constants
import { LOADING_SLUG, RECEIVE_ARTICLE, RECEIVE_DOCUMENTATION, RECEIVE_MENU } from 'cms/constants'; import { LOADING_SLUG, RECEIVE_ARTICLE, RECEIVE_DOCUMENTATION, RECEIVE_MENU, RECEIVE_LAST_NEWS, RECEIVE_POST } from 'cms/constants';
// model // model
import Article from 'model/cms/Article'; import Article from 'model/cms/Article';
import Menu from 'model/cms/Menu'; import Menu from 'model/cms/Menu';
import ADoc from 'model/cms/ADoc'; import ADoc from 'model/cms/ADoc';
import ActivityPost from 'model/cms/ActivityPost';
// service // service
import CmsService from 'service/genesys/CmsService'; import CmsService from 'service/genesys/CmsService';
import AsciiDocService from 'service/genesys/AsciiDocService'; import AsciiDocService from 'service/genesys/AsciiDocService';
...@@ -18,6 +19,16 @@ const receiveArticle = (slug: string, article: Article) => ({ ...@@ -18,6 +19,16 @@ const receiveArticle = (slug: string, article: Article) => ({
payload: {slug, article}, payload: {slug, article},
}); });
const receiveLastNews = (lastNews: ActivityPost[]) => ({
type: RECEIVE_LAST_NEWS,
payload: lastNews,
});
const receivePost = (post: ActivityPost, id: number) => ({
type: RECEIVE_POST,
payload: {post, id},
});
export const loadArticle = (locale: string, slug: string) => (dispatch) => { export const loadArticle = (locale: string, slug: string) => (dispatch) => {
dispatch(loadingSlug(slug)); dispatch(loadingSlug(slug));
return CmsService.getArticleBySlugAndLang(locale, slug) return CmsService.getArticleBySlugAndLang(locale, slug)
...@@ -48,3 +59,15 @@ export const loadMenu = (menuKey: string) => (dispatch) => { ...@@ -48,3 +59,15 @@ export const loadMenu = (menuKey: string) => (dispatch) => {
CmsService.getMenu(menuKey) CmsService.getMenu(menuKey)
.then((menuItem) => dispatch(receiveMenu(menuKey, menuItem))); .then((menuItem) => dispatch(receiveMenu(menuKey, menuItem)));
}; };
export const loadLastNews = () => (dispatch) => {
CmsService.getLastNews().then((lastNews) => {
dispatch(receiveLastNews(lastNews));
});
};
export const loadActivityPostById = (id: number) => (dispatch) => {
CmsService.getActivityPost(id).then((post) => {
dispatch(receivePost(post, id));
});
};
...@@ -2,12 +2,22 @@ export const RECEIVE_ARTICLE = 'cms/public/RECEIVE_ARTICLE'; ...@@ -2,12 +2,22 @@ export const RECEIVE_ARTICLE = 'cms/public/RECEIVE_ARTICLE';
export const RECEIVE_DOCUMENTATION = 'cms/public/RECEIVE_DOCUMENTATION'; export const RECEIVE_DOCUMENTATION = 'cms/public/RECEIVE_DOCUMENTATION';
export const LOADING_SLUG = 'cms/public/LOADING_SLUG'; export const LOADING_SLUG = 'cms/public/LOADING_SLUG';
export const RECEIVE_MENU = 'cms/public/RECEIVE_MENU'; export const RECEIVE_MENU = 'cms/public/RECEIVE_MENU';
export const RECEIVE_LAST_NEWS = 'cms/public/RECEIVE_LAST_NEWS';
export const RECEIVE_POST = 'cms/public/RECEIVE_POST';
// admin // admin
export const ADMIN_RECEIVE_ARTICLE = 'cms/admin/RECEIVE_ARTICLE'; export const ADMIN_RECEIVE_ARTICLE = 'cms/admin/RECEIVE_ARTICLE';
export const ADMIN_RECEIVE_ARTICLES = 'cms/admin/RECEIVE_ARTICLES'; export const ADMIN_RECEIVE_ARTICLES = 'cms/admin/RECEIVE_ARTICLES';
export const ADMIN_APPEND_ARTICLES = 'cms/admin/APPEND_ARTICLES'; export const ADMIN_APPEND_ARTICLES = 'cms/admin/APPEND_ARTICLES';
export const ADMIN_LOADING_ARTICLE = 'cms/admin/LOADING_ARTICLE'; export const ADMIN_LOADING_ARTICLE = 'cms/admin/LOADING_ARTICLE';
export const ADMIN_RECEIVE_ACTIVITY_POST = 'cms/admin/RECEIVE_ACTIVITY_POST';
export const ADMIN_RECEIVE_ACTIVITY_POSTS = 'cms/admin/RECEIVE_ACTIVITY_POSTS';
export const ADMIN_APPEND_ACTIVITY_POSTS = 'cms/admin/APPEND_ACTIVITY_POSTS';
export const ADMIN_LOADING_ACTIVITY_POST = 'cms/admin/LOADING_ACTIVITY_POST';
export const ARTICLE_FORM = 'form/cms/admin/article'; export const ARTICLE_FORM = 'form/cms/admin/article';
export const ACTIVITY_POST_FORM = 'form/cms/admin/activityPost';
export const ARTICLE_FILTERS = 'filter/cms/admin/article';
export const ACTIVITY_POST_FILTERS = 'filter/cms/admin/activityPost';
import { ADMIN_RECEIVE_ARTICLE, ADMIN_RECEIVE_ARTICLES, ADMIN_APPEND_ARTICLES, ADMIN_LOADING_ARTICLE } from 'cms/constants'; import { ADMIN_APPEND_ARTICLES, ADMIN_LOADING_ACTIVITY_POST, ADMIN_LOADING_ARTICLE, ADMIN_RECEIVE_ACTIVITY_POST, ADMIN_RECEIVE_ACTIVITY_POSTS, ADMIN_RECEIVE_ARTICLE, ADMIN_RECEIVE_ARTICLES } from 'cms/constants';
import update from 'immutability-helper'; import update from 'immutability-helper';
import Page from 'model/Page'; import Page from 'model/Page';
import Article from 'model/cms/Article'; import Article from 'model/cms/Article';
import ActivityPost from 'model/cms/ActivityPost';
const INITIAL_STATE: { const INITIAL_STATE: {
articles: any, articles: any,
loading: any, loading: any,
paged: Page<Article>, paged: Page<Article>,
pagedError: any, pagedError: any,
activityPost: {
paged: Page<ActivityPost>,
pagedError: any,
posts: any,
loading: any,
},
} = { } = {
articles: {}, articles: {},
loading: null, loading: null,
paged: null, paged: null,
pagedError: null, pagedError: null,
activityPost: {
paged: null,
pagedError: null,
posts: [],
loading: null,
},
}; };
export default function cmsAdmin(state = INITIAL_STATE, action: { type?: string, payload?: any } = {type: '', payload: {}}) { export default function cmsAdmin(state = INITIAL_STATE, action: { type?: string, payload?: any } = {type: '', payload: {}}) {
...@@ -59,6 +72,43 @@ export default function cmsAdmin(state = INITIAL_STATE, action: { type?: string, ...@@ -59,6 +72,43 @@ export default function cmsAdmin(state = INITIAL_STATE, action: { type?: string,
pagedError: { $set: error }, pagedError: { $set: error },
}); });
} }
case ADMIN_RECEIVE_ACTIVITY_POSTS: {
const { paged, error } = action.payload;
return update(state, {
activityPost: {
paged: { $set: paged },
pagedError: { $set: error },
},
});
}
case ADMIN_RECEIVE_ACTIVITY_POST: {
const {id, activityPost } = action.payload;
return update(state, {
activityPost: {
posts: {
[id]: { $set: activityPost },
},
loading: { $set: null },
},
});
}
case ADMIN_LOADING_ACTIVITY_POST: {
const { id } = action.payload;
return update(state, {
activityPost: {
current: { $set: null },
loading: {
$set: {
id: { $set: id },
},
},
},
});
}
default: default:
return state; return state;
} }
......
import { RECEIVE_ARTICLE, RECEIVE_DOCUMENTATION, RECEIVE_MENU, LOADING_SLUG } from 'cms/constants'; import { RECEIVE_ARTICLE, RECEIVE_DOCUMENTATION, RECEIVE_MENU, LOADING_SLUG, RECEIVE_LAST_NEWS, RECEIVE_POST } from 'cms/constants';
import update from 'immutability-helper'; import update from 'immutability-helper';
const INITIAL_STATE: { const INITIAL_STATE: {
...@@ -6,13 +6,19 @@ const INITIAL_STATE: { ...@@ -6,13 +6,19 @@ const INITIAL_STATE: {
documentations: any, documentations: any,
loadingSlug: string, loadingSlug: string,
menus: any, menus: any,
lastNews: any,
news: any,
} = { } = {
articles: {}, articles: {},
documentations: {}, documentations: {},
menus: {}, menus: {},
loadingSlug: null, loadingSlug: null,
lastNews: null,
news: {},
}; };
/* state will be changes */
export default function listPublic(state = INITIAL_STATE, action: { type?: string, payload?: any } = {type: '', payload: {}}) { export default function listPublic(state = INITIAL_STATE, action: { type?: string, payload?: any } = {type: '', payload: {}}) {
switch (action.type) { switch (action.type) {
...@@ -47,6 +53,20 @@ export default function listPublic(state = INITIAL_STATE, action: { type?: strin ...@@ -47,6 +53,20 @@ export default function listPublic(state = INITIAL_STATE, action: { type?: strin
}, },
}); });
} }
case RECEIVE_LAST_NEWS: {
const lastNews = action.payload;
return update(state, {
lastNews: {$set: lastNews},
});
}
case RECEIVE_POST: {
const {post, id} = action.payload;
return update(state, {
news: {
[id]: {$set: post},
},
});
}
default: default:
return state; return state;
} }
......
...@@ -3,6 +3,13 @@ import * as Loadable from 'react-loadable'; ...@@ -3,6 +3,13 @@ import * as Loadable from 'react-loadable';
const publicRoutes = [ const publicRoutes = [
{
path: '/content/news/:id/:slug',
component: Loadable({
loader: () => import(/* webpackMode:"lazy", webpackChunkName: "cms" */'cms/ui/ActivityPostDisplayPage'),
loading: Loading,
}),
},
{ {
path: '/content/:menuKey/:slug', path: '/content/:menuKey/:slug',
component: Loadable({ component: Loadable({
...@@ -27,6 +34,29 @@ const publicRoutes = [ ...@@ -27,6 +34,29 @@ const publicRoutes = [
]; ];
const adminRoutes = [ const adminRoutes = [
{
path: '/content/activity-post/:id/edit',
component: Loadable({
loader: () => import(/* webpackMode:"lazy", webpackChunkName: "cms" */'cms/ui/admin/ActivityPostEditPage'),
loading: Loading,
}),
exact: true,
},
{
path: '/content/activity-post/edit',
component: Loadable({
loader: () => import(/* webpackMode:"lazy", webpackChunkName: "cms" */'cms/ui/admin/ActivityPostEditPage'),
loading: Loading,
}),
exact: true,
},
{
path: '/content/activity-post/:filterCode(v.+)?',
component: Loadable({
loader: () => import(/* webpackMode:"lazy", webpackChunkName: "cms" */'cms/ui/admin/ActivityPostBrowsePage'),
loading: Loading,
}),
},
{ {
path: '/content/:slug/edit', path: '/content/:slug/edit',
component: Loadable({ component: Loadable({
......
...@@ -9,6 +9,10 @@ ...@@ -9,6 +9,10 @@
"slug": "Slug", "slug": "Slug",
"lang": "Language", "lang": "Language",
"isTemplate": "Is template" "isTemplate": "Is template"
},
"activityPostForm": {
"content": "Content",
"title": "Title"
} }
}, },
"f": { "f": {
...@@ -24,8 +28,13 @@ ...@@ -24,8 +28,13 @@
"title": "Browse articles", "title": "Browse articles",
"create": "Create new article" "create": "Create new article"
}, },
"browseActivityPost": {
"title": "Browse activity posts",
"create": "Create new activity post"
},
"edit": { "edit": {
"articleSaved": "Article saved", "articleSaved": "Article saved",
"activityPostSaved": "Activity post saved",
"transifex": { "transifex": {
"fetch": "Fetch translations", "fetch": "Fetch translations",
"fetchStarted": "Fetch started", "fetchStarted": "Fetch started",
...@@ -59,10 +68,16 @@ ...@@ -59,10 +68,16 @@
"c": { "c": {
"documentationSection": { "documentationSection": {
"toc": "Table of contents" "toc": "Table of contents"
},
"activityPostSection": {
"shareArticle": "Share this article",
"tweet": "Tweet!",
"shareLinkedin": "Share on LinkedIn"
} }
} }
}, },
"common": { "common": {
"articleList": "Article list" "articleList": "Article list",
"activityPostList": "Activity post list"
} }
} }
import * as React from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
// Actions
import { loadLastNews, loadActivityPostById } from 'cms/actions/public';
// Models