Teren-app/resources/js/Pages/Cases/Partials/ContractDrawer.vue
Simon Pocrnjič b7fa2d261b changes UI
2025-11-04 18:53:23 +01:00

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>