Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: upload and list documents on a table format #119

Merged
merged 5 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const config = {
"@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
"@typescript-eslint/require-await": "off",
"@typescript-eslint/no-misused-promises": [
"error",
"warn",
{
checksVoidReturn: { attributes: false },
},
Expand Down
20 changes: 20 additions & 0 deletions prisma/migrations/20240213070600_create_document/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- CreateTable
CREATE TABLE "Document" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"type" TEXT NOT NULL,
"size" INTEGER NOT NULL,
"url" TEXT NOT NULL,
"companyId" TEXT NOT NULL,
"uploadedById" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "Document_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE INDEX "Document_companyId_idx" ON "Document"("companyId");

-- CreateIndex
CREATE INDEX "Document_uploadedById_idx" ON "Document"("uploadedById");
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
Warnings:

- You are about to drop the column `url` on the `Document` table. All the data in the column will be lost.
- Added the required column `key` to the `Document` table without a default value. This is not possible if the table is not empty.

*/
-- AlterTable
ALTER TABLE "Document" DROP COLUMN "url",
ADD COLUMN "key" TEXT NOT NULL;
33 changes: 27 additions & 6 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ model User {
accounts Account[]
sessions Session[]
companies Membership[]
documents Document[]
}

model WaitlistUser {
Expand Down Expand Up @@ -87,6 +88,7 @@ model Company {
audits Audit[]
shareClasses ShareClass[]
equityPlans EquityPlan[]
documents Document[]

@@unique([publicId])
}
Expand Down Expand Up @@ -116,10 +118,10 @@ model Membership {
updatedAt DateTime @updatedAt

userId String
user User @relation(fields: [userId], references: [id])
user User @relation(fields: [userId], references: [id], onDelete: Cascade)

companyId String
company Company @relation(fields: [companyId], references: [id])
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)

@@unique([companyId, userId])
@@index([companyId])
Expand All @@ -131,7 +133,7 @@ model Audit {
id String @id @default(cuid())

companyId String
company Company @relation(fields: [companyId], references: [id])
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)

summary String?

Expand Down Expand Up @@ -190,7 +192,7 @@ model ShareClass {
participationCapMultiple Float

companyId String
company Company @relation(fields: [companyId], references: [id])
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
equityPlans EquityPlan[]

createdAt DateTime @default(now())
Expand All @@ -217,13 +219,32 @@ model EquityPlan {
comments String?

companyId String
company Company @relation(fields: [companyId], references: [id])
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
shareClassId String
shareClass ShareClass @relation(fields: [shareClassId], references: [id])
shareClass ShareClass @relation(fields: [shareClassId], references: [id], onDelete: Cascade)

createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

@@index([shareClassId])
@@index([companyId])
}

model Document {
id String @id @default(cuid())
name String
type String
size Int
key String
companyId String
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)

uploadedById String?
uploadedBy User? @relation(fields: [uploadedById], references: [id], onDelete: Cascade)

createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

@@index([companyId])
@@index([uploadedById])
}
3 changes: 3 additions & 0 deletions prisma/seeds/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ const nuke = async () => {
await db.user.deleteMany();
await db.membership.deleteMany();
await db.company.deleteMany();
await db.shareClass.deleteMany();
await db.equityPlan.deleteMany();
await db.document.deleteMany();
await db.audit.deleteMany();
await db.session.deleteMany();
});
Expand Down
31 changes: 31 additions & 0 deletions src/app/(authenticated)/(dashboard)/[publicId]/documents/modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"use client";

import { useState } from "react";
import Modal from "@/components/shared/modal";
import Uploader from "@/components/ui/uploader";

type DocumentUploadModalProps = {
trigger: React.ReactNode;
};

const DocumentUploadModal = ({ trigger }: DocumentUploadModalProps) => {
const [open, setOpen] = useState(false);

return (
<Modal
title="Upload a document"
subtitle="Upload a document to your company's document library."
trigger={trigger}
dialogProps={{
open,
onOpenChange: (val) => {
setOpen(val);
},
}}
>
<Uploader setOpen={setOpen} />
</Modal>
);
};

export default DocumentUploadModal;
80 changes: 71 additions & 9 deletions src/app/(authenticated)/(dashboard)/[publicId]/documents/page.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,78 @@
import { db } from "@/server/db";
import DocumentsTable from "./table";
import DocumentUploadModal from "./modal";
import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { withServerSession } from "@/server/auth";
import type { Document, User } from "@prisma/client";
import EmptyState from "@/components/shared/empty-state";
import { RiUploadCloudLine } from "@remixicon/react";
import { RiUploadCloudLine, RiAddFill } from "@remixicon/react";

interface DocumentType extends Document {
uploadedBy: User | null;
}

const getDocuments = async (companyId: string) => {
return await db.document.findMany({
where: { companyId },
include: {
uploadedBy: true,
},
});
};

const DocumentsPage = async () => {
const session = await withServerSession();
const companyId = session?.user?.companyId;
const documents: DocumentType[] = await getDocuments(companyId);

if (documents.length === 0) {
return (
<EmptyState
icon={<RiUploadCloudLine />}
title="You do not have any documents!"
subtitle="Please click the button below to upload a new document."
>
<DocumentUploadModal
trigger={
<Button size="lg">
<RiAddFill className="mr-2 h-5 w-5" />
Upload a document
</Button>
}
/>
</EmptyState>
);
}

const DocumentsPage = () => {
return (
<EmptyState
icon={<RiUploadCloudLine />}
title="You do not have any documents yet."
subtitle="Please click the button below to upload a document!"
>
<Button size="lg">Upload a document</Button>
</EmptyState>
<div className="flex flex-col gap-y-3">
<div className="flex items-center justify-between gap-y-3 ">
<div className="gap-y-3">
<h3 className="font-medium">Documents</h3>
<p className="text-sm text-muted-foreground">
Templates, agreements, and other important documents
</p>
</div>

<div>
<DocumentUploadModal
trigger={
<Button>
<RiAddFill className="mr-2 h-5 w-5" />
Upload a document
</Button>
}
/>
</div>
</div>

<Card className="mt-3">
<div className="p-6">
<DocumentsTable documents={documents} />
</div>
</Card>
</div>
);
};

Expand Down
60 changes: 60 additions & 0 deletions src/app/(authenticated)/(dashboard)/[publicId]/documents/table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Card } from "@/components/ui/card";
import type { Document, User } from "@prisma/client";
import FileIcon from "@/components/shared/file-icon";
import { RiExpandRightLine } from "@remixicon/react";

import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";

interface DocumentType extends Document {
uploadedBy: User | null;
}

type DocumentTableProps = {
documents: DocumentType[];
};

const DocumentsTable = ({ documents }: DocumentTableProps) => {
return (
<Card>
<Table className="">
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Type</TableHead>
<TableHead>Uploaded</TableHead>
<TableHead>Owner</TableHead>
<TableHead></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{documents.map((document) => (
<TableRow key={document.id}>
<TableCell className="relative flex">
<FileIcon
type={document.type}
className="mr-2 inline-block h-5 w-5 text-muted-foreground"
/>
<span className="inline-block">{document.name}</span>
</TableCell>
<TableCell>{document.type}</TableCell>
<TableCell>{document.createdAt.toDateString()}</TableCell>
<TableCell>{document.uploadedBy?.name}</TableCell>
<TableCell>
<RiExpandRightLine className="cursor-pointer text-muted-foreground" />
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</Card>
);
};

export default DocumentsTable;
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ type EquityFormType = {

const EquityPlanForm = ({
setOpen,
className,
type = "create",
shareClasses,
equityPlan = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
import EquityPlanModal from "./modal";
import Tldr from "@/components/shared/tldr";
import { Card } from "@/components/ui/card";
import type { EquityPlan } from "@prisma/client";
const formatter = new Intl.NumberFormat("en-US");
import { RiEqualizer2Line } from "@remixicon/react";
import { type EquityPlanMutationType } from "@/trpc/routers/equity-plan/schema";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ type ShareClassFormType = {

const ShareClassForm = ({
setOpen,
className,
type = "create",
shareClasses,
shareClass = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import Link from "next/link";
import { db } from "@/server/db";
import ShareClassTable from "./table";
import ShareClassModal from "./modal";
Expand All @@ -10,20 +9,13 @@ import EmptyState from "@/components/shared/empty-state";
import { RiPieChart2Line, RiAddFill } from "@remixicon/react";
import { type ShareClassMutationType } from "@/trpc/routers/share-class/schema";

type SharesPageParams = {
params: {
publicId: string;
};
};

const getShareClasses = async (companyId: string) => {
return await db.shareClass.findMany({
where: { companyId },
});
};

const SharesPage = async ({ params }: SharesPageParams) => {
const { publicId } = params;
const SharesPage = async () => {
const session = await withServerSession();
const companyId = session?.user?.companyId;
let shareClasses: ShareClassMutationType[] = [];
Expand Down
7 changes: 4 additions & 3 deletions src/common/uploads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {
type getPresignedUrlOptions,
} from "@/server/file-uploads";

import { type DocumentMutationType } from "@/trpc/routers/document-router/schema";

/**
* usage
* ```js
Expand Down Expand Up @@ -43,7 +45,6 @@ export const uploadFile = async (
);
}

return {
uploadKey: key,
};
const { name, type, size } = file;
return { key, name, type, size } as DocumentMutationType;
};
1 change: 0 additions & 1 deletion src/components/dashboard/sidebar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import {
import { usePathname } from "next/navigation";
import { OpenCapLogo } from "@/components/shared/logo";

import Image from "next/image";
import { NavLink } from "./nav-link";
import { ScrollArea } from "@/components/ui/scroll-area";
import { cn } from "@/lib/utils";
Expand Down
Loading
Loading