├── .gitignore
├── README.md
├── app.js
├── components
├── AppRoot.jsx
└── NewItemForm.jsx
├── config.js
├── dispatcher
└── AppDispatcher.js
├── dist
└── bundle.js
├── index.html
├── package.json
├── stores
└── ListStore.js
└── webpack.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-flux-cosmicjs
2 | This is an extenstion of the [easy-flux-example repo](https://github.com/tonyspiro/easy-flux-example). This repo demonstrates how to build a data-driven [React](http://facebook.github.io/react/) application using the [Flux](https://facebook.github.io/flux/) pattern and the [Cosmic JS browser client](https://www.npmjs.com/package/cosmicjs-browser) to perform read / write / delete operations on the [Cosmic JS API](https://cosmicjs.com).
3 |
4 | ##Getting started
5 | 1. Sign up for Cosmic JS and add a bucket: [https://cosmicjs.com](https://cosmicjs.com)
6 | 2. Install the repo
7 |
8 | ```git clone https://github.com/tonyspiro/react-flux-cosmicjs ```
9 |
10 | 3. Configure config.js to point to your Cosmic JS bucket
11 | ```
12 | // config.js
13 |
14 | let config = {};
15 | config.bucket = {
16 | slug: 'react-flux-cosmicjs', // your Cosmic JS bucket slug
17 | read_key: '', // add read_key if added to your Cosmic JS bucket settings
18 | write_key: '' // add write_key if added to your Cosmic JS bucket settings
19 | };
20 |
21 | export default config;
22 | ```
23 | 4. Run webpack-dev-server
24 |
25 | ```
26 | cd react-flux-cosmicjs
27 | npm install
28 | npm run dev
29 | ```
30 | Go to [http://localhost:8080/webpack-dev-server/](http://localhost:8080/webpack-dev-server/)
31 |
32 | 5. Production ready (minified)
33 | ```
34 | npm run prod
35 | ```
36 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import AppRoot from './components/AppRoot.jsx';
3 |
4 | React.render(
5 | ,
6 | document.getElementById('app-root')
7 | );
8 |
--------------------------------------------------------------------------------
/components/AppRoot.jsx:
--------------------------------------------------------------------------------
1 | // AppRoot.jsx
2 | import React from 'react';
3 | import ListStore from '../stores/ListStore';
4 | import AppDispatcher from '../dispatcher/AppDispatcher';
5 |
6 | // Sub components
7 | import NewItemForm from './NewItemForm.jsx';
8 |
9 | // Method to retrieve state from Stores
10 | let getListState = () => {
11 | return {
12 | items: ListStore.getItems()
13 | };
14 | }
15 |
16 | class AppRoot extends React.Component {
17 |
18 | // Method to setState based upon Store changes
19 | _onChange() {
20 | this.setState(getListState());
21 | }
22 |
23 | constructor() {
24 |
25 | super();
26 |
27 | // API data
28 | AppDispatcher.dispatch({
29 | action: 'init-app'
30 | });
31 |
32 | }
33 |
34 | // Add change listeners to stores
35 | componentDidMount() {
36 | ListStore.addChangeListener(this._onChange.bind(this));
37 | }
38 |
39 | // Remove change listeners from stores
40 | componentWillUnmount() {
41 | ListStore.removeChangeListener(this._onChange.bind(this));
42 | }
43 |
44 | removeItem(e){
45 |
46 | let _id = e.target.dataset._id;
47 |
48 | AppDispatcher.dispatch({
49 | action: 'remove-item',
50 | _id: _id
51 | });
52 | }
53 |
54 | render(){
55 |
56 | let _this = this;
57 |
58 | let items = ListStore.getItems();
59 | let itemHtml = items.map(( listItem ) => {
60 | return
61 | { listItem.title }
62 | ;
63 | });
64 |
65 | return (
66 |
72 | );
73 | }
74 | }
75 |
76 | export default AppRoot;
77 |
--------------------------------------------------------------------------------
/components/NewItemForm.jsx:
--------------------------------------------------------------------------------
1 | // NewItemForm.jsx
2 | import React from 'react';
3 | import AppDispatcher from '../dispatcher/AppDispatcher';
4 |
5 | class NewItemForm extends React.Component {
6 |
7 | createItem(e){
8 |
9 | // so we don't reload the page
10 | e.preventDefault();
11 |
12 | // this gets the value from the input
13 | let item_title = React.findDOMNode(this.refs.item_title).value.trim();
14 |
15 | if(!item_title) return false;
16 |
17 | // this removes the value from the input
18 | React.findDOMNode(this.refs.item_title).value = '';
19 |
20 | // This is where the magic happens,
21 | // no need to shoot this action all the way to the root of your application to edit state.
22 | // AppDispatcher does this for you.
23 | AppDispatcher.dispatch({
24 | action: 'add-item',
25 | new_item: {
26 | title: item_title
27 | }
28 | });
29 |
30 | }
31 |
32 | render(){
33 |
34 | return
38 | }
39 | }
40 |
41 | export default NewItemForm;
42 |
--------------------------------------------------------------------------------
/config.js:
--------------------------------------------------------------------------------
1 | /* Configure
2 | ================================ */
3 | let config = {};
4 | config.bucket = {
5 | slug: 'react-flux-cosmicjs', // this is your Cosmic JS bucket slug. Sign up for Cosmic JS (Free) and add a bucket: https://cosmicjs.com/
6 | read_key: '', // add read_key if added to your Cosmic JS bucket settings
7 | write_key: '' // add write_key if added to your Cosmic JS bucket settings
8 | };
9 |
10 | export default config;
--------------------------------------------------------------------------------
/dispatcher/AppDispatcher.js:
--------------------------------------------------------------------------------
1 | // AppDispatcher.js
2 | import {Dispatcher} from 'flux';
3 | let AppDispatcher = new Dispatcher();
4 |
5 | import ListStore from '../stores/ListStore';
6 |
7 | // Register callback with AppDispatcher
8 | AppDispatcher.register((payload) => {
9 |
10 | let action = payload.action;
11 |
12 | switch(action) {
13 |
14 | case 'init-app':
15 |
16 | ListStore.init();
17 |
18 | break;
19 |
20 | // Respond to add-item action
21 | case 'add-item':
22 |
23 | ListStore.addItem(payload);
24 |
25 | break;
26 |
27 | // Respond to remove-item action
28 | case 'remove-item':
29 |
30 | ListStore.removeItem(payload);
31 |
32 | break;
33 |
34 | default:
35 |
36 | return true;
37 |
38 | }
39 |
40 | return true;
41 |
42 | });
43 |
44 | export default AppDispatcher;
45 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | React Flux Cosmic JS
6 |
7 |
8 | React Flux Cosmic JS
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "easy-flux-cosmicjs",
3 | "version": "1.0.0",
4 | "description": "This is an extenstion of the [easy-flux-example repo](https://github.com/tonyspiro/easy-flux-example). This repo also demonstrates how to easily add the Cosmic JS browser client to perform read / write / delete operations on given data sets.",
5 | "main": "app.js",
6 | "dependencies": {
7 | "cosmicjs": "^2.0.0",
8 | "es6-promise": "^3.0.2",
9 | "events": "^1.0.2",
10 | "flux": "^2.1.1",
11 | "isomorphic-fetch": "^2.2.0",
12 | "lodash": "^3.10.1",
13 | "react": "^0.13.3"
14 | },
15 | "devDependencies": {
16 | "babel-core": "^5.8.25",
17 | "babel-loader": "^5.3.2"
18 | },
19 | "scripts": {
20 | "watch": "webpack --watch",
21 | "dev": "webpack-dev-server",
22 | "prod": "webpack -p",
23 | "test": "echo \"Error: no test specified\" && exit 1"
24 | },
25 | "author": "Tony Spiro (http://tonyspiro.com/)",
26 | "license": "ISC"
27 | }
28 |
--------------------------------------------------------------------------------
/stores/ListStore.js:
--------------------------------------------------------------------------------
1 | // ListStore.js
2 | import {EventEmitter} from 'events';
3 | import _ from 'lodash';
4 | import Cosmic from 'cosmicjs';
5 | import config from './../config';
6 |
7 | let ListStore = _.extend({}, EventEmitter.prototype, {
8 |
9 | // Initial data
10 | items: [],
11 |
12 | // Init items from Cosmic JS
13 | init: function(items){
14 |
15 | let _this = this;
16 |
17 | Cosmic.getObjects(config, function(err, response){
18 |
19 | let items = response.objects.type['list-items'];
20 | items = _.sortBy(items, 'order');
21 | _this.items = items;
22 | _this.emitChange();
23 |
24 | });
25 | },
26 |
27 | // Get all items
28 | getItems: function(){
29 | return this.items;
30 | },
31 |
32 | // Add item
33 | addItem: function(payload){
34 |
35 | let new_item = payload.new_item;
36 | let _this = this;
37 | let object = {
38 | type_slug: 'list-items',
39 | title: new_item.title
40 | };
41 |
42 | Cosmic.addObject(config, object, function(err, response){
43 |
44 | if(response.object){
45 | let new_cosmic_item = response.object;
46 | _this.items.push(new_cosmic_item);
47 | _this.emitChange();
48 | }
49 |
50 | });
51 | },
52 |
53 | // Remove item
54 | removeItem: function(payload){
55 |
56 | let _id = payload._id;
57 | let _this = this;
58 | let delete_object = {
59 | _id: _id
60 | };
61 |
62 | Cosmic.deleteObject(config, delete_object, function(err, object){
63 |
64 | let items = _this.items;
65 |
66 | _.remove(items,(item) => {
67 | return _id == item._id;
68 | });
69 |
70 | _this.items = items;
71 | _this.emitChange();
72 |
73 | });
74 |
75 | },
76 |
77 | // Emit Change event
78 | emitChange: function(){
79 | this.emit('change');
80 | },
81 |
82 | // Add change listener
83 | addChangeListener: function(callback){
84 | this.on('change', callback);
85 | },
86 |
87 | // Remove change listener
88 | removeChangeListener: function(callback) {
89 | this.removeListener('change', callback);
90 | }
91 |
92 | });
93 |
94 | export default ListStore;
95 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | entry: './app.js',
3 | output: { path: __dirname, filename: 'dist/bundle.js' },
4 | module: {
5 | loaders: [
6 | { test: /.jsx?$/, loader: 'babel-loader', exclude: /node_modules/ }
7 | ]
8 | },
9 | };
--------------------------------------------------------------------------------