changes to UI mostly

This commit is contained in:
Simon Pocrnjič
2025-09-30 22:00:03 +02:00
parent 53917f2ca0
commit db99a57030
18 changed files with 2169 additions and 777 deletions
@@ -1,53 +1,163 @@
<script setup>
import BasicTable from '@/Components/BasicTable.vue';
import { LinkOptions as C_LINK, TableColumn as C_TD, TableRow as C_TR} from '@/Shared/AppObjects';
import { ref } from "vue";
import { router } from "@inertiajs/vue3";
import Dropdown from "@/Components/Dropdown.vue";
import ConfirmationModal from "@/Components/ConfirmationModal.vue";
import SecondaryButton from "@/Components/SecondaryButton.vue";
import DangerButton from "@/Components/DangerButton.vue";
import {
FwbTable,
FwbTableHead,
FwbTableHeadCell,
FwbTableBody,
FwbTableRow,
FwbTableCell,
} from "flowbite-vue";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { library } from "@fortawesome/fontawesome-svg-core";
import { faTrash, faEllipsisVertical } from "@fortawesome/free-solid-svg-icons";
library.add(faTrash, faEllipsisVertical);
const props = defineProps({
client_case: Object,
activities: Object
client_case: Object,
activities: Object,
});
// Dropdown component manages its own open/close state
let header = [
C_TD.make('Pogodba', 'header'),
C_TD.make('Datum', 'header'),
C_TD.make('Akcija', 'header'),
C_TD.make('Odločitev', 'header'),
C_TD.make('Opomba', 'header'),
C_TD.make('Datum zapadlosti', 'header'),
C_TD.make('Znesek obljube', 'header'),
C_TD.make('Dodal', 'header')
];
const fmtDate = (d) => {
if (!d) return "";
try {
return new Date(d).toLocaleDateString("sl-SI");
} catch (e) {
return String(d);
}
};
const fmtCurrency = (v) => {
const n = Number(v ?? 0);
try {
return new Intl.NumberFormat("sl-SI", { style: "currency", currency: "EUR" }).format(
n
);
} catch {
return `${n.toFixed(2)}`;
}
};
const createBody = (data) => {
let body = [];
data.forEach((p) => {
const createdDate = new Date(p.created_at).toLocaleDateString('de');
const dueDate = (p.due_date) ? new Date().toLocaleDateString('de') : null;
const userName = (p.user && p.user.name) ? p.user.name : (p.user_name || '');
const cols = [
C_TD.make(p.contract?.reference ?? ''),
C_TD.make(createdDate, 'body' ),
C_TD.make(p.action.name, 'body'),
C_TD.make(p.decision.name, 'body'),
C_TD.make(p.note, 'body' ),
C_TD.make(dueDate, 'body' ),
C_TD.make(Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(p.amount), 'body' ),
C_TD.make(userName, 'body')
];
body.push(
C_TR.make(cols)
)
});
return body;
}
const deleteActivity = (row) => {
if (!row?.id) return;
router.delete(
route("clientCase.activity.delete", {
client_case: props.client_case.uuid,
activity: row.id,
}),
{
preserveScroll: true,
}
);
};
// Confirmation modal state and handlers
const confirmDelete = ref(false);
const toDeleteRow = ref(null);
const openDelete = (row) => {
toDeleteRow.value = row;
confirmDelete.value = true;
};
const cancelDelete = () => {
confirmDelete.value = false;
toDeleteRow.value = null;
};
const confirmDeleteAction = () => {
if (toDeleteRow.value) {
deleteActivity(toDeleteRow.value);
}
confirmDelete.value = false;
toDeleteRow.value = null;
};
</script>
<template>
<BasicTable :header="header" :body="createBody(activities.data)" />
</template>
<div class="overflow-x-auto">
<FwbTable hoverable striped class="min-w-full text-left text-sm">
<FwbTableHead>
<FwbTableHeadCell class="py-2 pr-4">Pogodba</FwbTableHeadCell>
<FwbTableHeadCell class="py-2 pr-4">Datum</FwbTableHeadCell>
<FwbTableHeadCell class="py-2 pr-4">Akcija</FwbTableHeadCell>
<FwbTableHeadCell class="py-2 pr-4">Odločitev</FwbTableHeadCell>
<FwbTableHeadCell class="py-2 pr-4">Opomba</FwbTableHeadCell>
<FwbTableHeadCell class="py-2 pr-4">Datum zapadlosti</FwbTableHeadCell>
<FwbTableHeadCell class="py-2 pr-4 text-right">Znesek obljube</FwbTableHeadCell>
<FwbTableHeadCell class="py-2 pr-4">Dodal</FwbTableHeadCell>
<FwbTableHeadCell class="py-2 pl-2 pr-2 w-8 text-right"></FwbTableHeadCell>
</FwbTableHead>
<FwbTableBody>
<FwbTableRow v-for="row in activities.data" :key="row.id" class="border-b">
<FwbTableCell class="py-2 pr-4">{{
row.contract?.reference || ""
}}</FwbTableCell>
<FwbTableCell class="py-2 pr-4">{{ fmtDate(row.created_at) }}</FwbTableCell>
<FwbTableCell class="py-2 pr-4">{{ row.action?.name || "" }}</FwbTableCell>
<FwbTableCell class="py-2 pr-4">{{ row.decision?.name || "" }}</FwbTableCell>
<FwbTableCell class="py-2 pr-4">{{ row.note || "" }}</FwbTableCell>
<FwbTableCell class="py-2 pr-4">{{ fmtDate(row.due_date) }}</FwbTableCell>
<FwbTableCell class="py-2 pr-4 text-right">{{
fmtCurrency(row.amount)
}}</FwbTableCell>
<FwbTableCell class="py-2 pr-4">{{
row.user?.name || row.user_name || ""
}}</FwbTableCell>
<FwbTableCell class="py-2 pl-2 pr-2 text-right">
<Dropdown align="right" width="30" :content-classes="['py-1', 'bg-white']">
<template #trigger>
<button
type="button"
class="inline-flex items-center justify-center w-8 h-8 rounded hover:bg-gray-100"
aria-haspopup="menu"
>
<FontAwesomeIcon
:icon="['fas', 'ellipsis-vertical']"
class="text-gray-600 text-[20px]"
/>
</button>
</template>
<template #content>
<button
type="button"
class="w-full flex items-center gap-2 px-3 py-2 text-sm hover:bg-red-50 text-red-600"
@click.stop="openDelete(row)"
>
<FontAwesomeIcon :icon="['fas', 'trash']" class="text-[16px]" />
<span>Izbriši</span>
</button>
</template>
</Dropdown>
</FwbTableCell>
</FwbTableRow>
<FwbTableRow v-if="!activities?.data || activities.data.length === 0">
<FwbTableCell :colspan="9" class="py-4 text-gray-500"
>Ni aktivnosti.</FwbTableCell
>
</FwbTableRow>
</FwbTableBody>
</FwbTable>
</div>
<!-- Confirm deletion modal -->
<ConfirmationModal :show="confirmDelete" @close="cancelDelete">
<template #title>Potrditev</template>
<template #content>
Ali ste prepričani, da želite izbrisati to aktivnost? Tega dejanja ni mogoče
razveljaviti.
</template>
<template #footer>
<SecondaryButton type="button" @click="cancelDelete">Prekliči</SecondaryButton>
<DangerButton type="button" class="ml-2" @click="confirmDeleteAction"
>Izbriši</DangerButton
>
</template>
</ConfirmationModal>
</template>
@@ -94,10 +94,21 @@ const storeOrUpdate = () => {
},
preserveScroll: true,
}
const params = {}
try {
const url = new URL(window.location.href)
const seg = url.searchParams.get('segment')
if (seg) params.segment = seg
} catch (e) {}
if (isEdit) {
formContract.put(route('clientCase.contract.update', { client_case: props.client_case.uuid, uuid: formContract.uuid }), options)
formContract.put(route('clientCase.contract.update', { client_case: props.client_case.uuid, uuid: formContract.uuid, ...params }), options)
} else {
formContract.post(route('clientCase.contract.store', props.client_case), options)
// route helper merges params for GET; for POST we can append query manually if needed
let postUrl = route('clientCase.contract.store', props.client_case)
if (params.segment) {
postUrl += (postUrl.includes('?') ? '&' : '?') + 'segment=' + encodeURIComponent(params.segment)
}
formContract.post(postUrl, options)
}
}