107 lines
3.0 KiB
Vue
107 lines
3.0 KiB
Vue
<template>
|
|
<div>
|
|
<h1 class="title">Calculator</h1>
|
|
|
|
<div class="box">
|
|
|
|
<div class="columns">
|
|
<app-text-field label="Input" v-model="input" class="column" :validation-error="inputErrors"></app-text-field>
|
|
<app-text-field label="Output Unit" v-model="outputUnit" class="column" :validation-error="outputUnitErrors"></app-text-field>
|
|
|
|
</div>
|
|
|
|
<div class="columns">
|
|
<div class="field column">
|
|
<label class="label">Ingredient</label>
|
|
<div class="control">
|
|
<app-autocomplete
|
|
:inputClass="{'is-success': ingredient !== null}"
|
|
ref="autocomplete"
|
|
v-model="ingredient_name"
|
|
:minLength="2"
|
|
valueAttribute="name"
|
|
labelAttribute="name"
|
|
placeholder=""
|
|
@optionSelected="searchItemSelected"
|
|
:onGetOptions="updateSearchItems"
|
|
>
|
|
</app-autocomplete>
|
|
</div>
|
|
</div>
|
|
|
|
<app-text-field label="Density" v-model="density" class="column" :disabled="ingredient !== null" :validation-error="densityErrors"></app-text-field>
|
|
|
|
</div>
|
|
|
|
<app-text-field label="Output" v-model="output" disabled></app-text-field>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
|
|
import { computed, ref, watch } from "vue";
|
|
import api from "../lib/Api";
|
|
import debounce from "lodash/debounce";
|
|
import { useLoadResource } from "../lib/useLoadResource";
|
|
|
|
const { loadResource } = useLoadResource();
|
|
|
|
const input = ref("");
|
|
const outputUnit = ref("");
|
|
const ingredient_name = ref("");
|
|
const ingredient = ref(null);
|
|
const density = ref("");
|
|
const output = ref("");
|
|
const errors = ref({});
|
|
|
|
const inputErrors = computed(() => getErrors("input"));
|
|
const outputUnitErrors = computed(() => getErrors("output_unit"));
|
|
const densityErrors = computed(() => getErrors("density"));
|
|
|
|
const updateOutput = debounce(function() {
|
|
if (input.value && input.value.length > 0) {
|
|
loadResource(api.getCalculate(input.value, outputUnit.value, ingredient.value ? ingredient.value.ingredient_id : null, density.value)
|
|
.then(data => {
|
|
output.value = data.output;
|
|
errors.value = data.errors;
|
|
})
|
|
);
|
|
}
|
|
}, 500);
|
|
|
|
watch(ingredient_name, function(val) {
|
|
if (ingredient.value && ingredient.value.name !== val) {
|
|
ingredient.value = null;
|
|
}
|
|
});
|
|
|
|
watch(
|
|
[input, outputUnit, density, ingredient],
|
|
() => updateOutput()
|
|
);
|
|
|
|
function updateSearchItems(text) {
|
|
return api.getSearchIngredients(text);
|
|
}
|
|
|
|
function searchItemSelected(ingredient) {
|
|
ingredient.value = ingredient || null;
|
|
ingredient_name.value = ingredient.name || null;
|
|
density.value = ingredient.density || null;
|
|
}
|
|
|
|
function getErrors(type) {
|
|
if (errors.value[type] && errors.value[type].length > 0) {
|
|
return errors.value[type].join(", ");
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
</style> |