Fix calendar implementation issues

This commit is contained in:
Karl Ludwig Weise
2026-07-01 20:13:30 +02:00
parent d6a527b89f
commit c7df68b908
4 changed files with 41 additions and 38 deletions
@@ -126,7 +126,7 @@
<div class="relative flex w-full flex-col">
{#if isWeekView && items}
{@const isSelected = selectedDate.toString() === items[0]?.date}
{@const isSelected = selectedDate.toString() === day.toString()}
{@const isToday = toCalendarDate(day).toString() === today(getLocalTimeZone()).toString()}
<Text
style="xs"
@@ -136,7 +136,10 @@
isToday && "rounded-sm border-2 border-red-500/50 px-1",
)}
>
{toDisplayDateTime(day.toDate(getLocalTimeZone()), { weekday: "short" })}
{toDisplayDateTime(day.toDate(getLocalTimeZone()), {
day: "numeric",
weekday: "short",
})}
</Text>
<Separator
orientation="vertical"
@@ -2,18 +2,23 @@
import { m } from "$i18n/messages";
import { getLocale } from "$i18n/runtime";
import { Button, buttonVariants } from "$lib/components/ui/button";
import { CalendarDate, getLocalTimeZone, today } from "@internationalized/date";
import {
CalendarDate,
getLocalTimeZone,
isWeekend,
today,
type DateValue,
} from "@internationalized/date";
import { ChevronLeft, ChevronRight } from "@lucide/svelte";
import * as Popover from "$lib/components/ui/popover/index.js";
import { cn } from "$lib/utils";
import CalendarMonth from "./CalendarMonth.svelte";
import type { TAppointmentFilter } from "$lib/types/calendar";
import type { OnChangeFn } from "vaul-svelte";
import type { CalendarView } from "../types";
let {
selectedDate = $bindable(),
view,
view = $bindable(),
shownAppointments,
shownChannels,
shownAgents,
@@ -50,8 +55,11 @@
selectedDate = today(getLocalTimeZone());
};
const onSelectDay: OnChangeFn<unknown> = () => {
const onSelectDay = (v: DateValue | undefined) => {
open = false;
if (view === "week-workdays" && v && isWeekend(v, getLocale())) {
view = "week";
}
};
const getISOWeek = (date: CalendarDate): { week: number; year: number } => {
@@ -76,7 +84,7 @@
<div
class="flex flex-col items-start justify-between gap-2 min-[500px]:flex-row min-[500px]:items-center"
>
<div class="-ml-1 flex w-87.5 items-center justify-between gap-5">
<div class={cn("-ml-1 flex items-center justify-between gap-5", isWeekView ? "w-60" : "w-75")}>
<Button size="sm" variant="ghost" class="h-6 p-1!" onclick={prev}>
<ChevronLeft />
</Button>
@@ -17,14 +17,12 @@
latestEndHour,
scale = $bindable(),
isLoading,
isWeekView,
}: {
day: CalendarDate;
earliestStartHour: number;
latestEndHour: number;
scale: number;
isLoading: boolean;
isWeekView?: boolean;
} = $props();
const hourSize = $derived(60 * scale);
@@ -73,15 +71,13 @@
class="relative z-0 flex w-full items-start justify-between transition-all duration-200 select-none"
style:height={`${hourSize}px`}
>
{#if !isWeekView}
<Text style="xs" class="text-muted-foreground -mt-2 w-16 shrink-0">
{Intl.DateTimeFormat(getLocale(), {
hour: "2-digit",
minute: "2-digit",
timeZone: getLocalTimeZone().toString(),
}).format(toCalendarDateTime(day).set({ hour }).toDate(getLocalTimeZone()))}
</Text>
{/if}
<Text style="xs" class="text-muted-foreground -mt-2 w-16 shrink-0">
{Intl.DateTimeFormat(getLocale(), {
hour: "2-digit",
minute: "2-digit",
timeZone: getLocalTimeZone().toString(),
}).format(toCalendarDateTime(day).set({ hour }).toDate(getLocalTimeZone()))}
</Text>
<Separator class="bg-muted-foreground -z-10 -ml-0.5 h-px w-auto! grow" />
<Separator class="bg-secondary absolute top-1/2 right-0 left-16 h-px w-auto!" />
</div>
@@ -66,13 +66,6 @@
});
let scale = $state(page.data.calendarZoom);
$effect(() => {
const getMonth = (x: string | undefined) => (x ? new Date(x).getMonth() + 1 : undefined);
if (!calendar || getMonth(calendar?.period.startDate) !== getMonth(selectedDate.toString())) {
updateCalendar();
}
});
$effect(() => {
if (calendar && history.state["sveltekit:states"]?.appointmentId) {
// Wait 100ms to ensure that the calendar items are rendered
@@ -96,21 +89,24 @@
"date" in page.state &&
"appointmentId" in page.state
) {
shownAppointments = "all";
// navigate to date
const date = convertDate(page.state.date as string);
if (date.toString() !== selectedDate.toString()) {
selectedDate = date;
replaceState("", { appointmentId: page.state.appointmentId });
} else {
if (calendar) {
openAppointmentById(
calendar,
channels,
history.state["sveltekit:states"].appointmentId,
() => {
replaceState("", {});
},
);
}
}
// open appointment
if (calendar) {
openAppointmentById(
calendar,
channels,
history.state["sveltekit:states"].appointmentId,
() => {
replaceState("", {});
},
);
}
}
});
@@ -142,7 +138,7 @@
<SidebarLayout breakcrumbs={[{ label: m["nav.calendar"](), href: ROUTES.DASHBOARD.CALENDAR }]}>
<div class="flex flex-col gap-10">
<CalendarHeader bind:selectedDate {view} {shownAppointments} {shownAgents} {shownChannels} />
<CalendarHeader bind:selectedDate bind:view {shownAppointments} {shownAgents} {shownChannels} />
<div
class="flex transition-all duration-200"
style:min-height={`${(hours.to * 30 + 60) * scale}px`}