changes UI

This commit is contained in:
Simon Pocrnjič
2025-11-04 18:53:23 +01:00
parent fd9f26d82a
commit b7fa2d261b
15 changed files with 911 additions and 730 deletions
@@ -15,7 +15,7 @@ import {
SelectTrigger,
SelectValue,
} from "@/Components/ui/select";
import { Checkbox } from "@/Components/ui/checkbox";
import { Switch } from "@/Components/ui/switch";
import { ref, watch, computed } from "vue";
const props = defineProps({
@@ -357,7 +357,7 @@ watch(
<div v-if="showSendAutoMail()" class="space-y-2">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-2">
<Checkbox
<Switch
v-model="form.send_auto_mail"
:disabled="autoMailDisabled"
/>
@@ -370,7 +370,7 @@ watch(
<div v-if="templateAllowsAttachments && form.contract_uuid" class="mt-3">
<label class="inline-flex items-center gap-2">
<Checkbox v-model="form.attach_documents" />
<Switch v-model="form.attach_documents" />
<span class="text-sm">Dodaj priponke iz izbrane pogodbe</span>
</label>
<div
@@ -392,9 +392,9 @@ watch(
:key="doc.uuid || doc.id"
class="flex items-center gap-2 text-sm"
>
<Checkbox
:checked="form.attachment_document_ids.includes(doc.id)"
@update:checked="(checked) => {
<Switch
:model-value="form.attachment_document_ids.includes(doc.id)"
@update:model-value="(checked) => {
if (checked) {
if (!form.attachment_document_ids.includes(doc.id)) {
form.attachment_document_ids.push(doc.id);
@@ -1,12 +1,12 @@
<script setup>
import { ref, computed } from "vue";
import { Link, router } from "@inertiajs/vue3";
import { router } from "@inertiajs/vue3";
import DataTable from "@/Components/DataTable/DataTable.vue";
import Dropdown from "@/Components/Dropdown.vue";
import DeleteDialog from "@/Components/Dialogs/DeleteDialog.vue";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { library } from "@fortawesome/fontawesome-svg-core";
import { faTrash, faEllipsisVertical, faCopy } from "@fortawesome/free-solid-svg-icons";
import Dropdown from "@/Components/Dropdown.vue";
library.add(faTrash, faEllipsisVertical, faCopy);
@@ -35,6 +35,7 @@ const fmtDate = (d) => {
return String(d);
}
};
const fmtDateTime = (d) => {
if (!d) return "";
try {
@@ -54,12 +55,11 @@ const fmtDateTime = (d) => {
return String(d);
}
};
const fmtCurrency = (v) => {
const n = Number(v ?? 0);
try {
return new Intl.NumberFormat("sl-SI", { style: "currency", currency: "EUR" }).format(
n
);
return new Intl.NumberFormat("sl-SI", { style: "currency", currency: "EUR" }).format(n);
} catch {
return `${n.toFixed(2)}`;
}
@@ -72,36 +72,32 @@ const deleteActivity = (row) => {
client_case: props.client_case.uuid,
activity: row.id,
}),
{
preserveScroll: true,
}
{ preserveScroll: true }
);
};
// Confirmation modal state
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;
cancelDelete();
};
// Copy function
const copyToClipboard = async (text) => {
try {
await navigator.clipboard.writeText(text);
// You could add a toast notification here if available
} catch (err) {
// Fallback for older browsers
const textArea = document.createElement("textarea");
textArea.value = text;
document.body.appendChild(textArea);
@@ -113,23 +109,24 @@ const copyToClipboard = async (text) => {
</script>
<template>
<div class="relative">
<div class="activity-scroll-wrapper max-h-[32rem] overflow-y-auto overflow-x-auto">
<DataTable
:columns="columns"
:rows="rows"
:show-toolbar="true"
:show-pagination="false"
:show-search="false"
:show-page-size="false"
:hoverable="true"
row-key="id"
empty-text="Ni aktivnosti."
class="border-0"
>
<div class="p-4">
<DataTable
:columns="columns"
:rows="rows"
:show-toolbar="true"
:show-pagination="false"
:show-search="false"
:show-page-size="false"
:show-add="!!$slots.add"
:hoverable="true"
row-key="id"
empty-text="Ni aktivnosti."
class="border-0"
>
<template #toolbar-add>
<slot name="add" />
</template>
<template #cell-decision_dot="{ row }">
<div class="flex justify-center">
<span
@@ -137,18 +134,13 @@ const copyToClipboard = async (text) => {
class="inline-block h-4 w-4 rounded-full ring-1 ring-gray-300"
:style="{ backgroundColor: row.decision?.color_tag }"
:title="row.decision?.color_tag"
aria-hidden="true"
></span>
/>
</div>
</template>
<template #cell-contract="{ row }">
<template v-if="row.contract?.reference">
{{ row.contract.reference }}
</template>
<template v-else>
<span class="text-gray-400"></span>
</template>
<span v-if="row.contract?.reference">{{ row.contract.reference }}</span>
<span v-else class="text-gray-400"></span>
</template>
<template #cell-decision="{ row }">
@@ -170,24 +162,15 @@ const copyToClipboard = async (text) => {
</template>
<template v-else-if="row.note">
<span>{{ row.note.slice(0, 60) }} </span>
<Dropdown
align="left"
width="56"
:content-classes="['p-2', 'bg-white', 'shadow', 'max-w-xs']"
>
<Dropdown align="left" width="56" :content-classes="['p-2', 'bg-white', 'shadow', 'max-w-xs']">
<template #trigger>
<button
type="button"
class="inline-flex items-center text-[11px] text-indigo-600 hover:underline focus:outline-none"
>
<button type="button" class="inline-flex items-center text-[11px] text-indigo-600 hover:underline">
Več
</button>
</template>
<template #content>
<div class="relative" @click.stop>
<div
class="flex items-center justify-between p-1 border-b border-gray-200"
>
<div class="flex items-center justify-between p-1 border-b border-gray-200">
<span class="text-xs font-medium text-gray-600">Opomba</span>
<button
@click="copyToClipboard(row.note)"
@@ -198,9 +181,7 @@ const copyToClipboard = async (text) => {
<span>Kopiraj</span>
</button>
</div>
<div
class="max-h-60 overflow-auto text-[12px] whitespace-pre-wrap break-words p-2"
>
<div class="max-h-60 overflow-auto text-[12px] whitespace-pre-wrap break-words p-2">
{{ row.note }}
</div>
</div>
@@ -223,10 +204,7 @@ const copyToClipboard = async (text) => {
<span class="text-gray-500">D:</span>
<span class="ml-1">{{ fmtDate(row.due_date) }}</span>
</div>
<div
v-if="!row.due_date && (!row.amount || Number(row.amount) === 0)"
class="text-gray-400"
>
<div v-if="!row.due_date && (!row.amount || Number(row.amount) === 0)" class="text-gray-400">
</div>
</div>
@@ -237,9 +215,7 @@ const copyToClipboard = async (text) => {
{{ row.user?.name || row.user_name || "" }}
</div>
<div v-if="row.created_at" class="mt-1">
<span
class="inline-block px-2 py-0.5 rounded text-[11px] bg-gray-100 text-gray-600 tracking-wide"
>
<span class="inline-block px-2 py-0.5 rounded text-[11px] bg-gray-100 text-gray-600 tracking-wide">
{{ fmtDateTime(row.created_at) }}
</span>
</div>
@@ -251,12 +227,9 @@ const copyToClipboard = async (text) => {
<button
type="button"
class="inline-flex items-center justify-center h-8 w-8 rounded-full hover:bg-gray-100 focus:outline-none"
title="Actions"
title="Možnosti"
>
<FontAwesomeIcon
:icon="faEllipsisVertical"
class="h-4 w-4 text-gray-700"
/>
<FontAwesomeIcon :icon="faEllipsisVertical" class="h-4 w-4 text-gray-700" />
</button>
</template>
<template #content>
@@ -271,8 +244,7 @@ const copyToClipboard = async (text) => {
</template>
</Dropdown>
</template>
</DataTable>
</div>
</DataTable>
</div>
<DeleteDialog
@@ -285,42 +257,3 @@ const copyToClipboard = async (text) => {
/>
</template>
<style scoped>
.activity-scroll-wrapper {
scrollbar-gutter: stable;
}
/* Ensure sticky header works within scroll container */
.activity-scroll-wrapper :deep(table) {
border-collapse: separate;
border-spacing: 0;
}
.activity-scroll-wrapper :deep([data-table-container]) {
overflow: visible !important;
}
.activity-scroll-wrapper :deep([data-table-container] > div) {
overflow-x: visible !important;
overflow-y: visible !important;
}
.activity-scroll-wrapper :deep(table thead) {
position: sticky;
top: 0;
z-index: 20;
}
.activity-scroll-wrapper :deep(table thead tr) {
background-color: white;
}
.activity-scroll-wrapper :deep(table thead th) {
background-color: white !important;
position: sticky;
top: 0;
z-index: 20;
box-shadow: 0 1px 0 0 #e5e7eb;
border-bottom: 1px solid #e5e7eb;
}
</style>
@@ -1,13 +1,20 @@
<script setup>
import ActionMessage from "@/Components/ActionMessage.vue";
import CreateDialog from "@/Components/Dialogs/CreateDialog.vue";
import UpdateDialog from "@/Components/Dialogs/UpdateDialog.vue";
import SectionTitle from "@/Components/SectionTitle.vue";
import CurrencyInput from "@/Components/CurrencyInput.vue";
import DatePicker from "@/Components/DatePicker.vue";
import { useForm, router } from "@inertiajs/vue3";
import { watch, nextTick, ref as vRef } from "vue";
import { Label } from "@/Components/ui/label";
import { useForm, Field as FormField } from "vee-validate";
import { toTypedSchema } from "@vee-validate/zod";
import * as z from "zod";
import { router } from "@inertiajs/vue3";
import { watch, ref } from "vue";
import {
FormControl,
FormItem,
FormLabel,
FormMessage,
} from "@/Components/ui/form";
import { Input } from "@/Components/ui/input";
import { Textarea } from "@/Components/ui/textarea";
import {
@@ -23,367 +30,428 @@ const props = defineProps({
show: { type: Boolean, default: false },
types: Array,
account_types: { type: Array, default: () => [] },
// Optional: when provided, drawer acts as edit mode
contract: { type: Object, default: null },
});
const emit = defineEmits(["close"]);
const close = () => {
// Clear any previous validation warnings when closing
formContract.clearErrors();
formContract.recentlySuccessful = false;
emit("close");
};
const formSchema = toTypedSchema(
z.object({
client_case_uuid: z.string(),
uuid: z.string().nullable().optional(),
reference: z.string().min(1, "Referenca je obvezna."),
start_date: z.string().optional(),
type_id: z.number().optional(),
description: z.string().optional(),
initial_amount: z.number().nullable().optional(),
balance_amount: z.number().nullable().optional(),
account_type_id: z.number().nullable().optional(),
})
);
// form state for create or edit
const formContract = useForm({
client_case_uuid: props.client_case.uuid,
uuid: props.contract?.uuid ?? null,
reference: props.contract?.reference ?? "",
start_date: props.contract?.start_date ?? new Date().toISOString(),
type_id: props.contract?.type_id ?? props.contract?.type?.id ?? props.types[0].id,
description: props.contract?.description ?? "",
// nested account fields, if exists
initial_amount: props.contract?.account?.initial_amount ?? null,
balance_amount: props.contract?.account?.balance_amount ?? null,
account_type_id: props.contract?.account?.type_id ?? null,
const form = useForm({
validationSchema: formSchema,
initialValues: {
client_case_uuid: props.client_case.uuid,
uuid: props.contract?.uuid ?? null,
reference: props.contract?.reference ?? "",
start_date: props.contract?.start_date ?? new Date().toISOString().split("T")[0],
type_id: props.contract?.type_id ?? props.contract?.type?.id ?? (props.types?.[0]?.id ?? null),
description: props.contract?.description ?? "",
initial_amount: props.contract?.account?.initial_amount ?? null,
balance_amount: props.contract?.account?.balance_amount ?? null,
account_type_id: props.contract?.account?.type_id ?? null,
},
});
// keep form in sync when switching between create and edit
const applyContract = (c) => {
formContract.uuid = c?.uuid ?? null;
formContract.reference = c?.reference ?? "";
formContract.start_date = c?.start_date ?? new Date().toISOString();
formContract.type_id = c?.type_id ?? c?.type?.id ?? props.types[0].id;
formContract.description = c?.description ?? "";
formContract.initial_amount = c?.account?.initial_amount ?? null;
formContract.balance_amount = c?.account?.balance_amount ?? null;
formContract.account_type_id = c?.account?.type_id ?? null;
const processing = ref(false);
const close = () => {
emit("close");
setTimeout(() => {
form.resetForm();
processing.value = false;
}, 300);
};
watch(
() => props.contract,
(c) => {
applyContract(c);
}
);
watch(
() => props.show,
(open) => {
if (open && !props.contract) {
// reset for create
applyContract(null);
() => [props.show, props.contract],
() => {
if (props.show && props.contract) {
// Edit mode - set values from contract
form.setValues({
client_case_uuid: props.client_case.uuid,
uuid: props.contract.uuid ?? null,
reference: props.contract.reference ?? "",
start_date: props.contract.start_date ?? new Date().toISOString().split("T")[0],
type_id: props.contract.type_id ?? props.contract.type?.id ?? (props.types?.[0]?.id ?? null),
description: props.contract.description ?? "",
initial_amount: props.contract.account?.initial_amount ?? null,
balance_amount: props.contract.account?.balance_amount ?? null,
account_type_id: props.contract.account?.type_id ?? null,
});
} else if (props.show && !props.contract) {
// Create mode - reset to defaults
form.resetForm({
values: {
client_case_uuid: props.client_case.uuid,
uuid: null,
reference: "",
start_date: new Date().toISOString().split("T")[0],
type_id: props.types?.[0]?.id ?? null,
description: "",
initial_amount: null,
balance_amount: null,
account_type_id: null,
},
});
}
if (!open) {
// Ensure warnings are cleared when dialog hides
formContract.clearErrors();
formContract.recentlySuccessful = false;
}
}
);
// optional: focus the reference input when a reference validation error appears
const contractRefInput = vRef(null);
watch(
() => formContract.errors.reference,
async (err) => {
if (err && props.show) {
await nextTick();
try {
contractRefInput.value?.focus?.();
} catch (e) {}
}
}
},
{ immediate: true }
);
const storeOrUpdate = () => {
const isEdit = !!formContract.uuid;
// Debug: log payload being sent to verify balance_amount presence
try {
console.debug('Submitting contract form', JSON.parse(JSON.stringify(formContract)));
} catch (e) {}
const { values } = form;
const isEdit = !!values.uuid;
processing.value = true;
const options = {
onBefore: () => {
formContract.start_date = formContract.start_date;
},
preserveScroll: true,
preserveState: true,
only: [],
onSuccess: () => {
close();
// keep state clean; reset to initial
if (!isEdit) formContract.reset();
// After edit ensure contracts list reflects updated balance
if (isEdit) {
try {
const params = {};
try {
const url = new URL(window.location.href);
const seg = url.searchParams.get('segment');
if (seg) params.segment = seg;
} catch (e) {}
router.visit(route('clientCase.show', { client_case: props.client_case.uuid, ...params }), {
preserveScroll: true,
replace: true,
});
} catch (e) {}
}
},
preserveScroll: true,
onError: (errors) => {
// Map Inertia errors to VeeValidate field errors
Object.keys(errors).forEach((field) => {
const message = Array.isArray(errors[field])
? errors[field][0]
: errors[field];
form.setFieldError(field, message);
});
},
onFinish: () => {
processing.value = false;
},
};
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(
router.put(
route("clientCase.contract.update", {
client_case: props.client_case.uuid,
uuid: formContract.uuid,
...params,
uuid: values.uuid,
}),
values,
options
);
} else {
// 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);
router.post(
route("clientCase.contract.store", props.client_case),
values,
options
);
}
};
const onSubmit = form.handleSubmit(() => {
storeOrUpdate();
});
const onConfirm = () => {
onSubmit();
};
</script>
<template>
<CreateDialog
v-if="!formContract.uuid"
v-if="!form.values.uuid"
:show="show"
title="Dodaj pogodbo"
confirm-text="Shrani"
:processing="formContract.processing"
:processing="processing"
@close="close"
@confirm="storeOrUpdate"
@confirm="onConfirm"
>
<form @submit.prevent="storeOrUpdate">
<div
v-if="formContract.errors.reference"
class="mb-4 rounded border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700"
>
{{ formContract.errors.reference }}
</div>
<SectionTitle class="mt-4 border-b mb-4">
<template #title> Pogodba </template>
</SectionTitle>
<form @submit.prevent="onSubmit" class="space-y-4">
<SectionTitle class="mt-4 border-b mb-4">
<template #title> Pogodba </template>
</SectionTitle>
<div class="space-y-4">
<div class="space-y-2">
<Label for="contractRef">Referenca</Label>
<Input
id="contractRef"
ref="contractRefInput"
v-model="formContract.reference"
type="text"
:class="[
formContract.errors.reference
? 'border-red-500 focus:border-red-500 focus:ring-red-500'
: '',
]"
autocomplete="contract-reference"
/>
<p v-if="formContract.errors.reference" class="text-sm text-red-600">
{{ formContract.errors.reference }}
</p>
</div>
<div class="space-y-4">
<FormField v-slot="{ componentField }" name="reference">
<FormItem>
<FormLabel>Referenca</FormLabel>
<FormControl>
<Input
id="contractRef"
type="text"
placeholder="Referenca"
autocomplete="contract-reference"
v-bind="componentField"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<div class="space-y-2">
<Label for="contractStartDate">Datum pričetka</Label>
<DatePicker
id="contractStartDate"
v-model="formContract.start_date"
format="dd.MM.yyyy"
:error="formContract.errors.start_date"
/>
</div>
<FormField v-slot="{ value, handleChange }" name="start_date">
<FormItem>
<FormLabel>Datum pričetka</FormLabel>
<FormControl>
<DatePicker
id="contractStartDate"
:model-value="value"
@update:model-value="handleChange"
format="dd.MM.yyyy"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<div class="space-y-2">
<Label for="contractTypeSelect">Tip</Label>
<Select v-model="formContract.type_id">
<SelectTrigger>
<SelectValue placeholder="Izberi tip" />
</SelectTrigger>
<FormField v-slot="{ value, handleChange }" name="type_id">
<FormItem>
<FormLabel>Tip</FormLabel>
<Select :model-value="value" @update:model-value="handleChange">
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Izberi tip" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem v-for="t in types" :key="t.id" :value="t.id">
<SelectItem
v-for="t in types"
:key="t.id"
:value="t.id"
>
{{ t.name }}
</SelectItem>
</SelectContent>
</Select>
</div>
<FormMessage />
</FormItem>
</FormField>
<div class="space-y-2">
<Label for="contractDescription">Opis</Label>
<Textarea
id="contractDescription"
v-model="formContract.description"
rows="3"
placeholder="Opis"
/>
</div>
<FormField v-slot="{ componentField }" name="description">
<FormItem>
<FormLabel>Opis</FormLabel>
<FormControl>
<Textarea
id="contractDescription"
rows="3"
placeholder="Opis"
v-bind="componentField"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<SectionTitle class="mt-6 border-b mb-4">
<template #title> Račun </template>
</SectionTitle>
<SectionTitle class="mt-6 border-b mb-4">
<template #title> Račun </template>
</SectionTitle>
<div class="space-y-2">
<Label for="accountTypeSelect">Tip računa</Label>
<Select v-model="formContract.account_type_id">
<SelectTrigger>
<SelectValue placeholder="Izberi tip računa" />
</SelectTrigger>
<FormField v-slot="{ value, handleChange }" name="account_type_id">
<FormItem>
<FormLabel>Tip računa</FormLabel>
<Select :model-value="value" @update:model-value="handleChange">
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Izberi tip računa" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem :value="null"></SelectItem>
<SelectItem v-for="at in account_types" :key="at.id" :value="at.id">
<SelectItem
v-for="at in account_types"
:key="at.id"
:value="at.id"
>
{{ at.name ?? "#" + at.id }}
</SelectItem>
</SelectContent>
</Select>
<p v-if="formContract.errors.account_type_id" class="text-sm text-red-600">
{{ formContract.errors.account_type_id }}
</p>
</div>
<FormMessage />
</FormItem>
</FormField>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div class="space-y-2">
<Label for="initialAmount">Predani znesek</Label>
<CurrencyInput id="initialAmount" v-model="formContract.initial_amount" />
</div>
<div class="space-y-2">
<Label for="balanceAmount">Odprti znesek</Label>
<CurrencyInput id="balanceAmount" v-model="formContract.balance_amount" />
</div>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<FormField v-slot="{ value, handleChange }" name="initial_amount">
<FormItem>
<FormLabel>Predani znesek</FormLabel>
<FormControl>
<CurrencyInput
id="initialAmount"
:model-value="value"
@update:model-value="handleChange"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<ActionMessage :on="formContract.recentlySuccessful" class="text-sm text-green-600">
Shranjuje.
</ActionMessage>
<FormField v-slot="{ value, handleChange }" name="balance_amount">
<FormItem>
<FormLabel>Odprti znesek</FormLabel>
<FormControl>
<CurrencyInput
id="balanceAmount"
:model-value="value"
@update:model-value="handleChange"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</div>
</form>
</CreateDialog>
<UpdateDialog
v-else
:show="show"
title="Uredi pogodbo"
confirm-text="Posodobi"
:processing="formContract.processing"
@close="close"
@confirm="storeOrUpdate"
>
<form @submit.prevent="storeOrUpdate">
<div
v-if="formContract.errors.reference"
class="mb-4 rounded border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700"
>
{{ formContract.errors.reference }}
</div>
<SectionTitle class="mt-4 border-b mb-4">
<template #title> Pogodba </template>
</SectionTitle>
</div>
</form>
</CreateDialog>
<div class="space-y-4">
<div class="space-y-2">
<Label for="contractRef">Referenca</Label>
<Input
id="contractRef"
ref="contractRefInput"
v-model="formContract.reference"
type="text"
:class="[
formContract.errors.reference
? 'border-red-500 focus:border-red-500 focus:ring-red-500'
: '',
]"
autocomplete="contract-reference"
/>
<p v-if="formContract.errors.reference" class="text-sm text-red-600">
{{ formContract.errors.reference }}
</p>
</div>
<UpdateDialog
v-else
:show="show"
title="Uredi pogodbo"
confirm-text="Posodobi"
:processing="processing"
@close="close"
@confirm="onConfirm"
>
<form @submit.prevent="onSubmit" class="space-y-4">
<SectionTitle class="mt-4 border-b mb-4">
<template #title> Pogodba </template>
</SectionTitle>
<div class="space-y-2">
<Label for="contractStartDate">Datum pričetka</Label>
<DatePicker
id="contractStartDate"
v-model="formContract.start_date"
format="dd.MM.yyyy"
:error="formContract.errors.start_date"
/>
</div>
<div class="space-y-4">
<FormField v-slot="{ componentField }" name="reference">
<FormItem>
<FormLabel>Referenca</FormLabel>
<FormControl>
<Input
id="contractRef"
type="text"
placeholder="Referenca"
autocomplete="contract-reference"
v-bind="componentField"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<div class="space-y-2">
<Label for="contractTypeSelect">Tip</Label>
<Select v-model="formContract.type_id">
<SelectTrigger>
<SelectValue placeholder="Izberi tip" />
</SelectTrigger>
<FormField v-slot="{ value, handleChange }" name="start_date">
<FormItem>
<FormLabel>Datum pričetka</FormLabel>
<FormControl>
<DatePicker
id="contractStartDate"
:model-value="value"
@update:model-value="handleChange"
format="dd.MM.yyyy"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<FormField v-slot="{ value, handleChange }" name="type_id">
<FormItem>
<FormLabel>Tip</FormLabel>
<Select :model-value="value" @update:model-value="handleChange">
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Izberi tip" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem v-for="t in types" :key="t.id" :value="t.id">
<SelectItem
v-for="t in types"
:key="t.id"
:value="t.id"
>
{{ t.name }}
</SelectItem>
</SelectContent>
</Select>
</div>
<FormMessage />
</FormItem>
</FormField>
<div class="space-y-2">
<Label for="contractDescription">Opis</Label>
<Textarea
id="contractDescription"
v-model="formContract.description"
rows="3"
placeholder="Opis"
/>
</div>
<FormField v-slot="{ componentField }" name="description">
<FormItem>
<FormLabel>Opis</FormLabel>
<FormControl>
<Textarea
id="contractDescription"
rows="3"
placeholder="Opis"
v-bind="componentField"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<SectionTitle class="mt-6 border-b mb-4">
<template #title> Račun </template>
</SectionTitle>
<SectionTitle class="mt-6 border-b mb-4">
<template #title> Račun </template>
</SectionTitle>
<div class="space-y-2">
<Label for="accountTypeSelect">Tip računa</Label>
<Select v-model="formContract.account_type_id">
<SelectTrigger>
<SelectValue placeholder="Izberi tip računa" />
</SelectTrigger>
<FormField v-slot="{ value, handleChange }" name="account_type_id">
<FormItem>
<FormLabel>Tip računa</FormLabel>
<Select :model-value="value" @update:model-value="handleChange">
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Izberi tip računa" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem :value="null"></SelectItem>
<SelectItem v-for="at in account_types" :key="at.id" :value="at.id">
<SelectItem
v-for="at in account_types"
:key="at.id"
:value="at.id"
>
{{ at.name ?? "#" + at.id }}
</SelectItem>
</SelectContent>
</Select>
<p v-if="formContract.errors.account_type_id" class="text-sm text-red-600">
{{ formContract.errors.account_type_id }}
</p>
</div>
<FormMessage />
</FormItem>
</FormField>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div class="space-y-2">
<Label for="initialAmount">Predani znesek</Label>
<CurrencyInput id="initialAmount" v-model="formContract.initial_amount" />
</div>
<div class="space-y-2">
<Label for="balanceAmount">Odprti znesek</Label>
<CurrencyInput id="balanceAmount" v-model="formContract.balance_amount" />
</div>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<FormField v-slot="{ value, handleChange }" name="initial_amount">
<FormItem>
<FormLabel>Predani znesek</FormLabel>
<FormControl>
<CurrencyInput
id="initialAmount"
:model-value="value"
@update:model-value="handleChange"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<ActionMessage :on="formContract.recentlySuccessful" class="text-sm text-green-600">
Shranjuje.
</ActionMessage>
<FormField v-slot="{ value, handleChange }" name="balance_amount">
<FormItem>
<FormLabel>Odprti znesek</FormLabel>
<FormControl>
<CurrencyInput
id="balanceAmount"
:model-value="value"
@update:model-value="handleChange"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</div>
</form>
</UpdateDialog>
</div>
</form>
</UpdateDialog>
</template>