mirror of
https://github.com/open-reception/appointment-booking-software.git
synced 2026-09-23 17:34:51 +02:00
Harden navigation for notifications on a all pages
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { goto } from "$app/navigation";
|
||||
import { resolve } from "$app/paths";
|
||||
import { page } from "$app/state";
|
||||
import { m } from "$i18n/messages";
|
||||
import { getLocale } from "$i18n/runtime";
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
@@ -16,8 +17,10 @@
|
||||
|
||||
let {
|
||||
item,
|
||||
closePopover,
|
||||
}: {
|
||||
item: TNotification;
|
||||
closePopover: () => void;
|
||||
} = $props();
|
||||
|
||||
const channels = $derived($channelsStore.channels);
|
||||
@@ -53,12 +56,23 @@
|
||||
class=" flex h-auto w-full shrink flex-col items-start gap-1 rounded-none px-3 last:rounded-b-md focus:ring-inset"
|
||||
onclick={() => {
|
||||
if (appointment) {
|
||||
goto(resolve(ROUTES.DASHBOARD.CALENDAR), {
|
||||
state: {
|
||||
date: appointment.appointmentDate,
|
||||
appointmentId: appointment.id,
|
||||
},
|
||||
});
|
||||
closePopover();
|
||||
if (page.url.pathname === ROUTES.DASHBOARD.CALENDAR) {
|
||||
goto(resolve(ROUTES.DASHBOARD.CALENDAR), {
|
||||
state: {
|
||||
isNavigatingOnCalendarPage: true,
|
||||
date: appointment.appointmentDate,
|
||||
appointmentId: appointment.id,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
goto(resolve(ROUTES.DASHBOARD.CALENDAR), {
|
||||
state: {
|
||||
date: appointment.appointmentDate,
|
||||
appointmentId: appointment.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
{/if}
|
||||
{#each notifications as notification (notification.id)}
|
||||
<div class="[&+&]:border-t-muted relative [&+&]:border-t">
|
||||
<NotificationItem item={notification} />
|
||||
<NotificationItem item={notification} closePopover={() => (open = false)} />
|
||||
<Button
|
||||
variant="ghost"
|
||||
class="absolute top-1.5 right-1.5 rounded-md p-1!"
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
{/if}
|
||||
</Dialog.Trigger>
|
||||
{/if}
|
||||
<Dialog.Content class="max-h-[95vh] sm:max-w-[425px]">
|
||||
<Dialog.Content class="max-h-[95vh] sm:max-w-106.25">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title class={cn(description ? "" : "-mb-1")}>{title}</Dialog.Title>
|
||||
{#if description}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import { Text } from "$lib/components/ui/typography";
|
||||
import { type CurAppointmentItem } from "$lib/stores/calendar";
|
||||
import { getLocalTimeZone } from "@internationalized/date";
|
||||
import { Calendar, Mail, Phone } from "@lucide/svelte";
|
||||
import { Calendar, Mail, Phone, User } from "@lucide/svelte";
|
||||
import { cancelAppointment } from "./utils";
|
||||
import { toast } from "svelte-sonner";
|
||||
import { m } from "$i18n/messages";
|
||||
@@ -42,6 +42,12 @@
|
||||
|
||||
{#if item.appointment.appointment}
|
||||
<div class="flex flex-col items-start gap-3">
|
||||
<div class="flex gap-2 p-1">
|
||||
<User class="size-4 " />
|
||||
<Text style="sm">
|
||||
{item.decrypted.name}
|
||||
</Text>
|
||||
</div>
|
||||
<div class="flex flex-col items-start gap-2">
|
||||
<Button
|
||||
class="h-auto w-auto justify-start gap-2 rounded-sm p-1"
|
||||
|
||||
@@ -122,7 +122,7 @@ export function positionItems(items: TCalendarItem[] | undefined) {
|
||||
export const cancelAppointment = async (opts: { tenant: string; appointment: string }) => {
|
||||
if (!browser) return;
|
||||
|
||||
const res = await fetch(`/api/tenants/${opts.tenant}/appointments/${opts.appointment}`, {
|
||||
const res = await fetch(`/api/tenants/${opts.tenant}/appointments/${opts.appointment}/delete`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { replaceState } from "$app/navigation";
|
||||
import { m } from "$i18n/messages";
|
||||
import { MaxPageWidth } from "$lib/components/layouts/max-page-width";
|
||||
import { SidebarLayout } from "$lib/components/layouts/sidebar-layout";
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import { ResponsiveDialog } from "$lib/components/ui/responsive-dialog";
|
||||
import { ROUTES } from "$lib/const/routes";
|
||||
import { agents as agentsStore } from "$lib/stores/agents";
|
||||
import { auth } from "$lib/stores/auth";
|
||||
import { calendarStore } from "$lib/stores/calendar";
|
||||
import { channels as channelsStore } from "$lib/stores/channels";
|
||||
@@ -26,13 +28,22 @@
|
||||
import CalendarFilters from "./(components)/CalendarFilters.svelte";
|
||||
import CalendarHeader from "./(components)/CalendarHeader.svelte";
|
||||
import { fetchCalendar, openAppointmentById } from "./(components)/utils";
|
||||
import { staffCrypto } from "$lib/stores/staff-crypto";
|
||||
import { replaceState } from "$app/navigation";
|
||||
import { page } from "$app/state";
|
||||
|
||||
const convertDate = (dateStr: string) => {
|
||||
const zonedDateTime = parseAbsoluteToLocal(dateStr);
|
||||
return toCalendarDate(zonedDateTime);
|
||||
};
|
||||
|
||||
const tenantId = $derived($auth.user?.tenantId);
|
||||
const curItem = $derived($calendarStore.curItem);
|
||||
const channels = $derived($channelsStore.channels);
|
||||
let startDate: CalendarDate = $state(today(getLocalTimeZone()));
|
||||
const agents = $derived($agentsStore.agents);
|
||||
let startDate: CalendarDate = $state(
|
||||
history.state["sveltekit:states"]?.date
|
||||
? convertDate(history.state["sveltekit:states"].date)
|
||||
: today(getLocalTimeZone()),
|
||||
);
|
||||
let calender: TCalendar | undefined = $state();
|
||||
let shownAppointments: TAppointmentFilter = $state("all");
|
||||
let shownChannels: string[] = $state([]);
|
||||
@@ -55,33 +66,47 @@
|
||||
return { from: Math.min(...from), to: Math.max(...to) };
|
||||
});
|
||||
let scale = $state(1);
|
||||
let openAppointmentAfterUpdate: string | undefined = $state();
|
||||
|
||||
$effect(() => {
|
||||
updateCalendar();
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
// Wait 100ms to ensure that the calendar items are rendered
|
||||
setTimeout(() => {
|
||||
if (items && openAppointmentAfterUpdate) {
|
||||
openAppointmentById(items, openAppointmentAfterUpdate, () => {
|
||||
openAppointmentAfterUpdate = undefined;
|
||||
if (items && history.state["sveltekit:states"]?.appointmentId) {
|
||||
// Wait 100ms to ensure that the calendar items are rendered
|
||||
setTimeout(() => {
|
||||
openAppointmentById(items, history.state["sveltekit:states"].appointmentId, () => {
|
||||
replaceState("", {});
|
||||
});
|
||||
}
|
||||
}, 100);
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
if (history.state["sveltekit:states"]?.date) {
|
||||
const isoDateString = history.state["sveltekit:states"].date;
|
||||
const zonedDateTime = parseAbsoluteToLocal(isoDateString);
|
||||
startDate = toCalendarDate(zonedDateTime);
|
||||
const { date, ...rest } = history.state["sveltekit:states"];
|
||||
replaceState("", rest);
|
||||
}
|
||||
});
|
||||
|
||||
if (history.state["sveltekit:states"]?.appointmentId) {
|
||||
openAppointmentAfterUpdate = history.state["sveltekit:states"].appointmentId;
|
||||
// Navigating to appointment, if calendar is already mounted
|
||||
$effect(() => {
|
||||
if (
|
||||
"isNavigatingOnCalendarPage" in page.state &&
|
||||
"date" in page.state &&
|
||||
"appointmentId" in page.state
|
||||
) {
|
||||
const date = convertDate(page.state.date as string);
|
||||
if (date.toString() !== startDate.toString()) {
|
||||
startDate = date;
|
||||
replaceState("", { appointmentId: page.state.appointmentId });
|
||||
} else {
|
||||
if (items) {
|
||||
openAppointmentById(items, history.state["sveltekit:states"].appointmentId, () => {
|
||||
replaceState("", {});
|
||||
});
|
||||
}
|
||||
}
|
||||
replaceState("", "");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -202,9 +227,10 @@
|
||||
|
||||
{#if curItem && tenantId}
|
||||
{@const channel = channels.find((c) => c.id === curItem.appointment.channelId)}
|
||||
{@const agent = agents.find((a) => a.id === curItem.appointment.appointment?.agentId)}
|
||||
<ResponsiveDialog
|
||||
id="current-calendar-item"
|
||||
title={curItem.decrypted.name}
|
||||
title={agent?.name || "unkown agent"}
|
||||
description={channel ? getCurrentTranlslation(channel.names) : undefined}
|
||||
triggerHidden={true}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user