feat(entry-states): display entity state for editors

This commit is contained in:
Benedikt Rötsch
2017-10-24 15:12:26 +02:00
parent 63ff3e0426
commit fd52efd625
8 changed files with 77 additions and 4 deletions

25
lib/entry-state.js Normal file
View File

@@ -0,0 +1,25 @@
const { getEntry } = require('./../services/contentful')
async function getPublishedEntry (entry) {
try {
return await getEntry(entry.sys.id)
} catch (err) {
return null
}
}
module.exports = async function attachEntryState (entry) {
const publishedEntry = await getPublishedEntry(entry)
entry.draft = false
entry.pendingChanges = false
if (!publishedEntry) {
entry.draft = true
}
if (entry && publishedEntry && (entry.sys.updatedAt !== publishedEntry.sys.updatedAt)) {
entry.pendingChanges = true
}
return entry
}

2
public

Submodule public updated: 1a87426e8c...4dcf29f69f

View File

@@ -1,10 +1,17 @@
const {getCourses, getCourse, getCategories, getCoursesByCategory} = require('./../services/contentful') const {getCourses, getCourse, getCategories, getCoursesByCategory} = require('./../services/contentful')
const attachEntryState = require('./../lib/entry-state')
exports.getCourses = async (req, res, next) => { exports.getCourses = async (req, res, next) => {
// we get all the entries with the content type `course` // we get all the entries with the content type `course`
let courses = [] let courses = []
let categories = [] let categories = []
courses = await getCourses(res.locals.currentLocale.code, res.locals.currentApi.id) courses = await getCourses(res.locals.currentLocale.code, res.locals.currentApi.id)
// Attach entry state flags when using preview API
if (res.locals.settings.editorialFeatures && res.locals.currentApi.id === 'cpa') {
courses = await Promise.all(courses.map(attachEntryState))
}
categories = await getCategories(res.locals.currentLocale.code, res.locals.currentApi.id) categories = await getCategories(res.locals.currentLocale.code, res.locals.currentApi.id)
res.render('courses', { title: `All Courses (${courses.length})`, categories, courses }) res.render('courses', { title: `All Courses (${courses.length})`, categories, courses })
} }
@@ -22,8 +29,13 @@ exports.getCourse = async (req, res, next) => {
let visitedLessons = cookie || [] let visitedLessons = cookie || []
visitedLessons.push(course.sys.id) visitedLessons.push(course.sys.id)
visitedLessons = [...new Set(visitedLessons)] visitedLessons = [...new Set(visitedLessons)]
res.cookie('visitedLessons', visitedLessons, { maxAge: 900000, httpOnly: true }) res.cookie('visitedLessons', visitedLessons, { maxAge: 900000, httpOnly: true })
// Attach entry state flags when using preview API
if (res.locals.settings.editorialFeatures && res.locals.currentApi.id === 'cpa') {
course = await attachEntryState(course)
}
res.render('course', {title: course.fields.title, course, lesson, lessons, lessonIndex, visitedLessons}) res.render('course', {title: course.fields.title, course, lesson, lessons, lessonIndex, visitedLessons})
} }
@@ -47,13 +59,21 @@ exports.getLesson = async (req, res, next) => {
let course = await getCourse(req.params.cslug, res.locals.currentLocale.code, res.locals.currentApi.id) let course = await getCourse(req.params.cslug, res.locals.currentLocale.code, res.locals.currentApi.id)
const lessons = course.fields.lessons const lessons = course.fields.lessons
const lessonIndex = lessons.findIndex((lesson) => lesson.fields.slug === req.params.lslug) const lessonIndex = lessons.findIndex((lesson) => lesson.fields.slug === req.params.lslug)
const lesson = lessons[lessonIndex] let lesson = lessons[lessonIndex]
const nextLesson = lessons[lessonIndex + 1] || null const nextLesson = lessons[lessonIndex + 1] || null
// save visited lessons
const cookie = req.cookies.visitedLessons const cookie = req.cookies.visitedLessons
let visitedLessons = cookie || [] let visitedLessons = cookie || []
visitedLessons.push(lesson.sys.id) visitedLessons.push(lesson.sys.id)
visitedLessons = [...new Set(visitedLessons)] visitedLessons = [...new Set(visitedLessons)]
res.cookie('visitedLessons', visitedLessons, { maxAge: 900000, httpOnly: true }) res.cookie('visitedLessons', visitedLessons, { maxAge: 900000, httpOnly: true })
// Attach entry state flags when using preview API
if (res.locals.settings.editorialFeatures && res.locals.currentApi.id === 'cpa') {
lesson = await attachEntryState(lesson)
}
res.render('course', { res.render('course', {
title: `${course.fields.title} | ${lesson.fields.title}`, title: `${course.fields.title} | ${lesson.fields.title}`,
course, course,

View File

@@ -1,14 +1,21 @@
const { getLandingPage } = require('../services/contentful') const { getLandingPage } = require('../services/contentful')
const attachEntryState = require('./../lib/entry-state')
const url = require('url') const url = require('url')
exports.getLandingPage = async (req, res, next) => { exports.getLandingPage = async (req, res, next) => {
let pathname = url.parse(req.url).pathname.split('/').filter(Boolean)[0] let pathname = url.parse(req.url).pathname.split('/').filter(Boolean)[0]
pathname = pathname || 'home' pathname = pathname || 'home'
const landingPage = await getLandingPage( let landingPage = await getLandingPage(
pathname, pathname,
res.locals.currentLocale.code, res.locals.currentLocale.code,
res.locals.currentApi.id res.locals.currentApi.id
) )
// Attach entry state flags when using preview APIgs
if (res.locals.settings.editorialFeatures && res.locals.currentApi.id === 'cpa') {
landingPage = await attachEntryState(landingPage)
}
res.render('landingPage', { title: pathname, landingPage }) res.render('landingPage', { title: pathname, landingPage })
} }

View File

@@ -26,11 +26,18 @@ exports.initClient = (options) => {
}) })
} }
// Get the Space the app is connected to. Used for the settings form and to get all available locales.
exports.getSpace = assert((api = `cda`) => { exports.getSpace = assert((api = `cda`) => {
const client = api === 'cda' ? cdaClient : cpaClient const client = api === 'cda' ? cdaClient : cpaClient
return client.getSpace() return client.getSpace()
}, 'Space') }, 'Space')
// Get a single entry. Used to detect the `Draft` or `Pending Changes` state.
exports.getEntry = assert((entryId, api = `cda`) => {
const client = api === 'cda' ? cdaClient : cpaClient
return client.getEntry(entryId)
}, 'Entry')
// to get all the courses we request all the entries // to get all the courses we request all the entries
// with the content_type `course` from Contentful // with the content_type `course` from Contentful
exports.getCourses = assert((locale = 'en-US', api = `cda`) => { exports.getCourses = assert((locale = 'en-US', api = `cda`) => {

View File

@@ -1,3 +1,5 @@
include _entryState
mixin courseCard(course = {fields: {title: '', description: '', categories: [], slug: ''}}) mixin courseCard(course = {fields: {title: '', description: '', categories: [], slug: ''}})
.course-card .course-card
.course-card__categories .course-card__categories
@@ -7,6 +9,8 @@ mixin courseCard(course = {fields: {title: '', description: '', categories: [],
a.course-card__category-link(href=`/courses/categories/${category.fields.slug}${queryString}`) #{category.fields.title} a.course-card__category-link(href=`/courses/categories/${category.fields.slug}${queryString}`) #{category.fields.title}
h2.course-card__title h2.course-card__title
a(href=`/courses/${course.fields.slug}${queryString}`)= course.fields.title a(href=`/courses/${course.fields.slug}${queryString}`)= course.fields.title
if currentApi.id === 'cpa' && (entry.draft || entry.pendingChanges)
+entryState(course)
p.course-card__description= course.fields.shortDescription p.course-card__description= course.fields.shortDescription
.course-card__link-wrapper .course-card__link-wrapper
a.course-card__link(href=`/courses/${course.fields.slug}${queryString}`) view course a.course-card__link(href=`/courses/${course.fields.slug}${queryString}`) view course

View File

@@ -1,6 +1,11 @@
include _entryState
mixin editorialFeatures(entry) mixin editorialFeatures(entry)
if settings.editorialFeatures if settings.editorialFeatures
.editorial-features .editorial-features
if currentApi.id === 'cpa' && (entry.draft || entry.pendingChanges)
.editorial-features__item
+entryState(entry)
.editorial-features__item .editorial-features__item
a.editorial-features__text( a.editorial-features__text(
href=`https://app.contentful.com/spaces/${settings.space}/entries/${entry.sys.id}` href=`https://app.contentful.com/spaces/${settings.space}/entries/${entry.sys.id}`

View File

@@ -0,0 +1,5 @@
mixin entryState(entry)
if entry.draft
.pill.pill--draft draft
if entry.pendingChanges
.pill.pill--pending-changes pending changes