feat(entry-states): display entity state for editors
This commit is contained in:
25
lib/entry-state.js
Normal file
25
lib/entry-state.js
Normal 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
2
public
Submodule public updated: 1a87426e8c...4dcf29f69f
@@ -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,
|
||||||
|
|||||||
@@ -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 })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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`) => {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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}`
|
||||||
|
|||||||
5
views/mixins/_entryState.pug
Normal file
5
views/mixins/_entryState.pug
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
mixin entryState(entry)
|
||||||
|
if entry.draft
|
||||||
|
.pill.pill--draft draft
|
||||||
|
if entry.pendingChanges
|
||||||
|
.pill.pill--pending-changes pending changes
|
||||||
Reference in New Issue
Block a user