feat: items-editor (#5)

* format readme

* update logo

* format html

* add logo to docs

* repository for document and document tokens

* add attachments type and repository

* autogenerate types via scripts

* use autogenerated types

* attachment type updates

* add insured and quantity fields for items

* implement HasID interface for entities

* implement label updates for items

* implement service update method

* WIP item update client side actions

* check err on attachment

* finish types for basic items editor

* remove unused var

* house keeping
This commit is contained in:
Hayden 2022-09-12 14:47:27 -08:00 committed by GitHub
parent fbc364dcd2
commit 95ab14b866
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
125 changed files with 15626 additions and 1791 deletions

View file

@ -70,7 +70,7 @@
<BaseContainer>
<h2 class="mt-1 text-4xl font-bold tracking-tight text-neutral-content sm:text-5xl lg:text-6xl flex">
HomeB
<AppLogo class="w-12 -mb-4" style="padding-left: 3px; padding-right: 2px" />
<AppLogo class="w-12 -mb-4" />
x
</h2>
<div class="ml-1 mt-2 text-lg text-neutral-content/75 space-x-2">

View file

@ -1,123 +1,47 @@
<template>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 596.5055138004384 585.369487986598">
<g
stroke-linecap="round"
transform="translate(437.568672588907 210.93877417794465) rotate(332.3235338946895 66.970006481548 27.559467997664797)"
>
<path
d="M-0.3 -0.89 L131.27 -1.27 L131.05 52.32 L-2.89 53.3"
stroke="none"
stroke-width="0"
fill="#15aabf"
></path>
<path
d="M1.61 2.92 C34.39 0.43, 67.49 -3.76, 136.43 -0.16 M-1.81 1.81 C54.26 1.13, 105.28 -0.86, 133.28 -0.04 M132.66 3.06 C133.92 12.97, 132.16 31.97, 132.92 51.2 M134.28 1.16 C131.72 11.69, 133.56 23.47, 134.52 54.65 M133.93 53.09 C103.49 59.22, 80.28 58.51, -1.19 52.09 M133.03 54.88 C92.08 50.88, 53.71 52.46, -0.4 54.88 M-3.64 53.12 C-1.65 33.33, 3.49 15.58, -2.23 -1.93 M-1.08 54.38 C0.63 44.74, -0.42 33.82, 0.29 1.34"
stroke="#000"
stroke-width="2"
fill="none"
></path>
</g>
<g stroke-linecap="round">
<g transform="translate(308.4481755172761 281.2115533662909) rotate(0 1.1385609918289674 145.9953857867422)">
<path
d="M-1.01 -2.17 C-1.07 46.71, 0.3 244.44, -0.46 294.16 M3.63 2.83 C3.44 50.71, -0.72 241.22, -1.36 289.41"
stroke="#000000"
stroke-width="2"
fill="none"
></path>
</g>
</g>
<g stroke-linecap="round">
<g transform="translate(308.16925883018916 284.66360015581995) rotate(0 135.1525798049602 -68.20042785962323)">
<path
d="M2.47 0.47 C46.8 -21.36, 220.33 -110.19, 264.96 -133.2 M0.37 -1.74 C45.62 -24.11, 225.01 -114.58, 269.93 -136.88"
stroke="#000000"
stroke-width="2"
fill="none"
></path>
</g>
</g>
<g stroke-linecap="round">
<g transform="translate(311.39372316987726 570.9674003164946) rotate(0 136.24116036890297 -67.43777376368234)">
<path
d="M-2.63 2.46 C20.4 -9.48, 94.34 -47.87, 140.63 -71.17 C186.92 -94.47, 252.17 -126.49, 275.11 -137.33 M1.14 1.33 C23.81 -10.35, 94.55 -46.04, 139.83 -68.58 C185.12 -91.11, 249.48 -121.76, 272.86 -133.89"
stroke="#000000"
stroke-width="2"
fill="none"
></path>
</g>
</g>
<g stroke-linecap="round">
<g transform="translate(580.6092831051336 150.72201134532952) rotate(0 1.5678417062894852 142.75141008423634)">
<path
d="M2.66 -1.91 C3.6 45.58, 2.41 239.01, 2.99 287.41 M0.67 3.23 C1.39 51.03, -0.51 235.96, 0.31 282.74"
stroke="#000000"
stroke-width="2"
fill="none"
></path>
</g>
</g>
<g stroke-linecap="round">
<g transform="translate(306.6976102947664 283.14653391715) rotate(0 -140.18354779216435 -59.60806644015338)">
<path
d="M-0.81 0.62 C-48.48 -18.36, -235.46 -96.23, -283.34 -115.75 M3.94 -1.52 C-44.13 -21.12, -236.56 -99.84, -284.31 -119.83"
stroke="#000000"
stroke-width="2"
fill="none"
></path>
</g>
</g>
<g stroke-linecap="round">
<g transform="translate(304.3414324224632 572.5226612839633) rotate(0 -144.27019052747903 -64.7761163684645)">
<path
d="M2.34 1.71 C-46 -19.52, -242.75 -105.04, -290.88 -126.78 M0.17 0.18 C-47.25 -21.98, -237.9 -110.2, -285.78 -131.27"
stroke="#000000"
stroke-width="2"
fill="none"
></path>
</g>
</g>
<g stroke-linecap="round">
<g
transform="translate(15.275892138818847 448.50738095516135) rotate(0 -0.49579063445983707 -143.71703352554232)"
>
<path
d="M-2.4 0.97 C-2.94 -47.38, -0.78 -240.15, -0.9 -288.41 M1.49 -0.97 C0.55 -49.09, -0.95 -237.81, -2.03 -285.33"
stroke="#000000"
stroke-width="2"
fill="none"
></path>
</g>
</g>
<g stroke-linecap="round">
<g transform="translate(10.301143858432795 164.72182108536072) rotate(0 142.35890827057267 -76.26873721417542)">
<path
d="M2.04 -1.02 C49.94 -26.43, 238.14 -126.5, 285.02 -151.52 M-0.3 -4.04 C47.43 -29.16, 234.44 -124.45, 282.68 -148.52"
stroke="#000000"
stroke-width="2"
fill="none"
></path>
</g>
</g>
<g stroke-linecap="round">
<g transform="translate(291.46813332015165 14.258444139957646) rotate(0 143.3244001532809 66.53622476241344)">
<path
d="M-0.18 -1.16 C46.98 21.36, 236.83 111.22, 284.98 134.14 M-3.72 -4.26 C44.15 18.77, 241.76 114.69, 290.37 137.33"
stroke="#000000"
stroke-width="2"
fill="none"
></path>
</g>
</g>
<g stroke-linecap="round">
<g transform="translate(175.60844139934756 81.23280016017816) rotate(0 131.7777041676277 66.73388742398038)">
<path
d="M-1.87 -0.8 C42.4 22.26, 220.78 113.99, 265.42 137.17 M2.32 -3.7 C46.4 18.63, 220.35 109.95, 264.21 132.92"
stroke="#000000"
stroke-width="2"
fill="none"
></path>
</g>
</g>
<svg
viewBox="0 0 10817 9730"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
style="
fill-rule: evenodd;
clip-rule: evenodd;
stroke-linecap: round;
stroke-linejoin: round;
stroke-miterlimit: 5.42683;
"
>
<path
d="M9310.16 2560.9c245.302 249.894 419.711 539.916 565.373 845.231 47.039 98.872 36.229 215.514-28.2 304.05-64.391 88.536-172.099 134.676-280.631 120.28 0 .053-.039.053-.039.053"
style="fill: gray; stroke: #000; stroke-width: 206.41px"
/>
<path
d="M5401.56 487.044c-127.958 6.227-254.855 40.77-370.992 103.628-765.271 414.225-2397.45 1297.68-3193.03 1728.32-137.966 74.669-250.327 183.605-328.791 313.046l3963.09 2122.43s-249.048 416.428-470.593 786.926c-189.24 316.445-592.833 429.831-919.198 258.219l-2699.36-1419.32v2215.59c0 226.273 128.751 435.33 337.755 548.466 764.649 413.885 2620.97 1418.66 3385.59 1832.51 209.018 113.137 466.496 113.137 675.514 0 764.623-413.857 2620.94-1418.63 3385.59-1832.51 208.989-113.136 337.743-322.193 337.743-548.466v-3513.48c0-318.684-174.59-611.722-454.853-763.409-795.543-430.632-2427.75-1314.09-3193.02-1728.32-141.693-76.684-299.364-111.227-455.442-103.628"
style="fill: #dadada; stroke: #000; stroke-width: 206.42px"
/>
<path
d="M5471.83 4754.46V504.71c-127.958 6.226-325.127 23.1-441.264 85.958-765.271 414.225-2397.45 1297.68-3193.03 1728.32-137.966 74.669-250.327 183.605-328.791 313.046l3963.09 2122.43Z"
style="fill: gray; stroke: #000; stroke-width: 206.42px"
/>
<path
d="m1459.34 2725.96-373.791 715.667c-177.166 339.292-46.417 758 292.375 936.167l4.75 2.5m0 0 2699.37 1419.29c326.374 171.625 729.916 58.25 919.165-258.208 221.542-370.5 470.583-786.917 470.583-786.917l-3963.04-2122.42-2.167 3.458-47.25 90.458"
style="fill: #dadada; stroke: #000; stroke-width: 206.42px"
/>
<path d="M5443.74 520.879v4149.79" style="fill: none; stroke: #000; stroke-width: 153.5px" />
<path
d="M8951.41 4102.72c0-41.65-22.221-80.136-58.291-100.961-36.069-20.825-80.51-20.825-116.58 0l-2439.92 1408.69c-36.07 20.825-58.29 59.311-58.29 100.961V7058c0 41.65 22.22 80.136 58.29 100.961 36.07 20.825 80.51 20.825 116.58 0l2439.92-1408.69c36.07-20.825 58.291-59.312 58.291-100.962v-1546.59Z"
style="fill: #567f67"
/>
<path
d="M8951.41 4102.72c0-41.65-22.221-80.136-58.291-100.961-36.069-20.825-80.51-20.825-116.58 0l-2439.92 1408.69c-36.07 20.825-58.29 59.311-58.29 100.961V7058c0 41.65 22.22 80.136 58.29 100.961 36.07 20.825 80.51 20.825 116.58 0l2439.92-1408.69c36.07-20.825 58.291-59.312 58.291-100.962v-1546.59ZM6463.98 5551.29v1387.06l2301.77-1328.92V4222.37L6463.98 5551.29Z"
/>
<path
d="M5443.76 9041.74v-4278.4"
style="fill: none; stroke: #000; stroke-width: 206.44px; stroke-linejoin: miter"
/>
<path
d="m5471.79 4773.86 3829.35-2188.22"
style="fill: none; stroke: #000; stroke-width: 206.43px; stroke-linejoin: miter"
/>
</svg>
</template>

View file

@ -15,7 +15,7 @@
{{ dKey }}
</dt>
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
<slot :name="dKey" v-bind="{ key: dKey, value: dValue }">
<slot :name="rmSpace(dKey)" v-bind="{ key: dKey, value: dValue }">
{{ dValue }}
</slot>
</dd>
@ -28,8 +28,13 @@
<script setup lang="ts">
type StringLike = string | number | boolean;
function rmSpace(str: string) {
return str.replace(" ", "");
}
defineProps({
details: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type: Object as () => Record<string, StringLike | any>,
required: true,
},

View file

@ -0,0 +1,35 @@
<template>
<div v-if="!inline" class="form-control w-full">
<label class="label cursor-pointer">
<span class="label-text"> {{ label }}</span>
<input v-model="value" type="checkbox" class="checkbox" />
</label>
</div>
<div v-else class="label cursor-pointer sm:grid sm:grid-cols-4 sm:items-start sm:gap-4">
<label>
<span class="label-text">
{{ label }}
</span>
</label>
<input v-model="value" type="checkbox" class="checkbox" />
</div>
</template>
<script setup lang="ts">
const props = defineProps({
modelValue: {
type: Boolean,
default: false,
},
inline: {
type: Boolean,
default: false,
},
label: {
type: String,
default: "",
},
});
const value = useVModel(props, "modelValue");
</script>

View file

@ -52,9 +52,14 @@
const selected = useVModel(props, "modelValue", emit);
const dateText = computed(() => {
if (!validDate(selected.value)) {
return "";
}
if (selected.value) {
return selected.value.toLocaleDateString();
}
return "";
});
@ -91,9 +96,7 @@
});
function select(e: MouseEvent, day: Date) {
console.log(day);
selected.value = day;
console.log(selected.value);
// @ts-ignore - this is a vue3 bug
e.target.blur();
resetTime();

View file

@ -17,7 +17,7 @@
v-for="(obj, idx) in items"
:key="idx"
:class="{
bordered: selectedIndexes[idx],
bordered: selected[idx],
}"
>
<button type="button" @click="toggle(idx)">
@ -37,10 +37,12 @@
default: "",
},
modelValue: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type: Array as () => any[],
default: null,
},
items: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type: Array as () => any[],
required: true,
},
@ -54,28 +56,23 @@
},
});
const selectedIndexes = ref<Record<number, boolean>>({});
const value = useVModel(props, "modelValue", emit);
const selected = computed<Record<number, boolean>>(() => {
const obj: Record<number, boolean> = {};
value.value.forEach(itm => {
const idx = props.items.findIndex(item => item[props.name] === itm.name);
obj[idx] = true;
});
return obj;
});
function toggle(index: number) {
selectedIndexes.value[index] = !selectedIndexes.value[index];
const item = props.items[index];
if (selectedIndexes.value[index]) {
value.value = [...value.value, item];
if (selected.value[index]) {
value.value = value.value.filter(itm => itm.name !== item.name);
} else {
value.value = value.value.filter(itm => itm !== item);
value.value = [...value.value, item];
}
}
watchOnce(
() => props.items,
() => {
if (props.selectFirst && props.items.length > 0) {
value.value = props.items[0];
}
}
);
const value = useVModel(props, "modelValue", emit);
</script>

View file

@ -3,9 +3,9 @@
<label class="label">
<span class="label-text">{{ label }}</span>
</label>
<select v-model="value" class="select select-bordered">
<select v-model="selectedIdx" class="select select-bordered">
<option disabled selected>Pick one</option>
<option v-for="obj in items" :key="name != '' ? obj[name] : obj" :value="obj">
<option v-for="(obj, idx) in items" :key="name != '' ? obj[name] : obj" :value="idx">
{{ name != "" ? obj[name] : obj }}
</option>
</select>
@ -24,10 +24,12 @@
default: "",
},
modelValue: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type: Object as any,
default: null,
},
items: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type: Array as () => any[],
required: true,
},
@ -45,10 +47,16 @@
() => props.items,
() => {
if (props.selectFirst && props.items.length > 0) {
value.value = props.items[0];
selectedIdx.value = 0;
}
}
);
const value = useVModel(props, "modelValue", emit);
const selectedIdx = ref(0);
watch(
() => selectedIdx.value,
() => {
emit("update:modelValue", props.items[selectedIdx.value]);
}
);
</script>

View file

@ -1,9 +1,9 @@
<template>
<div v-if="!inline" class="form-control">
<div v-if="!inline" class="form-control w-full">
<label class="label">
<span class="label-text">{{ label }}</span>
</label>
<textarea v-model="value" class="textarea textarea-bordered h-24" :placeholder="placeholder" />
<textarea ref="el" v-model="value" class="textarea w-full textarea-bordered h-28" :placeholder="placeholder" />
<label v-if="limit" class="label">
<span class="label-text-alt"></span>
<span class="label-text-alt"> {{ valueLen }}/{{ limit }}</span>
@ -14,10 +14,12 @@
<span class="label-text">{{ label }}</span>
</label>
<textarea
ref="el"
v-model="value"
class="textarea textarea-bordered col-span-3 mt-3 h-24"
class="textarea textarea-bordered w-full col-span-3 mt-3 h-28"
auto-grow
:placeholder="placeholder"
auto-height
/>
</div>
</template>
@ -51,6 +53,19 @@
},
});
const el = ref();
function setHeight() {
el.value.style.height = "auto";
el.value.style.height = el.value.scrollHeight + 5 + "px";
}
onUpdated(() => {
console.log("updated");
if (props.inline) {
setHeight();
}
});
const value = useVModel(props, "modelValue", emit);
const valueLen = computed(() => {
return value.value ? value.value.length : 0;

View file

@ -22,11 +22,11 @@
</template>
<script setup lang="ts">
import { Item } from "~~/lib/api/classes/items";
import { ItemOut, ItemSummary } from "~~/lib/api/types/data-contracts";
const props = defineProps({
item: {
type: Object as () => Item,
type: Object as () => ItemOut | ItemSummary,
required: true,
},
});

View file

@ -26,7 +26,8 @@
</template>
<script setup lang="ts">
import { type Location } from "~~/lib/api/classes/locations";
import { ItemCreate, LocationOut } from "~~/lib/api/types/data-contracts";
const props = defineProps({
modelValue: {
type: Boolean,
@ -40,7 +41,7 @@
const loading = ref(false);
const focused = ref(false);
const form = reactive({
location: {} as Location,
location: {} as LocationOut,
name: "",
description: "",
color: "", // Future!
@ -80,7 +81,7 @@
return;
}
const out = {
const out: ItemCreate = {
name: form.name,
description: form.description,
locationId: form.location.id as string,

View file

@ -1,10 +1,10 @@
<script setup lang="ts">
import { Label } from "~~/lib/api/classes/labels";
import { LabelOut, LabelSummary } from "~~/lib/api/types/data-contracts";
export type sizes = "sm" | "md" | "lg";
defineProps({
label: {
type: Object as () => Label,
type: Object as () => LabelOut | LabelSummary,
required: true,
},
size: {

View file

@ -26,11 +26,11 @@
</template>
<script lang="ts" setup>
import { Location } from "~~/lib/api/classes/locations";
import { LocationCount } from "~~/lib/api/types/data-contracts";
defineProps({
location: {
type: Object as () => Location,
type: Object as () => LocationCount,
required: true,
},
dense: {

View file

@ -0,0 +1,52 @@
<template>
{{ value }}
</template>
<script setup lang="ts">
enum DateTimeFormat {
RELATIVE = "relative",
LONG = "long",
SHORT = "short",
}
const value = computed(() => {
if (!props.date) {
return "";
}
const dt = typeof props.date === "string" ? new Date(props.date) : props.date;
if (!dt) {
return "";
}
if (nullDate(dt)) {
return "";
}
switch (props.format) {
case DateTimeFormat.RELATIVE:
return useTimeAgo(dt).value + useDateFormat(dt, " (MM-DD-YYYY)").value;
case DateTimeFormat.LONG:
return useDateFormat(dt, "YYYY-MM-DD (dddd)").value;
case DateTimeFormat.SHORT:
return useDateFormat(dt, "YYYY-MM-DD").value;
default:
return "";
}
});
function nullDate(dt: Date) {
return dt.getFullYear() === 1;
}
const props = defineProps({
date: {
type: [Date, String],
required: true,
},
format: {
type: String as () => DateTimeFormat,
default: "relative",
},
});
</script>