131 lines
3.1 KiB
Vue
131 lines
3.1 KiB
Vue
<template>
|
|
<div class="space-y-4">
|
|
<div
|
|
v-for="field in fields"
|
|
:key="field.fieldname"
|
|
v-show="field.condition ? field.condition() : true"
|
|
>
|
|
<div class="flex space-x-4" v-if="Array.isArray(field)">
|
|
<FormControl
|
|
v-bind="getBindProps(subfield)"
|
|
:key="subfield.fieldname"
|
|
class="w-full"
|
|
v-for="subfield in field"
|
|
/>
|
|
</div>
|
|
<FormControl v-else v-bind="getBindProps(field)" />
|
|
<ErrorMessage
|
|
class="mt-1"
|
|
v-if="requiredFieldNotSet.includes(field)"
|
|
error="This field is required"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
// https://github.com/eggert/tz/blob/main/backward add more if required.
|
|
const TZ_BACKWARD_COMPATBILITY_MAP = {
|
|
'Asia/Calcutta': 'Asia/Kolkata'
|
|
};
|
|
|
|
export default {
|
|
name: 'Form',
|
|
props: ['fields', 'modelValue'],
|
|
emits: ['update:modelValue'],
|
|
data() {
|
|
return {
|
|
requiredFieldNotSet: [],
|
|
guessedTimezone: ''
|
|
};
|
|
},
|
|
mounted() {
|
|
this.guessedTimezone = this.guessTimezone();
|
|
},
|
|
watch: {
|
|
fields: {
|
|
handler(new_fields) {
|
|
let timezoneFields = new_fields.filter(
|
|
f => f.fieldtype === 'Select' && f.fieldname.endsWith('_tz')
|
|
);
|
|
for (let field of timezoneFields) {
|
|
if (!field.options) {
|
|
field.options = [];
|
|
}
|
|
if (
|
|
this.guessedTimezone &&
|
|
field.options.includes(this.guessedTimezone)
|
|
) {
|
|
this.onChange(this.guessedTimezone, field);
|
|
}
|
|
}
|
|
},
|
|
deep: true
|
|
}
|
|
},
|
|
methods: {
|
|
onChange(value, field) {
|
|
this.checkRequired(field, value);
|
|
this.updateValue(field.fieldname, value);
|
|
},
|
|
updateValue(fieldname, value) {
|
|
let values = Object.assign({}, this.modelValue, {
|
|
[fieldname]: value
|
|
});
|
|
this.$emit('update:modelValue', values);
|
|
},
|
|
checkRequired(field, value) {
|
|
if (field.required) {
|
|
if (!value) {
|
|
this.requiredFieldNotSet.push(field);
|
|
return false;
|
|
} else {
|
|
this.requiredFieldNotSet = this.requiredFieldNotSet.filter(
|
|
f => f !== field
|
|
);
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
getBindProps(field) {
|
|
return {
|
|
label: field.label || field.fieldname,
|
|
type: this.getInputType(field),
|
|
options: field.options,
|
|
name: field.fieldname,
|
|
modelValue: this.modelValue[field.fieldname],
|
|
disabled: field.disabled,
|
|
required: field.required || false,
|
|
rows: field.rows,
|
|
placeholder: field.placeholder,
|
|
'onUpdate:modelValue': value => this.onChange(value, field),
|
|
onBlur: e => this.checkRequired(field, e)
|
|
};
|
|
},
|
|
getInputType(field) {
|
|
return {
|
|
Data: 'text',
|
|
Int: 'number',
|
|
Select: 'select',
|
|
Check: 'checkbox',
|
|
Password: 'password',
|
|
Text: 'textarea',
|
|
Date: 'date'
|
|
}[field.fieldtype || 'Data'];
|
|
},
|
|
guessTimezone() {
|
|
try {
|
|
let tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
if (TZ_BACKWARD_COMPATBILITY_MAP[tz]) {
|
|
return TZ_BACKWARD_COMPATBILITY_MAP[tz];
|
|
}
|
|
return tz;
|
|
} catch (e) {
|
|
console.error("Couldn't guess timezone", e);
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
</script>
|