field job added option to add multiple contracts to user at once

This commit is contained in:
Simon Pocrnjič
2025-10-16 21:28:40 +02:00
parent e782bcca7c
commit 04f31e62aa
8 changed files with 247 additions and 18 deletions
+39 -17
View File
@@ -78,21 +78,20 @@ function buildRelated(a) {
// Only client case link (other routes not defined yet)
if (a.client_case_uuid || a.client_case_id) {
const caseParam = a.client_case_uuid || a.client_case_id;
if (typeof route === "function" && route().hasOwnProperty) {
try {
links.push({
type: "client_case",
label: "Primer",
href: route("clientCase.show", caseParam),
});
} catch (e) {
/* silently ignore */
}
} else {
try {
// Prefer Ziggy when available and force stringification here
const href = String(route("clientCase.show", { client_case: caseParam }));
links.push({
type: "client_case",
label: "Primer",
href: route("clientCase.show", caseParam),
href,
});
} catch (e) {
// Safe fallback to a best-effort URL to avoid breaking render
links.push({
type: "client_case",
label: "Primer",
href: `/client-cases/${caseParam}`,
});
}
}
@@ -132,6 +131,24 @@ function formatJobTime(ts) {
return "";
}
}
// Safely build a client case href using Ziggy when available, with a plain fallback.
function safeCaseHref(uuid, segment = null) {
if (!uuid) {
return "#";
}
try {
const params = { client_case: uuid };
if (segment != null) {
params.segment = segment;
}
return String(route("clientCase.show", params));
} catch (e) {
return segment != null
? `/client-cases/${uuid}?segment=${segment}`
: `/client-cases/${uuid}`;
}
}
</script>
<template>
@@ -425,10 +442,14 @@ function formatJobTime(ts) {
>
<div class="min-w-0">
<Link
:href="route('clientCase.show', c.uuid)"
v-if="c?.uuid"
:href="safeCaseHref(c.uuid)"
class="text-indigo-600 dark:text-indigo-400 hover:underline font-medium"
>{{ c.client_ref || c.uuid.slice(0, 8) }}</Link
>
<span v-else class="text-gray-700 dark:text-gray-300 font-medium">{{
c.client_ref || "Primer"
}}</span>
<p class="text-[11px] text-gray-400 dark:text-gray-500">
Brez aktivnosti:
{{ formatStaleDaysLabel(c.days_without_activity ?? c.days_stale) }}
@@ -479,16 +500,17 @@ function formatJobTime(ts) {
<template v-if="f.contract">
·
<Link
v-if="f.contract.client_case_uuid"
:href="
route('clientCase.show', {
client_case: f.contract.client_case_uuid,
segment: f.contract.segment_id,
})
safeCaseHref(f.contract.client_case_uuid, f.contract.segment_id)
"
class="text-indigo-600 dark:text-indigo-400 hover:underline"
>
{{ f.contract.reference || f.contract.uuid?.slice(0, 8) }}
</Link>
<span v-else class="text-gray-700 dark:text-gray-300">{{
f.contract.reference || f.contract.uuid?.slice(0, 8)
}}</span>
<span
v-if="f.contract.person_full_name"
class="text-gray-500 dark:text-gray-400"
+41
View File
@@ -18,6 +18,12 @@ const form = useForm({
end_date: null,
});
// Bulk selection form
const bulkForm = useForm({
contract_uuids: [],
assigned_user_id: null,
});
// Global search (applies to both tables)
const search = ref("");
@@ -68,6 +74,16 @@ function assign(contract) {
form.post(route("fieldjobs.assign"));
}
function assignSelected() {
// Use the same selected user as in the single-assign dropdown
bulkForm.assigned_user_id = form.assigned_user_id;
bulkForm.post(route("fieldjobs.assign-bulk"), {
onSuccess: () => {
bulkForm.contract_uuids = [];
},
});
}
function cancelAssignment(contract) {
const payload = { contract_uuid: contract.uuid };
form.transform(() => payload).post(route("fieldjobs.cancel"));
@@ -154,6 +170,7 @@ watch([search, assignedFilterUserId], () => {
// Column definitions for DataTableClient
const unassignedColumns = [
{ key: "_select", label: "", class: "w-8" },
{ key: "reference", label: "Pogodba", sortable: true, class: "w-32" },
{
key: "case_person",
@@ -307,6 +324,22 @@ const assignedRows = computed(() =>
<div v-if="form.errors.assigned_user_id" class="text-red-600 text-sm mt-1">
{{ form.errors.assigned_user_id }}
</div>
<div class="mt-3 flex items-center gap-2">
<button
class="px-3 py-2 text-sm rounded bg-indigo-600 text-white disabled:opacity-50"
:disabled="!bulkForm.contract_uuids.length || !form.assigned_user_id"
@click="assignSelected"
>
Dodeli izbrane ({{ bulkForm.contract_uuids.length }})
</button>
<button
class="px-3 py-2 text-sm rounded border border-gray-300 disabled:opacity-50"
:disabled="!bulkForm.contract_uuids.length"
@click="bulkForm.contract_uuids = []"
>
Počisti izbor
</button>
</div>
</div>
<DataTableClient
:columns="unassignedColumns"
@@ -317,6 +350,14 @@ const assignedRows = computed(() =>
v-model:page="unassignedPage"
v-model:pageSize="unassignedPageSize"
>
<template #cell-_select="{ row }">
<input
type="checkbox"
class="h-4 w-4"
:value="row.uuid"
v-model="bulkForm.contract_uuids"
/>
</template>
<template #cell-case_person="{ row }">
<Link
v-if="row.client_case?.uuid"
+1 -1
View File
@@ -1321,7 +1321,7 @@ async function fetchSimulation() {
</div>
<div class="flex-shrink-0">
<a
:href="route('clientCase.show', row.case_uuid)"
:href="route('clientCase.show', { client_case: row.case_uuid })"
class="text-blue-600 hover:underline text-xs"
>Odpri primer</a
>