Compare commits

...

3 Commits

  1. 72
      model.js
  2. 102
      needs.js
  3. 5
      package.json
  4. 6
      server.js

72
model.js

@ -1,25 +1,77 @@
//import PouchDB from 'pouchdb'
var PouchDB = require('pouchdb');
PouchDB.plugin(require('pouchdb-upsert'))
var m = require('mithril')
var Stream = require('mithril/stream')
// TODO: Broken global state, needs model API for live updates
var db = null
var model = null
// TODO: Name is inappropriate now for a multiple call "promise"
function getModel(db_url) {
db_url = "http://exodus.strfry.org:82/hq_needs/"
var db = new PouchDB(db_url)
db = new PouchDB(db_url)
//var db = require('pouchdb')(db_url)
return new Promise((resolve, reject) => {
db.allDocs({include_docs: true}
db.allDocs({
include_docs: true,
update_seq: true}
).then(docs => {
var stores = docs.rows.map(doc => Object({store: doc.id, items: doc.doc.items}))
resolve(stores)
// TODO: validate docs against a schema?
var groupBy = function(xs, key) {
return xs.reduce(function(rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
var items = docs.rows.map(row => row.doc).filter(doc => doc.type == "item")
model = groupBy(items, 'store')
resolve(model)
console.log(docs)
console.log(model)
db.changes({
include_docs: true,
since: docs.update_seq,
live: true
}).on('change', change => {
console.log("change detected: ", change)
// TODO: More effective data structure
for (var key in model[change.doc.store]) {
if (model[change.doc.store][key]._id == change.doc._id) {
model[change.doc.store][key] = change.doc;
m.redraw() // TODO: move this out of model
return;
}
}
model[change.doc.store].push(change.doc)
m.redraw() // TODO: move this out of model
}).catch(error => console.log(error))
}).catch(reject)
})
}
var items = [
'Apfel',
'Birne',
'Schokoladenkuchen'
]
module.exports.getModel = getModel;
module.exports.setItemState = (item) => {
db.put(item)
}

102
needs.js

@ -7,10 +7,12 @@ var m = require('mithril')
var stream = require('mithril-stream')
//import stream from 'mithril-stream'
var {Card, Checkbox, ListTile, List} = require('polythene-mithril')
var {Card, Checkbox, Icon, IconButton, SVG, ListTile, List, TextField} = require('polythene-mithril')
//import {Card, Checkbox, ListTile, List} from 'polythene-mithril'
var model = require('./model')
const Item = {
/*
oninit: vnode => {
@ -19,33 +21,95 @@ const Item = {
},
*/
view: vnode => {
console.log('Item.view', vnode)
return m(ListTile, {title: vnode.attrs.name},
m(Checkbox, {
size: 'large',
// value: model.confirmed,
defaultChecked: vnode.attrs.confirmed,
// onChange: state => vnode.attrs.confirmed = state.checked,
onChange: state => vnode.state.checked = state.checked,
// checked: state => vnode.attrs.confirmed
checked: vnode.state.checked,
}))}
console.log("trigger redraw", vnode.attrs)
vnode.state.checked = vnode.attrs.confirmed
return m(ListTile, {
title: vnode.attrs.name,
front:
m(Checkbox, {
size: 'large',
style: { color: 'limegreen'} ,
// value: model.confirmed,
defaultChecked: vnode.attrs.confirmed,
onChange: state => {
var doc = vnode.attrs
doc.confirmed = state.checked
model.setItemState(doc)
},
checked: vnode.state.checked,
}),
})
}
}
const addIconSVG = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/><path d="M0 0h24v24H0z" fill="none"/></svg>'
const AddIcon = m(Icon, {svg: m.trust(addIconSVG), size: 'large' })
const ItemEntryBox = {
view: vnode =>
m(ListTile,
m(TextField, {
require: true,
autofocus: true,
disabled: true
})
)
}
const StoreCard = {
view: vnode =>
m(Card, {content:
m(List, {
header: {title: vnode.attrs.store},
tiles: vnode.attrs.items.map(item => m(Item, item)),
}),
})
m(Card, {
//shadowDepth: 5,
content: [
{
actions: {
content: [
m('.flex', { key: "space"}),
m(IconButton, {icon: AddIcon} )
]
}
},
]
},
m(List, {
header: {
title: vnode.attrs.store,
},
tiles: [
vnode.attrs.items.map(item => m(Item, item)),
m(ItemEntryBox, vnode.attrs)
]
} )
)
}
/*
const StoreCard = {
view: vnode =>
m(Card, {
content: [
{
m(List, {
header: {title: vnode.attrs.store},
tiles: vnode.attrs.items.map(item => m(Item, item))
}),
actions: {
content: [
m(IconButton, {icon: AddIcon} )
]
}
}
})
}
*/
//export
const NeedsApp = {
view: (vnode) => {
return m('div', {id: 'mountpoint'}, [vnode.attrs.stores.map(store => m(StoreCard, store))])
var stores = vnode.attrs.stores
var keys = Object.keys(stores)
return m('div', {id: 'mountpoint'}, [keys.map(store => m(StoreCard, { store: store, items: stores[store]} )),
])
},
// oninit: vnode => { console.log('oninit') },
// oncreate: vnode => console.log('oncreate'),

5
package.json

@ -8,10 +8,15 @@
"polka": "~0.5.2",
"polythene-mithril": "^1.5.4",
"pouchdb": "^7.0.0",
"pouchdb-upsert": "^2.2.0",
"serve-static": "^1.13.2"
},
"type": "module",
"devDependencies": {
"browser-sync": "^2.26.5",
"browserify": "^16.2.3"
},
"scripts": {
"live": "nodemon server.js"
}
}

6
server.js

@ -42,10 +42,16 @@ const ServerLayout = {
function render_index(req, res) {
getModel().then(model => {
console.log("the items i found: ", model)
var template = m(ServerLayout, m(NeedsApp, { stores: model}))
render(template).then(function (html) {
res.writeHead(200, {'Content-Type': 'text/html'})
res.end(html)
}).catch(error => {
res.writeHead(500)
console.log("ERR: ", error)
res.end(error.stack)
})
})
}

Loading…
Cancel
Save