diff --git a/drizzle/0013_invoice_public_token_expiry.sql b/drizzle/0013_invoice_public_token_expiry.sql new file mode 100644 index 0000000..480fc6b --- /dev/null +++ b/drizzle/0013_invoice_public_token_expiry.sql @@ -0,0 +1 @@ +ALTER TABLE "beenvoice_invoice" ADD COLUMN IF NOT EXISTS "publicTokenExpiresAt" timestamp; diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 7af12ea..011b412 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -92,6 +92,13 @@ "when": 1749340800000, "tag": "0012_verification_token_value_text", "breakpoints": true + }, + { + "idx": 13, + "version": "7", + "when": 1781194385000, + "tag": "0013_invoice_public_token_expiry", + "breakpoints": true } ] } diff --git a/src/app/dashboard/settings/_components/settings-content.tsx b/src/app/dashboard/settings/_components/settings-content.tsx index e96ac34..066200a 100644 --- a/src/app/dashboard/settings/_components/settings-content.tsx +++ b/src/app/dashboard/settings/_components/settings-content.tsx @@ -25,6 +25,7 @@ import { } from "lucide-react"; import dynamic from "next/dynamic"; import { authClient } from "~/lib/auth-client"; +import { useAuthSession } from "~/hooks/use-auth-session"; import * as React from "react"; import { useState } from "react"; @@ -178,8 +179,7 @@ function isFullHexColor(value: string) { } export function SettingsContent() { - const { data: session } = authClient.useSession(); - // const session = { user: null } as any; + const { data: session } = useAuthSession(); const [name, setName] = useState(""); const [deleteConfirmText, setDeleteConfirmText] = useState(""); const [importData, setImportData] = useState(""); diff --git a/src/components/layout/navbar.tsx b/src/components/layout/navbar.tsx index d62f98c..0dcb244 100644 --- a/src/components/layout/navbar.tsx +++ b/src/components/layout/navbar.tsx @@ -6,6 +6,7 @@ import { Logo } from "~/components/branding/logo"; import { SidebarTrigger } from "~/components/navigation/sidebar-trigger"; import { Button } from "~/components/ui/button"; import { Skeleton } from "~/components/ui/skeleton"; +import { useAuthSession } from "~/hooks/use-auth-session"; import { useRouter } from "next/navigation"; interface NavbarProps { @@ -13,8 +14,7 @@ interface NavbarProps { } export function Navbar({ allowRegistration = true }: NavbarProps) { - const { data: session, isPending } = authClient.useSession(); - // const session = { user: null } as any; const isPending = false; + const { data: session, isPending } = useAuthSession(); const [isMobileNavOpen, setIsMobileNavOpen] = useState(false); const router = useRouter(); diff --git a/src/components/layout/sidebar.tsx b/src/components/layout/sidebar.tsx index 21c32da..7ac9d7c 100644 --- a/src/components/layout/sidebar.tsx +++ b/src/components/layout/sidebar.tsx @@ -27,6 +27,7 @@ import { import { getGravatarUrl } from "~/lib/gravatar"; import { Avatar, AvatarFallback, AvatarImage } from "~/components/ui/avatar"; import { useAppearance } from "~/components/providers/appearance-provider"; +import { useAuthSession } from "~/hooks/use-auth-session"; interface SidebarProps { mobile?: boolean; @@ -35,8 +36,7 @@ interface SidebarProps { export function Sidebar({ mobile, onClose }: SidebarProps) { const pathname = usePathname(); - const { data: session, isPending } = authClient.useSession(); - // const session = { user: null } as any; const isPending = false; + const { data: session, isPending } = useAuthSession(); const { isCollapsed, toggleCollapse } = useSidebar(); const { sidebarStyle } = useAppearance(); diff --git a/src/components/navigation/sidebar-trigger.tsx b/src/components/navigation/sidebar-trigger.tsx index a4d4e67..62fdad3 100644 --- a/src/components/navigation/sidebar-trigger.tsx +++ b/src/components/navigation/sidebar-trigger.tsx @@ -1,11 +1,11 @@ "use client"; import { MenuIcon, X } from "lucide-react"; -import { authClient } from "~/lib/auth-client"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { Button } from "~/components/ui/button"; import { Skeleton } from "~/components/ui/skeleton"; +import { useAuthSession } from "~/hooks/use-auth-session"; import { navigationConfig } from "~/lib/navigation"; interface SidebarTriggerProps { @@ -15,8 +15,7 @@ interface SidebarTriggerProps { export function SidebarTrigger({ isOpen, onToggle }: SidebarTriggerProps) { const pathname = usePathname(); - const { isPending } = authClient.useSession(); - // const isPending = false; + const { isPending } = useAuthSession(); return ( <> diff --git a/src/hooks/use-auth-session.ts b/src/hooks/use-auth-session.ts new file mode 100644 index 0000000..5e91e9f --- /dev/null +++ b/src/hooks/use-auth-session.ts @@ -0,0 +1,34 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { authClient } from "~/lib/auth-client"; + +type AuthSession = typeof authClient.$Infer.Session; + +export function useAuthSession() { + const [session, setSession] = useState(null); + const [isPending, setIsPending] = useState(true); + + useEffect(() => { + let isCurrent = true; + + async function loadSession() { + const { data } = await authClient.getSession().catch(() => ({ + data: null, + })); + + if (isCurrent) { + setSession(data); + setIsPending(false); + } + } + + void loadSession(); + + return () => { + isCurrent = false; + }; + }, []); + + return { data: session, isPending }; +}