WorkshopTasker/pages/client/[id].vue

209 lines
6.2 KiB
Vue

<script setup lang="ts">
/* global $fetch */
import { useRoute, useFetch, createError } from "nuxt/app";
import { ref, type Ref } from "vue";
import { VBtn, VForm } from "vuetify/components";
import PagedList from "~/components/pagedList.vue";
import Snowflake from "~/utils/snowflake";
import { client as clientType, order, orderSummary } from "~/utils/types/database";
import OrderView from "~/components/orderView.vue";
import EntryEditor, { type fieldDefinition } from "~/components/entryEditor.vue";
const route = useRoute();
const id = route.params.id;
const clientRequest = await useFetch(`/api/clients/${id}`);
if (clientRequest.error.value) throw createError(clientRequest.error.value?.data ?? "");
const client = clientRequest.data as Ref<clientType>;
const clientOrdersRequest = await useFetch(`/api/clients/${id}/orders`);
if (clientOrdersRequest.error.value) throw createError(clientOrdersRequest.error.value?.data ?? "");
const clientOrders = clientOrdersRequest.data as Ref<Array<orderSummary>>;
const orders = ref<Map<string, {
loading: boolean,
value?: order
}>>(new Map());
for (const i of clientOrders.value)
orders.value.set(i.id, { loading: false });
async function loadOrder(id: string) {
const entry = orders.value.get(id);
if (!entry) throw createError(`excepted order entry for ${id}`);
entry.loading = true;
// @ts-expect-error
entry.value = await $fetch(`/api/orders/${id}` as "/api/order/:id", {
method: "GET",
});
entry.loading = false;
}
let lastPagedListVModel: Array<string> = [];
function updatePagedListVModel(element: Array<string>) {
const justOpened = element.filter(e => !lastPagedListVModel.includes(e));
for (const i of justOpened) loadOrder(i);
lastPagedListVModel = element;
}
const editMode = ref<boolean>(route.query?.edit === "1");
function editorFields(): Array<fieldDefinition> {
return [
{ key: "name", type: "text", label: "Name", value: client.value.name ?? undefined },
{ key: "address", type: "text", label: "Address", value: client.value.address ?? undefined },
{ key: "phone", type: "text", label: "Phone", value: client.value.phone ?? undefined },
{ key: "email", type: "text", label: "E-mail", value: client.value.email ?? undefined },
];
}
const submitting = ref<boolean>(false);
// const updateForm = ref<VForm | null>(null);
const formButton = ref<VBtn | null>(null);
const formData = ref<any>({});
function normalizeForm() {
for (const i in formData.value)
formData.value[i] = formData.value[i] === "" ? null : formData.value[i];
}
async function handleSubmit() {
submitting.value = true;
normalizeForm();
try {
const result = await $fetch(
`/api/clients/${client.value.id}` as "/api/clients/:id", {
method: "PATCH",
body: formData.value,
},
);
client.value = result;
} catch (e) {
console.error(e);
submitting.value = false;
return;
}
submitting.value = false;
editMode.value = false;
}
function getCreationDate() {
const date = new Date(Number(new Snowflake(BigInt(client.value.id)).timestamp.toString())).toLocaleDateString();
return date;
}
</script>
<template>
<VDialog
v-model="editMode"
:persistent="submitting"
:activator="formButton as unknown as (Element | null) ?? undefined"
width="auto"
>
<VCard width="400px" :loading="submitting">
<VCardTitle>
Edit client
</VCardTitle>
<VForm
ref="updateForm"
:disabled="submitting"
class="px-4"
>
<EntryEditor
:fields="editorFields()"
@update-sub-model-value="(k, v) => { formData[k] = v; }"
/>
</VForm>
<VCardActions>
<VBtn
color="primary"
@click="handleSubmit"
>
Submit
</VBtn>
</VCardActions>
</VCard>
</VDialog>
<VRow>
<VCol cols="12">
<div
class="text-h4"
:class="client.name === null ? ['font-italic'] : []"
>
{{ client.name ?? "[none]" }}
</div>
</VCol>
</VRow>
<VRow>
<VCol md="4" cols="12">
<VCard class="mx-auto">
<VList>
<VListItem
v-if="client.address"
prepend-icon="mdi-map-marker"
>
<VListItemTitle class="text-wrap">
{{ client.address }}
</VListItemTitle>
</VListItem>
<VListItem
v-if="client.phone"
prepend-icon="mdi-phone"
>
<VListItemTitle class="text-wrap">
{{ client.phone }}
</VListItemTitle>
</VListItem>
<VListItem
v-if="client.email"
prepend-icon="mdi-email"
>
<VListItemTitle class="text-wrap">
{{ client.email }}
</VListItemTitle>
</VListItem>
</VList>
<template #actions>
<VBtn
ref="formButton"
>
edit
</VBtn>
</template>
</VCard>
<span class="font-italic text-caption">Created {{ getCreationDate() }}</span>
</VCol>
<VCol cols="12" md="8">
<PagedList
:records="clientOrders"
record-key="id"
record-value="id"
@update:model-value="updatePagedListVModel"
>
<template #title="i">
<VRow>
<VCol>{{ new Date(Number(new Snowflake(BigInt(((i.record) as orderSummary).id)).timestamp)).toLocaleDateString() }}</VCol>
<VCol>{{ ((i.record) as orderSummary).value }} PLN</VCol>
<VCol>
{{ ((i.record) as orderSummary).imported_products_count }}
products,
{{ ((i.record) as orderSummary).work_count }}
works
</VCol>
</VRow>
</template>
<template #text="i">
<VProgressLinear
:height="orders.get((i.record as orderSummary).id)?.loading ?? true ? undefined : 0"
absolute
:progress="orders.get((i.record as orderSummary).id)?.loading ?? true"
:indeterminate="orders.get((i.record as orderSummary).id)?.loading ?? true"
/>
<OrderView :order="(orders.get((i.record as orderSummary).id)?.value as order | undefined)" />
</template>
</PagedList>
</VCol>
</VRow>
</template>