Skip to content

Commit

Permalink
Initial code commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Kris Hoyt committed Feb 9, 2018
1 parent f0c3196 commit 4c485f7
Show file tree
Hide file tree
Showing 93 changed files with 14,230 additions and 0 deletions.
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# AppNexus CMP
CMP is a tool for publishers to engage users of their properties and gather & store end user consent.

### Installation

```sh
git clone https://github.com/appnexus/cmp.git
cd cmp
yarn install
```

## Build for Production

```sh
npm run build
```

This produces a production build of the `cmp` script and the docs application:
+ `./build/cmp.bundle.js` - CMP script to include on your site
+ `./build/docs/` - Application hosting the documentation

## Documentation

Instructions to install the CMP as well as API docs and examples are available in the `docs`
application included with the repo.

```sh
npm start
```

The documentation can be viewed at:
`http://localhost:5000/docs/`

## Development
You can start a development server that will monitor changes to all CMP and docs files with:
```sh
npm run dev
```

Development server can be accessed at:
`http://localhost:8080/`

## Testing

```sh
npm test
```
108 changes: 108 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
{
"name": "appnexus-cmp",
"version": "0.0.0",
"scripts": {
"clean": "rm -rf build",
"dev": "cross-env NODE_ENV=development webpack-dev-server --inline --hot --progress",
"start": "serve build -s -c 1",
"prestart": "npm run build",
"build": "cross-env NODE_ENV=production webpack --progress",
"prebuild": "npm run clean && mkdirp build",
"test": "npm run -s lint && jest --coverage",
"test:watch": "npm run -s test -- --watch",
"lint": "eslint src test",
"preversion": "npm test",
"version": "npm run build"
},
"repository": {
"type": "git",
"url": "https://github.com/appnexus/cmp.git"
},
"license": "Apache-2.0",
"author": "AppNexus",
"jest": {
"setupFiles": [
"./test/setup.js"
],
"testURL": "http://localhost:8080",
"moduleFileExtensions": [
"js",
"jsx"
],
"moduleDirectories": [
"node_modules"
],
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(css|less)$": "identity-obj-proxy",
"^react$": "preact-compat",
"^react-dom$": "preact-compat"
},
"collectCoverageFrom": [
"src/lib/**/*.{js,jsx}",
"src/components/**/*.{js,jsx}"
]
},
"devDependencies": {
"autoprefixer": "^7.0.1",
"babel": "^6.5.2",
"babel-core": "^6.24.0",
"babel-eslint": "^8.2.1",
"babel-jest": "^22.2.0",
"babel-loader": "^7.0.0",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-object-assign": "^6.22.0",
"babel-plugin-transform-react-jsx": "^6.8.0",
"babel-preset-es2015": "^6.24.0",
"babel-preset-stage-0": "^6.5.0",
"babel-register": "^6.24.0",
"babel-runtime": "^6.11.6",
"chai": "^4.0.2",
"copy-webpack-plugin": "^4.3.1",
"cross-env": "^5.0.1",
"css-loader": "^0.28.0",
"eslint": "^4.1.0",
"eslint-plugin-jest": "^21.7.0",
"eslint-plugin-react": "^7.0.0",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^1.1.6",
"html-webpack-plugin": "^2.28.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^22.2.1",
"json-loader": "^0.5.4",
"less": "^3.0.0-alpha.3",
"less-loader": "^4.0.3",
"mkdirp": "^0.5.1",
"ncp": "^2.0.0",
"postcss-loader": "^2.0.3",
"preact-jsx-chai": "^2.2.1",
"raw-loader": "^1.0.0-beta.0",
"regenerator-runtime": "^0.11.1",
"replace-bundle-webpack-plugin": "^1.0.0",
"script-ext-html-webpack-plugin": "^1.3.4",
"sinon": "^4.2.2",
"sinon-chai": "^2.9.0",
"source-map-loader": "^0.2.1",
"style-loader": "^0.20.1",
"url-loader": "^0.6.1",
"webpack": "^3.0.0",
"webpack-dev-server": "^2.4.4"
},
"dependencies": {
"classnames": "^2.2.5",
"codemirror": "^5.34.0",
"core-js": "^2.5.3",
"js-beautify": "^1.7.5",
"lodash": "^4.17.4",
"preact": "^8.1.0",
"preact-compat": "^3.15.0",
"preact-render-to-string": "^3.6.0",
"promise-polyfill": "^7.1.0",
"proptypes": "^1.0.0",
"query-string": "^5.0.1",
"react-codemirror2": "^4.0.0",
"react-router-dom": "^4.2.2",
"serve": "^6.0.0",
"whatwg-fetch": "^2.0.3"
}
}
42 changes: 42 additions & 0 deletions src/components/app.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { h, Component } from 'preact';
import style from './app.less';

import Popup from './popup/popup';

export default class App extends Component {
state = {
store: this.props.store
};

onSave = () => {
const { store, notify } = this.props;
store.persist();
notify('onSubmit');
store.toggleConsentToolShowing(false);
};


updateState = (store) => {
this.setState({ store });
};

componentWillMount() {
const { store } = this.props;
store.subscribe(this.updateState);
}

render(props, state) {

const {
store,
} = state;

return (
<div class={style.gdpr}>
<Popup store={store}
onSave={this.onSave}
/>
</div>
);
}
}
43 changes: 43 additions & 0 deletions src/components/app.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
@import '../style/variables';

.gdpr {
@import '../style/normalize';

font-family: 'Helvetica Neue', arial, sans-serif;
font-weight: 400;
font-size: 16px;
line-height: 1.5;

* {
box-sizing: border-box;
}

a {
text-decoration: none;
color: @color-linkColor;
cursor: pointer;
&:hover {
color: @color-linkColorHover;
}
}

table {
margin: 0;
}

input:not([type]), input[type="text"], input[type="password"] {
box-sizing: border-box;
box-shadow: 0 3px 3px rgba(0, 0, 0, 0.05) inset;
background-color: #fff;
border-radius: 4px;
border: 1px solid #c5c5c5;
color: #333;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 1em;
margin: 0;
padding: 0 9px;
height: 28px;
}
}


72 changes: 72 additions & 0 deletions src/components/app.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/* eslint-disable react/jsx-no-bind */
import { h, render } from 'preact';
import { expect } from 'chai';
import style from './app.less';
import Store from '../lib/store';

import App from './app';

describe('App', () => {
let scratch;

beforeAll(() => {
scratch = document.createElement('div');
(document.body || document.documentElement).appendChild(scratch);
});

beforeEach(() => {
scratch.innerHTML = '';
});

afterAll(() => {
scratch.parentNode.removeChild(scratch);
scratch = null;
});


it('should render app content', () => {
render(<App store={new Store()} />, scratch);
expect(scratch.innerHTML).to.contain(style.gdpr);
});

it('add a listener to the store to receive updates', () => {
const store = new Store();
render(<App store={store} />, scratch);
expect(store.listeners.size).to.equal(1);
});

it('persist state on save', () => {
const store = new Store();
const notify = jest.fn();
store.persist = jest.fn();
store.toggleConsentToolShowing = jest.fn();

let app;
render(<App
store={store}
notify={notify}
ref={ref => app = ref}
/>, scratch);

app.onSave();

expect(notify.mock.calls[0][0]).to.equal('onSubmit');
expect(store.persist.mock.calls.length).to.equal(1);
expect(store.toggleConsentToolShowing.mock.calls[0][0]).to.equal(false);
});

it('updates local state when store changes', () => {
const store = new Store();

let app;
render(<App
store={store}
notify={() => {}}
ref={ref => app = ref}
/>, scratch);

expect(app.state.store.vendorConsentData.selectedVendorIds).to.deep.equal(new Set());
store.selectVendor(1, true);
expect(app.state.store.vendorConsentData.selectedVendorIds).to.deep.equal(new Set([1]));
});
});
27 changes: 27 additions & 0 deletions src/components/button/button.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { h, Component } from 'preact';
import style from './button.less';

export default class Button extends Component {

static defaultProps = {
onClick: () => {},
invert: false
};


render(props) {
const {
children,
onClick,
invert
} = props;

return (
<button
class={[style.button, props.class, invert ? style.invert : ''].join(' ')}
onClick={onClick}>
{children}
</button>
);
}
}
28 changes: 28 additions & 0 deletions src/components/button/button.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
@import '../../style/variables.less';

button, input[type=button] {
&.button {
cursor: pointer;
outline: none;
padding: 1em;
background: @color-primary;
color: white;
border: none;
border-radius: 4px;
font-size: 1em;
font-weight: bold;
text-transform: uppercase;
&:hover {
color: @color-linkColorHover;
}

&.invert {
background: white;
border: 2px solid @color-primary;
color: @color-primary;
&:hover {
color: lighten(@color-primary, 20%);
}
}
}
}
15 changes: 15 additions & 0 deletions src/components/panel/panel.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { h, Component } from 'preact';


export default class Panel extends Component {

render(props) {
const { children=[], selectedIndex } = props;
const section = children.length && selectedIndex < children.length ? children[selectedIndex] : null;

return (
section
);
}
}

Loading

0 comments on commit 4c485f7

Please sign in to comment.