Package and individual mail sender, new report, and other changes
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { reactive, ref, computed, onMounted } from "vue";
|
||||
import { reactive, ref, computed, onMounted, watch } from "vue";
|
||||
import { Link, router, usePage } from "@inertiajs/vue3";
|
||||
import axios from "axios";
|
||||
import AppLayout from "@/Layouts/AppLayout.vue";
|
||||
@@ -138,11 +138,61 @@ const hasClientFilter = computed(() =>
|
||||
(props.inputs || []).some((i) => i.type === "select:client")
|
||||
);
|
||||
|
||||
// Async action options for select:action inputs
|
||||
const actionOptions = ref([]);
|
||||
const actionLoading = ref(false);
|
||||
async function fetchActions() {
|
||||
actionLoading.value = true;
|
||||
try {
|
||||
const res = await axios.get(route("reports.actions"));
|
||||
actionOptions.value = Array.isArray(res.data) ? res.data : [];
|
||||
} finally {
|
||||
actionLoading.value = false;
|
||||
}
|
||||
}
|
||||
const hasActionFilter = computed(() =>
|
||||
(props.inputs || []).some((i) => i.type === "select:action")
|
||||
);
|
||||
|
||||
// Async decision options for select:decision inputs (filtered by selected action)
|
||||
const decisionOptions = ref([]);
|
||||
const decisionLoading = ref(false);
|
||||
async function fetchDecisions(actionId = null) {
|
||||
decisionLoading.value = true;
|
||||
try {
|
||||
const params = actionId ? { action_id: actionId } : {};
|
||||
const res = await axios.get(route("reports.decisions"), { params });
|
||||
decisionOptions.value = Array.isArray(res.data) ? res.data : [];
|
||||
} finally {
|
||||
decisionLoading.value = false;
|
||||
}
|
||||
}
|
||||
const hasDecisionFilter = computed(() =>
|
||||
(props.inputs || []).some((i) => i.type === "select:decision")
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
if (hasUserFilter.value) fetchUsers(true);
|
||||
if (hasClientFilter.value) fetchClients(true);
|
||||
if (hasActionFilter.value) fetchActions();
|
||||
if (hasDecisionFilter.value) {
|
||||
const actionInput = (props.inputs || []).find((i) => i.type === "select:action");
|
||||
fetchDecisions(actionInput ? (filters[actionInput.key] ?? null) : null);
|
||||
}
|
||||
});
|
||||
|
||||
// When action filter changes, reload decisions filtered to that action
|
||||
const actionKey = (props.inputs || []).find((i) => i.type === "select:action")?.key;
|
||||
if (hasDecisionFilter.value && actionKey) {
|
||||
watch(
|
||||
() => filters[actionKey],
|
||||
(newActionId) => {
|
||||
filters.decision_id = null;
|
||||
fetchDecisions(newActionId ?? null);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Formatting helpers (EU style)
|
||||
function formatNumberEU(val) {
|
||||
if (typeof val !== "number") return String(val ?? "");
|
||||
@@ -382,6 +432,38 @@ function formatCell(value, key) {
|
||||
Nalagam…
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="inp.type === 'select:action'">
|
||||
<AppCombobox
|
||||
v-model="filters[inp.key]"
|
||||
:items="
|
||||
actionOptions.map((a) => ({ value: a.id, label: a.name }))
|
||||
"
|
||||
placeholder="Brez"
|
||||
search-placeholder="Išči akcijo..."
|
||||
empty-text="Ni akcij"
|
||||
:disabled="actionLoading"
|
||||
button-class="w-full"
|
||||
/>
|
||||
<div v-if="actionLoading" class="text-xs text-muted-foreground">
|
||||
Nalagam…
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="inp.type === 'select:decision'">
|
||||
<AppCombobox
|
||||
v-model="filters[inp.key]"
|
||||
:items="
|
||||
decisionOptions.map((d) => ({ value: d.id, label: d.name }))
|
||||
"
|
||||
placeholder="Brez"
|
||||
search-placeholder="Išči odločitev..."
|
||||
empty-text="Ni odločitev"
|
||||
:disabled="decisionLoading"
|
||||
button-class="w-full"
|
||||
/>
|
||||
<div v-if="decisionLoading" class="text-xs text-muted-foreground">
|
||||
Nalagam…
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<Input
|
||||
v-model="filters[inp.key]"
|
||||
|
||||
Reference in New Issue
Block a user