mirror of
https://github.com/Sosokker/B2D-Ventures.git
synced 2025-12-18 21:44:06 +01:00
feat: add dataroom files page
This commit is contained in:
parent
5636abc609
commit
d0d9c7a0f8
2044
package-lock.json
generated
2044
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -32,7 +32,7 @@
|
||||
"@stripe/stripe-js": "^4.7.0",
|
||||
"@supabase-cache-helpers/postgrest-react-query": "^1.10.1",
|
||||
"@supabase/ssr": "^0.4.1",
|
||||
"@supabase/supabase-js": "^2.45.2",
|
||||
"@supabase/supabase-js": "^2.46.1",
|
||||
"@tanstack/react-query": "^5.59.0",
|
||||
"@tanstack/react-query-devtools": "^5.59.0",
|
||||
"b2d-ventures": "file:",
|
||||
@ -48,6 +48,7 @@
|
||||
"react": "^18",
|
||||
"react-countup": "^6.5.3",
|
||||
"react-dom": "^18",
|
||||
"react-file-icon": "^1.5.0",
|
||||
"react-hook-form": "^7.53.0",
|
||||
"react-hot-toast": "^2.4.1",
|
||||
"react-lottie": "^1.2.4",
|
||||
@ -70,6 +71,7 @@
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"@types/react-fade-in": "^2.0.2",
|
||||
"@types/react-file-icon": "^1.0.4",
|
||||
"@types/react-lottie": "^1.2.10",
|
||||
"@types/react-select-country-list": "^2.2.3",
|
||||
"eslint": "^8.57.1",
|
||||
|
||||
136
src/app/dataroom/[dataroomId]/files/page.tsx
Normal file
136
src/app/dataroom/[dataroomId]/files/page.tsx
Normal file
@ -0,0 +1,136 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { FileIcon, defaultStyles } from "react-file-icon";
|
||||
import { getFilesByDataroomId } from "@/lib/data/dataroomQuery";
|
||||
import { createSupabaseClient } from "@/lib/supabase/clientComponentClient";
|
||||
import { format } from "date-fns";
|
||||
import { useQuery } from "@supabase-cache-helpers/postgrest-react-query";
|
||||
import Link from "next/link";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import toast from "react-hot-toast";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
export default function ViewDataRoomFilesPage({ params }: { params: { dataroomId: number } }) {
|
||||
const dataroomId = params.dataroomId;
|
||||
const supabase = createSupabaseClient();
|
||||
const router = useRouter();
|
||||
|
||||
const getProjectDataQuery = supabase
|
||||
.from("project")
|
||||
.select(`id, project_name, dataroom_id`)
|
||||
.eq("dataroom_id", dataroomId);
|
||||
const { data: project, error: projectError, isLoading: isLoadingProject } = useQuery(getProjectDataQuery);
|
||||
const { data: files, error, isLoading: isLoadingFiles } = useQuery(getFilesByDataroomId(supabase, dataroomId));
|
||||
|
||||
function getFileNameFromUrl(fileUrl: string): string {
|
||||
const fullFileName = fileUrl.split("/").pop() || "";
|
||||
return decodeURIComponent(fullFileName.split("?")[0]);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
toast.error("Unable to load files.");
|
||||
router.push("/");
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (projectError) {
|
||||
toast.error("Unable to load project that relate to dataroom.");
|
||||
router.push("/");
|
||||
throw projectError;
|
||||
}
|
||||
|
||||
const [sortOption, setSortOption] = useState("name");
|
||||
const sortedFiles = [...(files || [])].sort((a, b) => {
|
||||
if (sortOption === "name") {
|
||||
const nameA = getFileNameFromUrl(a.file_url).toLowerCase();
|
||||
const nameB = getFileNameFromUrl(b.file_url).toLowerCase();
|
||||
return nameA.localeCompare(nameB);
|
||||
} else if (sortOption === "date") {
|
||||
return new Date(b.uploaded_at).getTime() - new Date(a.uploaded_at).getTime();
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="container max-w-screen-xl p-4">
|
||||
<h2 className="text-xl font-semibold mb-4 text-gray-900 dark:text-gray-100">
|
||||
Dataroom Files |
|
||||
{isLoadingProject ? (
|
||||
"Loading..."
|
||||
) : project && project.length > 0 ? (
|
||||
<Link href={`/deals/${project[0].id}`} className="text-blue-600">
|
||||
{project[0].project_name}
|
||||
</Link>
|
||||
) : (
|
||||
"Project Not Found"
|
||||
)}
|
||||
</h2>
|
||||
<div
|
||||
id="file-section"
|
||||
className="border border-border dark:border-gray-700 rounded-md p-4 space-y-4 bg-white dark:bg-gray-900 shadow-sm"
|
||||
>
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<p className="text-gray-700 dark:text-gray-300">{`Uploaded files (${sortedFiles.length})`}</p>
|
||||
<div className="flex items-center space-x-2">
|
||||
<label htmlFor="sort" className="text-gray-500 dark:text-gray-400">
|
||||
Sort by:
|
||||
</label>
|
||||
<select
|
||||
id="sort"
|
||||
value={sortOption}
|
||||
onChange={(e) => setSortOption(e.target.value)}
|
||||
className="border border-gray-300 dark:border-gray-600 rounded-md p-1 text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800"
|
||||
>
|
||||
<option value="name">Name</option>
|
||||
<option value="date">Date</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Conditional rendering based on loading state */}
|
||||
{isLoadingProject || isLoadingFiles ? (
|
||||
<div className="space-y-3">
|
||||
{[...Array(3)].map((_, index) => (
|
||||
<Skeleton key={index} />
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
{sortedFiles.length > 0 ? (
|
||||
sortedFiles.map((file) => (
|
||||
<div
|
||||
key={file.id}
|
||||
className="flex justify-between items-center border border-border dark:border-gray-700 rounded-md p-3 bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700 transition"
|
||||
>
|
||||
<span className="flex items-center space-x-3">
|
||||
<div className="w-8 h-8 flex items-center justify-center">
|
||||
<FileIcon
|
||||
extension={file.file_type.value}
|
||||
{...defaultStyles[file.file_type.value as keyof typeof defaultStyles]}
|
||||
/>
|
||||
</div>
|
||||
<Link href={file.file_url} rel="noopener noreferrer" target="_blank">
|
||||
<p className="text-blue-600 dark:text-blue-400 hover:text-blue-800">
|
||||
{getFileNameFromUrl(file.file_url)}
|
||||
</p>
|
||||
</Link>
|
||||
</span>
|
||||
<span className="flex items-center space-x-4 text-gray-600 dark:text-gray-400">
|
||||
<p>{"Unknown size"}</p>
|
||||
<p>{format(new Date(file.uploaded_at), "MMM d, yyyy")}</p>
|
||||
<button className="px-3 py-1 bg-blue-500 text-white rounded-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-400">
|
||||
Select
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<p className="text-gray-500 dark:text-gray-400">No files uploaded yet.</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
66
src/lib/data/dataroomQuery.ts
Normal file
66
src/lib/data/dataroomQuery.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { Database } from "@/types/database.types";
|
||||
import { SupabaseClient } from "@supabase/supabase-js";
|
||||
|
||||
export const getFilesByDataroomId = (client: SupabaseClient<Database>, dataroomId: number) => {
|
||||
const query = client
|
||||
.from("dataroom_material")
|
||||
.select(
|
||||
`
|
||||
id,
|
||||
dataroom_id,
|
||||
file_url,
|
||||
file_type:material_file_type!inner (
|
||||
id,
|
||||
value
|
||||
),
|
||||
uploaded_at
|
||||
`
|
||||
)
|
||||
.eq("dataroom_id", dataroomId);
|
||||
return query;
|
||||
};
|
||||
|
||||
export const getDataRoomsByProjectId = (client: SupabaseClient, projectId: number) => {
|
||||
return client
|
||||
.from("dataroom")
|
||||
.select(
|
||||
`
|
||||
id,
|
||||
project_id,
|
||||
is_public,
|
||||
created_at,
|
||||
updated_at,
|
||||
dataroom_material (
|
||||
id,
|
||||
file_url,
|
||||
...file_type_id (
|
||||
file_type_id:id,
|
||||
file_type_value:value
|
||||
),
|
||||
uploaded_at
|
||||
)
|
||||
`
|
||||
)
|
||||
.eq("project_id", projectId);
|
||||
};
|
||||
|
||||
export const getAccessRequests = (client: SupabaseClient, filters: { dataroomId?: number; userId?: string }) => {
|
||||
let query = client.from("access_request").select(
|
||||
`
|
||||
id,
|
||||
user_id,
|
||||
status,
|
||||
requested_at
|
||||
`
|
||||
);
|
||||
|
||||
if (filters.dataroomId !== undefined) {
|
||||
query = query.eq("data_room_id", filters.dataroomId);
|
||||
}
|
||||
|
||||
if (filters.userId !== undefined) {
|
||||
query = query.eq("user_id", filters.userId);
|
||||
}
|
||||
|
||||
return query;
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user