Teren-app/resources/js/Components/PersonInfo/PersonInfoGrid.vue
Simon Pocrnjič b7fa2d261b changes UI
2025-11-04 18:53:23 +01:00

499 lines
14 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 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">Oseba</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">
<span>Naslovi</span>
<span
v-if="addressesCount > 0"
class="h-5 min-w-[20px] 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">
<span>Telefonske</span>
<span
v-if="phonesCount > 0"
class="h-5 min-w-[20px] 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">
<span>Email</span>
<span
v-if="emailsCount > 0"
class="h-5 min-w-[20px] 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">
<span>TRR</span>
<span
v-if="trrsCount > 0"
class="h-5 min-w-[20px] 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>