Home

web-commons-export

Library for exporting presentations for Nielsen Marketing Cloud

Standard - JavaScript Style Guide

Description

This library contains helpers for generating presentations with minimal effort using server-side rendering techniques. Using this Library, any App in Nielsen Marketing Cloud can create an export server which exposes an endpoint for generating presentations with nielsen theme (logo, background, copyright, etc) and automatic title injection, as well as automatic page counts and more.

Usage

Creating documents

  1. Create a directory under documents to hold your document. e.g: /src/documents/SegmentDocument/SegmentDocument.js.

the file exports your document creator function and unique document identifier. e.g:

export default {
  documentName: 'segment',
  documentCreator: async function (authorizationHeader) {
    let data = await getDataAsync(authorizationHeader)
    let pages = [Page1, Page2]
    return {
      pages,
      data,
    }
  }
}

add the document into your array of all defined documents in /documents/index.js:

import segmentDocument from './SegmentDocument/SegmentDocument'
export default [
  segmentDocument
]
  1. if required, you can create a dedicated export styles file SegmentDocument.less and import it in SegmentDocument.js.

  2. implement the getDataAsync function to return the data required for the document

    async function getDataAsync (authorizationHeader) {
    const headers = {
     'authorization': authorizationHeader
    }
    return fetch('http://localhost:6200/dmp/entities', {headers})
     .then(res => res.json())
    }
  3. define the Page classes. each class represents a Page in the presentation you export. use the page decorator for built-in capabilities by the library. e.g:

    import { page } from 'web-export/documents'
    @page({
     title: 'SEGMENT REPORT', 
     bodyText:'make love not segments', 
     theme: 'NIELSEN_SIDEBAR_AND_N', 
     skipPageNumber: true
    })
    class Page1 {
    constructor (data) {
     this.data = data
    }
    
    getMainContent () {
     const data = this.data
     return (
         <SegmentViewer data={data} isExportMode />
     )
    }
    }

if you would like to build the presentation via custom code, you can expose getCustomContent method. e.g:

@page({bodyText: 'page 2 text body'})
class Page2 {
  getCustomContent (slide) {
    slide.addText('Title with manual location and design',
     {x: '50%', y: 0.25, font_size: 18, font_face: 'Arial', color: 'FF0000'})
  }

  getMainContent () {
    return (
      <div>
        Did you know? method `getMainContent` is optionally. if you use getCustomContent you may not even need it.
      </div>
    )
  }
}

read here for more details on how to write custom code.

page decorator options

Option Type Default Description Possible Values
title string title in page header
bodyText string paragraph below the title
skipPageNumber bool false skip the page count true, false
theme string NIELSEN_SIDEBAR_AND_N theme (background, logo, copyright, etc) null, NIELSEN_SIDEBAR_AND_N

Settings the server

The library exports setServer function which gets an express app and initializes the endpoint /export. the function also receives array of documents and optional array of themes, and registers them.

usage example:

const express = require('express')
const {setServer} = require('web-commons-export/server')
const themes = require('web-commons-export-themes')

let documents = require('./dist/documents')
const app = express()
setServer(app, '/agen/export', documents, themes)
app.listen(9003, () => {
  console.log('Export Server is listening on port 9003 ...')
})

to access the /export endpoint, specify document in the query string with the document you wish to export. e.g: https://localhost/file/agen/download/export?document=segment

Setting authentication for api requests

the export server should implement server-side jwt authentication in order to be able to perform api requests for getting data required for the export. read here for instructions.

Themes

Themes repository

There is an additional library web-commons-export-themes which acts as a decoupled repository of the common themes. when calling setServer initialization function, you pass it the themes from this library as follows:

const themes = require('web-commons-export-themes')
setServer(app, '/agen/export', documentsRegisters, themes)

Creating custom themes

If you would like to use a custom theme unique to your app across documents, you can register a new theme manually. to do so, add it to the themes argument of the setServer function. e.g:

let copyrightTheme = {
  themeId: 'NIELSEN_SIDEBAR_AND_N',
  apply: function (slide) {
    registerTheme('COPYRIGHT_THEME', slide => {
      const copyright = `Copyright © ${new Date().getFullYear()} The Nielsen Company (US), LLC. Confidential and proprietary. Do not distribute.`
      slide.addText(copyright, {
        x: -2.73,
        y: 4.4,
        w: 5,
        align: 'r',
        rotate: 270,
        font_size: 6,
        font_face: 'Arial',
        color: 'FFFFFF'
      })
    })
  }
}
setServer(app, '/agen/export', documentsRegisters, [...themes, copyrightTheme])

now you can pass it to any page in the theme property of the page decorator.

note: If you created a theme that can be useful for other NMC apps, please make a PR to the web-commons-export-themes library.

Configuring the server

Styles

The library expects the server's webpack to bundle all the styles imported into a single bundled css file. to achieve that, you must use the ExtractTextPlugin webpack Plugin (see example). The file location is expected to be: /dist/styles.css

Webpack loaders

The library expects the server to be able to import all required files of the app itself. to achieve that you need to configure appropriate webpack loaders (see example).

Using Infra goodness

When NMC app is loaded, the Infra injects all kind of libraries for it to use before it loads the app, such as: Underscore, React, Moment, WebInfra-Components and more.

since there is no such Infra injection for us in the export server, its our responsibility to simulate that injection for any library required by the document.

The trick is to define a global variable that would hint us that we are on server-side, and if that the case, then we inject what required. webpack conf:

plugins: [
    new DefinePlugin({
      __IS_SERVER_SIDE__: true
    }),
    ...
]

then in a InfraFacade.js file:

/**
 * Facade for connecting with Infra
 */

let facade
// we run in Server Side
if (__IS_SERVER_SIDE__) {
  // Mock window
  global.window = {}

  // expose underscore from the actual package, because there is no Infra to inject it globally for us
  let underscore = require('underscore')
  global.window._ = underscore
  global._ = underscore

  // import Infra components from the actual package, because there is no Infra to inject it globally for us
  let InfraComponents = require('@master/webinfra-frontend-components')
  facade = {InfraComponents}
}
// we run in browser
else {
  // use facade which exposes the global Infra components injected for us by the Infra globally
  facade = require('webapps-frontend-components/src/main/Infra/InfraFacadeShared')
}

export default facade

now in the app, we can import what required from the facade. e.g:

import { InfraComponents } from 'InfraFacade'
const { CancelButton, DetailsActionButton } = InfraComponents

NMC webapp usage example

https://github.com/xl8/web-agen-frontend/tree/master/agen-app/export-server