458 lines
14 KiB
Vue
458 lines
14 KiB
Vue
<script setup>
|
|
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, 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 {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@/Components/ui/select";
|
|
|
|
const props = defineProps({
|
|
client_case: Object,
|
|
show: { type: Boolean, default: false },
|
|
types: Array,
|
|
account_types: { type: Array, default: () => [] },
|
|
contract: { type: Object, default: null },
|
|
});
|
|
|
|
const emit = defineEmits(["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(),
|
|
})
|
|
);
|
|
|
|
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,
|
|
},
|
|
});
|
|
|
|
const processing = ref(false);
|
|
|
|
const close = () => {
|
|
emit("close");
|
|
setTimeout(() => {
|
|
form.resetForm();
|
|
processing.value = false;
|
|
}, 300);
|
|
};
|
|
|
|
watch(
|
|
() => [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,
|
|
},
|
|
});
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
|
|
const storeOrUpdate = () => {
|
|
const { values } = form;
|
|
const isEdit = !!values.uuid;
|
|
|
|
processing.value = true;
|
|
|
|
const options = {
|
|
preserveScroll: true,
|
|
preserveState: true,
|
|
only: [],
|
|
onSuccess: () => {
|
|
close();
|
|
},
|
|
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;
|
|
},
|
|
};
|
|
|
|
if (isEdit) {
|
|
router.put(
|
|
route("clientCase.contract.update", {
|
|
client_case: props.client_case.uuid,
|
|
uuid: values.uuid,
|
|
}),
|
|
values,
|
|
options
|
|
);
|
|
} else {
|
|
router.post(
|
|
route("clientCase.contract.store", props.client_case),
|
|
values,
|
|
options
|
|
);
|
|
}
|
|
};
|
|
|
|
const onSubmit = form.handleSubmit(() => {
|
|
storeOrUpdate();
|
|
});
|
|
|
|
const onConfirm = () => {
|
|
onSubmit();
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<CreateDialog
|
|
v-if="!form.values.uuid"
|
|
:show="show"
|
|
title="Dodaj pogodbo"
|
|
confirm-text="Shrani"
|
|
: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-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>
|
|
|
|
<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"
|
|
>
|
|
{{ t.name }}
|
|
</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
<FormMessage />
|
|
</FormItem>
|
|
</FormField>
|
|
|
|
<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>
|
|
|
|
<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"
|
|
>
|
|
{{ at.name ?? "#" + at.id }}
|
|
</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
<FormMessage />
|
|
</FormItem>
|
|
</FormField>
|
|
|
|
<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>
|
|
|
|
<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>
|
|
</div>
|
|
</form>
|
|
</CreateDialog>
|
|
|
|
<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-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>
|
|
|
|
<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"
|
|
>
|
|
{{ t.name }}
|
|
</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
<FormMessage />
|
|
</FormItem>
|
|
</FormField>
|
|
|
|
<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>
|
|
|
|
<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"
|
|
>
|
|
{{ at.name ?? "#" + at.id }}
|
|
</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
<FormMessage />
|
|
</FormItem>
|
|
</FormField>
|
|
|
|
<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>
|
|
|
|
<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>
|
|
</div>
|
|
</form>
|
|
</UpdateDialog>
|
|
</template>
|