feat: update dependencies and refactor layout and homepage components
- Added new dependencies: @daveyplate/better-auth-ui, next-themes, and sonner. - Refactored layout component to use Providers and Toaster for better state management and notifications. - Updated homepage to utilize authClient for session management and improved user experience with navigation links for sign-in and sign-up.
This commit is contained in:
33
components/init-user.tsx
Normal file
33
components/init-user.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
"use client";
|
||||
|
||||
import { authClient } from "@/lib/auth-client";
|
||||
import { useMutation, useQuery } from "convex/react";
|
||||
import { api } from "@/convex/_generated/api";
|
||||
import { useEffect } from "react";
|
||||
|
||||
/**
|
||||
* Initialisiert die Credit-Balance für neue User.
|
||||
* Wird einmal im Layout eingebunden und sorgt dafür,
|
||||
* dass jeder eingeloggte User eine Balance + Free-Subscription hat.
|
||||
*/
|
||||
export function InitUser() {
|
||||
const { data: session } = authClient.useSession();
|
||||
const balance = useQuery(
|
||||
api.credits.getBalance,
|
||||
session?.user ? {} : "skip"
|
||||
);
|
||||
const initBalance = useMutation(api.credits.initBalance);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
session?.user &&
|
||||
balance &&
|
||||
balance.balance === 0 &&
|
||||
balance.monthlyAllocation === 0
|
||||
) {
|
||||
initBalance();
|
||||
}
|
||||
}, [session?.user, balance, initBalance]);
|
||||
|
||||
return null;
|
||||
}
|
||||
40
components/providers.tsx
Normal file
40
components/providers.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
"use client";
|
||||
|
||||
import { ReactNode } from "react";
|
||||
import { ConvexReactClient } from "convex/react";
|
||||
import { ConvexBetterAuthProvider } from "@convex-dev/better-auth/react";
|
||||
import { AuthUIProvider } from "@daveyplate/better-auth-ui";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
import { authClient } from "@/lib/auth-client";
|
||||
|
||||
const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);
|
||||
|
||||
export function Providers({
|
||||
children,
|
||||
initialToken,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
initialToken?: string | null;
|
||||
}) {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<ConvexBetterAuthProvider
|
||||
client={convex}
|
||||
authClient={authClient}
|
||||
initialToken={initialToken}
|
||||
>
|
||||
<AuthUIProvider
|
||||
authClient={authClient}
|
||||
navigate={router.push}
|
||||
replace={router.replace}
|
||||
onSessionChange={() => router.refresh()}
|
||||
Link={Link}
|
||||
>
|
||||
{children}
|
||||
</AuthUIProvider>
|
||||
</ConvexBetterAuthProvider>
|
||||
);
|
||||
}
|
||||
24
components/ui/label.tsx
Normal file
24
components/ui/label.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { Label as LabelPrimitive } from "radix-ui"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Label({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof LabelPrimitive.Root>) {
|
||||
return (
|
||||
<LabelPrimitive.Root
|
||||
data-slot="label"
|
||||
className={cn(
|
||||
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Label }
|
||||
49
components/ui/sonner.tsx
Normal file
49
components/ui/sonner.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
"use client"
|
||||
|
||||
import { useTheme } from "next-themes"
|
||||
import { Toaster as Sonner, type ToasterProps } from "sonner"
|
||||
import { CircleCheckIcon, InfoIcon, TriangleAlertIcon, OctagonXIcon, Loader2Icon } from "lucide-react"
|
||||
|
||||
const Toaster = ({ ...props }: ToasterProps) => {
|
||||
const { theme = "system" } = useTheme()
|
||||
|
||||
return (
|
||||
<Sonner
|
||||
theme={theme as ToasterProps["theme"]}
|
||||
className="toaster group"
|
||||
icons={{
|
||||
success: (
|
||||
<CircleCheckIcon className="size-4" />
|
||||
),
|
||||
info: (
|
||||
<InfoIcon className="size-4" />
|
||||
),
|
||||
warning: (
|
||||
<TriangleAlertIcon className="size-4" />
|
||||
),
|
||||
error: (
|
||||
<OctagonXIcon className="size-4" />
|
||||
),
|
||||
loading: (
|
||||
<Loader2Icon className="size-4 animate-spin" />
|
||||
),
|
||||
}}
|
||||
style={
|
||||
{
|
||||
"--normal-bg": "var(--popover)",
|
||||
"--normal-text": "var(--popover-foreground)",
|
||||
"--normal-border": "var(--border)",
|
||||
"--border-radius": "var(--radius)",
|
||||
} as React.CSSProperties
|
||||
}
|
||||
toastOptions={{
|
||||
classNames: {
|
||||
toast: "cn-toast",
|
||||
},
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Toaster }
|
||||
Reference in New Issue
Block a user