const _ = require('lodash') const app = require('../../app') const { Set } = require('immutable') const { dollarIcon, dropdownIcon } = require('../../assets') /** * @param {CrudPagesOptions} opts */ const details = (opts) => { const hideCriteria = column => column.routeParam ? `$ctrl.$routeParams.${column.routeParam} !== '${opts.paramAll}'` : 'false' const autocompleteInput = column => { if (!column.apiPrefix) throw new Error('apiPrefix is required for autocomplete fields') return html` {{item.name || item.key || item.id}} ` } const multiSelectInput = column => { if (!column.apiPrefix) throw new Error('apiPrefix is required for multi-select fields') return html` {{item.name || item.key}} ` } const attrs = obj => obj ? raw(_.toPairs(obj).map(([key, value]) => `${key}="${value}"`).join(' ')) : '' const standardInput = column => html` ` const currencyInput = column => html` ` const defaultField = column => column.type === 'autocomplete' ? autocompleteInput(column) : column.type === 'currency' ? currencyInput(column) : column.type === 'multi-select' ? multiSelectInput(column) : standardInput(column) const layout = () => { if (opts.layout) { const cols = _.fromPairs(opts.columns.map(col => [col.camelName, col])) return opts.layout.map(section => html` ${section.section ? html`

${section.section}

`:''} ${raw(section.rows ? section.rows.map( row => html`
${raw(row .map(field => cols[field]) .map(c => c.field || defaultField(c)) .join('\n') )}
`).join('\n') : '')}
`).join('\n') } else { return html` ${opts.columns.map(c => html` ${c.field || defaultField(c)} `)} ` } } const template = html`
${raw(layout())}
Submit
` console.log(`crud: app${opts.pascalName}DetailsPage`) app.component(`app${opts.pascalName}DetailsPage`, { template, controller: function(api, $scope, $routeParams, $mdToast, $location, $q, util) { this.titleFn = opts.titles && opts.titles.details this.$scope = $scope this.$mdToast = $mdToast this.$location = $location this.$q = $q this.util = util this.api = api this.$routeParams = $routeParams this.template = template // For inspection purposes this.apiPrefix = util.fillPath(opts.apiPrefix, $routeParams) this.appPrefix = util.fillPath(opts.appPrefix, $routeParams) this.isNew = $routeParams[opts.routeParam] === opts.paramNew const crud = api.crud(this.apiPrefix) let original if (this.isNew) { original = {} $scope.model = Object.create(original) this.loadingPromise = $q.resolve($scope.model) } else { this.loadingPromise = crud.read($routeParams[opts.routeParam]).then(model => { original = model $scope.model = Object.create(original) return $scope.model }) } this.submit = async () => { try { if (this.isNew) { await crud.create($scope.model) } else { const obj = {} for (var key in $scope.model) { if ($scope.model.hasOwnProperty(key)) { obj[key] = $scope.model[key] } } await crud.update(original.id, obj) } $mdToast.showSimple(`${opts.titleName} saved.`) $location.url(this.appPrefix) } catch (err) { console.error(err) $mdToast.showSimple(`Could not save ${opts.titleName}: ${err.message || err.statusText || err}`) } } /* Autocomplete fields */ this.searchText = {} this.autocomplete = {} opts.columns.filter(c => c.type === 'autocomplete').forEach(c => { const crud = api.crud(util.fillPath(c.apiPrefix, $routeParams)) const ac = this.autocomplete[c.camelName] = { onChange() { $scope.model[c.camelName] = ac.selectedItem ? ac.selectedItem.id : null }, getItems(searchText) { return crud.autocomplete(searchText) } } this.loadingPromise.then(model => { if (model[c.camelName]) { crud.read(model[c.camelName]).then(record => { ac.selectedItem = record }) } }) }) /* Multi-Select fields */ this.multiSelect = {} opts.columns.filter(c => c.type === 'multi-select').forEach(c => { const crud = api.crud(util.fillPath(c.apiPrefix, $routeParams)) const ms = {} this.multiSelect[c.camelName] = ms const updateLabel = () => { ms.label = ms.set.toArray() .map(key => ms.lookup[key].name || key) .join(', ') } this.loadingPromise.then(() => { crud.list().then(items => { ms.lookup = _.fromPairs(items.map(x => [x.key, x])) ms.items = items ms.set = new Set($scope.model[c.camelName]) updateLabel() }) }) ms.add = (key) => { ms.set = ms.set.add(key) $scope.model[c.camelName] = ms.set.toArray() updateLabel() } ms.remove = (key) => { ms.set = ms.set.remove(key) $scope.model[c.camelName] = ms.set.toArray() updateLabel() } ms.toggle = (key) => ms.set.has(key) ? ms.remove(key) : ms.add(key) }) if (opts.controllers && opts.controllers.details) { opts.controllers.details.apply(this) } } }) } module.exports = details