Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f38e5aad8e |
@@ -31,7 +31,7 @@ import { mutate } from "swr";
|
||||
import { moveDocumentToFolder } from "@/lib/documents/move-documents";
|
||||
import { moveFolderToFolder } from "@/lib/documents/move-folder";
|
||||
import { DataroomFolderWithCount } from "@/lib/swr/use-dataroom";
|
||||
import { FolderWithCount } from "@/lib/swr/use-documents";
|
||||
import { FolderWithCount, FolderWithCountAndPath } from "@/lib/swr/use-documents";
|
||||
import { DocumentWithLinksAndLinkCountAndViewCount } from "@/lib/types";
|
||||
import { useMediaQuery } from "@/lib/utils/use-media-query";
|
||||
|
||||
@@ -75,7 +75,7 @@ export function DocumentsList({
|
||||
loading,
|
||||
foldersLoading,
|
||||
}: {
|
||||
folders: FolderWithCount[] | undefined;
|
||||
folders: FolderWithCount[] | FolderWithCountAndPath[] | undefined;
|
||||
documents: DocumentWithLinksAndLinkCountAndViewCount[] | undefined;
|
||||
teamInfo: TeamContextType | null;
|
||||
folderPathName?: string[];
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
@@ -5,9 +6,11 @@ import { useEffect, useRef, useState } from "react";
|
||||
import { TeamContextType } from "@/context/team-context";
|
||||
import {
|
||||
BetweenHorizontalStartIcon,
|
||||
ChevronRight,
|
||||
ClipboardCopyIcon,
|
||||
CopyIcon,
|
||||
EyeOffIcon,
|
||||
FolderIcon,
|
||||
FolderInputIcon,
|
||||
FolderPenIcon,
|
||||
MoreVertical,
|
||||
@@ -19,8 +22,8 @@ import { mutate } from "swr";
|
||||
|
||||
import { getFolderColorClasses, getFolderIcon } from "@/lib/constants/folder-constants";
|
||||
import { DataroomFolderWithCount } from "@/lib/swr/use-dataroom";
|
||||
import { FolderWithCount } from "@/lib/swr/use-documents";
|
||||
import { timeAgo } from "@/lib/utils";
|
||||
import { FolderWithCount, FolderWithCountAndPath } from "@/lib/swr/use-documents";
|
||||
import { getBreadcrumbPath, timeAgo } from "@/lib/utils";
|
||||
import {
|
||||
HIERARCHICAL_DISPLAY_STYLE,
|
||||
useHierarchicalDisplayName,
|
||||
@@ -42,7 +45,7 @@ import { AddFolderToDataroomModal } from "./add-folder-to-dataroom-modal";
|
||||
import { MoveToFolderModal } from "./move-folder-modal";
|
||||
|
||||
type FolderCardProps = {
|
||||
folder: FolderWithCount | DataroomFolderWithCount;
|
||||
folder: FolderWithCount | FolderWithCountAndPath | DataroomFolderWithCount;
|
||||
teamInfo: TeamContextType | null;
|
||||
isDataroom?: boolean;
|
||||
dataroomId?: string;
|
||||
@@ -65,6 +68,10 @@ export default function FolderCard({
|
||||
onDelete,
|
||||
}: FolderCardProps) {
|
||||
const router = useRouter();
|
||||
const queryParams = router.query;
|
||||
const searchQuery = queryParams["search"];
|
||||
const sortQuery = queryParams["sort"];
|
||||
const folderList = "folderList" in folder ? folder.folderList : undefined;
|
||||
const [moveFolderOpen, setMoveFolderOpen] = useState<boolean>(false);
|
||||
const [openFolder, setOpenFolder] = useState<boolean>(false);
|
||||
const [menuOpen, setMenuOpen] = useState<boolean>(false);
|
||||
@@ -237,6 +244,37 @@ export default function FolderCard({
|
||||
{folder._count.childFolders === 1 ? "Folder" : "Folders"}
|
||||
</p>
|
||||
</div>
|
||||
{searchQuery && folderList !== undefined ? (
|
||||
<div className="relative z-10 mt-1 flex flex-wrap items-center space-x-1 text-xs leading-5 text-muted-foreground">
|
||||
{getBreadcrumbPath(folderList).map((segment, index) => (
|
||||
<p
|
||||
className="inset-2 flex items-center gap-x-1 truncate"
|
||||
key={segment.pathLink}
|
||||
>
|
||||
{index !== 0 && <ChevronRight className="h-3 w-3" />}
|
||||
<FolderIcon className="h-3 w-3" />
|
||||
<Link
|
||||
href={segment.pathLink}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="relative z-10 hover:underline"
|
||||
>
|
||||
{segment.name}
|
||||
</Link>
|
||||
</p>
|
||||
))}
|
||||
<p className="inset-2 flex items-center gap-x-1 truncate">
|
||||
<ChevronRight className="h-3 w-3" />
|
||||
<FolderIcon className="h-3 w-3" />
|
||||
<Link
|
||||
href={folderPath}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="relative z-10 hover:underline"
|
||||
>
|
||||
{folder.name}
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ interface PaginationProps {
|
||||
onPageSizeChange: (size: number) => void;
|
||||
totalShownItems: number;
|
||||
itemName: string;
|
||||
extraInfo?: string;
|
||||
}
|
||||
|
||||
export function Pagination({
|
||||
@@ -35,6 +36,7 @@ export function Pagination({
|
||||
onPageSizeChange,
|
||||
totalShownItems,
|
||||
itemName,
|
||||
extraInfo,
|
||||
}: PaginationProps) {
|
||||
return (
|
||||
<Card className="mt-4 p-4">
|
||||
@@ -42,6 +44,7 @@ export function Pagination({
|
||||
<div className="flex-1 text-sm text-muted-foreground">
|
||||
Showing <span className="font-bold">{totalShownItems}</span> of{" "}
|
||||
{totalItems} {itemName}
|
||||
{extraInfo && <span className="ml-2">· {extraInfo}</span>}
|
||||
</div>
|
||||
<div className="flex items-center space-x-6 lg:space-x-8">
|
||||
<div className="hidden items-center space-x-2 sm:flex">
|
||||
|
||||
@@ -29,6 +29,7 @@ export default function useDocuments() {
|
||||
|
||||
const { data, isValidating, error } = useSWR<{
|
||||
documents: DocumentWithLinksAndLinkCountAndViewCount[];
|
||||
folders?: FolderWithCountAndPath[];
|
||||
pagination?: {
|
||||
total: number;
|
||||
pages: number;
|
||||
@@ -47,6 +48,7 @@ export default function useDocuments() {
|
||||
|
||||
return {
|
||||
documents: data?.documents || [],
|
||||
searchFolders: data?.folders,
|
||||
pagination: data?.pagination,
|
||||
isValidating,
|
||||
loading: !data && !error,
|
||||
@@ -85,6 +87,10 @@ export type FolderWithCount = Folder & {
|
||||
};
|
||||
};
|
||||
|
||||
export type FolderWithCountAndPath = FolderWithCount & {
|
||||
folderList: string[];
|
||||
};
|
||||
|
||||
export function useFolder({ name }: { name: string[] }) {
|
||||
const teamInfo = useTeam();
|
||||
const router = useRouter();
|
||||
|
||||
@@ -248,8 +248,68 @@ export default async function handle(
|
||||
);
|
||||
}
|
||||
|
||||
let matchingFolders: any[] = [];
|
||||
if (query) {
|
||||
const folders = await prisma.folder.findMany({
|
||||
where: {
|
||||
teamId,
|
||||
hiddenInAllDocuments: false,
|
||||
name: {
|
||||
contains: query,
|
||||
mode: "insensitive",
|
||||
},
|
||||
OR: [
|
||||
{ parentId: null },
|
||||
{
|
||||
parentFolder: {
|
||||
hiddenInAllDocuments: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
include: {
|
||||
_count: {
|
||||
select: {
|
||||
documents: true,
|
||||
childFolders: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: { name: "asc" },
|
||||
});
|
||||
|
||||
matchingFolders = await Promise.all(
|
||||
folders.map(async (folder) => {
|
||||
const folderNames: string[] = [];
|
||||
const parentPath = folder.path.substring(
|
||||
0,
|
||||
folder.path.lastIndexOf("/"),
|
||||
);
|
||||
if (parentPath) {
|
||||
const pathSegments = parentPath.split("/").filter(Boolean);
|
||||
if (pathSegments.length > 0) {
|
||||
const parentPaths = pathSegments.map((_, index) =>
|
||||
"/" + pathSegments.slice(0, index + 1).join("/"),
|
||||
);
|
||||
const parentFolders = await prisma.folder.findMany({
|
||||
where: {
|
||||
teamId,
|
||||
path: { in: parentPaths },
|
||||
},
|
||||
select: { path: true, name: true },
|
||||
orderBy: { path: "asc" },
|
||||
});
|
||||
folderNames.push(...parentFolders.map((f) => f.name));
|
||||
}
|
||||
}
|
||||
return { ...folder, folderList: folderNames };
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return res.status(200).json({
|
||||
documents: documentsWithFolderList,
|
||||
...(query && { folders: matchingFolders }),
|
||||
...(usePagination && {
|
||||
pagination: {
|
||||
total: totalDocuments,
|
||||
|
||||
@@ -32,8 +32,14 @@ export default function Documents() {
|
||||
}
|
||||
|
||||
const { folders, loading: foldersLoading } = useRootFolders();
|
||||
const { documents, pagination, isValidating, isFiltered, loading } =
|
||||
useDocuments();
|
||||
const {
|
||||
documents,
|
||||
searchFolders,
|
||||
pagination,
|
||||
isValidating,
|
||||
isFiltered,
|
||||
loading,
|
||||
} = useDocuments();
|
||||
const { folders: hiddenFolders, documents: hiddenDocuments } =
|
||||
useHiddenDocuments();
|
||||
|
||||
@@ -55,7 +61,7 @@ export default function Documents() {
|
||||
});
|
||||
};
|
||||
|
||||
const displayFolders = isFiltered ? [] : folders;
|
||||
const displayFolders = isFiltered ? searchFolders ?? [] : folders;
|
||||
|
||||
return (
|
||||
<AppLayout>
|
||||
@@ -121,7 +127,7 @@ export default function Documents() {
|
||||
folders={displayFolders}
|
||||
teamInfo={teamInfo}
|
||||
loading={loading}
|
||||
foldersLoading={foldersLoading}
|
||||
foldersLoading={isFiltered ? loading : foldersLoading}
|
||||
/>
|
||||
|
||||
{isFiltered && pagination && (
|
||||
@@ -134,6 +140,11 @@ export default function Documents() {
|
||||
onPageChange={updatePagination}
|
||||
onPageSizeChange={(size) => updatePagination(undefined, size)}
|
||||
itemName="documents"
|
||||
extraInfo={
|
||||
searchFolders && searchFolders.length > 0
|
||||
? `${searchFolders.length} folder${searchFolders.length > 1 ? "s" : ""} found`
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user