Dashboard final version, TODO: update main sidebar menu

This commit is contained in:
Simon Pocrnjič
2025-11-23 21:33:01 +01:00
parent c3de189e9d
commit c1ac92efbf
67 changed files with 5195 additions and 844 deletions
@@ -4,7 +4,13 @@ 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 {
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";
@@ -24,6 +30,7 @@ import PersonInfoPhonesTab from "./PersonInfoPhonesTab.vue";
import PersonInfoEmailsTab from "./PersonInfoEmailsTab.vue";
import PersonInfoTrrTab from "./PersonInfoTrrTab.vue";
import PersonInfoSmsDialog from "./PersonInfoSmsDialog.vue";
import { Badge } from "@/Components/ui/badge";
const props = defineProps({
person: Object,
@@ -102,7 +109,7 @@ const closeDrawerAddAddress = () => {
editAddress.value = false;
editAddressId.value = 0;
if (!wasEdit) {
switchToTab('addresses');
switchToTab("addresses");
}
};
@@ -122,7 +129,7 @@ const closeDrawerAddPhone = () => {
editPhone.value = false;
editPhoneId.value = 0;
if (!wasEdit) {
switchToTab('phones');
switchToTab("phones");
}
};
@@ -139,7 +146,7 @@ const closeDrawerAddEmail = () => {
editEmail.value = false;
editEmailId.value = 0;
if (!wasEdit) {
switchToTab('emails');
switchToTab("emails");
}
};
@@ -156,7 +163,7 @@ const closeDrawerAddTrr = () => {
editTrr.value = false;
editTrrId.value = 0;
if (!wasEdit) {
switchToTab('trr');
switchToTab("trr");
}
};
@@ -181,35 +188,29 @@ const closeConfirm = () => {
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();
},
}
);
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();
},
}
);
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 }),
@@ -223,21 +224,18 @@ const onConfirmDelete = async () => {
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();
},
}
);
} 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();
},
});
}
};
@@ -278,20 +276,22 @@ 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 || [];
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);
return count >= 999 ? "999+" : String(count);
};
// Tab switching
const activeTab = ref('person');
const activeTab = ref("person");
const switchToTab = (tab) => {
activeTab.value = tab;
};
@@ -300,66 +300,85 @@ const switchToTab = (tab) => {
<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">
<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">
<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
<Badge
variant="secondary"
class="h-5 min-w-5 flex items-center justify-center rounded-full px-1 font-mono tabular-nums text-sm bg-primary-50 text-primary-700"
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>
</Badge>
</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">
<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
<Badge
variant="secondary"
class="h-5 min-w-5 flex items-center justify-center rounded-full px-1 font-mono tabular-nums text-sm bg-primary-50 text-primary-700"
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>
</Badge>
</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">
<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
<Badge
variant="secondary"
class="h-5 min-w-5 flex items-center justify-center rounded-full px-1 font-mono tabular-nums text-sm bg-primary-50 text-primary-700"
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>
</Badge>
</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">
<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
<Badge
variant="secondary"
class="h-5 min-w-5 flex items-center justify-center rounded-full px-1 font-mono tabular-nums text-sm bg-primary-50 text-primary-700"
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>
</Badge>
</div>
</TabsTrigger>
</TabsList>