forked from Wroclaw/WorkshopTasker
Refactor entry editor and add some new types to it
This commit is contained in:
parent
0151a6c713
commit
b12e91ed13
2 changed files with 92 additions and 14 deletions
|
@ -1,15 +1,25 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
|
||||||
type optionalMap<Optional> = Optional extends true ? undefined : string | number;
|
import FormClient from "~/components/formClient.vue";
|
||||||
// type typeMap<Type extends string = {};
|
|
||||||
|
|
||||||
export type fieldDefinition<Optional extends boolean = boolean> = {
|
type optionalMap<Optional, type> = Optional extends true ? undefined | type : type;
|
||||||
|
|
||||||
|
type typeMap = {
|
||||||
|
"text": string,
|
||||||
|
"password": string,
|
||||||
|
"number": number,
|
||||||
|
"boolean": boolean,
|
||||||
|
"none": undefined,
|
||||||
|
"client": `${bigint}`
|
||||||
|
};
|
||||||
|
|
||||||
|
export type fieldDefinition<Optional extends boolean = boolean, type extends keyof typeMap = keyof typeMap> = {
|
||||||
key: string,
|
key: string,
|
||||||
label?: string,
|
label?: string,
|
||||||
type: "text" | "password" | "number",
|
type: type,
|
||||||
optional?: Optional,
|
optional?: Optional,
|
||||||
value?: optionalMap<Optional>,
|
value?: optionalMap<Optional, typeMap[type]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
@ -22,7 +32,7 @@ const emit = defineEmits<{
|
||||||
(e: "updateSubModelValue", key: fieldDefinition["key"], value: fieldDefinition["value"]): void,
|
(e: "updateSubModelValue", key: fieldDefinition["key"], value: fieldDefinition["value"]): void,
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const modelValue = ref<{[key: string]: string | number | undefined}>({});
|
const modelValue = ref<{[key: string]: string | number | boolean | undefined}>({});
|
||||||
|
|
||||||
for (const i of props.fields) {
|
for (const i of props.fields) {
|
||||||
modelValue.value[i.key] = i.value;
|
modelValue.value[i.key] = i.value;
|
||||||
|
@ -39,12 +49,43 @@ emit("update:modelValue", modelValue.value);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<div v-for="i of fields" :key="i.key">
|
||||||
<VTextField
|
<VTextField
|
||||||
v-for="i of fields"
|
v-if="i.type == 'text'"
|
||||||
:key="i.key"
|
|
||||||
:model-value="modelValue[i.key]"
|
:model-value="modelValue[i.key]"
|
||||||
:label="i.label"
|
:label="i.label"
|
||||||
:type="i.type"
|
type="text"
|
||||||
@update:model-value="v => updateModel(i.key, v)"
|
@update:model-value="v => updateModel(i.key, v)"
|
||||||
/>
|
/>
|
||||||
|
<VTextField
|
||||||
|
v-if="i.type == 'password'"
|
||||||
|
:model-value="modelValue[i.key]"
|
||||||
|
:label="i.label"
|
||||||
|
type="password"
|
||||||
|
@update:model-value="v => updateModel(i.key, v)"
|
||||||
|
/>
|
||||||
|
<VTextField
|
||||||
|
v-if="i.type == 'number'"
|
||||||
|
:model-value="modelValue[i.key]"
|
||||||
|
:label="i.label"
|
||||||
|
type="number"
|
||||||
|
@update:model-value="v => updateModel(i.key, Number(v))"
|
||||||
|
/>
|
||||||
|
<v-checkbox
|
||||||
|
v-if="i.type == 'boolean'"
|
||||||
|
:label="i.label"
|
||||||
|
:model-value="modelValue[i.key]"
|
||||||
|
@update:model-value="v => updateModel(i.key, Boolean(v))"
|
||||||
|
/>
|
||||||
|
<p v-if="i.type == 'none'">
|
||||||
|
{{ i.label }}
|
||||||
|
</p>
|
||||||
|
<FormClient
|
||||||
|
v-if="i.type == 'client'"
|
||||||
|
:model-value="modelValue[i.key] as `${bigint}`"
|
||||||
|
:label="i.label"
|
||||||
|
:optional="i.optional"
|
||||||
|
@update:model-value="v => updateModel(i.key, v)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
37
components/formClient.vue
Normal file
37
components/formClient.vue
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useFetch, createError } from '#app';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
label?: string,
|
||||||
|
optional?: boolean,
|
||||||
|
modelValue?: `${bigint}`,
|
||||||
|
}>();
|
||||||
|
|
||||||
|
// eslint-disable-next-line func-call-spacing
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: "update:modelValue", value: `${bigint}`): void,
|
||||||
|
}>();
|
||||||
|
|
||||||
|
// FIXME: allow to search all clients instead of newest 50 (needs api call)
|
||||||
|
const clientsRequest = await useFetch("/api/clients");
|
||||||
|
if (clientsRequest.error.value) throw createError(clientsRequest.error.value?.data ?? "");
|
||||||
|
const clients = clientsRequest.data.value?.map((e) => {
|
||||||
|
return {
|
||||||
|
value: e.id,
|
||||||
|
title: e.name ?? `[null] (${e.id})`,
|
||||||
|
props: {
|
||||||
|
subtitle: e.address,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}) ?? [];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<v-autocomplete
|
||||||
|
:label="label ?? 'Client'"
|
||||||
|
:model-value="modelValue"
|
||||||
|
:items="clients"
|
||||||
|
:clearable="optional"
|
||||||
|
@update:model-value="v => emit('update:modelValue', v)"
|
||||||
|
/>
|
||||||
|
</template>
|
Loading…
Reference in a new issue