Teren-app/resources/js/Components/PersonInfo/TrrCreateForm.vue
Simon Pocrnjič 63e0958b66 Dev branch
2025-11-02 12:31:01 +01:00

325 lines
9.8 KiB
Vue

<script setup>
import { ref, watch } from 'vue';
import { useForm, Field as FormField } from "vee-validate";
import { toTypedSchema } from "@vee-validate/zod";
import * as z from "zod";
import axios from 'axios';
import CreateDialog from '../Dialogs/CreateDialog.vue';
import UpdateDialog from '../Dialogs/UpdateDialog.vue';
import SectionTitle from '../SectionTitle.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({
show: { type: Boolean, default: false },
person: { type: Object, required: true },
currencies: { type: Array, default: () => ['EUR'] },
edit: { type: Boolean, default: false },
id: { type: Number, default: 0 },
});
const processing = ref(false);
const errors = ref({});
const emit = defineEmits(['close']);
const initialCurrency = () => (props.currencies && props.currencies.length ? props.currencies[0] : 'EUR');
const formSchema = toTypedSchema(
z.object({
iban: z.string().optional(),
bank_name: z.string().optional(),
bic_swift: z.string().optional(),
account_number: z.string().optional(),
routing_number: z.string().optional(),
currency: z.string().default(initialCurrency()),
country_code: z.string().optional(),
holder_name: z.string().optional(),
notes: z.string().optional(),
})
);
const form = useForm({
validationSchema: formSchema,
initialValues: {
iban: '',
bank_name: '',
bic_swift: '',
account_number: '',
routing_number: '',
currency: initialCurrency(),
country_code: '',
holder_name: '',
notes: ''
},
});
const close = () => {
emit('close');
setTimeout(() => {
errors.value = {};
form.resetForm();
}, 300);
};
const resetForm = () => {
form.resetForm({
values: {
iban: '',
bank_name: '',
bic_swift: '',
account_number: '',
routing_number: '',
currency: initialCurrency(),
country_code: '',
holder_name: '',
notes: ''
}
});
};
const create = async () => {
processing.value = true;
errors.value = {};
const { values } = form;
try {
const { data } = await axios.post(route('person.trr.create', props.person), values);
if (!Array.isArray(props.person.trrs)) props.person.trrs = (props.person.bank_accounts || props.person.accounts || props.person.bankAccounts || []);
(props.person.trrs).push(data.trr);
processing.value = false;
close();
resetForm();
} catch (e) {
errors.value = e?.response?.data?.errors || {};
// Map axios errors to VeeValidate field errors
if (errors.value) {
Object.keys(errors.value).forEach((field) => {
const errorMessages = Array.isArray(errors.value[field])
? errors.value[field]
: [errors.value[field]];
form.setFieldError(field, errorMessages[0]);
});
}
processing.value = false;
}
};
const update = async () => {
processing.value = true;
errors.value = {};
const { values } = form;
try {
const { data } = await axios.put(route('person.trr.update', { person: props.person, trr_id: props.id }), values);
let list = props.person.trrs || props.person.bank_accounts || props.person.accounts || props.person.bankAccounts || [];
const idx = list.findIndex(a => a.id === data.trr.id);
if (idx !== -1) list[idx] = data.trr;
processing.value = false;
close();
resetForm();
} catch (e) {
errors.value = e?.response?.data?.errors || {};
// Map axios errors to VeeValidate field errors
if (errors.value) {
Object.keys(errors.value).forEach((field) => {
const errorMessages = Array.isArray(errors.value[field])
? errors.value[field]
: [errors.value[field]];
form.setFieldError(field, errorMessages[0]);
});
}
processing.value = false;
}
};
watch(
() => props.id,
(id) => {
if (props.edit && id) {
const list = props.person.trrs || props.person.bank_accounts || props.person.accounts || props.person.bankAccounts || [];
const current = list.find(a => a.id === id);
if (current) {
form.setValues({
iban: current.iban || current.account_number || current.number || '',
bank_name: current.bank_name || '',
bic_swift: current.bic_swift || '',
account_number: current.account_number || '',
routing_number: current.routing_number || '',
currency: current.currency || initialCurrency(),
country_code: current.country_code || '',
holder_name: current.holder_name || '',
notes: current.notes || ''
});
return;
}
}
resetForm();
},
{ immediate: true }
);
watch(() => props.show, (val) => {
if (val && props.edit && props.id) {
const list = props.person.trrs || props.person.bank_accounts || props.person.accounts || props.person.bankAccounts || [];
const current = list.find(a => a.id === props.id);
if (current) {
form.setValues({
iban: current.iban || current.account_number || current.number || '',
bank_name: current.bank_name || '',
bic_swift: current.bic_swift || '',
account_number: current.account_number || '',
routing_number: current.routing_number || '',
currency: current.currency || initialCurrency(),
country_code: current.country_code || '',
holder_name: current.holder_name || '',
notes: current.notes || ''
});
}
} else if (val && !props.edit) {
resetForm();
}
});
const submit = () => (props.edit ? update() : create());
const onSubmit = form.handleSubmit(() => {
submit();
});
const onConfirm = () => {
onSubmit();
};
</script>
<template>
<component
:is="edit ? UpdateDialog : CreateDialog"
:show="show"
:title="edit ? 'Spremeni TRR' : 'Dodaj TRR'"
confirm-text="Shrani"
:processing="processing"
@close="close"
@confirm="onConfirm"
>
<form @submit.prevent="onSubmit">
<SectionTitle class="border-b mb-4">
<template #title>TRR</template>
</SectionTitle>
<div class="space-y-4">
<FormField v-slot="{ componentField }" name="iban">
<FormItem>
<FormLabel>IBAN</FormLabel>
<FormControl>
<Input id="trr_iban" placeholder="IBAN" autocomplete="off" v-bind="componentField" />
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<FormField v-slot="{ componentField }" name="bank_name">
<FormItem>
<FormLabel>Banka</FormLabel>
<FormControl>
<Input id="trr_bank_name" placeholder="Banka" autocomplete="organization" v-bind="componentField" />
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<FormField v-slot="{ componentField }" name="bic_swift">
<FormItem>
<FormLabel>BIC / SWIFT</FormLabel>
<FormControl>
<Input id="trr_bic" placeholder="BIC / SWIFT" autocomplete="off" v-bind="componentField" />
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<FormField v-slot="{ componentField }" name="account_number">
<FormItem>
<FormLabel>Številka računa</FormLabel>
<FormControl>
<Input id="trr_accnum" placeholder="Številka računa" autocomplete="off" v-bind="componentField" />
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<FormField v-slot="{ componentField }" name="routing_number">
<FormItem>
<FormLabel>Usmerjevalna številka (routing)</FormLabel>
<FormControl>
<Input id="trr_route" placeholder="Routing number" autocomplete="off" v-bind="componentField" />
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<FormField v-if="currencies && currencies.length" v-slot="{ value, handleChange }" name="currency">
<FormItem>
<FormLabel>Valuta</FormLabel>
<Select :model-value="value" @update:model-value="handleChange">
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Izberi valuto" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem v-for="c in currencies" :key="c" :value="c">
{{ c }}
</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormItem>
</FormField>
<FormField v-slot="{ componentField }" name="country_code">
<FormItem>
<FormLabel>Koda države (2-znaki, npr. SI)</FormLabel>
<FormControl>
<Input id="trr_cc" placeholder="SI" autocomplete="country" v-bind="componentField" />
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<FormField v-slot="{ componentField }" name="holder_name">
<FormItem>
<FormLabel>Imetnik računa</FormLabel>
<FormControl>
<Input id="trr_holder" placeholder="Imetnik računa" autocomplete="name" v-bind="componentField" />
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<FormField v-slot="{ componentField }" name="notes">
<FormItem>
<FormLabel>Opombe</FormLabel>
<FormControl>
<Textarea id="trr_notes" placeholder="Opombe" v-bind="componentField" />
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</div>
</form>
</component>
</template>