This commit is contained in:
Karl Ludwig Weise
2026-01-21 21:53:53 +01:00
parent 9c86b28182
commit 214e201f21
20 changed files with 56 additions and 32 deletions
@@ -12,6 +12,7 @@
import AgentsIcon from "@lucide/svelte/icons/user-star";
import { m } from "$i18n/messages";
import type { NavItem } from "..";
import { resolve } from "path";
const items: NavItem[] = [
{
@@ -66,7 +67,8 @@
<Sidebar.MenuItem>
<Sidebar.MenuButton isActive={isCurrentSection(item.url)} tooltipContent={item.title}>
{#snippet child({ props })}
<a href={item.url} {...props}>
<!-- eslint-disable-next-line svelte/no-navigation-without-resolve -->
<a href={resolve(item.url)} {...props}>
<item.icon />
<Text style="md" class="ml-2">{item.title}</Text>
</a>
@@ -42,6 +42,7 @@
{#if $auth.user && item.roles.includes($auth.user?.role)}
<Sidebar.MenuItem>
<Sidebar.MenuButton isActive={isCurrentSection(item.url)} tooltipContent={item.title}>
<!-- eslint-disable svelte/no-navigation-without-resolve -->
{#snippet child({ props })}
<a
href={item.url}
@@ -55,6 +56,7 @@
{/if}
</a>
{/snippet}
<!-- eslint-enable svelte/no-navigation-without-resolve -->
</Sidebar.MenuButton>
</Sidebar.MenuItem>
{/if}
@@ -12,6 +12,7 @@
import { nameToAvatarFallback } from "$lib/utils/name";
import { LanguageSwitch } from "$lib/components/templates/language-switch";
import { m } from "$i18n/messages";
import { resolve } from "$app/paths";
const sidebar = useSidebar();
</script>
@@ -61,13 +62,13 @@
<DropdownMenu.Separator />
<DropdownMenu.Group>
<LanguageSwitch class="w-full" triggerClass="w-[100%] [&>svg]:ml-auto" />
<DropdownMenu.Item onclick={() => goto(ROUTES.DASHBOARD.ACCOUNT.MAIN)}>
<DropdownMenu.Item onclick={() => goto(resolve(ROUTES.DASHBOARD.ACCOUNT.MAIN))}>
<AccountIcon />
{m["nav.account"]()}
</DropdownMenu.Item>
</DropdownMenu.Group>
<DropdownMenu.Separator />
<DropdownMenu.Item onclick={() => goto(ROUTES.LOGOUT)}>
<DropdownMenu.Item onclick={() => goto(resolve(ROUTES.LOGOUT))}>
<LogOutIcon />
{m["nav.logout"]()}
</DropdownMenu.Item>
@@ -14,6 +14,7 @@
import UnknownTenantIcon from "@lucide/svelte/icons/landmark";
import Loader from "@lucide/svelte/icons/loader-2";
import { cn } from "$lib/utils";
import { resolve } from "$app/paths";
const sidebar = useSidebar();
@@ -116,7 +117,10 @@
{/each}
{#if $tenants?.tenants.length > maxTenantsToShow}
<DropdownMenu.Separator />
<DropdownMenu.Item class="gap-2 p-2" onclick={() => goto(ROUTES.DASHBOARD.TENANTS)}>
<DropdownMenu.Item
class="gap-2 p-2"
onclick={() => goto(resolve(ROUTES.DASHBOARD.TENANTS))}
>
<div
class="flex size-6 items-center justify-center rounded-md border bg-transparent"
>
@@ -58,6 +58,7 @@
</script>
{#if href}
<!-- eslint-disable svelte/no-navigation-without-resolve -->
<a
bind:this={ref}
data-slot="button"
@@ -70,6 +71,7 @@
>
{@render children?.()}
</a>
<!-- eslint-enable svelte/no-navigation-without-resolve -->
{:else}
<button
bind:this={ref}
@@ -5,7 +5,7 @@
export function openDialog(id: string) {
responsiveDialogs.update((state) => {
const newState = new Map(state);
const newState = new SvelteMap(state);
newState.set(id, true);
return newState;
});
@@ -13,7 +13,7 @@
export function closeDialog(id: string) {
responsiveDialogs.update((state) => {
const newState = new Map(state);
const newState = new SvelteMap(state);
if (newState.has(id)) {
newState.set(id, false);
}
@@ -34,7 +34,7 @@
import * as Drawer from "$lib/components/ui/drawer";
import { onDestroy, type Snippet } from "svelte";
import type { HTMLAttributes } from "svelte/elements";
import { MediaQuery } from "svelte/reactivity";
import { MediaQuery, SvelteMap } from "svelte/reactivity";
import { HorizontalPagePadding } from "../page";
import { ScrollArea } from "../scroll-area";
import { cn } from "$lib/utils";
@@ -80,7 +80,7 @@
onDestroy(() => {
responsiveDialogs.update((state) => {
const newState = new Map(state);
const newState = new SvelteMap(state);
newState.delete(id);
return newState;
});
+1 -1
View File
@@ -28,4 +28,4 @@ export const ROUTES = {
CHANGE_PASSPHRASE: "/dashboard/account/change-passphrase",
},
},
};
} as const;
@@ -3,6 +3,7 @@
</script>
<div class="button-container">
<!-- eslint-disable-next-line svelte/no-navigation-without-resolve -->
<a class="button" {href}>{@render children?.()}</a>
</div>
+4 -3
View File
@@ -9,6 +9,7 @@ import { goto } from "$app/navigation";
import { ROUTES } from "$lib/const/routes";
import { agents } from "./agents";
import { channels } from "./channels";
import { resolve } from "$app/paths";
const log = logger.setContext("TenantsStore");
@@ -54,7 +55,7 @@ const createTenantsStore = () => {
// Redirect to dashboard main if tenant changed to avaoid showing data from previous tenant
if (tenantId !== curTenant) {
goto(ROUTES.DASHBOARD.MAIN);
goto(resolve(ROUTES.DASHBOARD.MAIN));
}
},
reload: async () => {
@@ -81,7 +82,7 @@ const createTenantsStore = () => {
description: m["dashboard.onboarding.notification.ongoing.description"](),
action: {
label: m["dashboard.onboarding.notification.ongoing.action"](),
onClick: () => goto(ROUTES.DASHBOARD.MAIN),
onClick: () => goto(resolve(ROUTES.DASHBOARD.MAIN)),
},
});
} else {
@@ -92,7 +93,7 @@ const createTenantsStore = () => {
description: m["dashboard.onboarding.notification.done.description"](),
action: {
label: m["dashboard.onboarding.notification.done.action"](),
onClick: () => goto(ROUTES.MAIN),
onClick: () => goto(resolve(ROUTES.MAIN)),
},
});
}
+3 -2
View File
@@ -1,4 +1,5 @@
import { goto } from "$app/navigation";
import { resolve } from "$app/paths";
import { ROUTES } from "$lib/const/routes";
import { auth } from "$lib/stores/auth";
@@ -19,7 +20,7 @@ export const refreshSession = async () => {
if (!response.ok) {
if (response.status === 401) {
auth.setRefreshing(false);
goto(ROUTES.LOGOUT);
goto(resolve(ROUTES.LOGOUT));
return;
}
}
@@ -42,7 +43,7 @@ export const refreshUserData = async () => {
if (!response.ok) {
if (response.status === 401) {
goto(ROUTES.LOGOUT);
goto(resolve(ROUTES.LOGOUT));
return;
}
}
@@ -1,5 +1,6 @@
<script lang="ts">
import { goto } from "$app/navigation";
import { resolve } from "$app/paths";
import { m } from "$i18n/messages";
import { getLocale } from "$i18n/runtime";
import { Button } from "$lib/components/ui/button";
@@ -39,7 +40,7 @@
)
.then(() => {
const isRequest = channel.requiresConfirmation;
goto(ROUTES.APPOINTMENT_BOOKED, { state: { isRequest } });
goto(resolve(ROUTES.APPOINTMENT_BOOKED), { state: { isRequest } });
})
.catch(() => {
toast.error(m["public.steps.summary.error"]());
@@ -1,5 +1,6 @@
import { browser } from "$app/environment";
import { goto } from "$app/navigation";
import { resolve } from "$app/paths";
import { ROUTES } from "$lib/const/routes";
import { publicStore } from "$lib/stores/public";
import type { TPublicAppointment, TPublicSchedule } from "$lib/types/public";
@@ -74,7 +75,7 @@ export const proceed = (
newAppointment: updatedAppointment,
}));
}
goto(`${ROUTES.BOOK_APPOINTMENT}/${newAppointment.channel}`);
goto(resolve(`${ROUTES.BOOK_APPOINTMENT}/${newAppointment.channel}`));
return { ...newAppointment, step: "SELECT_AGENT" };
}
default:
@@ -83,7 +84,7 @@ export const proceed = (
};
export const resest = () => {
goto(ROUTES.BOOK_APPOINTMENT, { invalidateAll: true });
goto(resolve(ROUTES.BOOK_APPOINTMENT), { invalidateAll: true });
};
export const fetchSchedule = async (opts: {
@@ -9,6 +9,7 @@
import Check from "@lucide/svelte/icons/check";
import { ROUTES } from "$lib/const/routes";
import { goto } from "$app/navigation";
import { resolve } from "$app/paths";
const { data } = $props();
</script>
@@ -65,7 +66,7 @@
size="lg"
class="w-full"
onclick={() =>
goto(ROUTES.SETUP_PASSKEY, {
goto(resolve(ROUTES.SETUP_PASSKEY), {
state: {
id: confirmation.id,
email: confirmation.email,
@@ -23,6 +23,7 @@
import { formSchema, type FormSchema } from "./schema";
import { onMount } from "svelte";
import { UnifiedAppointmentCrypto } from "$lib/client/appointment-crypto";
import { resolve } from "$app/paths";
let {
data,
@@ -49,7 +50,7 @@
if (event.result.type === "success") {
toast.success(m["setupPasskey.success"]());
await storeStaffKeyPair();
await goto(ROUTES.LOGIN);
await goto(resolve(ROUTES.LOGIN));
} else {
toast.error(m["setupPasskey.error"]());
}
+6 -5
View File
@@ -1,5 +1,6 @@
<script lang="ts">
import { goto } from "$app/navigation";
import { resolve } from "$app/paths";
import { m } from "$i18n/messages";
import { SidebarLayout } from "$lib/components/layouts/sidebar-layout";
import { Button } from "$lib/components/ui/button";
@@ -72,7 +73,7 @@
{
label: m["dashboard.tenants.setup.sections.tenants.action"](),
onClick: () => {
goto(ROUTES.DASHBOARD.TENANTS, { state: { action: "add" } });
goto(resolve(ROUTES.DASHBOARD.TENANTS), { state: { action: "add" } });
},
},
],
@@ -103,7 +104,7 @@
{
label: m["dashboard.onboarding.sections.settings.action"](),
onClick: () => {
goto(ROUTES.DASHBOARD.SETTINGS);
goto(resolve(ROUTES.DASHBOARD.SETTINGS));
},
},
],
@@ -116,7 +117,7 @@
{
label: m["dashboard.onboarding.sections.agents.action"](),
onClick: () => {
goto(ROUTES.DASHBOARD.AGENTS, { state: { action: "add" } });
goto(resolve(ROUTES.DASHBOARD.AGENTS), { state: { action: "add" } });
},
},
],
@@ -130,7 +131,7 @@
{
label: m["dashboard.onboarding.sections.channels.action"](),
onClick: () => {
goto(ROUTES.DASHBOARD.CHANNELS, { state: { action: "add" } });
goto(resolve(ROUTES.DASHBOARD.CHANNELS), { state: { action: "add" } });
},
},
],
@@ -144,7 +145,7 @@
{
label: m["dashboard.onboarding.sections.staff.action"](),
onClick: () => {
goto(ROUTES.DASHBOARD.STAFF, { state: { action: "add" } });
goto(resolve(ROUTES.DASHBOARD.STAFF), { state: { action: "add" } });
},
},
],
@@ -1,4 +1,5 @@
<script lang="ts">
import { resolve } from "$app/paths";
import { m } from "$i18n/messages";
import { MaxPageWidth } from "$lib/components/layouts/max-page-width";
import { SidebarLayout } from "$lib/components/layouts/sidebar-layout";
@@ -22,7 +23,7 @@
<Item.Group class="gap-2">
<Item.Root variant="outline">
{#snippet child({ props })}
<a href={ROUTES.DASHBOARD.ACCOUNT.GENERAL} {...props}>
<a href={resolve(ROUTES.DASHBOARD.ACCOUNT.GENERAL)} {...props}>
<Item.Content>
<Item.Title>
<Text style="md">{m["account.general.title"]()}</Text>
@@ -39,7 +40,7 @@
</Item.Root>
<Item.Root variant="outline">
{#snippet child({ props })}
<a href={ROUTES.DASHBOARD.ACCOUNT.CHANGE_EMAIL} {...props}>
<a href={resolve(ROUTES.DASHBOARD.ACCOUNT.CHANGE_EMAIL)} {...props}>
<Item.Content>
<Item.Title>
<Text style="md">{m["account.change-email.title"]()}</Text>
@@ -56,7 +57,7 @@
</Item.Root>
<Item.Root variant="outline">
{#snippet child({ props })}
<a href={ROUTES.DASHBOARD.ACCOUNT.PASSKEYS} {...props}>
<a href={resolve(ROUTES.DASHBOARD.ACCOUNT.PASSKEYS)} {...props}>
<Item.Content>
<Item.Title>
<Text style="md">{m["account.passkeys.title"]()}</Text>
@@ -74,7 +75,7 @@
{#if $auth.user?.role === "GLOBAL_ADMIN"}
<Item.Root variant="outline">
{#snippet child({ props })}
<a href={ROUTES.DASHBOARD.ACCOUNT.CHANGE_PASSPHRASE} {...props}>
<a href={resolve(ROUTES.DASHBOARD.ACCOUNT.CHANGE_PASSPHRASE)} {...props}>
<Item.Content>
<Item.Title>
<Text style="md">{m["account.change-passphrase.title"]()}</Text>
@@ -1,5 +1,6 @@
import { browser } from "$app/environment";
import { goto } from "$app/navigation";
import { resolve } from "$app/paths";
import { ROUTES } from "$lib/const/routes";
import type { TCalendar, TCalendarItem } from "$lib/types/calendar";
import { toCalendarDateTime, toZoned, type CalendarDate } from "@internationalized/date";
@@ -32,7 +33,7 @@ export const fetchCalendar = async (opts: { tenant: string; startDate: CalendarD
}
} else {
if (res.status === 401) {
goto(ROUTES.LOGIN);
goto(resolve(ROUTES.LOGIN));
} else {
console.error("Unable to fetch calendar", res.status, res.statusText);
}
+2 -1
View File
@@ -19,6 +19,7 @@
import { superForm } from "sveltekit-superforms";
import { zod4Client as zodClient } from "sveltekit-superforms/adapters";
import { baseSchema, formSchema } from "./schema";
import { resolve } from "$app/paths";
let { formId, onEvent }: { formId: string; onEvent: EventReporter } = $props();
@@ -42,7 +43,7 @@
onResult: async (event) => {
if (event.result.type === "success") {
auth.setUser(event.result.data?.user);
await goto(ROUTES.DASHBOARD.MAIN);
await goto(resolve(ROUTES.DASHBOARD.MAIN));
} else {
toast.error(m["login.error"]());
}
@@ -14,6 +14,7 @@
import { goto } from "$app/navigation";
import { ROUTES } from "$lib/const/routes";
import { Input } from "$lib/components/ui/input";
import { resolve } from "$app/paths";
let { data }: { data: { form: SuperValidated<Infer<FormSchema>> } } = $props();
@@ -43,7 +44,7 @@
// This page is only of help, if you have just created an admin account
if (!email) {
await goto(ROUTES.SETUP.CREATE_ADMIN_ACCOUNT);
await goto(resolve(ROUTES.SETUP.CREATE_ADMIN_ACCOUNT));
}
// Set email from previous step
@@ -20,6 +20,7 @@
import type { PasskeyState } from "$lib/components/ui/passkey/state.svelte";
import { arrayBufferToBase64, fetchChallenge, generatePasskey } from "$lib/utils/passkey";
import logger from "$lib/logger";
import { resolve } from "$app/paths";
let {
data,
@@ -39,7 +40,7 @@
onResult: async (event) => {
if (event.result.type === "success") {
toast.success(m["setup.create_admin_account.success"]());
await goto(ROUTES.SETUP.CHECK_EMAIL, {
await goto(resolve(ROUTES.SETUP.CHECK_EMAIL), {
state: { email: event.result.data?.form.data.email },
});
}