Add total price indicator to labels and locations

This commit is contained in:
Jack Bailey 2023-11-24 11:39:22 +00:00
parent 8cc0f30291
commit 58cf7e816b
No known key found for this signature in database
3 changed files with 78 additions and 5 deletions

View file

@ -193,6 +193,7 @@ export interface LabelOut {
id: string; id: string;
name: string; name: string;
updatedAt: Date | string; updatedAt: Date | string;
totalPrice: number | undefined;
} }
export interface LabelSummary { export interface LabelSummary {
@ -217,6 +218,7 @@ export interface LocationOut {
name: string; name: string;
parent: LocationSummary; parent: LocationSummary;
updatedAt: Date | string; updatedAt: Date | string;
totalPrice: number | undefined;
} }
export interface LocationOutCount { export interface LocationOutCount {

View file

@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import Currency from "~~/components/global/Currency.vue";
definePageMeta({ definePageMeta({
middleware: ["auth"], middleware: ["auth"],
}); });
@ -84,6 +86,8 @@
return []; return [];
} }
label.value.totalPrice = resp.data.items.map(item => Number(item.purchasePrice)).reduce((a, b) => a + b, 0);
return resp.data.items; return resp.data.items;
}); });
</script> </script>
@ -111,8 +115,17 @@
</div> </div>
</div> </div>
<div> <div>
<h1 class="text-2xl pb-1"> <h1 class="text-2xl pb-1 flex items-center gap-3">
{{ label ? label.name : "" }} {{ label ? label.name : "" }}
<div
v-if="label && label.totalPrice"
class="text-xs bg-secondary text-secondary-content rounded-full px-2 py-1"
>
<div>
<Currency :amount="label.totalPrice" />
</div>
</div>
</h1> </h1>
<div class="flex gap-1 flex-wrap text-xs"> <div class="flex gap-1 flex-wrap text-xs">
<div> <div>

View file

@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { LocationSummary, LocationUpdate } from "~~/lib/api/types/data-contracts"; import { LocationSummary, LocationUpdate, TreeItem } from "~~/lib/api/types/data-contracts";
import { useLocationStore } from "~~/stores/locations"; import { useLocationStore } from "~~/stores/locations";
import Currency from "~~/components/global/Currency.vue";
definePageMeta({ definePageMeta({
middleware: ["auth"], middleware: ["auth"],
@ -89,8 +90,47 @@
return []; return [];
} }
const locationTreeResp = await api.locations.getTree();
if (locationTreeResp.error) {
toast.error("Failed to load items");
return [];
}
const fullLocationTree: TreeItem[] = locationTreeResp.data;
function flattenLocation(location: TreeItem): string[] {
return location.children.reduce((acc, child) => [...acc, ...flattenLocation(child)], [location.id]);
}
function findObjectById(locations: TreeItem[], targetId: string): TreeItem | undefined {
if (!locations || !Array.isArray(locations)) {
return undefined;
}
const target = locations.find(location => location.id === targetId);
if (target) return target;
for (let i = 0; i < locations.length; i++) {
const result = findObjectById(locations[i].children, targetId);
if (result) return result;
}
return undefined;
}
const locationTree: TreeItem | undefined = findObjectById(fullLocationTree, location.value.id);
if (!locationTree) {
toast.error("Failed to get tree for current location");
return [];
}
const allChildLocations = flattenLocation(locationTree);
const resp = await api.items.getAll({ const resp = await api.items.getAll({
locations: [location.value.id], locations: allChildLocations,
}); });
if (resp.error) { if (resp.error) {
@ -98,7 +138,16 @@
return []; return [];
} }
return resp.data.items; const locationItems = resp.data.items.filter(item => {
if (item.location && location.value) return item?.location.id === location?.value.id;
return false;
});
const totalPrice = resp.data.items.map(item => Number(item.purchasePrice)).reduce((a, b) => a + b, 0);
location.value.totalPrice = totalPrice;
return locationItems;
}); });
</script> </script>
@ -135,8 +184,17 @@
<li>{{ location.name }}</li> <li>{{ location.name }}</li>
</ul> </ul>
</div> </div>
<h1 class="text-2xl pb-1"> <h1 class="text-2xl pb-1 flex items-center gap-3">
{{ location ? location.name : "" }} {{ location ? location.name : "" }}
<div
v-if="location && location.totalPrice"
class="text-xs bg-secondary text-secondary-content rounded-full px-2 py-1"
>
<div>
<Currency :amount="location.totalPrice" />
</div>
</div>
</h1> </h1>
<div class="flex gap-1 flex-wrap text-xs"> <div class="flex gap-1 flex-wrap text-xs">
<div> <div>