Updated Application icon and notifcation pagination items per page, and updated NotificationsBell

This commit is contained in:
Simon Pocrnjič 2026-01-18 19:49:48 +01:00
parent cc4c07717e
commit 068bbdf583
6 changed files with 83 additions and 99 deletions

View File

@ -19,7 +19,7 @@ public function unread(Request $request)
}
$today = now()->toDateString();
$perPage = max(1, min(100, (int) $request->integer('perPage', 15)));
$perPage = max(1, min(100, (int) $request->integer('per_page', 15)));
$search = trim((string) $request->input('search', ''));
$clientUuid = trim((string) $request->input('client', ''));
$clientId = null;

View File

@ -251,19 +251,17 @@ function isActive(patterns) {
: 'sticky top-0 h-screen overflow-y-auto',
]"
>
<div
class="h-16 px-4 flex items-center justify-between border-b border-gray-200 bg-white"
>
<div class="h-16 px-4 flex items-center border-b border-sidebar-border bg-sidebar">
<Link
:href="route('dashboard')"
class="flex items-center gap-2 hover:opacity-80 transition-opacity"
class="flex items-center gap-1 hover:opacity-80 transition-opacity"
>
<ApplicationMark />
<span
v-if="!sidebarCollapsed"
class="text-sm font-semibold text-gray-900 transition-opacity"
class="text-lg font-semibold text-sidebar-foreground transition-opacity"
>
Admin
Administrator
</span>
</Link>
</div>

View File

@ -10,19 +10,6 @@ import GlobalSearch from "./Partials/GlobalSearch.vue";
import NotificationsBell from "./Partials/NotificationsBell.vue";
import ToastContainer from "@/Components/Toast/ToastContainer.vue";
import { Button } from "@/Components/ui/button";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import {
faMobileScreenButton,
faGaugeHigh,
faLayerGroup,
faUserGroup,
faFolderOpen,
faFileImport,
faTableList,
faFileCirclePlus,
faMap,
faGear,
} from "@fortawesome/free-solid-svg-icons";
import { MenuIcon } from "lucide-vue-next";
import { SearchIcon } from "lucide-vue-next";
import { ChevronDownIcon } from "lucide-vue-next";
@ -310,18 +297,18 @@ function isActive(patterns) {
]"
>
<div
class="h-16 px-4 flex items-center justify-between border-b border-sidebar-border bg-sidebar"
class="h-16 px-4 flex items-center border-b border-sidebar-border bg-sidebar"
>
<Link
:href="route('dashboard')"
class="flex items-center gap-2 hover:opacity-80 transition-opacity"
class="flex items-center gap-1 hover:opacity-80 transition-opacity"
>
<ApplicationMark />
<span
v-if="!sidebarCollapsed"
class="text-sm font-semibold text-sidebar-foreground transition-opacity"
class="text-lg font-semibold text-sidebar-foreground transition-opacity"
>
Teren
Aplikacija
</span>
</Link>
</div>

View File

@ -149,14 +149,14 @@ const closeSearch = () => (searchOpen.value = false);
>
<Link
:href="route('phone.index')"
class="flex items-center gap-2 hover:opacity-80 transition-opacity"
class="flex items-center gap-1 hover:opacity-80 transition-opacity"
>
<ApplicationMark />
<span
v-if="showLabels"
class="text-sm font-semibold text-sidebar-foreground transition-opacity"
class="text-lg font-semibold text-sidebar-foreground transition-opacity"
>
Teren
Mobitel
</span>
</Link>
</div>

View File

@ -1,12 +1,12 @@
<script setup>
import { computed, onMounted, ref, watch } from "vue";
import { usePage, Link, router } from "@inertiajs/vue3";
import Dropdown from "@/Components/Dropdown.vue";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { faBell } from "@fortawesome/free-solid-svg-icons";
import { BellIcon } from "lucide-vue-next";
import { Badge } from "@/Components/ui/badge";
import { Button } from "@/Components/ui/button";
import { Popover, PopoverContent, PopoverTrigger } from "@/Components/ui/popover";
import { ScrollArea } from "@/Components/ui/scroll-area";
import { Separator } from "@/Components/ui/separator";
const page = usePage();
const due = computed(
@ -83,12 +83,8 @@ function markRead(item) {
</script>
<template>
<Dropdown
align="right"
width="72"
:content-classes="['p-0', 'bg-white', 'max-h-96', 'overflow-hidden']"
>
<template #trigger>
<Popover>
<PopoverTrigger as-child>
<Button variant="ghost" size="default" class="relative">
<BellIcon />
@ -100,32 +96,30 @@ function markRead(item) {
{{ count }}
</Badge>
</Button>
</template>
</PopoverTrigger>
<template #content>
<div
class="px-3 py-2 text-xs text-gray-400 border-b sticky top-0 bg-white z-10 flex items-center justify-between"
>
<span>Zapadejo danes</span>
<PopoverContent align="end" class="w-96 p-0">
<div class="px-4 py-3 flex items-center justify-between border-b">
<span class="text-sm font-medium">Zapadejo danes</span>
<Link
:href="route('notifications.unread')"
class="text-indigo-600 hover:text-indigo-700"
class="text-sm text-primary hover:underline"
>Vsa obvestila</Link
>
</div>
<!-- Scrollable content area with max height -->
<div class="max-h-80 overflow-auto">
<div v-if="!count" class="px-3 py-3 text-sm text-gray-500">
Ni zapadlih aktivnosti danes.
<ScrollArea class="h-72">
<div v-if="!count" class="px-4 py-8 text-center">
<p class="text-sm text-muted-foreground">Ni zapadlih aktivnosti danes.</p>
</div>
<ul v-else class="divide-y">
<li
<div v-else class="divide-y">
<div
v-for="item in items"
:key="item.id"
class="px-3 py-2 text-sm flex items-start gap-2"
class="px-4 py-3 flex items-start gap-3 hover:bg-accent/50 transition-colors"
>
<div class="flex-1 min-w-0">
<div class="font-medium text-gray-800 truncate">
<div class="flex-1 min-w-0 space-y-1">
<div class="font-medium truncate">
<template v-if="item.contract?.uuid">
Pogodba:
<Link
@ -135,7 +129,7 @@ function markRead(item) {
client_case: item.contract.client_case.uuid,
})
"
class="text-indigo-600 hover:text-indigo-700 hover:underline"
class="text-primary hover:underline"
>
{{ item.contract?.reference || "—" }}
</Link>
@ -148,7 +142,7 @@ function markRead(item) {
:href="
route('clientCase.show', { client_case: item.client_case.uuid })
"
class="text-indigo-600 hover:text-indigo-700 hover:underline"
class="text-primary hover:underline"
>
{{ item.client_case?.person?.full_name || "—" }}
</Link>
@ -157,37 +151,38 @@ function markRead(item) {
</div>
<!-- Partner / Client full name (use contract.client when available; fallback to case.client) -->
<div
class="text-xs text-gray-500 truncate"
class="text-xs text-muted-foreground truncate"
v-if="item.contract?.client?.person?.full_name"
>
Partner: {{ item.contract.client.person.full_name }}
</div>
<div
class="text-xs text-gray-500 truncate"
class="text-xs text-muted-foreground truncate"
v-else-if="item.client_case?.client?.person?.full_name"
>
Partner: {{ item.client_case.client.person.full_name }}
</div>
<div class="text-gray-600 truncate" v-if="item.contract">
<div class="text-sm truncate" v-if="item.contract">
{{ fmtEUR(item.contract?.account?.balance_amount) }}
</div>
</div>
<div class="flex flex-col items-end gap-1">
<div class="text-xs text-gray-500 whitespace-nowrap">
<div class="flex flex-col items-end gap-1.5 shrink-0">
<div class="text-xs text-muted-foreground whitespace-nowrap">
{{ fmtDate(item.due_date) }}
</div>
<button
type="button"
class="text-[11px] text-gray-400 hover:text-gray-600"
<Button
variant="ghost"
size="sm"
class="h-6 px-2 text-xs"
@click.stop="markRead(item)"
title="Skrij obvestilo"
>
Skrij
</button>
</Button>
</div>
</li>
</ul>
</div>
</template>
</Dropdown>
</div>
</ScrollArea>
</PopoverContent>
</Popover>
</template>

View File

@ -265,20 +265,22 @@ const update = () => {
// Transform actions from array of IDs to array of objects
const actionsPayload = form.actions
.map(id => {
const action = props.actions.find(a => a.id === Number(id) || a.id === id);
.map((id) => {
const action = props.actions.find((a) => a.id === Number(id) || a.id === id);
if (!action) {
console.warn('Action not found for id:', id);
console.warn("Action not found for id:", id);
return null;
}
return { id: action.id, name: action.name };
})
.filter(Boolean); // Remove null entries
form.transform((data) => ({
form
.transform((data) => ({
...data,
actions: actionsPayload
})).put(route("settings.decisions.update", { id: form.id }), {
actions: actionsPayload,
}))
.put(route("settings.decisions.update", { id: form.id }), {
onSuccess: () => {
closeEditDrawer();
},
@ -299,20 +301,22 @@ const store = () => {
// Transform actions from array of IDs to array of objects
const actionsPayload = createForm.actions
.map(id => {
const action = props.actions.find(a => a.id === Number(id) || a.id === id);
.map((id) => {
const action = props.actions.find((a) => a.id === Number(id) || a.id === id);
if (!action) {
console.warn('Action not found for id:', id);
console.warn("Action not found for id:", id);
return null;
}
return { id: action.id, name: action.name };
})
.filter(Boolean); // Remove null entries
createForm.transform((data) => ({
createForm
.transform((data) => ({
...data,
actions: actionsPayload
})).post(route("settings.decisions.store"), {
actions: actionsPayload,
}))
.post(route("settings.decisions.store"), {
onSuccess: () => {
closeCreateDrawer();
},
@ -665,7 +669,7 @@ const destroyDecision = () => {
</div>
<div class="flex items-center gap-2 self-end">
<label class="flex items-center gap-2 text-sm">
<Checkbox v-model:checked="ev.active" />
<Checkbox v-model="ev.active" />
Aktivno
</label>
<Button
@ -703,7 +707,7 @@ const destroyDecision = () => {
</div>
<div class="flex items-end">
<label class="flex items-center gap-2 text-sm mt-6">
<Checkbox v-model:checked="ev.config.deactivate_previous" />
<Checkbox v-model="ev.config.deactivate_previous" />
Deaktiviraj prejšnje
</label>
</div>