update case index page segment index and show page

This commit is contained in:
Simon Pocrnjič
2025-12-14 20:57:39 +01:00
parent a6ec92ec6b
commit 80948d2944
14 changed files with 1141 additions and 626 deletions
+150 -21
View File
@@ -2,44 +2,87 @@
import AppLayout from "@/Layouts/AppLayout.vue";
import SectionTitle from "@/Components/SectionTitle.vue";
import { Link, router } from "@inertiajs/vue3";
import { ref } from "vue";
import { computed, ref } from "vue";
import DataTable from "@/Components/DataTable/DataTableNew2.vue";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { faFolderOpen } from "@fortawesome/free-solid-svg-icons";
import Pagination from "@/Components/Pagination.vue";
import AppCard from "@/Components/app/ui/card/AppCard.vue";
import { FolderOpenIcon } from "lucide-vue-next";
import { Filter, FolderOpenIcon } from "lucide-vue-next";
import CardTitle from "@/Components/ui/card/CardTitle.vue";
import { fmtCurrency, fmtDateDMY } from "@/Utilities/functions";
import { Button } from "@/Components/ui/button";
import AppPopover from "@/Components/app/ui/AppPopover.vue";
import InputLabel from "@/Components/InputLabel.vue";
import { Input } from "@/Components/ui/input";
import DateRangePicker from "@/Components/DateRangePicker.vue";
import AppMultiSelect from "@/Components/app/ui/AppMultiSelect.vue";
const props = defineProps({
client_cases: Object,
filters: Object,
clients: {
type: Array,
default: () => [],
},
});
// Initial search for DataTable toolbar
const search = ref(props.filters?.search || "");
const dateRange = ref({
start: props.filters?.from || null,
end: props.filters?.to || null,
});
const selectedClients = ref(
Array.isArray(props.filters?.clients)
? props.filters.clients.map((value) => String(value))
: []
);
const filterPopoverOpen = ref(false);
// Format helpers
const fmtCurrency = (v) => {
const n = Number(v ?? 0);
try {
return new Intl.NumberFormat("sl-SI", { style: "currency", currency: "EUR" }).format(
n
);
} catch (e) {
return `${n.toFixed(2)}`;
const appliedFilterCount = computed(() => {
let count = 0;
if (search.value?.trim()) count += 1;
if (dateRange.value?.start || dateRange.value?.end) count += 1;
if (selectedClients.value.length) count += 1;
return count;
});
function applyFilters() {
filterPopoverOpen.value = false;
const params = {};
const searchParams = new URLSearchParams(window.location.search);
const currentPerPage = searchParams.get("perPage");
if (currentPerPage) {
params.perPage = currentPerPage;
}
if (search.value && search.value.trim() !== "") {
params.search = search.value.trim();
}
if (dateRange.value?.start) {
params.from = dateRange.value.start;
}
if (dateRange.value?.end) {
params.to = dateRange.value.end;
}
if (selectedClients.value.length > 0) {
params.clients = selectedClients.value.join(",");
}
};
const fmtDateDMY = (v) => {
if (!v) return "-";
const d = new Date(v);
if (isNaN(d)) return "-";
const dd = String(d.getDate()).padStart(2, "0");
const mm = String(d.getMonth() + 1).padStart(2, "0");
const yyyy = d.getFullYear();
return `${dd}.${mm}.${yyyy}`;
};
router.get(route("clientCase"), params, {
preserveState: true,
replace: true,
preserveScroll: true,
});
}
function clearFilters() {
dateRange.value = { start: null, end: null };
selectedClients.value = [];
search.value = "";
applyFilters();
}
</script>
<template>
<AppLayout title="Client cases">
@@ -80,13 +123,99 @@ const fmtDateDMY = (v) => {
},
]"
:data="client_cases.data || []"
:meta="client_cases"
route-name="clientCase"
page-param-name="clientCasesPage"
per-page-param-name="perPage"
:page-size="client_cases.per_page"
:page-size-options="[10, 15, 25, 50, 100]"
:show-pagination="false"
:show-toolbar="true"
:hoverable="true"
row-key="uuid"
empty-text="Ni najdenih primerov."
>
<template #toolbar-filters>
<AppPopover
v-model:open="filterPopoverOpen"
align="start"
content-class="w-[400px]"
>
<template #trigger>
<Button variant="outline" size="sm" class="gap-2">
<Filter class="h-4 w-4" />
Filtri
<span
v-if="appliedFilterCount > 0"
class="ml-1 rounded-full bg-primary px-2 py-0.5 text-xs text-primary-foreground"
>
{{ appliedFilterCount }}
</span>
</Button>
</template>
<div class="space-y-4">
<div class="space-y-2">
<h4 class="font-medium text-sm">Filtri primerov</h4>
<p class="text-sm text-muted-foreground">
Izberite parametre za zožanje prikaza primerov.
</p>
</div>
<div class="space-y-3">
<div class="space-y-1.5">
<InputLabel>Iskanje</InputLabel>
<Input
v-model="search"
type="text"
placeholder="Išči po imenu, davčni številki ..."
/>
</div>
<div class="space-y-1.5">
<InputLabel>Datumski obseg (ustvarjeno)</InputLabel>
<DateRangePicker
v-model="dateRange"
format="dd.MM.yyyy"
placeholder="Izberi datume"
/>
</div>
<div class="space-y-1.5">
<InputLabel>Stranke</InputLabel>
<AppMultiSelect
v-model="selectedClients"
:items="
(props.clients || []).map((client) => ({
value: String(client.id),
label: client.name,
}))
"
placeholder="Vse stranke"
search-placeholder="Išči stranko..."
empty-text="Ni strank"
chip-variant="secondary"
/>
</div>
<div class="flex justify-end gap-2 pt-2 border-t">
<Button
type="button"
variant="outline"
size="sm"
:disabled="
!dateRange?.start &&
!dateRange?.end &&
selectedClients.length === 0 &&
search === ''
"
@click="clearFilters"
>
Počisti
</Button>
<Button type="button" size="sm" @click="applyFilters">
Uporabi
</Button>
</div>
</div>
</div>
</AppPopover>
</template>
<template #cell-nu="{ row }">
{{ row.person?.nu || "-" }}
</template>
@@ -364,7 +364,7 @@ const copyToClipboard = async (text) => {
</span>
</Button>
</PopoverTrigger>
<PopoverContent class="w-[400px]" align="start">
<PopoverContent class="w-100" align="start">
<div class="space-y-4">
<div class="space-y-2">
<h4 class="font-medium text-sm">Filtri aktivnosti</h4>