This commit is contained in:
2025-08-09 13:45:16 +02:00
parent 298fae916b
commit d322283064
28 changed files with 135 additions and 80 deletions

View File

@@ -0,0 +1,16 @@
type DashBoardTitleProps = {
renderSubtitle: true
subtitle: string
} | {
renderSubtitle?: false
subtitle?: never
}
export default function DashBoardTitle({ title, subtitle, renderSubtitle }: DashBoardTitleProps & { title: string }) {
return (
<div className="pb-6">
<h1 className="mb-2 text-2xl font-bold text-foreground">{title}</h1>
{renderSubtitle && <p className="text-sm text-muted-foreground">{subtitle}</p>}
</div>
)
}

View File

@@ -0,0 +1,7 @@
import { getSession } from "@/lib/auth/session"
export default async function PasswordSettings() {
const {} = await getSession()
return null
}

View File

@@ -1,6 +1,6 @@
"use client"
import { HomeIcon, LayoutDashboard, List, PanelLeft, Plus, User2 } from "lucide-react"
import { HomeIcon, KeyRoundIcon, LayoutDashboard, List, PanelLeft, Plus, User2 } from "lucide-react"
import Link from "next/link"
import { usePathname } from "next/navigation"
@@ -20,24 +20,37 @@ import {
import { SidebarThemeToggle } from "./sidebar-theme-toggle"
import { SidebarUserDropdown } from "./sidebar-user-dropdown"
const items = [
const dashboardItems = [
{
title: "Dashboard",
url: "/dashboard",
url: "/admin/dashboard",
icon: LayoutDashboard
},
{
title: "List",
url: "/dashboard/list",
url: "/admin/dashboard/list",
icon: List
},
{
title: "Create",
url: "/dashboard/create",
url: "/admin/dashboard/create",
icon: Plus
}
]
const userItems = [
{
title: "Profile",
url: "/admin/user",
icon: User2
},
{
title: "Auth",
url: "/admin/user/auth",
icon: KeyRoundIcon
}
]
export function DashboardSidebar() {
const pathname = usePathname()
const { toggleSidebar } = useSidebar()
@@ -81,7 +94,7 @@ export function DashboardSidebar() {
</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{items.map((item) => (
{dashboardItems.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton
asChild
@@ -99,23 +112,25 @@ export function DashboardSidebar() {
</SidebarGroupContent>
</SidebarGroup>
<SidebarGroup>
<SidebarGroupLabel>
Other
<SidebarGroupLabel className="group-data-[collapsible=icon]:hidden">
User
</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
{userItems.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton
asChild
isActive={pathname === "/dashboard/user"}
tooltip="User Profile"
isActive={pathname === item.url}
tooltip={item.title}
>
<Link href="/dashboard/user">
<User2 />
<span>User Profile</span>
<Link href={item.url}>
<item.icon />
<span>{item.title}</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>

View File

@@ -226,12 +226,12 @@ function EditUrlForm({ data }: { data: typeof urls.$inferSelect }) {
toast.error(res.message)
} else {
toast.success(res.message)
router.push("/dashboard/list")
router.push("/admin/dashboard/list")
}
}
const handleCancel = () => {
router.push("/dashboard/list")
router.push("/admin/dashboard/list")
}
return (

View File

@@ -283,7 +283,7 @@ export function UrlsDataTable({ data }: UrlsDataTableProps) {
Copy URL
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link href={`/dashboard/edit/${urlRecord.id}`}>
<Link href={`/admin/dashboard/edit/${urlRecord.id}`}>
<Copy className="mr-2 w-4 h-4" />
Edit URL
</Link>

View File

@@ -1,15 +1,15 @@
import { getSession } from "@/lib/auth/session"
import { UrlFormCard } from "../_components/url-form-card"
import { UrlFormCard } from "../../_components/url-form-card"
export default async function DashboardCreatePage() {
const { session, redirect } = await getSession()
const { session, redirectToSignIn } = await getSession()
if (!session) {
redirect("/sign-in")
redirectToSignIn()
}
return (
<div className="p-6 space-y-6">
<div className="space-y-6">
<div>
<h1 className="mb-2 text-2xl font-bold text-foreground">Create Short Link</h1>
</div>

View File

@@ -25,12 +25,12 @@ export default function NotFound() {
</ul>
<div className="flex gap-2">
<Button asChild>
<Link href="/dashboard/list">
<Link href="/admin/dashboard/list">
View All Links
</Link>
</Button>
<Button asChild variant="outline">
<Link href="/dashboard/create">
<Link href="/admin/dashboard/create">
Create New Link
</Link>
</Button>

View File

@@ -1,17 +1,17 @@
import { getSession } from "@/lib/auth/session"
import { getUrlById } from "@/lib/db/urls"
import { notFound } from "next/navigation"
import { UrlFormCard } from "../../_components/url-form-card"
import { UrlFormCard } from "../../../_components/url-form-card"
export default async function EditPage({
params
}: {
params: Promise<{ id: string }>
}) {
const { session, redirect } = await getSession()
const { session, redirectToSignIn } = await getSession()
if (!session) {
redirect("/sign-in")
redirectToSignIn()
}
const { id } = await params
@@ -23,7 +23,7 @@ export default async function EditPage({
}
return (
<div className="p-6 space-y-6">
<div className="space-y-6">
<div>
<h1 className="mb-2 text-2xl font-bold text-foreground">Edit Short Link</h1>
</div>

View File

@@ -1,18 +1,18 @@
import { getSession } from "@/lib/auth/session"
import { getAllUrls } from "@/lib/db/urls"
import { UrlsDataTable } from "../_components/urls-data-table"
import { UrlsDataTable } from "../../_components/urls-data-table"
export default async function DashboardListPage() {
const { session, redirect } = await getSession()
const { session, redirectToSignIn } = await getSession()
if (!session) {
redirect("/sign-in")
redirectToSignIn()
}
const urls = await getAllUrls()
return (
<div className="p-6">
<div>
<div className="mb-6">
<h1 className="block mb-2 text-2xl font-bold text-foreground">URLs</h1>
<h1 className="block text-muted-foreground">Manage all your shortened URLs.</h1>

View File

@@ -1,14 +1,14 @@
import { getSession } from "@/lib/auth/session"
import { getDashboardStats } from "@/lib/dashboard/stats"
import { LinkIcon, MousePointerClick, TrendingUp } from "lucide-react"
import { UrlFormCard } from "./_components/simple-url-form-card"
import { StatsCard } from "./_components/stats-card"
import { UrlFormCard } from "../_components/simple-url-form-card"
import { StatsCard } from "../_components/stats-card"
export default async function Dashboard() {
const { session, redirect } = await getSession()
const { session, redirectToSignIn } = await getSession()
if (!session) {
redirect("/sign-in")
redirectToSignIn()
}
const stats = await getDashboardStats()
@@ -20,7 +20,7 @@ export default async function Dashboard() {
: "No URLs"
return (
<div className="p-6">
<div>
<h1 className="block mb-4 text-2xl font-bold text-foreground">Dashboard</h1>
<div className="grid grid-cols-1 gap-4 mb-6 md:grid-cols-2 lg:grid-cols-3">
<StatsCard

View File

@@ -13,7 +13,7 @@ export default function DashboardLayout({
<SidebarClient>
<div className="flex w-full min-h-screen">
<DashboardSidebar />
<main className="overflow-auto flex-1">
<main className="overflow-auto flex-1 p-6">
{children}
</main>
</div>

View File

@@ -0,0 +1,22 @@
import { getSession } from "@/lib/auth/session"
import DashBoardTitle from "../../_components/dashboard-title"
import { PasskeyAdd } from "../../_components/passkey"
import PasskeysList from "../../_components/passkeys-list"
export default async function UserAuthPage() {
const { session, redirectToSignIn } = await getSession()
if (!session) {
redirectToSignIn()
}
return (
<div>
<DashBoardTitle title="User Auth" renderSubtitle subtitle="Manage user settings" />
<div className="flex flex-col gap-6">
<PasskeyAdd />
<PasskeysList />
</div>
</div>
)
}

View File

@@ -0,0 +1,18 @@
import { getSession } from "@/lib/auth/session"
import DashBoardTitle from "../_components/dashboard-title"
import UserProfile from "../_components/user-profile"
export default async function UserPage() {
const { session, redirectToSignIn } = await getSession()
if (!session) {
redirectToSignIn()
}
return (
<div>
<DashBoardTitle title="User Profile" renderSubtitle subtitle="Manage Profile" />
<UserProfile />
</div>
)
}

View File

@@ -1,26 +0,0 @@
import { getSession } from "@/lib/auth/session"
import { PasskeyAdd } from "../_components/passkey"
import PasskeysList from "../_components/passkeys-list"
import UserProfile from "../_components/user-profile"
export default async function UserPage() {
const { session, redirect } = await getSession()
if (!session) {
redirect("/login")
}
return (
<div className="p-6">
<div className="pb-6">
<h1 className="block mb-2 text-2xl font-bold text-foreground">User Profile</h1>
<h1 className="block text-muted-foreground">Manage user settings</h1>
</div>
<div className="flex flex-col gap-6">
<UserProfile />
<PasskeyAdd />
<PasskeysList />
</div>
</div>
)
}

View File

@@ -22,7 +22,7 @@ export function OAuthSignInButton({
setIsLoading(true)
const res = await authClient.signIn.oauth2({
providerId: "authentik",
callbackURL: "/dashboard"
callbackURL: "/admin/dashboard"
})
if (res && res.error) {
@@ -39,7 +39,7 @@ export function OAuthSignInButton({
const res = await authClient.signIn.passkey({
fetchOptions: {
onSuccess: () => {
router.push("/dashboard")
router.push("/admin/dashboard")
}
}
})

View File

@@ -4,10 +4,10 @@ import { getSession } from "@/lib/auth/session"
import { LogIn } from "lucide-react"
export default async function SignInPage() {
const { session, redirect } = await getSession()
const { session, redirectToHome } = await getSession()
if (session) {
redirect("/dashboard")
redirectToHome()
}
return (

View File

@@ -85,9 +85,9 @@ export function UserDropdown({ className }: UserDropdownProps) {
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem asChild>
<Link href="/dashboard">
<Link href="/admin/dashboard">
<Settings className="mr-2 w-4 h-4" />
<span>Dashboard</span>
<span>Admin</span>
</Link>
</DropdownMenuItem>
<DropdownMenuSeparator />

View File

@@ -37,7 +37,7 @@ export async function addUrl(unsafeData: unknown): Promise<Response> {
title: await getWebsiteTitle(data.url)
})
revalidatePath("/dashboard")
revalidatePath("/admin/dashboard")
return {
error: false,

View File

@@ -6,9 +6,12 @@ export async function getSession() {
const session = await auth.api.getSession({
headers: await headers()
})
const redirectFunc = (path: string) => {
redirect(path)
function redirectToSignIn() {
redirect("/sign-in")
}
function redirectToHome() {
redirect("/")
}
return { session, redirect: redirectFunc }
return { session, redirectToSignIn, redirectToHome }
}

View File

@@ -10,4 +10,4 @@ export async function middleware(request: NextRequest) {
return NextResponse.next()
}
export const config = { matcher: ["/dashboard"] }
export const config = { matcher: ["/admin"] }