518 lines
15 KiB
Vue
518 lines
15 KiB
Vue
<script setup>
|
|
import { ref, computed } from "vue";
|
|
import { router } from "@inertiajs/vue3";
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/Components/ui/tabs";
|
|
import { Button } from "@/Components/ui/button";
|
|
import { PlusIcon } from "@/Utilities/Icons";
|
|
import { faUser, faMapMarkerAlt, faPhone, faEnvelope, faUniversity } from "@fortawesome/free-solid-svg-icons";
|
|
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
|
import PersonUpdateForm from "./PersonUpdateForm.vue";
|
|
import AddressCreateForm from "./AddressCreateForm.vue";
|
|
import AddressUpdateForm from "./AddressUpdateForm.vue";
|
|
import PhoneCreateForm from "./PhoneCreateForm.vue";
|
|
import PhoneUpdateForm from "./PhoneUpdateForm.vue";
|
|
import EmailCreateForm from "./EmailCreateForm.vue";
|
|
import EmailUpdateForm from "./EmailUpdateForm.vue";
|
|
import TrrCreateForm from "./TrrCreateForm.vue";
|
|
import TrrUpdateForm from "./TrrUpdateForm.vue";
|
|
import ConfirmDialog from "../ConfirmDialog.vue";
|
|
|
|
// Tab components
|
|
import PersonInfoPersonTab from "./PersonInfoPersonTab.vue";
|
|
import PersonInfoAddressesTab from "./PersonInfoAddressesTab.vue";
|
|
import PersonInfoPhonesTab from "./PersonInfoPhonesTab.vue";
|
|
import PersonInfoEmailsTab from "./PersonInfoEmailsTab.vue";
|
|
import PersonInfoTrrTab from "./PersonInfoTrrTab.vue";
|
|
import PersonInfoSmsDialog from "./PersonInfoSmsDialog.vue";
|
|
|
|
const props = defineProps({
|
|
person: Object,
|
|
personEdit: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
edit: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
tabColor: {
|
|
type: String,
|
|
default: "blue-600",
|
|
},
|
|
types: {
|
|
type: Object,
|
|
default: {
|
|
address_types: [],
|
|
phone_types: [],
|
|
},
|
|
},
|
|
enableSms: { type: Boolean, default: false },
|
|
clientCaseUuid: { type: String, default: null },
|
|
smsProfiles: { type: Array, default: () => [] },
|
|
smsSenders: { type: Array, default: () => [] },
|
|
smsTemplates: { type: Array, default: () => [] },
|
|
});
|
|
|
|
// Dialog states
|
|
const drawerUpdatePerson = ref(false);
|
|
const drawerAddAddress = ref(false);
|
|
const drawerAddPhone = ref(false);
|
|
const drawerAddEmail = ref(false);
|
|
const drawerAddTrr = ref(false);
|
|
|
|
// Edit states
|
|
const editAddress = ref(false);
|
|
const editAddressId = ref(0);
|
|
const editPhone = ref(false);
|
|
const editPhoneId = ref(0);
|
|
const editEmail = ref(false);
|
|
const editEmailId = ref(0);
|
|
const editTrr = ref(false);
|
|
const editTrrId = ref(0);
|
|
|
|
// Confirm dialog state
|
|
const confirm = ref({
|
|
show: false,
|
|
title: "Potrditev brisanja",
|
|
message: "",
|
|
type: "",
|
|
id: 0,
|
|
itemName: null,
|
|
});
|
|
|
|
// SMS dialog state
|
|
const showSmsDialog = ref(false);
|
|
const smsTargetPhone = ref(null);
|
|
|
|
// Person handlers
|
|
const openDrawerUpdateClient = () => {
|
|
drawerUpdatePerson.value = true;
|
|
};
|
|
|
|
// Address handlers
|
|
const openDrawerAddAddress = (edit = false, id = 0) => {
|
|
drawerAddAddress.value = true;
|
|
editAddress.value = edit;
|
|
editAddressId.value = id;
|
|
};
|
|
|
|
const closeDrawerAddAddress = () => {
|
|
drawerAddAddress.value = false;
|
|
const wasEdit = editAddress.value;
|
|
editAddress.value = false;
|
|
editAddressId.value = 0;
|
|
if (!wasEdit) {
|
|
switchToTab('addresses');
|
|
}
|
|
};
|
|
|
|
// Phone handlers
|
|
const openDrawerAddPhone = (edit = false, id = 0) => {
|
|
editPhone.value = edit;
|
|
editPhoneId.value = id;
|
|
drawerAddPhone.value = true;
|
|
};
|
|
|
|
// Keep the old name for backward compatibility if needed, but use the correct name
|
|
const operDrawerAddPhone = openDrawerAddPhone;
|
|
|
|
const closeDrawerAddPhone = () => {
|
|
drawerAddPhone.value = false;
|
|
const wasEdit = editPhone.value;
|
|
editPhone.value = false;
|
|
editPhoneId.value = 0;
|
|
if (!wasEdit) {
|
|
switchToTab('phones');
|
|
}
|
|
};
|
|
|
|
// Email handlers
|
|
const openDrawerAddEmail = (edit = false, id = 0) => {
|
|
drawerAddEmail.value = true;
|
|
editEmail.value = edit;
|
|
editEmailId.value = id;
|
|
};
|
|
|
|
const closeDrawerAddEmail = () => {
|
|
drawerAddEmail.value = false;
|
|
const wasEdit = editEmail.value;
|
|
editEmail.value = false;
|
|
editEmailId.value = 0;
|
|
if (!wasEdit) {
|
|
switchToTab('emails');
|
|
}
|
|
};
|
|
|
|
// TRR handlers
|
|
const openDrawerAddTrr = (edit = false, id = 0) => {
|
|
drawerAddTrr.value = true;
|
|
editTrr.value = edit;
|
|
editTrrId.value = id;
|
|
};
|
|
|
|
const closeDrawerAddTrr = () => {
|
|
drawerAddTrr.value = false;
|
|
const wasEdit = editTrr.value;
|
|
editTrr.value = false;
|
|
editTrrId.value = 0;
|
|
if (!wasEdit) {
|
|
switchToTab('trr');
|
|
}
|
|
};
|
|
|
|
// Confirm dialog handlers
|
|
const openConfirm = (type, id, label = "") => {
|
|
confirm.value = {
|
|
show: true,
|
|
title: "Potrditev brisanja",
|
|
message: label
|
|
? `Ali res želite izbrisati "${label}"?`
|
|
: "Ali res želite izbrisati izbran element?",
|
|
type,
|
|
id,
|
|
itemName: label || null,
|
|
};
|
|
};
|
|
|
|
const closeConfirm = () => {
|
|
confirm.value.show = false;
|
|
confirm.value.itemName = null;
|
|
};
|
|
|
|
const onConfirmDelete = async () => {
|
|
const { type, id } = confirm.value;
|
|
|
|
if (type === "email") {
|
|
router.delete(
|
|
route("person.email.delete", { person: props.person, email_id: id }),
|
|
{
|
|
preserveScroll: true,
|
|
onSuccess: () => {
|
|
closeConfirm();
|
|
},
|
|
onError: (errors) => {
|
|
console.error("Delete failed", errors);
|
|
closeConfirm();
|
|
},
|
|
}
|
|
);
|
|
} else if (type === "trr") {
|
|
router.delete(
|
|
route("person.trr.delete", { person: props.person, trr_id: id }),
|
|
{
|
|
preserveScroll: true,
|
|
onSuccess: () => {
|
|
closeConfirm();
|
|
},
|
|
onError: (errors) => {
|
|
console.error("Delete failed", errors);
|
|
closeConfirm();
|
|
},
|
|
}
|
|
);
|
|
} else if (type === "address") {
|
|
router.delete(
|
|
route("person.address.delete", { person: props.person, address_id: id }),
|
|
{
|
|
preserveScroll: true,
|
|
onSuccess: () => {
|
|
closeConfirm();
|
|
},
|
|
onError: (errors) => {
|
|
console.error("Delete failed", errors);
|
|
closeConfirm();
|
|
},
|
|
}
|
|
);
|
|
} else if (type === "phone") {
|
|
router.delete(
|
|
route("person.phone.delete", { person: props.person, phone_id: id }),
|
|
{
|
|
preserveScroll: true,
|
|
onSuccess: () => {
|
|
closeConfirm();
|
|
},
|
|
onError: (errors) => {
|
|
console.error("Delete failed", errors);
|
|
closeConfirm();
|
|
},
|
|
}
|
|
);
|
|
}
|
|
};
|
|
|
|
// SMS handlers
|
|
const openSmsDialog = (phone) => {
|
|
if (!props.enableSms || !props.clientCaseUuid) return;
|
|
smsTargetPhone.value = phone;
|
|
showSmsDialog.value = true;
|
|
};
|
|
|
|
const closeSmsDialog = () => {
|
|
showSmsDialog.value = false;
|
|
smsTargetPhone.value = null;
|
|
};
|
|
|
|
// Tab event handlers
|
|
const handlePersonEdit = () => openDrawerUpdateClient();
|
|
|
|
const handleAddressAdd = () => openDrawerAddAddress(false, 0);
|
|
const handleAddressEdit = (id) => openDrawerAddAddress(true, id);
|
|
const handleAddressDelete = (id, label) => openConfirm("address", id, label);
|
|
|
|
const handlePhoneAdd = () => openDrawerAddPhone(false, 0);
|
|
const handlePhoneEdit = (id) => openDrawerAddPhone(true, id);
|
|
const handlePhoneDelete = (id, label) => openConfirm("phone", id, label);
|
|
const handlePhoneSms = (phone) => openSmsDialog(phone);
|
|
|
|
const handleEmailAdd = () => openDrawerAddEmail(false, 0);
|
|
const handleEmailEdit = (id) => openDrawerAddEmail(true, id);
|
|
const handleEmailDelete = (id, label) => openConfirm("email", id, label);
|
|
|
|
const handleTrrAdd = () => openDrawerAddTrr(false, 0);
|
|
const handleTrrEdit = (id) => openDrawerAddTrr(true, id);
|
|
const handleTrrDelete = (id, label) => openConfirm("trr", id, label);
|
|
|
|
// Computed counts for badges
|
|
const addressesCount = computed(() => (props.person?.addresses || []).length);
|
|
const phonesCount = computed(() => (props.person?.phones || []).length);
|
|
const emailsCount = computed(() => (props.person?.emails || []).length);
|
|
const trrsCount = computed(() => {
|
|
const list = props.person?.trrs ||
|
|
props.person?.bank_accounts ||
|
|
props.person?.accounts ||
|
|
props.person?.bankAccounts || [];
|
|
return list.length;
|
|
});
|
|
|
|
// Format badge count (show 999+ if >= 999)
|
|
const formatBadgeCount = (count) => {
|
|
return count >= 999 ? '999+' : String(count);
|
|
};
|
|
|
|
// Tab switching
|
|
const activeTab = ref('person');
|
|
const switchToTab = (tab) => {
|
|
activeTab.value = tab;
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<Tabs v-model="activeTab" class="mt-2">
|
|
<TabsList class="flex w-full bg-white gap-2 p-1">
|
|
<TabsTrigger value="person" class="border border-gray-200 data-[state=active]:bg-primary-50 data-[state=active]:text-primary-700 flex-1 py-2">
|
|
<div class="flex items-center gap-2">
|
|
<FontAwesomeIcon :icon="faUser" class="h-4 w-4" />
|
|
<span>Oseba</span>
|
|
</div>
|
|
</TabsTrigger>
|
|
<TabsTrigger value="addresses" class="border border-gray-200 data-[state=active]:bg-primary-50 data-[state=active]:text-primary-700 flex-1 py-2 px-3">
|
|
<div class="flex items-center justify-between gap-2 w-full">
|
|
<div class="flex items-center gap-2">
|
|
<FontAwesomeIcon :icon="faMapMarkerAlt" class="h-4 w-4" />
|
|
<span>Naslovi</span>
|
|
</div>
|
|
<span
|
|
v-if="addressesCount > 0"
|
|
class="h-5 min-w-5 px-1.5 flex items-center justify-center rounded-full bg-red-600 text-white text-xs font-semibold leading-tight shrink-0"
|
|
>
|
|
{{ formatBadgeCount(addressesCount) }}
|
|
</span>
|
|
</div>
|
|
</TabsTrigger>
|
|
<TabsTrigger value="phones" class="border border-gray-200 data-[state=active]:bg-primary-50 data-[state=active]:text-primary-700 flex-1 py-2 px-3">
|
|
<div class="flex items-center justify-between gap-2 w-full">
|
|
<div class="flex items-center gap-2">
|
|
<FontAwesomeIcon :icon="faPhone" class="h-4 w-4" />
|
|
<span>Telefonske</span>
|
|
</div>
|
|
<span
|
|
v-if="phonesCount > 0"
|
|
class="h-5 min-w-5 px-1.5 flex items-center justify-center rounded-full bg-red-600 text-white text-xs font-semibold leading-tight shrink-0"
|
|
>
|
|
{{ formatBadgeCount(phonesCount) }}
|
|
</span>
|
|
</div>
|
|
</TabsTrigger>
|
|
<TabsTrigger value="emails" class="border border-gray-200 data-[state=active]:bg-primary-50 data-[state=active]:text-primary-700 flex-1 py-2 px-3">
|
|
<div class="flex items-center justify-between gap-2 w-full">
|
|
<div class="flex items-center gap-2">
|
|
<FontAwesomeIcon :icon="faEnvelope" class="h-4 w-4" />
|
|
<span>Email</span>
|
|
</div>
|
|
<span
|
|
v-if="emailsCount > 0"
|
|
class="h-5 min-w-5 px-1.5 flex items-center justify-center rounded-full bg-red-600 text-white text-xs font-semibold leading-tight shrink-0"
|
|
>
|
|
{{ formatBadgeCount(emailsCount) }}
|
|
</span>
|
|
</div>
|
|
</TabsTrigger>
|
|
<TabsTrigger value="trr" class="border border-gray-200 data-[state=active]:bg-primary-50 data-[state=active]:text-primary-700 flex-1 py-2 px-3">
|
|
<div class="flex items-center justify-between gap-2 w-full">
|
|
<div class="flex items-center gap-2">
|
|
<FontAwesomeIcon :icon="faUniversity" class="h-4 w-4" />
|
|
<span>TRR</span>
|
|
</div>
|
|
<span
|
|
v-if="trrsCount > 0"
|
|
class="h-5 min-w-5 px-1.5 flex items-center justify-center rounded-full bg-red-600 text-white text-xs font-semibold leading-tight shrink-0"
|
|
>
|
|
{{ formatBadgeCount(trrsCount) }}
|
|
</span>
|
|
</div>
|
|
</TabsTrigger>
|
|
</TabsList>
|
|
<TabsContent value="person" class="py-2">
|
|
<PersonInfoPersonTab
|
|
:person="person"
|
|
:edit="edit"
|
|
:person-edit="personEdit"
|
|
@edit="handlePersonEdit"
|
|
/>
|
|
</TabsContent>
|
|
|
|
<TabsContent value="addresses" class="py-4">
|
|
<PersonInfoAddressesTab
|
|
:person="person"
|
|
:edit="edit"
|
|
@add="handleAddressAdd"
|
|
@edit="handleAddressEdit"
|
|
@delete="handleAddressDelete"
|
|
/>
|
|
</TabsContent>
|
|
|
|
<TabsContent value="phones" class="py-4">
|
|
<PersonInfoPhonesTab
|
|
:person="person"
|
|
:edit="edit"
|
|
:enable-sms="enableSms && !!clientCaseUuid"
|
|
@add="handlePhoneAdd"
|
|
@edit="handlePhoneEdit"
|
|
@delete="handlePhoneDelete"
|
|
@sms="handlePhoneSms"
|
|
/>
|
|
</TabsContent>
|
|
|
|
<TabsContent value="emails" class="py-4">
|
|
<PersonInfoEmailsTab
|
|
:person="person"
|
|
:edit="edit"
|
|
@add="handleEmailAdd"
|
|
@edit="handleEmailEdit"
|
|
@delete="handleEmailDelete"
|
|
/>
|
|
</TabsContent>
|
|
|
|
<TabsContent value="trr" class="py-4">
|
|
<PersonInfoTrrTab
|
|
:person="person"
|
|
:edit="edit"
|
|
@add="handleTrrAdd"
|
|
@edit="handleTrrEdit"
|
|
@delete="handleTrrDelete"
|
|
/>
|
|
</TabsContent>
|
|
</Tabs>
|
|
|
|
<!-- Person Update Dialog -->
|
|
<PersonUpdateForm
|
|
:show="drawerUpdatePerson"
|
|
@close="drawerUpdatePerson = false"
|
|
:person="person"
|
|
/>
|
|
|
|
<!-- Address Dialogs -->
|
|
<AddressCreateForm
|
|
:show="drawerAddAddress && !editAddress"
|
|
@close="closeDrawerAddAddress"
|
|
:person="person"
|
|
:types="types.address_types"
|
|
:id="editAddressId"
|
|
:edit="editAddress"
|
|
/>
|
|
<AddressUpdateForm
|
|
:show="drawerAddAddress && editAddress"
|
|
@close="closeDrawerAddAddress"
|
|
:person="person"
|
|
:types="types.address_types"
|
|
:id="editAddressId"
|
|
/>
|
|
|
|
<!-- Phone Dialogs -->
|
|
<PhoneCreateForm
|
|
:show="drawerAddPhone && !editPhone"
|
|
@close="closeDrawerAddPhone"
|
|
:person="person"
|
|
:types="types.phone_types"
|
|
/>
|
|
<PhoneUpdateForm
|
|
:show="drawerAddPhone && editPhone"
|
|
@close="closeDrawerAddPhone"
|
|
:person="person"
|
|
:types="types.phone_types"
|
|
:id="editPhoneId"
|
|
/>
|
|
|
|
<!-- Email Dialogs -->
|
|
<EmailCreateForm
|
|
:show="drawerAddEmail && !editEmail"
|
|
@close="closeDrawerAddEmail"
|
|
:person="person"
|
|
:types="types.email_types ?? []"
|
|
:is-client-context="!!person?.client"
|
|
/>
|
|
<EmailUpdateForm
|
|
:show="drawerAddEmail && editEmail"
|
|
@close="closeDrawerAddEmail"
|
|
:person="person"
|
|
:types="types.email_types ?? []"
|
|
:id="editEmailId"
|
|
:is-client-context="!!person?.client"
|
|
/>
|
|
|
|
<!-- TRR Dialogs -->
|
|
<TrrCreateForm
|
|
:show="drawerAddTrr && !editTrr"
|
|
@close="closeDrawerAddTrr"
|
|
:person="person"
|
|
:types="types.trr_types ?? []"
|
|
:banks="types.banks ?? []"
|
|
:currencies="types.currencies ?? ['EUR']"
|
|
/>
|
|
<TrrUpdateForm
|
|
:show="drawerAddTrr && editTrr"
|
|
@close="closeDrawerAddTrr"
|
|
:person="person"
|
|
:types="types.trr_types ?? []"
|
|
:banks="types.banks ?? []"
|
|
:currencies="types.currencies ?? ['EUR']"
|
|
:id="editTrrId"
|
|
/>
|
|
|
|
<!-- Confirm Deletion Dialog -->
|
|
<ConfirmDialog
|
|
:show="confirm.show"
|
|
:title="confirm.title"
|
|
:message="confirm.message"
|
|
:item-name="confirm.itemName"
|
|
confirm-text="Izbriši"
|
|
cancel-text="Prekliči"
|
|
:danger="true"
|
|
@close="closeConfirm"
|
|
@confirm="onConfirmDelete"
|
|
/>
|
|
|
|
<!-- SMS Dialog -->
|
|
<PersonInfoSmsDialog
|
|
v-if="clientCaseUuid"
|
|
:show="showSmsDialog"
|
|
:phone="smsTargetPhone"
|
|
:client-case-uuid="clientCaseUuid"
|
|
:sms-profiles="smsProfiles"
|
|
:sms-senders="smsSenders"
|
|
:sms-templates="smsTemplates"
|
|
@close="closeSmsDialog"
|
|
/>
|
|
</template>
|