import { Component } from '../../lib/vues6/vues6.js'
import { utility } from '../service/Utility.service.js'
import { location_service } from '../service/Location.service.js'
import { resource_service } from '../service/Resource.service.js'
import { action_service } from '../service/Action.service.js'
const template = `
{{ title }}
{{ t['common.loading'] }}...
{{ error_message }}
{{ other_message }}
`
const title_map = {
insert: 'Create',
update: 'Edit',
view: 'View',
}
export default class FormComponent extends Component {
static get selector() {
return 'cobalt-form'
}
static get template() {
return template
}
static get props() {
return ['resource', 'form_id', 'initial_mode']
}
definition = {}
data = {}
uuid = ''
title = ''
error_message = ''
other_message = ''
access_msg = ''
can_access = false
is_ready = false
mode = ''
id = ''
t = {}
reset() {
this.definition = {}
this.data = {}
this.uuid = ''
this.title = ''
this.error_message = ''
this.other_message = ''
this.is_ready = false
}
async vue_on_create(internal = false) {
this.t = await T(
'common.loading',
'common.confirm',
'common.save',
'common.not_permission',
'common.item_saved',
'common.unknown_error',
'common.field_required',
'common.confirmation_not_match',
'common.invalid_json'
)
if ( !internal ) {
this.mode = this.initial_mode
this.id = this.form_id
this.resource_class = await resource_service.get(this.resource)
if ( await this.resource_class.can(this.mode) ) {
this.can_access = true
this.access_msg = true
} else {
this.can_access = false
this.access_msg = this.t['common.not_permission'].replace('ACTION', this.mode)
return
}
} else {
this.reset()
}
this.uuid = utility.uuid()
await this.init()
await this.load()
}
async init() {
this.definition = this.resource_class.form_definition
for ( const field of this.definition.fields ) {
if ( field.type.startsWith('select.dynamic') ) {
field._options = field._options || field.options
const rsc = await resource_service.get(field._options.resource)
const other_params = field._options.other_params || {}
field.options = (await rsc.list(other_params)).map(item => {
return {
display: typeof field._options.display === 'function' ? field._options.display(item) : item[field._options.display || 'display'],
value: typeof field._options.value === 'function' ? field._options.value(item) : item[field._options.value || 'display'],
}
})
}
}
}
async load() {
if (this.mode !== 'insert') {
this.data = await this.resource_class.get(this.id)
}
for ( const field of this.definition.fields ) {
if ( field.type.endsWith('.multiple') && !this.data[field.field] ) {
this.data[field.field] = []
}
if ( field.type === 'json' ) {
this.data[field.field] = JSON.stringify(this.data[field.field], undefined, 4)
}
}
this.title = title_map[this.mode] + ' ' + this.resource_class.item
this.is_ready = true
this.$nextTick(() => {
if ( this.mode !== 'view' ) this.$refs.input[0].focus()
})
}
async on_create() {
this.id = this.data.id
this.mode = 'update'
if ( this.definition.handlers && this.definition.handlers.insert ) {
await action_service.perform(this.definition.handlers.insert)
}
await this.vue_on_create(true)
location_service.set_query(`mode=update&id=${this.id}`)
}
async on_update() {
if ( this.definition.handlers && this.definition.handlers.update ) {
await action_service.perform(this.definition.handlers.update)
}
}
data_to_save() {
const data = Object.assign({}, this.data)
for ( const field of this.definition.fields ) {
if ( field.type === 'json' ) {
data[field.field] = JSON.parse(data[field.field])
}
}
return data
}
data_to_restore(data) {
const new_data = Object.assign({}, data)
for ( const field of this.definition.fields ) {
if ( field.type === 'json' ) {
new_data[field.field] = JSON.stringify(data[field.field], undefined, 4)
}
}
this.data = new_data
}
async save_click() {
if ( !this.validate() ) return
try {
if (this.mode === 'insert') {
this.data_to_restore(await this.resource_class.create(this.data_to_save()))
await this.on_create()
} else if (this.mode === 'update') {
await this.resource_class.update(this.id, this.data_to_save())
await this.on_update()
}
this.error_message = ''
this.other_message = this.t['common.item_saved'].replace('ITEM', this.resource_class.item)
} catch (e) {
console.error(e)
if ( e.response && e.response.data && e.response.data.message )
this.error_message = e.response.data.message
else this.error_message = this.t['common.unknown_error']
}
}
is_json(string) {
try {
JSON.parse(string)
return true
} catch (e) {
return false
}
}
validate() {
let valid = true
for ( const field of this.definition.fields ) {
if ( (Array.isArray(field.required) ? field.required.includes(this.mode) : field.required) && (!(field.field in this.data) || !this.data[field.field]) ) {
field.error = this.t['common.field_required']
valid = false
} else if ( field.type === 'password' && this.data[field.field] !== this.data[field.field + '-confirm'] ) {
field.error = field.name + ' ' + this.t['common.confirmation_not_match']
valid = false
} else if ( field.type === 'json' && !this.is_json(this.data[field.field]) ) {
field.error = field.name + ' ' + this.t['common.invalid_json']
valid = false
} else {
field.error = ''
}
}
this.$forceUpdate()
return valid
}
back() {
return action_service.perform({
text: '',
type: 'resource',
resource: this.resource,
action: 'list',
})
}
do_nothing() {}
}