Some refactor

This commit is contained in:
2025-12-28 18:41:31 +01:00
parent ce658849e9
commit eaf822d73a
11 changed files with 202 additions and 36 deletions

View File

@ -18,10 +18,6 @@ RUN bunx prisma generate
# Uncomment the following line in case you want to disable telemetry during the build. # Uncomment the following line in case you want to disable telemetry during the build.
ENV NEXT_TELEMETRY_DISABLED=1 ENV NEXT_TELEMETRY_DISABLED=1
ARG DATABASE_URL
ENV DATABASE_URL=$DATABASE_URL
ARG BETTER_AUTH_SECRET
ENV BETTER_AUTH_SECRET=$BETTER_AUTH_SECRET
# Copy the rest of the code # Copy the rest of the code
RUN bun run build -d RUN bun run build -d

View File

@ -0,0 +1,22 @@
"use server"
import { prisma } from "@/lib/prisma"
export async function getSingleArtwork(id: string) {
return await prisma.artwork.findUnique({
where: { id },
include: {
// album: true,
// type: true,
file: true,
gallery: true,
metadata: true,
albums: true,
categories: true,
colors: { include: { color: true } },
// sortContexts: true,
tags: true,
variants: true
}
})
}

View File

@ -0,0 +1,16 @@
"use server"
import { prisma } from "@/lib/prisma"
export async function getCategoriesWithTags() {
return await prisma.artCategory.findMany({ include: { tags: true }, orderBy: { sortIndex: "asc" } })
}
export async function getCategoriesWithCount() {
return await prisma.artCategory.findMany({
include: {
_count: { select: { artworks: true, tags: true } },
},
orderBy: [{ sortIndex: "asc" }, { name: "asc" }],
})
}

View File

@ -0,0 +1,7 @@
"use server"
import { prisma } from "@/lib/prisma"
export async function getTags() {
return await prisma.artTag.findMany({ orderBy: { sortIndex: "asc" } })
}

View File

@ -1,31 +1,18 @@
import { getSingleArtwork } from "@/actions/artworks/getArtworks";
import { getCategoriesWithTags } from "@/actions/categories/getCategories";
import { getTags } from "@/actions/tags/getTags";
import ArtworkColors from "@/components/artworks/single/ArtworkColors"; import ArtworkColors from "@/components/artworks/single/ArtworkColors";
import ArtworkVariants from "@/components/artworks/single/ArtworkVariants"; import ArtworkVariants from "@/components/artworks/single/ArtworkVariants";
import DeleteArtworkButton from "@/components/artworks/single/DeleteArtworkButton"; import DeleteArtworkButton from "@/components/artworks/single/DeleteArtworkButton";
import EditArtworkForm from "@/components/artworks/single/EditArtworkForm"; import EditArtworkForm from "@/components/artworks/single/EditArtworkForm";
import { prisma } from "@/lib/prisma";
export default async function ArtworkSinglePage({ params }: { params: { id: string } }) { export default async function ArtworkSinglePage({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params; const { id } = await params;
const item = await prisma.artwork.findUnique({ const item = await getSingleArtwork(id);
where: { id },
include: {
// album: true,
// type: true,
file: true,
gallery: true,
metadata: true,
albums: true,
categories: true,
colors: { include: { color: true } },
// sortContexts: true,
tags: true,
variants: true
}
})
const categories = await prisma.artCategory.findMany({ include: { tags: true }, orderBy: { sortIndex: "asc" } }); const categories = await getCategoriesWithTags();
const tags = await prisma.artTag.findMany({ orderBy: { sortIndex: "asc" } }); const tags = await getTags();
if (!item) return <div>Artwork with this id not found</div> if (!item) return <div>Artwork with this id not found</div>

View File

@ -1,15 +1,11 @@
import { getCategoriesWithCount } from "@/actions/categories/getCategories";
import CategoryTable from "@/components/categories/CategoryTable"; import CategoryTable from "@/components/categories/CategoryTable";
import { prisma } from "@/lib/prisma";
import { PlusCircleIcon } from "lucide-react"; import { PlusCircleIcon } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { Suspense } from "react";
export default async function CategoriesPage() { export default async function CategoriesPage() {
const items = await prisma.artCategory.findMany({ const items = await getCategoriesWithCount();
include: {
_count: { select: { artworks: true, tags: true } },
},
orderBy: [{ sortIndex: "asc" }, { name: "asc" }],
});
return ( return (
<div> <div>
@ -19,11 +15,13 @@ export default async function CategoriesPage() {
<PlusCircleIcon className="h-[1.2rem] w-[1.2rem] scale-100 rotate-0 transition-all text-primary-foreground" /> Add new category <PlusCircleIcon className="h-[1.2rem] w-[1.2rem] scale-100 rotate-0 transition-all text-primary-foreground" /> Add new category
</Link> </Link>
</div> </div>
<Suspense fallback={<p>Loading...</p>}>
{items.length > 0 ? ( {items.length > 0 ? (
<CategoryTable categories={items} /> <CategoryTable categories={items} />
) : ( ) : (
<p>There are no categories yet. Consider adding some!</p> <p>There are no categories yet. Consider adding some!</p>
)} )}
</Suspense>
</div> </div>
); );
} }

51
src/app/error.tsx Normal file
View File

@ -0,0 +1,51 @@
"use client";
import { useEffect } from "react";
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
console.error(error);
}, [error]);
return (
<main className="min-h-dvh flex items-center justify-center px-6">
<div className="max-w-lg text-center space-y-6">
<h1 className="text-2xl font-semibold tracking-tight">
Something went wrong
</h1>
<p className="text-muted-foreground">
An unexpected error occurred while loading this section.
</p>
<div className="flex justify-center gap-4 pt-2">
<button
onClick={reset}
className="rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition"
>
Try again
</button>
<a
href="/"
className="rounded-md border px-4 py-2 text-sm font-medium hover:bg-muted transition"
>
Go home
</a>
</div>
{process.env.NODE_ENV === "development" && (
<pre className="mt-6 rounded-md bg-muted p-4 text-left text-xs overflow-auto">
{error.message}
</pre>
)}
</div>
</main>
);
}

38
src/app/global-error.tsx Normal file
View File

@ -0,0 +1,38 @@
"use client";
export default function GlobalError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<html lang="en">
<body className="min-h-dvh flex items-center justify-center bg-background px-6">
<div className="max-w-lg text-center space-y-6">
<h1 className="text-3xl font-semibold tracking-tight">
Application error
</h1>
<p className="text-muted-foreground">
A critical error occurred. Please reload the application.
</p>
<button
onClick={reset}
className="rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition"
>
Reload
</button>
{process.env.NODE_ENV === "development" && (
<pre className="mt-6 rounded-md bg-muted p-4 text-left text-xs overflow-auto">
{error.message}
</pre>
)}
</div>
</body>
</html>
);
}

View File

@ -1,3 +1,6 @@
export const dynamic = "force-dynamic";
export const revalidate = 0;
import { ThemeProvider } from "@/components/global/ThemeProvider"; import { ThemeProvider } from "@/components/global/ThemeProvider";
import type { Metadata } from "next"; import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google"; import { Geist, Geist_Mono } from "next/font/google";

17
src/app/loading.tsx Normal file
View File

@ -0,0 +1,17 @@
export default function Loading() {
return (
<main className="min-h-dvh flex items-center justify-center">
<div className="flex flex-col items-center gap-6">
{/* Spinner */}
<div className="relative h-14 w-14">
<div className="absolute inset-0 rounded-full border-4 border-muted opacity-25" />
<div className="absolute inset-0 rounded-full border-4 border-t-primary animate-spin" />
</div>
<p className="text-sm text-muted-foreground tracking-wide">
Loading content...
</p>
</div>
</main>
);
}

31
src/app/not-found.tsx Normal file
View File

@ -0,0 +1,31 @@
import Link from "next/link";
export default function NotFound() {
return (
<main className="min-h-dvh flex items-center justify-center px-6">
<div className="max-w-xl text-center space-y-6">
{/* Placeholder artwork */}
<div className="mx-auto h-48 w-48 rounded-xl bg-linear-to-br from-muted to-muted/30 flex items-center justify-center">
<span className="text-6xl font-serif text-muted-foreground">404</span>
</div>
<h1 className="text-2xl font-semibold tracking-tight">
This page does not exist
</h1>
<p className="text-muted-foreground">
The item you are looking for may have been moved, renamed, or never existed.
</p>
<div className="flex justify-center gap-4 pt-2">
<Link
href="/"
className="inline-flex items-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition"
>
Go home
</Link>
</div>
</div>
</main>
);
}