Files
homebox/frontend/pages/home/index.vue
Tonya 6cd9e2779f Use Tanstack table for Selectable Table, quick actions (#998)
* feat: implement example of data table

* feat: load item data into table

* chore: begin switching dialogs

* feat: implement old dialog for controlling headers and page size

* feat: get table into relatively usable state

* feat: enhance dropdown actions for multi-selection and CSV download

* feat: enhance table cell and dropdown button styles for better usability

* feat: json download for table

* feat: add expanded row component for item details in data table

* chore: add translation support

* feat: restore table on home page

* fix: oops need ids

* feat: move card view to use tanstack to allow for pagination

* feat: switch the items search to use ItemViewSelectable

* fix: update pagination handling and improve button click logic

* feat: improve selectable table

* feat: add indeterminate to checkbox

* feat: overhaul maintenance dialog to use new system and add maintenance options to table

* feat: add label ids and location id to item patch api

* feat: change location and labels in table view

* feat: add quick actions preference and enable toggle in table settings

* fix: lint

* fix: remove sized 1 pages

* fix: attempt to fix type error

* fix: various issues

* fix: remove

* fix: refactor item fetching logic to use useAsyncData for improved reactivity and improve use confirm

* fix: sort backend issues

* fix: enhance CSV export functionality by escaping fields to prevent formula injection

* fix: put aria sort on th not button

* chore: update api types
2025-09-24 02:37:38 +01:00

78 lines
2.8 KiB
Vue

<script setup lang="ts">
import { useI18n } from "vue-i18n";
import { statCardData } from "./statistics";
import { itemsTable } from "./table";
import { useLabelStore } from "~~/stores/labels";
import { useLocationStore } from "~~/stores/locations";
import BaseContainer from "@/components/Base/Container.vue";
import BaseCard from "@/components/Base/Card.vue";
import Subtitle from "~/components/global/Subtitle.vue";
import StatCard from "~/components/global/StatCard/StatCard.vue";
import ItemCard from "~/components/Item/Card.vue";
import LocationCard from "~/components/Location/Card.vue";
import LabelChip from "~/components/Label/Chip.vue";
import Table from "~/components/Item/View/Table.vue";
const { t } = useI18n();
definePageMeta({
middleware: ["auth"],
});
useHead({
title: "HomeBox | " + t("menu.home"),
});
const api = useUserApi();
const breakpoints = useBreakpoints();
const locationStore = useLocationStore();
const locations = computed(() => locationStore.parentLocations);
const labelsStore = useLabelStore();
const labels = computed(() => labelsStore.labels);
const itemTable = itemsTable(api);
const stats = statCardData(api);
</script>
<template>
<div>
<BaseContainer class="flex flex-col gap-4">
<section>
<Subtitle> {{ $t("home.quick_statistics") }} </Subtitle>
<div class="grid grid-cols-2 gap-2 md:grid-cols-4 md:gap-6">
<StatCard v-for="(stat, i) in stats" :key="i" :title="stat.label" :value="stat.value" :type="stat.type" />
</div>
</section>
<section>
<Subtitle> {{ $t("home.recently_added") }} </Subtitle>
<p v-if="itemTable.items.length === 0" class="ml-2 text-sm">{{ $t("items.no_results") }}</p>
<BaseCard v-else-if="breakpoints.lg">
<Table :items="itemTable.items" />
</BaseCard>
<div v-else class="grid grid-cols-1 gap-4 md:grid-cols-2">
<ItemCard v-for="item in itemTable.items" :key="item.id" :item="item" />
</div>
</section>
<section>
<Subtitle> {{ $t("home.storage_locations") }} </Subtitle>
<p v-if="locations.length === 0" class="ml-2 text-sm">{{ $t("locations.no_results") }}</p>
<div v-else class="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-3">
<LocationCard v-for="location in locations" :key="location.id" :location="location" />
</div>
</section>
<section>
<Subtitle> {{ $t("home.labels") }} </Subtitle>
<p v-if="labels.length === 0" class="ml-2 text-sm">{{ $t("labels.no_results") }}</p>
<div v-else class="flex flex-wrap gap-4">
<LabelChip v-for="label in labels" :key="label.id" size="lg" :label="label" class="shadow-md" />
</div>
</section>
</BaseContainer>
</div>
</template>