mirror of
https://github.com/Since-3/since3-portal.git
synced 2026-10-12 19:51:17 +00:00
96 lines
4.5 KiB
TypeScript
96 lines
4.5 KiB
TypeScript
import Link from "next/link"
|
|
import { notFound } from "next/navigation"
|
|
import { ChevronRightIcon, FolderIcon } from "lucide-react"
|
|
import { z } from "zod"
|
|
import { getClientId } from "@/modules/shared/queries/profile"
|
|
import { getDocuments, getFolder, getFolders } from "@/modules/shared/queries/documents"
|
|
import { CreateFolderDialog, DeleteFolderDialog } from "@/modules/shared/ui/components/folder-dialogs"
|
|
import { DocumentsBrowser } from "@/modules/shared/ui/components/documents-browser"
|
|
|
|
function EmptyState({ children }: { children: React.ReactNode }) {
|
|
return <p className="rounded-lg border border-border bg-surface/50 p-8 text-center text-muted-foreground">{children}</p>
|
|
}
|
|
|
|
export async function DocumentsPanel({
|
|
profileId,
|
|
isAdmin,
|
|
basePath,
|
|
folderId,
|
|
}: {
|
|
profileId: string
|
|
isAdmin: boolean
|
|
basePath: string
|
|
folderId?: string
|
|
}) {
|
|
const clientId = await getClientId(profileId)
|
|
|
|
if (!clientId) {
|
|
return (
|
|
<div className="flex w-full flex-col gap-6 md:gap-8">
|
|
<h1 className="text-2xl font-semibold md:text-3xl">Dokumente</h1>
|
|
<EmptyState>
|
|
{isAdmin
|
|
? "Für diesen Client sind noch keine Stammdaten hinterlegt. Bitte zuerst die Stammdaten ausfüllen."
|
|
: "Sobald eure Stammdaten hinterlegt sind, könnt ihr hier Dokumente ablegen."}
|
|
</EmptyState>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
if (folderId) {
|
|
if (!z.string().uuid().safeParse(folderId).success) notFound()
|
|
const folder = await getFolder(clientId, folderId)
|
|
if (!folder) notFound()
|
|
const documents = await getDocuments(clientId, folder.id)
|
|
|
|
return (
|
|
<div className="flex flex-col gap-6 w-full">
|
|
<div className="flex flex-wrap items-center justify-between gap-3">
|
|
<nav aria-label="Pfad" className="flex min-w-0 items-center gap-1.5 text-2xl font-semibold md:text-3xl">
|
|
<Link href={basePath} className="text-muted-foreground hover:text-foreground">Dokumente</Link>
|
|
<ChevronRightIcon className="size-5 shrink-0 text-muted-foreground md:size-6" aria-hidden />
|
|
<span className="truncate">{folder.name}</span>
|
|
</nav>
|
|
{isAdmin && documents.length === 0 && (
|
|
<DeleteFolderDialog profileId={profileId} folderId={folder.id} folderName={folder.name} redirectTo={basePath} />
|
|
)}
|
|
</div>
|
|
<DocumentsBrowser profileId={profileId} folderId={folder.id} isAdmin={isAdmin} documents={documents} />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const folders = await getFolders(clientId)
|
|
|
|
return (
|
|
<div className="flex flex-col gap-6 w-full">
|
|
<div className="flex flex-wrap items-center justify-between gap-3">
|
|
<h1 className="text-2xl font-semibold md:text-3xl">Dokumente</h1>
|
|
{isAdmin && <CreateFolderDialog profileId={profileId} />}
|
|
</div>
|
|
|
|
{folders.length === 0 ? (
|
|
<EmptyState>
|
|
{isAdmin ? "Noch keine Ordner. Lege einen Ordner an, damit Dateien hochgeladen werden können." : "Noch keine Ordner vorhanden."}
|
|
</EmptyState>
|
|
) : (
|
|
<ul className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">
|
|
{folders.map((folder) => (
|
|
<li key={folder.id}>
|
|
<Link
|
|
href={`${basePath}?folder=${folder.id}`}
|
|
className="flex flex-col items-center gap-2 rounded-lg border border-border bg-background p-4 text-center sm:p-5 transition-colors hover:border-ink-300 hover:bg-surface focus-visible:ring-2 focus-visible:ring-ring outline-none"
|
|
>
|
|
<FolderIcon className="size-10 sm:size-12 fill-accent-400/20 stroke-[1.25] text-accent-500" aria-hidden />
|
|
<span className="w-full truncate font-medium">{folder.name}</span>
|
|
<span className="text-label text-muted-foreground">
|
|
{folder.documentCount} {folder.documentCount === 1 ? "Datei" : "Dateien"}
|
|
</span>
|
|
</Link>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|